diff --git a/README.md b/README.md
index b99417c3dd..8ae189435a 100644
--- a/README.md
+++ b/README.md
@@ -699,104 +699,124 @@ Type "help" for help.
(not connected)=> \?
General
- \q quit usql
- \copyright show usql usage and distribution terms
- \drivers display information about available database drivers
+ \q quit usql
+ \quit alias for \q
+ \copyright show usage and distribution terms for usql
+ \drivers show database drivers available to usql
-Query Execute
- \g [(OPTIONS)] [FILE] or ; execute query (and send results to file or |pipe)
- \go [(OPTIONS)] [FILE] alias for \g
- \G [(OPTIONS)] [FILE] as \g, but forces vertical output mode
- \ego [(OPTIONS)] [FILE] alias for \G
- \gx [(OPTIONS)] [FILE] as \g, but forces expanded output mode
- \gexec execute query and execute each value of the result
- \gset [PREFIX] execute query and store results in usql variables
- \crosstabview [(OPTIONS)] [COLUMNS] execute query and display results in crosstab
- \chart CHART [(OPTIONS)] execute query and display results as a chart
- \watch [(OPTIONS)] [DURATION] execute query every specified interval
- \bind [PARAM]... set query parameters
+Help
+ \? [commands] show help on usql's meta (backslash) commands
+ \? options show help on usql command-line options
+ \? variables show help on special usql variables
-Query Buffer
- \e [FILE] [LINE] edit the query buffer (or file) with external editor
- \edit [-exec] edit the query (or exec) buffer
- \p show the contents of the query buffer
- \raw show the raw (non-interpolated) contents of the query buffer
- \exec show the contents of the exec buffer
- \r reset (clear) the query buffer
- \w FILE write query buffer to file
+Connection
+ \c DSN or \c NAME connect to dsn or named database connection
+ \c DRIVER PARAMS... connect to database with driver and parameters
+ \connect alias for \c
+ \Z close (disconnect) database connection
+ \disconnect alias for \Z
+ \password [USER] change password for user
+ \passwd alias for \password
+ \conninfo display information about the current database connection
-Help
- \? [commands] show help on backslash commands
- \? options show help on usql command-line options
- \? variables show help on special usql variables
+Query Execute
+ \g [(OPTIONS)] [FILE] or ; execute query (and send results to file or |pipe)
+ \go alias for \g
+ \G [(OPTIONS)] [FILE] as \g, but forces vertical output mode
+ \ego alias for \G
+ \gx [(OPTIONS)] [FILE] as \g, but forces expanded output mode
+ \gexec execute query and execute each value of the result
+ \gset [PREFIX] execute query and store results in usql variables
+ \bind [PARAM]... set query parameters
+ \timing [on|off] toggle timing of commands
+
+Query View
+ \crosstab [(OPTIONS)] [COLUMNS] execute query and display results in crosstab
+ \crosstabview alias for \crosstab
+ \xtab alias for \crosstab
+ \chart CHART [(OPTIONS)] execute query and display results as a chart
+ \watch [(OPTIONS)] [INTERVAL] execute query every specified interval
-Input/Output
- \copy SRC DST QUERY TABLE copy query from source url to table on destination url
- \copy SRC DST QUERY TABLE(A,...) copy query from source url to columns of table on destination url
- \echo [-n] [STRING] write string to standard output (-n for no newline)
- \qecho [-n] [STRING] write string to \o output stream (-n for no newline)
- \warn [-n] [STRING] write string to standard error (-n for no newline)
- \o [FILE] send all query results to file or |pipe
- \i FILE execute commands from file
- \ir FILE as \i, but relative to location of current script
-
-Conditional
- \if EXPR begin conditional block
- \elif EXPR alternative within current conditional block
- \else final alternative within current conditional block
- \endif end conditional block
+Query Buffer
+ \e [-raw|-exec] [FILE] [LINE] edit the query buffer, raw (non-interpolated) buffer, the
+ exec buffer, or a file with external editor
+ \edit alias for \e
+ \p [-raw|-exec] show the contents of the query buffer, the raw
+ (non-interpolated) buffer or the exec buffer
+ \print alias for \p
+ \raw alias for \p
+ \exec alias for \p
+ \w [-raw|-exec] FILE write the contents of the query buffer, raw
+ (non-interpolated) buffer, or exec buffer to file
+ \write alias for \w
+ \r reset (clear) the query buffer
+ \reset alias for \r
Informational
- \d[S+] [NAME] list tables, views, and sequences or describe table, view, sequence, or index
- \da[S+] [PATTERN] list aggregates
- \df[S+] [PATTERN] list functions
- \di[S+] [PATTERN] list indexes
- \dm[S+] [PATTERN] list materialized views
- \dn[S+] [PATTERN] list schemas
- \dp[S] [PATTERN] list table, view, and sequence access privileges
- \ds[S+] [PATTERN] list sequences
- \dt[S+] [PATTERN] list tables
- \dv[S+] [PATTERN] list views
- \l[+] list databases
- \ss[+] [TABLE|QUERY] [k] show stats for a table or a query
-
-Formatting
- \pset [NAME [VALUE]] set table output option
- \a toggle between unaligned and aligned output mode
- \C [STRING] set table title, or unset if none
- \f [STRING] show or set field separator for unaligned query output
- \H toggle HTML output mode
- \T [STRING] set HTML
tag attributes, or unset if none
- \t [on|off] show only rows
- \x [on|off|auto] toggle expanded output
+ \d[S+] [NAME] list tables, views, and sequences or describe table, view,
+ sequence, or index
+ \da[S+] [PATTERN] list aggregates
+ \df[S+] [PATTERN] list functions
+ \di[S+] [PATTERN] list indexes
+ \dm[S+] [PATTERN] list materialized views
+ \dn[S+] [PATTERN] list schemas
+ \dp[S] [PATTERN] list table, view, and sequence access privileges
+ \ds[S+] [PATTERN] list sequences
+ \dt[S+] [PATTERN] list tables
+ \dv[S+] [PATTERN] list views
+ \l[+] list databases
+ \ss[+] [TABLE|QUERY] [k] show stats for a table or a query
-Transaction
- \begin begin a transaction
- \begin -read-only ISOLATION begin a transaction with isolation level
- \commit commit current transaction
- \rollback rollback (abort) current transaction
+Variables
+ \set [NAME [VALUE]] set usql application variable, or show all usql application
+ variables if no parameters
+ \unset NAME unset (delete) usql application variable
+ \pset [NAME [VALUE]] set table print formatting option, or show all print
+ formatting options if no parameters
+ \a toggle between unaligned and aligned output mode
+ \C [TITLE] set table title, or unset if none
+ \f [SEPARATOR] show or set field separator for unaligned query output
+ \H toggle HTML output mode
+ \T [ATTRIBUTES] set HTML tag attributes, or unset if none
+ \t [on|off] show only rows
+ \x [on|off|auto] toggle expanded output
+ \cset [NAME [URL]] set named connection, or show all named connections if no
+ parameters
+ \cset NAME DRIVER PARAMS... set named connection for driver and parameters
+ \prompt [-TYPE] VAR [PROMPT] prompt user to set application variable
-Connection
- \c DSN connect to database url
- \c DRIVER PARAMS... connect to database with driver and parameters
- \cset show named connections
- \cset NAME DSN set named connection
- \cset NAME DRIVER PARAMS... define named connection for database driver
- \Z close database connection
- \password [USER] change password for user
- \conninfo display information about the current database connection
-
-Operating System
- \cd [DIR] change the current working directory
- \getenv VARNAME ENVVAR fetch environment variable
- \setenv NAME [VALUE] set or unset environment variable
- \! [COMMAND] execute command in shell or start interactive shell
- \timing [on|off] toggle timing of commands
+Input/Output
+ \echo [-n] [MESSAGE]... write message to standard output (-n for no newline)
+ \qecho [-n] [MESSAGE]... write message to \o output stream (-n for no newline)
+ \warn [-n] [MESSAGE]... write message to standard error (-n for no newline)
+ \o [FILE] send all query results to file or |pipe
+ \out alias for \o
+ \copy SRC DST QUERY TABLE copy results of query from source database into table on
+ destination database
+ \copy SRC DST QUERY TABLE(A,...) copy results of query from source database into table's
+ columns on destination database
+
+Control/Conditional
+ \i FILE execute commands from file
+ \include alias for \i
+ \ir FILE as \i, but relative to location of current script
+ \include_relative alias for \ir
+ \if EXPR begin conditional block
+ \elif EXPR alternative within current conditional block
+ \else final alternative within current conditional block
+ \endif end conditional block
-Variables
- \prompt [-TYPE] VAR [PROMPT] prompt user to set variable
- \set [NAME [VALUE]] set internal variable, or list all if no parameters
- \unset NAME unset (delete) internal variable
+Transaction
+ \begin [-read-only [ISOLATION]] begin transaction, with optional isolation level
+ \commit commit current transaction
+ \rollback rollback (abort) current transaction
+ \abort alias for \rollback
+
+Operating System/Environment
+ \! [COMMAND] execute command in shell or start interactive shell
+ \cd [DIR] change the current working directory
+ \getenv VARNAME ENVVAR fetch environment variable
+ \setenv NAME [VALUE] set or unset environment variable
```
Parameters passed to commands [can be backticked][backticks].
diff --git a/env/list.go b/env/list.go
index b5e2a246b2..ee6f857da4 100644
--- a/env/list.go
+++ b/env/list.go
@@ -16,7 +16,7 @@ import (
// Listing writes a formatted listing of the special environment variables to
// w, separated in sections based on variable type.
-func Listing(w io.Writer) {
+func Listing(w io.Writer) error {
varsWithDesc := make([]string, len(varNames))
for i, v := range varNames {
varsWithDesc[i] = v.String()
@@ -48,39 +48,9 @@ func Listing(w io.Writer) {
if configExtra != "" {
configExtra = " (" + configExtra + ")"
}
-
- template := `List of specially treated variables
-
-%s variables:
-Usage:
- %[1]s --set=NAME=VALUE
- or \set NAME VALUE inside %[1]s
-
-%[2]s
-
-Display settings:
-Usage:
- %[1]s --pset=NAME[=VALUE]
- or \pset NAME [VALUE] inside %[1]s
-
-%[3]s
-
-Environment variables:
-Usage:
- NAME=VALUE [NAME=VALUE] %[1]s ...
- or \setenv NAME [VALUE] inside %[1]s
-
-%[4]s
-
-Connection variables:
-Usage:
- %[1]s --cset NAME[=DSN]
- or \cset NAME [DSN] inside %[1]s
- or \cset NAME DRIVER PARAMS... inside %[1]s
- or define in %[5]s%[6]s
-`
fmt.Fprintf(
- w, template,
+ w,
+ variableTpl,
text.CommandName,
strings.TrimRightFunc(strings.Join(varsWithDesc, ""), unicode.IsSpace),
strings.TrimRightFunc(strings.Join(pvarsWithDesc, ""), unicode.IsSpace),
@@ -88,6 +58,7 @@ Usage:
configDir,
configExtra,
)
+ return nil
}
func buildConfigDir(configName string) (string, string) {
@@ -295,3 +266,34 @@ var envVarNames = []varName{
`shell used by the \! command`,
},
}
+
+const variableTpl = `List of specially treated variables
+
+%s variables:
+Usage:
+ %[1]s --set=NAME=VALUE
+ or \set NAME VALUE inside %[1]s
+
+%[2]s
+
+Display settings:
+Usage:
+ %[1]s --pset=NAME[=VALUE]
+ or \pset NAME [VALUE] inside %[1]s
+
+%[3]s
+
+Environment variables:
+Usage:
+ NAME=VALUE [NAME=VALUE] %[1]s ...
+ or \setenv NAME [VALUE] inside %[1]s
+
+%[4]s
+
+Connection variables:
+Usage:
+ %[1]s --cset NAME[=DSN]
+ or \cset NAME [DSN] inside %[1]s
+ or \cset NAME DRIVER PARAMS... inside %[1]s
+ or define in %[5]s%[6]s
+`
diff --git a/gen.go b/gen.go
index 21c18da464..51ba0656da 100644
--- a/gen.go
+++ b/gen.go
@@ -365,42 +365,42 @@ func parseDriverInfo(tag, filename string) (DriverInfo, error) {
// desc is a meta command description.
type desc struct {
- Name string
- Params string
- Desc string
- Func string
- Hidden bool
- Alias string
+ Func string
+ Name string
+ Params string
+ Desc string
+ Hidden bool
+ Deprecated bool
}
func newDesc(funcName, alias string, v []string) desc {
- name, params, descstr := v[0], "", ""
- switch len(v) {
- case 1:
+ name, params, descstr, hidden := v[0], "", "", false
+ switch n := len(v); {
+ case n == 1:
if i := strings.Index(name, ":"); i != -1 {
name, alias = name[:i], name[i+1:]
}
- case 2:
+ case n == 2:
descstr = v[1]
- case 3:
+ case n >= 3:
params, descstr = v[1], v[2]
}
+ if descstr == "" {
+ hidden, descstr = true, `alias for \`+alias
+ }
return desc{
- Name: name,
- Params: params,
- Desc: descstr,
- Func: funcName,
- Alias: alias,
+ Func: funcName,
+ Name: name,
+ Params: params,
+ Desc: descstr,
+ Hidden: hidden,
+ Deprecated: v[len(v)-1] == "DEPRECATED",
}
}
func (d desc) String() string {
- if d.Desc != "" {
- s := strings.ReplaceAll(fmt.Sprintf("%q", d.Desc), "{{CommandName}}", `" + text.CommandName + "`)
- return fmt.Sprintf("{%q, %q, %s, %s, %t}", d.Name, d.Params, s, d.Func, false)
- }
- s := `alias for \` + d.Alias
- return fmt.Sprintf("{%q, %q, %q, %s, %t}", d.Name, d.Params, s, d.Func, true)
+ s := strings.ReplaceAll(d.Desc, "{{CommandName}}", "` + text.CommandName + `")
+ return fmt.Sprintf("{%s, `%s`, `%s`, `%s`, %t, %t}", d.Func, d.Name, d.Params, s, d.Hidden, d.Deprecated)
}
func findCommand(name string) string {
@@ -647,17 +647,16 @@ var baseOrder = map[string]int{
var sections = []string{
"General",
"Help",
+ "Connection",
"Query Execute",
- //"Query View",
+ "Query View",
"Query Buffer",
"Informational",
"Variables",
- "Connection",
- "Conditional",
"Input/Output",
+ "Control/Conditional",
"Transaction",
"Operating System/Environment",
- //"Formatting",
}
// regexps.
diff --git a/metacmd/cmds.go b/metacmd/cmds.go
index 8989d999c4..444876082a 100644
--- a/metacmd/cmds.go
+++ b/metacmd/cmds.go
@@ -20,44 +20,6 @@ import (
"github.com/xo/usql/text"
)
-// Question is a Help meta command (\?). Writes a help message to the output.
-//
-// Descs:
-//
-// ? [commands] show help on meta (backslash) commands
-// ? options show help on {{CommandName}} command-line options
-// ? variables show help on special {{CommandName}} variables
-func Question(p *Params) error {
- name, err := p.Next(false)
- if err != nil {
- return err
- }
- stdout, stderr := p.Handler.IO().Stdout(), p.Handler.IO().Stderr()
- var cmd *exec.Cmd
- var wc io.WriteCloser
- if pager := env.Get("PAGER"); p.Handler.IO().Interactive() && pager != "" {
- if wc, cmd, err = env.Pipe(stdout, stderr, pager); err != nil {
- return err
- }
- stdout = wc
- }
- switch name = strings.TrimSpace(strings.ToLower(name)); {
- case name == "options":
- text.Usage(stdout, true)
- case name == "variables":
- env.Listing(stdout)
- default:
- Dump(stdout, name == "commands")
- }
- if cmd != nil {
- if err := wc.Close(); err != nil {
- return err
- }
- return cmd.Wait()
- }
- return nil
-}
-
// Quit is a General meta command (\q \quit). Quits the application.
//
// Descs:
@@ -74,7 +36,7 @@ func Quit(p *Params) error {
//
// Descs:
//
-// copyright show {{CommandName}} usage and distribution terms
+// copyright show usage and distribution terms for {{CommandName}}
func Copyright(p *Params) error {
stdout := p.Handler.IO().Stdout()
if typ := env.TermGraphics(); typ.Available() {
@@ -84,159 +46,12 @@ func Copyright(p *Params) error {
return nil
}
-// Connect is a Connection meta command (\c, \connect). Opens (connects) a
-// database connection.
-//
-// Descs:
-//
-// c URL connect to database URL
-// c DRIVER PARAMS... connect to database with driver and parameters
-// connect
-func Connect(p *Params) error {
- vals, err := p.All(true)
- if err != nil {
- return err
- }
- ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
- defer cancel()
- return p.Handler.Open(ctx, vals...)
-}
-
-// SetConn is a Connection meta command (\cset). Sets a connection variable.
-//
-// Descs:
-//
-// cset show named connections
-// cset NAME URL set named connection to URL
-// cset NAME DRIVER PARAMS... set named connection for database driver and parameters
-func SetConn(p *Params) error {
- switch n, ok, err := p.NextOK(true); {
- case err != nil:
- return err
- case ok:
- vals, err := p.All(true)
- if err != nil {
- return err
- }
- return env.Vars().SetConn(n, vals...)
- }
- return env.Vars().DumpConn(p.Handler.IO().Stdout())
-}
-
-// Copy is a Input/Output meta command (\copy). Copies data between databases.
-//
-// Descs:
-//
-// copy SRC DST QUERY TABLE copy query from source url to table on destination url
-// copy SRC DST QUERY TABLE(A,...) copy query from source url to columns of table on destination url
-func Copy(p *Params) error {
- ctx := context.Background()
- stdout, stderr := p.Handler.IO().Stdout, p.Handler.IO().Stderr
- srcDsn, err := p.Next(true)
- if err != nil {
- return err
- }
- srcURL, err := dburl.Parse(srcDsn)
- if err != nil {
- return err
- }
- destDsn, err := p.Next(true)
- if err != nil {
- return err
- }
- destURL, err := dburl.Parse(destDsn)
- if err != nil {
- return err
- }
- query, err := p.Next(true)
- if err != nil {
- return err
- }
- table, err := p.Next(true)
- if err != nil {
- return err
- }
- src, err := drivers.Open(ctx, srcURL, stdout, stderr)
- if err != nil {
- return err
- }
- defer src.Close()
- dest, err := drivers.Open(ctx, destURL, stdout, stderr)
- if err != nil {
- return err
- }
- defer dest.Close()
- ctx, cancel := signal.NotifyContext(ctx, os.Interrupt)
- defer cancel()
- // get the result set
- r, err := src.QueryContext(ctx, query)
- if err != nil {
- return err
- }
- defer r.Close()
- n, err := drivers.Copy(ctx, destURL, stdout, stderr, r, table)
- if err != nil {
- return err
- }
- p.Handler.Print("COPY %d", n)
- return nil
-}
-
-// Disconnect is a Connection meta command (\Z). Closes (disconnects) the
-// current database connection.
-//
-// Descs:
-//
-// Z close database connection
-// disconnect
-func Disconnect(p *Params) error {
- return p.Handler.Close()
-}
-
-// Password is a Connection meta command (\password). Changes the database
-// user's password.
-//
-// Descs:
-//
-// password [USER] change password for user
-// passwd
-func Password(p *Params) error {
- username, err := p.Next(true)
- if err != nil {
- return err
- }
- user, err := p.Handler.ChangePassword(username)
- switch {
- case err == text.ErrPasswordNotSupportedByDriver || err == text.ErrNotConnected:
- return err
- case err != nil:
- return fmt.Errorf(text.PasswordChangeFailed, user, err)
- }
- // p.Handler.Print(text.PasswordChangeSucceeded, user)
- return nil
-}
-
-// ConnectionInfo is a Connection meta command (\conninfo). Writes information
-// about the connection to the output.
-//
-// Descs:
-//
-// conninfo display information about the current database connection
-func ConnectionInfo(p *Params) error {
- s := text.NotConnected
- if db, u := p.Handler.DB(), p.Handler.URL(); db != nil && u != nil {
- s = fmt.Sprintf(text.ConnInfo, u.Driver, u.DSN)
- }
- fmt.Fprintln(p.Handler.IO().Stdout(), s)
- return nil
-}
-
// Drivers is a General meta command (\drivers). Writes information about the
// database drivers the application was built with to the output.
//
// Descs:
//
-// drivers display information about available database drivers
+// drivers show database drivers available to {{CommandName}}
func Drivers(p *Params) error {
stdout, stderr := p.Handler.IO().Stdout(), p.Handler.IO().Stderr()
var cmd *exec.Cmd
@@ -264,9 +79,7 @@ func Drivers(p *Params) error {
s += " (" + driver + ")"
}
if len(aliases) > 0 {
- if len(aliases) > 0 {
- s += " [" + strings.Join(aliases, ", ") + "]"
- }
+ s += " [" + strings.Join(aliases, ", ") + "]"
}
fmt.Fprintln(stdout, s)
}
@@ -279,55 +92,40 @@ func Drivers(p *Params) error {
return nil
}
-// Describe is a Informational meta command (\d and variants). Queries the open
-// database connection for information about the database schema and writes the
-// information to the output.
+// Help is a Help meta command (\?). Writes a help message to the output.
//
// Descs:
//
-// d[S+] [NAME] list tables, views, and sequences or describe table, view, sequence, or index
-// da[S+] [PATTERN] list aggregates
-// df[S+] [PATTERN] list functions
-// di[S+] [PATTERN] list indexes
-// dm[S+] [PATTERN] list materialized views
-// dn[S+] [PATTERN] list schemas
-// dp[S] [PATTERN] list table, view, and sequence access privileges
-// ds[S+] [PATTERN] list sequences
-// dt[S+] [PATTERN] list tables
-// dv[S+] [PATTERN] list views
-// l[+] list databases
-func Describe(p *Params) error {
- ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
- defer cancel()
- m, err := p.Handler.MetadataWriter(ctx)
+// ? [commands] show help on {{CommandName}}'s meta (backslash) commands
+// ? options show help on {{CommandName}} command-line options
+// ? variables show help on special {{CommandName}} variables
+func Help(p *Params) error {
+ name, err := p.Next(false)
if err != nil {
return err
}
- verbose := strings.ContainsRune(p.Name, '+')
- showSystem := strings.ContainsRune(p.Name, 'S')
- name := strings.TrimRight(p.Name, "S+")
- pattern, err := p.Next(true)
- if err != nil {
- return err
+ stdout, stderr := p.Handler.IO().Stdout(), p.Handler.IO().Stderr()
+ var cmd *exec.Cmd
+ var wc io.WriteCloser
+ if pager := env.Get("PAGER"); p.Handler.IO().Interactive() && pager != "" {
+ if wc, cmd, err = env.Pipe(stdout, stderr, pager); err != nil {
+ return err
+ }
+ stdout = wc
}
- switch name {
- case "d":
- if pattern != "" {
- return m.DescribeTableDetails(p.Handler.URL(), pattern, verbose, showSystem)
+ switch name = strings.TrimSpace(strings.ToLower(name)); {
+ case name == "options":
+ text.Usage(stdout, true)
+ case name == "variables":
+ _ = env.Listing(stdout)
+ default:
+ _ = Dump(stdout, name == "commands")
+ }
+ if cmd != nil {
+ if err := wc.Close(); err != nil {
+ return err
}
- return m.ListTables(p.Handler.URL(), "tvmsE", pattern, verbose, showSystem)
- case "df", "da":
- return m.DescribeFunctions(p.Handler.URL(), name, pattern, verbose, showSystem)
- case "dt", "dtv", "dtm", "dts", "dv", "dm", "ds":
- return m.ListTables(p.Handler.URL(), name, pattern, verbose, showSystem)
- case "dn":
- return m.ListSchemas(p.Handler.URL(), pattern, verbose, showSystem)
- case "di":
- return m.ListIndexes(p.Handler.URL(), pattern, verbose, showSystem)
- case "l":
- return m.ListAllDbs(p.Handler.URL(), pattern, verbose)
- case "dp":
- return m.ListPrivilegeSummaries(p.Handler.URL(), pattern, showSystem)
+ return cmd.Wait()
}
return nil
}
@@ -344,18 +142,17 @@ func Describe(p *Params) error {
// gx [(OPTIONS)] [FILE] as \g, but forces expanded output mode
// gexec execute query and execute each value of the result
// gset [PREFIX] execute query and store results in {{CommandName}} variables
-// crosstabview [(OPTIONS)] [COLUMNS] execute query and display results in crosstab
-// chart CHART [(OPTIONS)] execute query and display results as a chart
-// watch [(OPTIONS)] [DURATION] execute query every specified interval
func Execute(p *Params) error {
p.Option.Exec = ExecOnly
switch p.Name {
case "g", "go", "G", "ego", "gx", "gset":
params, err := p.All(true)
- if err != nil {
+ switch {
+ case err != nil:
return err
+ case p.Name != "gset":
+ p.Option.ParseParams(params, "pipe")
}
- p.Option.ParseParams(params, "pipe")
switch p.Name {
case "G", "ego":
p.Option.Params["format"] = "vertical"
@@ -363,65 +160,10 @@ func Execute(p *Params) error {
p.Option.Params["expanded"] = "on"
case "gset":
p.Option.Exec = ExecSet
+ p.Option.ParseParams(params, "prefix")
}
case "gexec":
p.Option.Exec = ExecExec
- case "crosstabview":
- p.Option.Exec = ExecCrosstab
- for i := 0; i < 4; i++ {
- col, ok, err := p.NextOK(true)
- if err != nil {
- return err
- }
- p.Option.Crosstab = append(p.Option.Crosstab, col)
- if !ok {
- break
- }
- }
- case "chart":
- p.Option.Exec = ExecChart
- if p.Option.Params == nil {
- p.Option.Params = make(map[string]string, 1)
- }
- params, err := p.All(true)
- if err != nil {
- return err
- }
- for i := 0; i < len(params); i++ {
- param := params[i]
- if param == "help" {
- p.Option.Params["help"] = ""
- return nil
- }
- equal := strings.IndexByte(param, '=')
- switch {
- case equal == -1 && i >= len(params)-1:
- return text.ErrWrongNumberOfArguments
- case equal == -1:
- i++
- p.Option.Params[param] = params[i]
- default:
- p.Option.Params[param[:equal]] = param[equal+1:]
- }
- }
- case "watch":
- p.Option.Exec = ExecWatch
- p.Option.Watch = 2 * time.Second
- switch s, ok, err := p.NextOK(true); {
- case err != nil:
- return err
- case ok:
- d, err := time.ParseDuration(s)
- if err != nil {
- if f, err := strconv.ParseFloat(s, 64); err == nil {
- d = time.Duration(f * float64(time.Second))
- }
- }
- if d == 0 {
- return text.ErrInvalidWatchDuration
- }
- p.Option.Watch = d
- }
}
return nil
}
@@ -440,7 +182,7 @@ func Bind(p *Params) error {
var v []interface{}
if n := len(bind); n != 0 {
v = make([]interface{}, len(bind))
- for i := 0; i < n; i++ {
+ for i := range n {
v[i] = bind[i]
}
}
@@ -448,13 +190,199 @@ func Bind(p *Params) error {
return nil
}
+// Timing is a Query Execute meta command (\timing). Sets (or toggles) writing
+// timing information for executed queries to the output.
+//
+// Descs:
+//
+// timing [on|off] toggle timing of commands
+func Timing(p *Params) error {
+ v, err := p.Next(true)
+ switch {
+ case err != nil:
+ return err
+ case v == "":
+ p.Handler.SetTiming(!p.Handler.GetTiming())
+ default:
+ s, err := env.ParseBool(v, `\timing`)
+ if err != nil {
+ stderr := p.Handler.IO().Stderr()
+ fmt.Fprintf(stderr, "error: %v", err)
+ fmt.Fprintln(stderr)
+ }
+ var b bool
+ if s == "on" {
+ b = true
+ }
+ p.Handler.SetTiming(b)
+ }
+ setting := "off"
+ if p.Handler.GetTiming() {
+ setting = "on"
+ }
+ p.Handler.Print(text.TimingSet, setting)
+ return nil
+}
+
+// Crosstab is a Query View meta command (\crosstab). Executes the active query
+// on the open database connection and displays results in a crosstab view.
+//
+// Descs:
+//
+// crosstab [(OPTIONS)] [COLUMNS] execute query and display results in crosstab
+// crosstabview
+// xtab
+func Crosstab(p *Params) error {
+ p.Option.Exec = ExecCrosstab
+ for i := 0; i < 4; i++ {
+ col, ok, err := p.NextOK(true)
+ if err != nil {
+ return err
+ }
+ p.Option.Crosstab = append(p.Option.Crosstab, col)
+ if !ok {
+ break
+ }
+ }
+ return nil
+}
+
+// Chart is a Query View meta command (\chart). Executes the active query on
+// the open database connection and displays results in a chart view.
+//
+// Descs:
+//
+// chart CHART [(OPTIONS)] execute query and display results as a chart
+func Chart(p *Params) error {
+ p.Option.Exec = ExecChart
+ if p.Option.Params == nil {
+ p.Option.Params = make(map[string]string, 1)
+ }
+ params, err := p.All(true)
+ if err != nil {
+ return err
+ }
+ for i := 0; i < len(params); i++ {
+ param := params[i]
+ if param == "help" {
+ p.Option.Params["help"] = ""
+ return nil
+ }
+ equal := strings.IndexByte(param, '=')
+ switch {
+ case equal == -1 && i >= len(params)-1:
+ return text.ErrWrongNumberOfArguments
+ case equal == -1:
+ i++
+ p.Option.Params[param] = params[i]
+ default:
+ p.Option.Params[param[:equal]] = param[equal+1:]
+ }
+ }
+ return nil
+}
+
+// Watch is a Query View meta command (\watch). Executes (and re-executes) the
+// active query on the open database connection until canceled by the user.
+//
+// Descs:
+//
+// watch [(OPTIONS)] [INTERVAL] execute query every specified interval
+func Watch(p *Params) error {
+ p.Option.Exec = ExecWatch
+ p.Option.Watch = 2 * time.Second
+ switch s, ok, err := p.NextOK(true); {
+ case err != nil:
+ return err
+ case ok:
+ d, err := time.ParseDuration(s)
+ if err != nil {
+ if f, err := strconv.ParseFloat(s, 64); err == nil {
+ d = time.Duration(f * float64(time.Second))
+ }
+ }
+ if d == 0 {
+ return text.ErrInvalidWatchDuration
+ }
+ p.Option.Watch = d
+ }
+ return nil
+}
+
+// Connect is a Connection meta command (\c, \connect). Opens (connects) a
+// database connection.
+//
+// Descs:
+//
+// c DSN or \c NAME connect to dsn or named database connection
+// c DRIVER PARAMS... connect to database with driver and parameters
+// connect
+func Connect(p *Params) error {
+ vals, err := p.All(true)
+ if err != nil {
+ return err
+ }
+ ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
+ defer cancel()
+ return p.Handler.Open(ctx, vals...)
+}
+
+// Disconnect is a Connection meta command (\Z). Closes (disconnects) the
+// current database connection.
+//
+// Descs:
+//
+// Z close (disconnect) database connection
+// disconnect
+func Disconnect(p *Params) error {
+ return p.Handler.Close()
+}
+
+// Password is a Connection meta command (\password). Changes the database
+// user's password.
+//
+// Descs:
+//
+// password [USER] change password for user
+// passwd
+func Password(p *Params) error {
+ username, err := p.Next(true)
+ if err != nil {
+ return err
+ }
+ user, err := p.Handler.ChangePassword(username)
+ switch {
+ case err == text.ErrPasswordNotSupportedByDriver || err == text.ErrNotConnected:
+ return err
+ case err != nil:
+ return fmt.Errorf(text.PasswordChangeFailed, user, err)
+ }
+ // p.Handler.Print(text.PasswordChangeSucceeded, user)
+ return nil
+}
+
+// ConnectionInfo is a Connection meta command (\conninfo). Writes information
+// about the connection to the output.
+//
+// Descs:
+//
+// conninfo display information about the current database connection
+func ConnectionInfo(p *Params) error {
+ s := text.NotConnected
+ if db, u := p.Handler.DB(), p.Handler.URL(); db != nil && u != nil {
+ s = fmt.Sprintf(text.ConnInfo, u.Driver, u.DSN)
+ }
+ fmt.Fprintln(p.Handler.IO().Stdout(), s)
+ return nil
+}
+
// Edit is a Query Buffer meta command (\e \edit). Opens the query buffer for
// editing in an external application.
//
// Descs:
//
-// e [FILE] [LINE] edit the query buffer (or file) with external editor
-// edit [-exec] edit the query (or exec) buffer
+// e [-raw|-exec] [FILE] [LINE] edit the query buffer, raw (non-interpolated) buffer, the exec buffer, or a file with external editor
+// edit
func Edit(p *Params) error {
var exec bool
path, ok, err := p.NextOpt(true)
@@ -499,10 +427,10 @@ func Edit(p *Params) error {
//
// Descs:
//
-// p show the contents of the query buffer
+// p [-raw|-exec] show the contents of the query buffer, the raw (non-interpolated) buffer or the exec buffer
// print
-// raw show the raw (non-interpolated) contents of the query buffer
-// exec show the contents of the exec buffer
+// raw
+// exec
func Print(p *Params) error {
// get last statement
var s string
@@ -533,6 +461,26 @@ func Print(p *Params) error {
return nil
}
+// Write is a Query Buffer meta command (\w \write). Writes the query buffer to
+// a file.
+//
+// Descs:
+//
+// w [-raw|-exec] FILE write the contents of the query buffer, raw (non-interpolated) buffer, or exec buffer to file
+// write
+func Write(p *Params) error {
+ // get last statement
+ s, buf := p.Handler.LastExec(), p.Handler.Buf()
+ if buf.Len != 0 {
+ s = buf.String()
+ }
+ name, err := p.Next(true)
+ if err != nil {
+ return err
+ }
+ return os.WriteFile(name, []byte(strings.TrimSuffix(s, "\n")+"\n"), 0o644)
+}
+
// Reset is a Query Buffer meta command (\r, \reset). Clears (resets) the query
// buffer.
//
@@ -584,127 +532,97 @@ func Echo(p *Params) error {
return nil
}
-// Write is a Query Buffer meta command (\w \write). Writes the query buffer to
-// a file.
+// Out is a Input/Output meta command (\o \out). Sets (redirects) the output to
+// a file or a command.
//
// Descs:
//
-// w FILE write query buffer to file
-// write
-func Write(p *Params) error {
- // get last statement
- s, buf := p.Handler.LastExec(), p.Handler.Buf()
- if buf.Len != 0 {
- s = buf.String()
+// o [FILE] send all query results to file or |pipe
+// out
+func Out(p *Params) error {
+ p.Handler.SetOutput(nil)
+ params, err := p.All(true)
+ if err != nil {
+ return err
+ }
+ pipe := strings.Join(params, " ")
+ if pipe == "" {
+ return nil
+ }
+ var out io.WriteCloser
+ if pipe[0] == '|' {
+ out, _, err = env.Pipe(p.Handler.IO().Stdout(), p.Handler.IO().Stderr(), pipe[1:])
+ } else {
+ out, err = os.OpenFile(pipe, os.O_TRUNC|os.O_CREATE|os.O_WRONLY, 0o644)
}
- name, err := p.Next(true)
if err != nil {
return err
}
- return os.WriteFile(name, []byte(strings.TrimSuffix(s, "\n")+"\n"), 0o644)
+ p.Handler.SetOutput(out)
+ return nil
}
-// Chdir is a Operating System/Environment meta command (\cd). Changes the
-// current directory for the Operating System/Environment.
+// Copy is a Input/Output meta command (\copy). Copies data between databases.
//
// Descs:
//
-// cd [DIR] change the current working directory
-func Chdir(p *Params) error {
- dir, err := p.Next(true)
+// copy SRC DST QUERY TABLE copy results of query from source database into table on destination database
+// copy SRC DST QUERY TABLE(A,...) copy results of query from source database into table's columns on destination database
+func Copy(p *Params) error {
+ srcstr, err := p.Next(true)
if err != nil {
return err
}
- return env.Chdir(p.Handler.User(), dir)
-}
-
-// Getenv is a Operating System/Environment meta command (\getenv). Sets the
-// application's variable value returned from the Operating
-// System/Environment's variables.
-//
-// Descs:
-//
-// getenv VARNAME ENVVAR fetch environment variable
-func Getenv(p *Params) error {
- n, err := p.Next(true)
- switch {
- case err != nil:
+ src, err := dburl.Parse(srcstr)
+ if err != nil {
return err
- case n == "":
- return text.ErrMissingRequiredArgument
}
- v, err := p.Next(true)
- switch {
- case err != nil:
+ deststr, err := p.Next(true)
+ if err != nil {
return err
- case v == "":
- return text.ErrMissingRequiredArgument
}
- value, _ := env.Getenv(v)
- return env.Vars().Set(n, value)
-}
-
-// Setenv is a Operating System/Environment meta command (\setenv). Sets (or
-// unsets) a Operating System/Environment variable. Environment variables set
-// this way will be passed to any child processes.
-//
-// Descs:
-//
-// setenv NAME [VALUE] set or unset environment variable
-func Setenv(p *Params) error {
- n, err := p.Next(true)
+ dest, err := dburl.Parse(deststr)
+ if err != nil {
+ return err
+ }
+ query, err := p.Next(true)
+ if err != nil {
+ return err
+ }
+ table, err := p.Next(true)
+ if err != nil {
+ return err
+ }
+ ctx := context.Background()
+ stdout, stderr := p.Handler.IO().Stdout, p.Handler.IO().Stderr
+ srcDb, err := drivers.Open(ctx, src, stdout, stderr)
if err != nil {
return err
}
- v, err := p.Next(true)
+ defer srcDb.Close()
+ destDb, err := drivers.Open(ctx, dest, stdout, stderr)
if err != nil {
return err
}
- return os.Setenv(n, v)
-}
-
-// Shell is a Operating System/Environment meta command (\!). Executes a
-// command using the Operating System/Environment's shell.
-//
-// Descs:
-//
-// ! [COMMAND] execute command in shell or start interactive shell
-func Shell(p *Params) error {
- return env.Shell(p.Raw())
-}
-
-// Out is a Input/Output meta command (\o \out). Sets (redirects) the output to
-// a file or a command.
-//
-// Descs:
-//
-// o [FILE] send all query results to file or |pipe
-// out
-func Out(p *Params) error {
- p.Handler.SetOutput(nil)
- params, err := p.All(true)
+ defer destDb.Close()
+ ctx, cancel := signal.NotifyContext(ctx, os.Interrupt)
+ defer cancel()
+ // get the result set
+ r, err := srcDb.QueryContext(ctx, query)
if err != nil {
return err
}
- pipe := strings.Join(params, " ")
- if pipe == "" {
- return nil
- }
- var out io.WriteCloser
- if pipe[0] == '|' {
- out, _, err = env.Pipe(p.Handler.IO().Stdout(), p.Handler.IO().Stderr(), pipe[1:])
- } else {
- out, err = os.OpenFile(pipe, os.O_TRUNC|os.O_CREATE|os.O_WRONLY, 0o644)
- }
+ defer r.Close()
+ n, err := drivers.Copy(ctx, dest, stdout, stderr, r, table)
if err != nil {
return err
}
- p.Handler.SetOutput(out)
+ p.Handler.Print("COPY %d", n)
return nil
}
-// Include is a Input/Output meta command (\i, \include and variants). Includes
-// (runs) the specified file in the current execution environment.
+// Include is a Control/Conditional meta command (\i, \include and variants).
+// Includes (runs) the specified file in the current execution environment.
//
// Descs:
//
@@ -725,13 +643,12 @@ func Include(p *Params) error {
}
// Transact is a Transaction meta command (\begin, \commit, \rollback). Begins,
-// commits, or rollsback the current database transaction on the open database
-// connection.
+// commits, or aborts (rollback) the current database transaction on the open
+// database connection.
//
// Descs:
//
-// begin begin a transaction
-// begin -read-only ISOLATION begin a transaction with isolation level
+// begin [-read-only [ISOLATION]] begin transaction, with optional isolation level
// commit commit current transaction
// rollback rollback (abort) current transaction
// abort:rollback
@@ -786,47 +703,11 @@ func Transact(p *Params) error {
return p.Handler.Begin(txOpts)
}
-// Prompt is a Variables meta command (\prompt). Prompts the user for input,
-// setting a application variable to the user's response.
-//
-// Descs:
-//
-// prompt [-TYPE] VAR [PROMPT] prompt user to set variable
-func Prompt(p *Params) error {
- typ := "string"
- n, ok, err := p.NextOpt(true)
- if err != nil {
- return err
- }
- if ok {
- typ = n
- n, err = p.Next(true)
- if err != nil {
- return err
- }
- }
- if n == "" {
- return text.ErrMissingRequiredArgument
- }
- if err := env.ValidIdentifier(n); err != nil {
- return err
- }
- vals, err := p.All(true)
- if err != nil {
- return err
- }
- v, err := p.Handler.ReadVar(typ, strings.Join(vals, " "))
- if err != nil {
- return err
- }
- return env.Vars().Set(n, v)
-}
-
-// Set is a Variables meta command (\set). Sets (or lists) the application variables.
+// Set is a Variables meta command (\set). Sets (or shows) the application variables.
//
// Descs:
//
-// set [NAME [VALUE]] set internal variable, or list all if no parameters
+// set [NAME [VALUE]] set {{CommandName}} application variable, or show all {{CommandName}} application variables if no parameters
func Set(p *Params) error {
switch n, ok, err := p.NextOK(true); {
case err != nil:
@@ -845,7 +726,7 @@ func Set(p *Params) error {
//
// Descs:
//
-// unset NAME unset (delete) internal variable
+// unset NAME unset (delete) {{CommandName}} application variable
func Unset(p *Params) error {
n, err := p.Next(true)
if err != nil {
@@ -859,14 +740,14 @@ func Unset(p *Params) error {
//
// Descs:
//
-// pset [NAME [VALUE]] set table output option
-// a toggle between unaligned and aligned output mode
-// C [TITLE] set table title, or unset if none
-// f [SEPARATOR] show or set field separator for unaligned query output
-// H toggle HTML output mode
-// T [ATTRIBUTES] set HTML tag attributes, or unset if none
-// t [on|off] show only rows
-// x [on|off|auto] toggle expanded output
+// pset [NAME [VALUE]] set table print formatting option, or show all print formatting options if no parameters
+// a toggle between unaligned and aligned output mode DEPRECATED
+// C [TITLE] set table title, or unset if none DEPRECATED
+// f [SEPARATOR] show or set field separator for unaligned query output DEPRECATED
+// H toggle HTML output mode DEPRECATED
+// T [ATTRIBUTES] set HTML tag attributes, or unset if none DEPRECATED
+// t [on|off] show only rows DEPRECATED
+// x [on|off|auto] toggle expanded output DEPRECATED
func SetPrint(p *Params) error {
var ok bool
var val string
@@ -940,37 +821,112 @@ func SetPrint(p *Params) error {
return nil
}
-// Timing is a Operating System/Environment meta command (\timing). Sets (or
-// toggles) writing timing information for executed queries to the output.
+// SetConn is a Variables meta command (\cset). Sets a connection variable.
//
// Descs:
//
-// timing [on|off] toggle timing of commands
-func Timing(p *Params) error {
- v, err := p.Next(true)
+// cset [NAME [URL]] set named connection, or show all named connections if no parameters
+// cset NAME DRIVER PARAMS... set named connection for driver and parameters
+func SetConn(p *Params) error {
+ switch n, ok, err := p.NextOK(true); {
+ case err != nil:
+ return err
+ case ok:
+ vals, err := p.All(true)
+ if err != nil {
+ return err
+ }
+ return env.Vars().SetConn(n, vals...)
+ }
+ return env.Vars().DumpConn(p.Handler.IO().Stdout())
+}
+
+// Prompt is a Variables meta command (\prompt). Prompts the user for input,
+// setting a application variable to the user's response.
+//
+// Descs:
+//
+// prompt [-TYPE] VAR [PROMPT] prompt user to set application variable
+func Prompt(p *Params) error {
+ typ := "string"
+ n, ok, err := p.NextOpt(true)
if err != nil {
return err
}
- if v == "" {
- p.Handler.SetTiming(!p.Handler.GetTiming())
- } else {
- s, err := env.ParseBool(v, `\timing`)
+ if ok {
+ typ = n
+ n, err = p.Next(true)
if err != nil {
- stderr := p.Handler.IO().Stderr()
- fmt.Fprintf(stderr, "error: %v", err)
- fmt.Fprintln(stderr)
- }
- var b bool
- if s == "on" {
- b = true
+ return err
}
- p.Handler.SetTiming(b)
}
- setting := "off"
- if p.Handler.GetTiming() {
- setting = "on"
+ if n == "" {
+ return text.ErrMissingRequiredArgument
+ }
+ if err := env.ValidIdentifier(n); err != nil {
+ return err
+ }
+ vals, err := p.All(true)
+ if err != nil {
+ return err
+ }
+ v, err := p.Handler.ReadVar(typ, strings.Join(vals, " "))
+ if err != nil {
+ return err
+ }
+ return env.Vars().Set(n, v)
+}
+
+// Describe is a Informational meta command (\d and variants). Queries the open
+// database connection for information about the database schema and writes the
+// information to the output.
+//
+// Descs:
+//
+// d[S+] [NAME] list tables, views, and sequences or describe table, view, sequence, or index
+// da[S+] [PATTERN] list aggregates
+// df[S+] [PATTERN] list functions
+// di[S+] [PATTERN] list indexes
+// dm[S+] [PATTERN] list materialized views
+// dn[S+] [PATTERN] list schemas
+// dp[S] [PATTERN] list table, view, and sequence access privileges
+// ds[S+] [PATTERN] list sequences
+// dt[S+] [PATTERN] list tables
+// dv[S+] [PATTERN] list views
+// l[+] list databases
+func Describe(p *Params) error {
+ ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
+ defer cancel()
+ m, err := p.Handler.MetadataWriter(ctx)
+ if err != nil {
+ return err
+ }
+ verbose := strings.ContainsRune(p.Name, '+')
+ showSystem := strings.ContainsRune(p.Name, 'S')
+ name := strings.TrimRight(p.Name, "S+")
+ pattern, err := p.Next(true)
+ if err != nil {
+ return err
+ }
+ switch name {
+ case "d":
+ if pattern != "" {
+ return m.DescribeTableDetails(p.Handler.URL(), pattern, verbose, showSystem)
+ }
+ return m.ListTables(p.Handler.URL(), "tvmsE", pattern, verbose, showSystem)
+ case "df", "da":
+ return m.DescribeFunctions(p.Handler.URL(), name, pattern, verbose, showSystem)
+ case "dt", "dtv", "dtm", "dts", "dv", "dm", "ds":
+ return m.ListTables(p.Handler.URL(), name, pattern, verbose, showSystem)
+ case "dn":
+ return m.ListSchemas(p.Handler.URL(), pattern, verbose, showSystem)
+ case "di":
+ return m.ListIndexes(p.Handler.URL(), pattern, verbose, showSystem)
+ case "l":
+ return m.ListAllDbs(p.Handler.URL(), pattern, verbose)
+ case "dp":
+ return m.ListPrivilegeSummaries(p.Handler.URL(), pattern, showSystem)
}
- p.Handler.Print(text.TimingSet, setting)
return nil
}
@@ -1013,8 +969,9 @@ func Stats(p *Params) error {
return m.ShowStats(p.Handler.URL(), name, pattern, verbose, k)
}
-// Conditional is a Conditional meta command (\if, \elif, \else, \endif).
-// Starts, closes, and ends a conditional block within the application.
+// Conditional is a Control/Conditional meta command (\if, \elif, \else,
+// \endif). Starts, closes, and ends a conditional block within the
+// application.
//
// Descs:
//
@@ -1031,3 +988,72 @@ func Conditional(p *Params) error {
}
return nil
}
+
+// Shell is a Operating System/Environment meta command (\!). Executes a
+// command using the Operating System/Environment's shell.
+//
+// Descs:
+//
+// ! [COMMAND] execute command in shell or start interactive shell
+func Shell(p *Params) error {
+ return env.Shell(p.Raw())
+}
+
+// Chdir is a Operating System/Environment meta command (\cd). Changes the
+// current directory for the Operating System/Environment.
+//
+// Descs:
+//
+// cd [DIR] change the current working directory
+func Chdir(p *Params) error {
+ dir, err := p.Next(true)
+ if err != nil {
+ return err
+ }
+ return env.Chdir(p.Handler.User(), dir)
+}
+
+// Getenv is a Operating System/Environment meta command (\getenv). Sets the
+// application's variable value returned from the Operating
+// System/Environment's variables.
+//
+// Descs:
+//
+// getenv VARNAME ENVVAR fetch environment variable
+func Getenv(p *Params) error {
+ n, err := p.Next(true)
+ switch {
+ case err != nil:
+ return err
+ case n == "":
+ return text.ErrMissingRequiredArgument
+ }
+ v, err := p.Next(true)
+ switch {
+ case err != nil:
+ return err
+ case v == "":
+ return text.ErrMissingRequiredArgument
+ }
+ value, _ := env.Getenv(v)
+ return env.Vars().Set(n, value)
+}
+
+// Setenv is a Operating System/Environment meta command (\setenv). Sets (or
+// unsets) a Operating System/Environment variable. Environment variables set
+// this way will be passed to any child processes.
+//
+// Descs:
+//
+// setenv NAME [VALUE] set or unset environment variable
+func Setenv(p *Params) error {
+ n, err := p.Next(true)
+ if err != nil {
+ return err
+ }
+ v, err := p.Next(true)
+ if err != nil {
+ return err
+ }
+ return os.Setenv(n, v)
+}
diff --git a/metacmd/descs.go b/metacmd/descs.go
index dc0600bbdf..4e91403209 100644
--- a/metacmd/descs.go
+++ b/metacmd/descs.go
@@ -10,13 +10,14 @@ import (
var sections = []string{
"General",
"Help",
+ "Connection",
"Query Execute",
+ "Query View",
"Query Buffer",
"Informational",
"Variables",
- "Connection",
- "Conditional",
"Input/Output",
+ "Control/Conditional",
"Transaction",
"Operating System/Environment",
}
@@ -31,123 +32,126 @@ func init() {
descs = [][]desc{
// General
{
- {"q", "", "quit " + text.CommandName + "", Quit, false},
- {"quit", "", "alias for \\q", Quit, true},
- {"copyright", "", "show " + text.CommandName + " usage and distribution terms", Copyright, false},
- {"drivers", "", "display information about available database drivers", Drivers, false},
+ {Quit, `q`, ``, `quit ` + text.CommandName + ``, false, false},
+ {Quit, `quit`, ``, `alias for \q`, true, false},
+ {Copyright, `copyright`, ``, `show usage and distribution terms for ` + text.CommandName + ``, false, false},
+ {Drivers, `drivers`, ``, `show database drivers available to ` + text.CommandName + ``, false, false},
},
// Help
{
- {"?", "[commands]", "show help on meta (backslash) commands", Question, false},
- {"?", "options", "show help on " + text.CommandName + " command-line options", Question, false},
- {"?", "variables", "show help on special " + text.CommandName + " variables", Question, false},
+ {Help, `?`, `[commands]`, `show help on ` + text.CommandName + `'s meta (backslash) commands`, false, false},
+ {Help, `?`, `options`, `show help on ` + text.CommandName + ` command-line options`, false, false},
+ {Help, `?`, `variables`, `show help on special ` + text.CommandName + ` variables`, false, false},
+ },
+ // Connection
+ {
+ {Connect, `c`, `DSN or \c NAME`, `connect to dsn or named database connection`, false, false},
+ {Connect, `c`, `DRIVER PARAMS...`, `connect to database with driver and parameters`, false, false},
+ {Connect, `connect`, ``, `alias for \c`, true, false},
+ {Disconnect, `Z`, ``, `close (disconnect) database connection`, false, false},
+ {Disconnect, `disconnect`, ``, `alias for \Z`, true, false},
+ {Password, `password`, `[USER]`, `change password for user`, false, false},
+ {Password, `passwd`, ``, `alias for \password`, true, false},
+ {ConnectionInfo, `conninfo`, ``, `display information about the current database connection`, false, false},
},
// Query Execute
{
- {"g", "[(OPTIONS)] [FILE] or ;", "execute query (and send results to file or |pipe)", Execute, false},
- {"go", "[(OPTIONS)] [FILE]", "alias for \\g", Execute, false},
- {"G", "[(OPTIONS)] [FILE]", "as \\g, but forces vertical output mode", Execute, false},
- {"ego", "[(OPTIONS)] [FILE]", "alias for \\G", Execute, false},
- {"gx", "[(OPTIONS)] [FILE]", "as \\g, but forces expanded output mode", Execute, false},
- {"gexec", "", "execute query and execute each value of the result", Execute, false},
- {"gset", "[PREFIX]", "execute query and store results in " + text.CommandName + " variables", Execute, false},
- {"crosstabview", "[(OPTIONS)] [COLUMNS]", "execute query and display results in crosstab", Execute, false},
- {"chart", "CHART [(OPTIONS)]", "execute query and display results as a chart", Execute, false},
- {"watch", "[(OPTIONS)] [DURATION]", "execute query every specified interval", Execute, false},
- {"bind", "[PARAM]...", "set query parameters", Bind, false},
+ {Execute, `g`, `[(OPTIONS)] [FILE] or ;`, `execute query (and send results to file or |pipe)`, false, false},
+ {Execute, `go`, ``, `alias for \g`, true, false},
+ {Execute, `G`, `[(OPTIONS)] [FILE]`, `as \g, but forces vertical output mode`, false, false},
+ {Execute, `ego`, ``, `alias for \G`, true, false},
+ {Execute, `gx`, `[(OPTIONS)] [FILE]`, `as \g, but forces expanded output mode`, false, false},
+ {Execute, `gexec`, ``, `execute query and execute each value of the result`, false, false},
+ {Execute, `gset`, `[PREFIX]`, `execute query and store results in ` + text.CommandName + ` variables`, false, false},
+ {Bind, `bind`, `[PARAM]...`, `set query parameters`, false, false},
+ {Timing, `timing`, `[on|off]`, `toggle timing of commands`, false, false},
+ },
+ // Query View
+ {
+ {Crosstab, `crosstab`, `[(OPTIONS)] [COLUMNS]`, `execute query and display results in crosstab`, false, false},
+ {Crosstab, `crosstabview`, ``, `alias for \crosstab`, true, false},
+ {Crosstab, `xtab`, ``, `alias for \crosstab`, true, false},
+ {Chart, `chart`, `CHART [(OPTIONS)]`, `execute query and display results as a chart`, false, false},
+ {Watch, `watch`, `[(OPTIONS)] [INTERVAL]`, `execute query every specified interval`, false, false},
},
// Query Buffer
{
- {"e", "[FILE] [LINE]", "edit the query buffer (or file) with external editor", Edit, false},
- {"edit", "[-exec]", "edit the query (or exec) buffer", Edit, false},
- {"p", "", "show the contents of the query buffer", Print, false},
- {"print", "", "alias for \\p", Print, true},
- {"raw", "", "show the raw (non-interpolated) contents of the query buffer", Print, false},
- {"exec", "", "show the contents of the exec buffer", Print, false},
- {"r", "", "reset (clear) the query buffer", Reset, false},
- {"reset", "", "alias for \\r", Reset, true},
- {"w", "FILE", "write query buffer to file", Write, false},
- {"write", "", "alias for \\w", Write, true},
+ {Edit, `e`, `[-raw|-exec] [FILE] [LINE]`, `edit the query buffer, raw (non-interpolated) buffer, the exec buffer, or a file with external editor`, false, false},
+ {Edit, `edit`, ``, `alias for \e`, true, false},
+ {Print, `p`, `[-raw|-exec]`, `show the contents of the query buffer, the raw (non-interpolated) buffer or the exec buffer`, false, false},
+ {Print, `print`, ``, `alias for \p`, true, false},
+ {Print, `raw`, ``, `alias for \p`, true, false},
+ {Print, `exec`, ``, `alias for \p`, true, false},
+ {Write, `w`, `[-raw|-exec] FILE`, `write the contents of the query buffer, raw (non-interpolated) buffer, or exec buffer to file`, false, false},
+ {Write, `write`, ``, `alias for \w`, true, false},
+ {Reset, `r`, ``, `reset (clear) the query buffer`, false, false},
+ {Reset, `reset`, ``, `alias for \r`, true, false},
},
// Informational
{
- {"d[S+]", "[NAME]", "list tables, views, and sequences or describe table, view, sequence, or index", Describe, false},
- {"da[S+]", "[PATTERN]", "list aggregates", Describe, false},
- {"df[S+]", "[PATTERN]", "list functions", Describe, false},
- {"di[S+]", "[PATTERN]", "list indexes", Describe, false},
- {"dm[S+]", "[PATTERN]", "list materialized views", Describe, false},
- {"dn[S+]", "[PATTERN]", "list schemas", Describe, false},
- {"dp[S]", "[PATTERN]", "list table, view, and sequence access privileges", Describe, false},
- {"ds[S+]", "[PATTERN]", "list sequences", Describe, false},
- {"dt[S+]", "[PATTERN]", "list tables", Describe, false},
- {"dv[S+]", "[PATTERN]", "list views", Describe, false},
- {"l[+]", "", "list databases", Describe, false},
- {"ss[+]", "[TABLE|QUERY] [k]", "show stats for a table or a query", Stats, false},
+ {Describe, `d[S+]`, `[NAME]`, `list tables, views, and sequences or describe table, view, sequence, or index`, false, false},
+ {Describe, `da[S+]`, `[PATTERN]`, `list aggregates`, false, false},
+ {Describe, `df[S+]`, `[PATTERN]`, `list functions`, false, false},
+ {Describe, `di[S+]`, `[PATTERN]`, `list indexes`, false, false},
+ {Describe, `dm[S+]`, `[PATTERN]`, `list materialized views`, false, false},
+ {Describe, `dn[S+]`, `[PATTERN]`, `list schemas`, false, false},
+ {Describe, `dp[S]`, `[PATTERN]`, `list table, view, and sequence access privileges`, false, false},
+ {Describe, `ds[S+]`, `[PATTERN]`, `list sequences`, false, false},
+ {Describe, `dt[S+]`, `[PATTERN]`, `list tables`, false, false},
+ {Describe, `dv[S+]`, `[PATTERN]`, `list views`, false, false},
+ {Describe, `l[+]`, ``, `list databases`, false, false},
+ {Stats, `ss[+]`, `[TABLE|QUERY] [k]`, `show stats for a table or a query`, false, false},
},
// Variables
{
- {"prompt", "[-TYPE] VAR [PROMPT]", "prompt user to set variable", Prompt, false},
- {"set", "[NAME [VALUE]]", "set internal variable, or list all if no parameters", Set, false},
- {"unset", "NAME", "unset (delete) internal variable", Unset, false},
- {"pset", "[NAME [VALUE]]", "set table output option", SetPrint, false},
- {"a", "", "toggle between unaligned and aligned output mode", SetPrint, false},
- {"C", "[TITLE]", "set table title, or unset if none", SetPrint, false},
- {"f", "[SEPARATOR]", "show or set field separator for unaligned query output", SetPrint, false},
- {"H", "", "toggle HTML output mode", SetPrint, false},
- {"T", "[ATTRIBUTES]", "set HTML tag attributes, or unset if none", SetPrint, false},
- {"t", "[on|off]", "show only rows", SetPrint, false},
- {"x", "[on|off|auto]", "toggle expanded output", SetPrint, false},
- },
- // Connection
- {
- {"c", "URL", "connect to database URL", Connect, false},
- {"c", "DRIVER PARAMS...", "connect to database with driver and parameters", Connect, false},
- {"connect", "", "alias for \\c", Connect, true},
- {"cset", "", "show named connections", SetConn, false},
- {"cset", "NAME URL", "set named connection to URL", SetConn, false},
- {"cset", "NAME DRIVER PARAMS...", "set named connection for database driver and parameters", SetConn, false},
- {"Z", "", "close database connection", Disconnect, false},
- {"disconnect", "", "alias for \\Z", Disconnect, true},
- {"password", "[USER]", "change password for user", Password, false},
- {"passwd", "", "alias for \\password", Password, true},
- {"conninfo", "", "display information about the current database connection", ConnectionInfo, false},
+ {Set, `set`, `[NAME [VALUE]]`, `set ` + text.CommandName + ` application variable, or show all ` + text.CommandName + ` application variables if no parameters`, false, false},
+ {Unset, `unset`, `NAME`, `unset (delete) ` + text.CommandName + ` application variable`, false, false},
+ {SetPrint, `pset`, `[NAME [VALUE]]`, `set table print formatting option, or show all print formatting options if no parameters`, false, false},
+ {SetPrint, `a`, ``, `toggle between unaligned and aligned output mode`, false, true},
+ {SetPrint, `C`, `[TITLE]`, `set table title, or unset if none`, false, true},
+ {SetPrint, `f`, `[SEPARATOR]`, `show or set field separator for unaligned query output`, false, true},
+ {SetPrint, `H`, ``, `toggle HTML output mode`, false, true},
+ {SetPrint, `T`, `[ATTRIBUTES]`, `set HTML tag attributes, or unset if none`, false, true},
+ {SetPrint, `t`, `[on|off]`, `show only rows`, false, true},
+ {SetPrint, `x`, `[on|off|auto]`, `toggle expanded output`, false, true},
+ {SetConn, `cset`, `[NAME [URL]]`, `set named connection, or show all named connections if no parameters`, false, false},
+ {SetConn, `cset`, `NAME DRIVER PARAMS...`, `set named connection for driver and parameters`, false, false},
+ {Prompt, `prompt`, `[-TYPE] VAR [PROMPT]`, `prompt user to set application variable`, false, false},
},
- // Conditional
+ // Input/Output
{
- {"if", "EXPR", "begin conditional block", Conditional, false},
- {"elif", "EXPR", "alternative within current conditional block", Conditional, false},
- {"else", "", "final alternative within current conditional block", Conditional, false},
- {"endif", "", "end conditional block", Conditional, false},
+ {Echo, `echo`, `[-n] [MESSAGE]...`, `write message to standard output (-n for no newline)`, false, false},
+ {Echo, `qecho`, `[-n] [MESSAGE]...`, `write message to \o output stream (-n for no newline)`, false, false},
+ {Echo, `warn`, `[-n] [MESSAGE]...`, `write message to standard error (-n for no newline)`, false, false},
+ {Out, `o`, `[FILE]`, `send all query results to file or |pipe`, false, false},
+ {Out, `out`, ``, `alias for \o`, true, false},
+ {Copy, `copy`, `SRC DST QUERY TABLE`, `copy results of query from source database into table on destination database`, false, false},
+ {Copy, `copy`, `SRC DST QUERY TABLE(A,...)`, `copy results of query from source database into table's columns on destination database`, false, false},
},
- // Input/Output
+ // Control/Conditional
{
- {"copy", "SRC DST QUERY TABLE", "copy query from source url to table on destination url", Copy, false},
- {"copy", "SRC DST QUERY TABLE(A,...)", "copy query from source url to columns of table on destination url", Copy, false},
- {"echo", "[-n] [MESSAGE]...", "write message to standard output (-n for no newline)", Echo, false},
- {"qecho", "[-n] [MESSAGE]...", "write message to \\o output stream (-n for no newline)", Echo, false},
- {"warn", "[-n] [MESSAGE]...", "write message to standard error (-n for no newline)", Echo, false},
- {"o", "[FILE]", "send all query results to file or |pipe", Out, false},
- {"out", "", "alias for \\o", Out, true},
- {"i", "FILE", "execute commands from file", Include, false},
- {"include", "", "alias for \\i", Include, true},
- {"ir", "FILE", "as \\i, but relative to location of current script", Include, false},
- {"include_relative", "", "alias for \\ir", Include, true},
+ {Include, `i`, `FILE`, `execute commands from file`, false, false},
+ {Include, `include`, ``, `alias for \i`, true, false},
+ {Include, `ir`, `FILE`, `as \i, but relative to location of current script`, false, false},
+ {Include, `include_relative`, ``, `alias for \ir`, true, false},
+ {Conditional, `if`, `EXPR`, `begin conditional block`, false, false},
+ {Conditional, `elif`, `EXPR`, `alternative within current conditional block`, false, false},
+ {Conditional, `else`, ``, `final alternative within current conditional block`, false, false},
+ {Conditional, `endif`, ``, `end conditional block`, false, false},
},
// Transaction
{
- {"begin", "", "begin a transaction", Transact, false},
- {"begin", "-read-only ISOLATION", "begin a transaction with isolation level", Transact, false},
- {"commit", "", "commit current transaction", Transact, false},
- {"rollback", "", "rollback (abort) current transaction", Transact, false},
- {"abort", "", "alias for \\rollback", Transact, true},
+ {Transact, `begin`, `[-read-only [ISOLATION]]`, `begin transaction, with optional isolation level`, false, false},
+ {Transact, `commit`, ``, `commit current transaction`, false, false},
+ {Transact, `rollback`, ``, `rollback (abort) current transaction`, false, false},
+ {Transact, `abort`, ``, `alias for \rollback`, true, false},
},
// Operating System/Environment
{
- {"cd", "[DIR]", "change the current working directory", Chdir, false},
- {"getenv", "VARNAME ENVVAR", "fetch environment variable", Getenv, false},
- {"setenv", "NAME [VALUE]", "set or unset environment variable", Setenv, false},
- {"!", "[COMMAND]", "execute command in shell or start interactive shell", Shell, false},
- {"timing", "[on|off]", "toggle timing of commands", Timing, false},
+ {Shell, `!`, `[COMMAND]`, `execute command in shell or start interactive shell`, false, false},
+ {Chdir, `cd`, `[DIR]`, `change the current working directory`, false, false},
+ {Getenv, `getenv`, `VARNAME ENVVAR`, `fetch environment variable`, false, false},
+ {Setenv, `setenv`, `NAME [VALUE]`, `set or unset environment variable`, false, false},
},
}
cmds = make(map[string]func(*Params) error)
diff --git a/metacmd/metacmd.go b/metacmd/metacmd.go
index 62b2e3d0b5..1e34bec132 100644
--- a/metacmd/metacmd.go
+++ b/metacmd/metacmd.go
@@ -80,7 +80,7 @@ func Dump(w io.Writer, hidden bool) error {
n := 0
for i := range sections {
for _, desc := range descs[i] {
- if !desc.Hidden || hidden {
+ if (!desc.Hidden && !desc.Deprecated) || hidden {
n = max(n, runewidth.StringWidth(desc.Name)+1+runewidth.StringWidth(desc.Params))
}
}
@@ -91,8 +91,8 @@ func Dump(w io.Writer, hidden bool) error {
}
fmt.Fprintln(w, s)
for _, desc := range descs[i] {
- if !desc.Hidden || hidden {
- _, _ = fmt.Fprintf(w, " \\%- *s %s\n", n, desc.Name+" "+desc.Params, desc.Desc)
+ if (!desc.Hidden && !desc.Deprecated) || hidden {
+ _, _ = fmt.Fprintf(w, " \\%- *s %s\n", n, desc.Name+" "+desc.Params, wrap(desc.Desc, 95, n+5))
}
}
}
@@ -249,11 +249,12 @@ const (
// desc wraps a meta command description.
type desc struct {
- Name string
- Params string
- Desc string
- Func func(*Params) error
- Hidden bool
+ Func func(*Params) error
+ Name string
+ Params string
+ Desc string
+ Hidden bool
+ Deprecated bool
}
// Names returns the names for the command.
@@ -272,3 +273,24 @@ func (d desc) Names() []string {
return v
}
}
+
+// wrap wraps a line of text to the specified width, and adding the prefix to
+// each wrapped line.
+func wrap(s string, width, prefixWidth int) string {
+ words := strings.Fields(strings.TrimSpace(s))
+ if len(words) == 0 {
+ return ""
+ }
+ prefix, wrapped := strings.Repeat(" ", prefixWidth), words[0]
+ left := width - prefixWidth - len(wrapped)
+ for _, word := range words[1:] {
+ if left < len(word)+1 {
+ wrapped += "\n" + prefix + word
+ left = width - len(word)
+ } else {
+ wrapped += " " + word
+ left -= 1 + len(word)
+ }
+ }
+ return wrapped
+}