From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on inbox.vuxu.org X-Spam-Level: X-Spam-Status: No, score=-1.0 required=5.0 tests=DKIMWL_WL_MED,DKIM_SIGNED, DKIM_VALID,MAILING_LIST_MULTI,RCVD_IN_DNSWL_NONE autolearn=ham autolearn_force=no version=3.4.2 Received: from primenet.com.au (ns1.primenet.com.au [203.24.36.2]) by inbox.vuxu.org (OpenSMTPD) with ESMTP id 59362bd3 for ; Thu, 21 Mar 2019 21:35:52 +0000 (UTC) Received: (qmail 27828 invoked by alias); 21 Mar 2019 21:35:36 -0000 Mailing-List: contact zsh-workers-help@zsh.org; run by ezmlm Precedence: bulk X-No-Archive: yes List-Id: Zsh Workers List List-Post: List-Help: List-Unsubscribe: X-Seq: 44158 Received: (qmail 2784 invoked by uid 1010); 21 Mar 2019 21:35:36 -0000 X-Qmail-Scanner-Diagnostics: from mail-io1-f65.google.com by f.primenet.com.au (envelope-from , uid 7791) with qmail-scanner-2.11 (clamdscan: 0.101.1/25393. spamassassin: 3.4.2. Clear:RC:0(209.85.166.65):SA:0(-1.9/5.0):. Processed in 4.192242 secs); 21 Mar 2019 21:35:36 -0000 X-Envelope-From: dana@dana.is X-Qmail-Scanner-Mime-Attachments: | X-Qmail-Scanner-Zip-Files: | Received-SPF: pass (ns1.primenet.com.au: SPF record at _netblocks.google.com designates 209.85.166.65 as permitted sender) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=dana-is.20150623.gappssmtp.com; s=20150623; h=from:content-transfer-encoding:mime-version:subject:message-id:date :to; bh=lVSVc11F2J5Irl07EuKHD77oZFMZRRVaLvOiLr2Ra+c=; b=v2nzCT5jJD7chjHLB3bcD+16cFvP7DI6BaGY/7nH3qu/rFylXxAl7t1gQdaO8UK/hL XP/WehSn4V4enfu8GsT8PBcihUaDBE/AQVBA57n8edl+fmDUlHCakB0HHrrstpP0tz5X 2yMN7xuVhRI+lD6J4HrTiUz6XV+j1EzSUeRtAMldhXQQ40q3Smy6BSSHNuEs0myHzohM bZgLKq2aqQWpii0qfNsv3sVxoi8O7mBhRq/nsr30Tm2VYTRhge0x5S3JOTTk/jR97CLs pBldCF06+KFC1ES0W9XFlFmLlV68s4HHPxstMzvV6RekIp2LJuQzW9VUTb1lbl4+uUlV ls7g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:content-transfer-encoding:mime-version :subject:message-id:date:to; bh=lVSVc11F2J5Irl07EuKHD77oZFMZRRVaLvOiLr2Ra+c=; b=oCwjn0tVzp4Amgof13l5CdBAQZtsWhf+vMafn79jPCWHaySuf32WBISgp+4MaLpotj wQgajJciuXY2x8TkP6E3ZH4KEeo7z1s5DJNLlUHpVR/fmC4AlwEXwdlrBTUW+ZxH0i8B 54C7Zqo7bU0M/JYDjwSumWEBO4jgeHB0pmmrrleiGldtlT+LZAb2ZjZSn4IvgYm0dvzi dGv+gRwODO8LP9r0ksCtf/XVaBt2PRUn9h9VsUjRN/VJUmWWMw0luLroa/0yE4w1K5f5 7sWpoZEmMMUmuy3jAVrFVndA2K5uH/dUPxJ3edFL2CO7sEsXUy2HpklcIvOe64B25RK6 3o8Q== X-Gm-Message-State: APjAAAVLhrVMe3I8hZLnoTXd94GLzEBWiiYtBKdfi5KZqDyGF2PVq24y 0eTmgEAHLroRwVWcyno0qVirPBllo28uyg== X-Google-Smtp-Source: APXvYqyZRP4sKviNh0K45wqJeztcMChIrvpF+zFFaHvMvlTZ3KxY/CFXRszF2g6OrOJKODVKNr7ufw== X-Received: by 2002:a6b:5c0a:: with SMTP id z10mr4025525ioh.138.1553204096737; Thu, 21 Mar 2019 14:34:56 -0700 (PDT) From: dana Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: quoted-printable Mime-Version: 1.0 (Mac OS X Mail 11.5 \(3445.9.1\)) Subject: [PATCH] Completion: Add _postgresql Message-Id: Date: Thu, 21 Mar 2019 16:34:55 -0500 To: Zsh hackers list X-Mailer: Apple Mail (2.3445.9.1) This adds completion for the major tools included with PostgreSQL. There = are some that i've missed, and in particular it would be nice to handle = Debian's wrapper tools for 'multi-cluster' administration, but every time i've = looked at this over the last several months i've found new things to do; at = some point i just need to get it out. _mysql_utils offers possibilities like user and table names by querying = the database, and that seemed nice, so i ran with the idea here. That (along = with trying to be accurate with option exclusivity, as usual) is mostly why = it's so complicated. Let me know if you can think of any issues with that. (Support for gain-privileges might be warranted, since 'peer' = authentication with Postgres is often achieved via `sudo -u`, but i haven't added that = here) dana diff --git a/Completion/Unix/Command/_postgresql = b/Completion/Unix/Command/_postgresql new file mode 100644 index 000000000..dc9c2405a --- /dev/null +++ b/Completion/Unix/Command/_postgresql @@ -0,0 +1,1148 @@ +#compdef clusterdb createdb createuser dropdb dropuser initdb pg_config = pg_ctl pg_dump pg_dumpall pg_isready pg_restore pg_upgrade postgres = postmaster psql reindexdb vacuumdb + +# Notes: +# - @todo We don't complete postgres:// URIs or conninfo strings, and = we don't +# account for postgres:// URIs when calling psql +# - @todo We don't handle a few less-used tools like ecpg and pgbench +# - @todo We don't handle Debian's wrapper tools (pg_ctlcluster, &al.) + +# Construct conninfo string for use with completion helper functions +# +# -o =3D> include only specified parameters +# -O =3D> exclude specified parameters +# $1 =3D> scalar parameter to store result in (conninfo by = default) +# +# Explanation: +# +# Postgres supports a dizzying number of ways to specify connection = parameters; +# in roughly ascending order of precedence, they are (where = applicable): +# +# - PG* environment variables +# - Database name as first operand +# - User name as second operand +# - Options -d/-h/-p/-U +# - Conninfo string as first operand +# - URI as first operand -- authority/path component +# - URI as first operand -- query component +# +# The following command demonstrates four ways to pass the user name: +# +# PGUSER=3Dfoo1 psql 'postgres://foo2@localhost/mydb?user=3Dfoo3' -U = foo4 +# +# In this case, per the above, the query component of the URI wins, and = foo3 +# gets used. +# +# Many connection parameters can only be supplied via conninfo string, = URI, or +# environment variable. Thus, in order for our helper functions to = accurately +# obtain completion possibilities, it's preferable to normalise the = various +# methods of supplying parameters. Since conninfo strings are easiest = to +# construct, we'll use those. +# +# See also: +# +# - https://www.postgresql.org/docs/current/static/libpq-envars.html +# - https://www.postgresql.org/docs/current/static/libpq-connect.html +# - = https://github.com/postgres/postgres/blob/master/src/bin/psql/startup.c +(( $+functions[__pgsql_get_conninfo] )) || +__pgsql_get_conninfo() { + local i_ + local -a conninfo_ + local -aU incl_ excl_ + + zparseopts -D -E -- o+:-=3Dincl_ O+:-=3Dexcl_ + + (( $#incl_ )) && + incl_=3D( ${(@s<,>)${(@)${(@)incl_#-o}//[[:punct:][:space:]]/,}} ) + (( $#excl_ )) && + excl_=3D( ${(@s<,>)${(@)${(@)excl_#-O}//[[:punct:][:space:]]/,}} ) + + # Parameters supplied via options. We must quote parameter values for = conninfo + # strings like foo=3D'bar\'baz'. Should we also handle = -l/--maintenance-db here? + [[ -n ${opt_args[(i)c-(-d|--dbname)]} ]] && + conninfo_+=3D( = dbname=3D"'${(Q)${(v)opt_args[(i)c-(-d|--dbname)]}//\'/\\\'}'" ) + [[ -n ${opt_args[(i)c-(-h|--host)]} ]] && + conninfo_+=3D( = host=3D"${(Q)${(v)opt_args[(i)c-(-h|--host)]}//\'/\\\'}'" ) + [[ -n ${opt_args[(i)c-(-p|--port)]} ]] && + conninfo_+=3D( = port=3D"'${(Q)${(v)opt_args[(i)c-(-p|--port)]}//\'/\\\'}'" ) + [[ -n ${opt_args[(i)c-(-U|--user)]} ]] && + conninfo_+=3D( = user=3D"'${(Q)${(v)opt_args[(i)c-(-U|--user)]}//\'/\\\'}'" ) + + # Parameters supplied via operands -- since these have such a high = precedence + # they can't do much for completing the above options, but they're = still + # useful for the helper functions + case ${(Q)line[1]} in + # First operand is URI + postgres(ql|)://*) + # @todo To parse this properly we need to handle = percent-encoding; it + # might be nice to have a utility function for that some day + ;; + # First operand is conninfo string. The user should have already = properly + # quoted any parameter values here, so we don't need to re-quote + *'=3D'*) + conninfo_+=3D( ${(z)${(Q)line[1]}} ) + # Normalise parameter pairs (note that empty values must be = quoted) + for (( i_ =3D 1; i_ < $#conninfo_; i_++ )); do + # Parameter pair already one word (`param=3Dvalue`) + if [[ $conninfo_[i_] =3D=3D *?'=3D'?* ]]; then + continue + # Parameter pair in three words (`param =3D value`) + elif [[ $conninfo_[(i_+1)] =3D=3D '=3D' ]]; then + conninfo_[i_]+=3D"=3D${conninfo_[(i_+2)]}" + conninfo_[(i_+1)]=3D + conninfo_[(i_+2)]=3D + (( i_ +=3D 2 )) + # Parameter pair in two words (`param=3D value` or `param = =3Dvalue`) + else + conninfo_[i_]+=3D${conninfo_[(i_+1)]} + conninfo_[(i_+1)]=3D + (( i_ +=3D 1 )) + fi + done + conninfo_=3D( $conninfo_ ) + ;; + # First and second operands may be database/user + *) + (( $+line[1] )) && conninfo_+=3D( = dbname=3D"'${(Q)line[1]//\'/\\\'}'" ) + (( $+line[2] )) && conninfo_+=3D( user=3D"'${(Q)line[2]//\'/\\\'}'"= ) + ;; + esac + + (( $#conninfo_ && $#incl_ )) && + conninfo_=3D( ${(M@)conninfo_:#(${(~j<|>)incl_})=3D*} ) + (( $#conninfo_ && $#excl_ )) && + conninfo_=3D( ${(@)conninfo_:#(${(~j<|>)excl_})=3D*} ) + + : ${(P)${1:-conninfo}::=3D${(j< >)conninfo_}} + return $(( $#conninfo_ ? 0 : 1 )) +} + +# Call psql and return results +# -f =3D> keep empty lines +# $1 =3D> array parameter to store results in +# $2 =3D> _call_program tag +# $3 =3D> preferred conninfo string (use '' if none) +# $4 ... =3D> arguments to psql (usually -c ...); automatically quoted = for eval +__pgsql_call_psql() { + local c_ f_ psql_=3Dpsql + local -a tmp_ + + [[ $1 =3D=3D -f ]] && { + f_=3D1 + shift + } + + (( $# >=3D 4 )) || { + print -ru2 "$0: bad argument count" + return 1 + } + + # Use the psql from the command line if we can + [[ $service =3D=3D psql ]] && psql_=3D$words[1] + + # Make a few attempts with common settings in case the first fails. = Maybe this + # behaviour could be controlled by a user style + for c_ in $3{,' dbname=3Dtemplate1',' dbname=3Dtemplate1 = user=3Dpostgres'}; do + c_+=3D' connect_timeout=3D4' + tmp_=3D( "${(@f)"$( + _call_program $2 $psql_ -qtAX ${(q)c_} ${(@q)@[4,-1]} + )"}" ) + (( f_ )) || tmp_=3D( $tmp_ ) + (( $#tmp_ )) && break + done + + : ${(PA)1::=3D"${(@)tmp_}"} + return $(( $#tmp ? 0 : 1 )) +} + +# Complete PostgreSQL authentication methods +(( $+functions[__pgsql_auth_methods] )) || +__pgsql_auth_methods() { + # See = https://www.postgresql.org/docs/current/static/auth-pg-hba-conf.html + local -a tmp=3D( + 'trust:allow unconditionally' + 'reject:reject unconditionally' + 'scram-sha-256:authenticate via SCRAM-SHA-256 challenge-response' + 'md5:authenticate via MD5 or SCRAM-SHA-256 challenge-response' + 'password:authenticate via clear-text password' + 'gss:authenticate via GSSAPI (TCP/IP only)' + 'sspi:authenticate via SSPI (Windows only)' + 'ident:authenticate via ident user name (TCP/IP only; local peer = fall-back)' + 'peer:authenticate via local OS user name (local only)' + 'ldap:authenticate via LDAP' + 'radius:authenticate via RADIUS' + 'cert:authenticate via SSL client certificate' + 'pam:authenticate via PAM' + 'bsd:authenticate via BSD Authentication' + ) + _describe -t auth-methods 'PostgreSQL authentication method' tmp "$@" +} + +# Complete PostgreSQL run-time configuration parameters +(( $+functions[__pgsql_cfg_params] )) || +__pgsql_cfg_params() { + local conninfo + local -a expl tmp + + __pgsql_get_conninfo -O dbname + __pgsql_call_psql tmp databases "$conninfo" -c ' + SELECT name + FROM pg_catalog.pg_settings; + ' + + _wanted -x parameters expl 'PostgreSQL run-time configuration = parameter' \ + compadd -a "$@" - tmp +} + +# Complete PostgreSQL run-time configuration parameters (name=3Dvalue = format) +(( $+functions[__pgsql_cfg_params_values] )) || +__pgsql_cfg_params_values() { + if compset -P '*=3D'; then + _message -e values 'PostgreSQL run-time configuration-parameter = value' + else + compset -S '=3D*' + __pgsql_cfg_params "$@" -qS=3D + fi +} + +# Complete PostgreSQL character encodings +(( $+functions[__pgsql_encodings] )) || +__pgsql_encodings() { + # These rarely change, and they're most needed when creating a new = database, + # so trying to pull them from an existing one doesn't seem that = helpful; see + # = https://www.postgresql.org/docs/current/static/multibyte.html#CHARSET-TABL= E + local -a expl tmp=3D( + BIG5 {WIN,Windows}950 + EUC_{CN,JP,JIS_2004,KR,TW} + GB18030 + GBK {WIN,Windows}936 + ISO_8859_{5..8} + JOHAB + KOI8{,R,U} + LATIN{1..10} ISO8859{{1..4},9,10,{13..16}} + MULE_INTERNAL + SJIS Mskanji ShiftJIS {WIN,Windows}932 + SHIFT_JIS_2004 + SQL_ASCII + UHC {WIN,Windows}949 + UTF8 Unicode + WIN{866,874,{1250..1258}} ALT WIN ABC TCVN{,5712} VSCII + ) + _wanted encodings expl 'PostgreSQL character encoding' compadd -a = "$@" - tmp +} + +# Complete PostgreSQL server hosts +# -/ =3D> exclude TCP/IP hosts (include directories only) +# -a =3D> include UNIX-domain socket directories +(( $+functions[__pgsql_hosts] )) || +__pgsql_hosts() { + local -a copts tmp alts + local -A opts + + # We want the compadd options from _sequence, but -J screws with = grouping + zparseopts -A opts -D -E -- / a J: + copts=3D( "$@" ) + + (( $+opts[-/] )) || { + tmp=3D( ${(s<,>)PGHOST} $${(s<,>)PGHOSTADDR} ) + (( $#tmp )) && alts+=3D( + "hosts:PostgreSQL server host:(${(j< >)${(@uq-)tmp}})" + ) + alts=3D( 'hosts:PostgreSQL server host:_hosts' ) + } + (( $+opts[-/] || $+opts[-a] )) && alts+=3D( + 'directories:PostgreSQL UNIX-domain socket directory:_directories' + ) + + _alternative -O copts $alts +} + +# Complete sequence of PostgreSQL host addresses and directories +(( $+functions[__pgsql_hosts_seq] )) || +__pgsql_hosts_seq() { + local -a opts + zparseopts -a opts -D -E -- / a + _sequence "$@" -s , __pgsql_hosts "${(@)opts}" +} + +# Complete PostgreSQL server port numbers +(( $+functions[__pgsql_ports] )) || +__pgsql_ports() { + local -a tmp=3D( + $PGPORT $PGPORTOLD $PGPORTNEW + 5432 # Customary + /tmp/.s.PGSQL.<->(#qN:e) # Customary + /var/run/postgresql/.s.PGSQL.<->(#qN:e) # Debian/Ubuntu + /var/pgsql_socket/.s.PGSQL.<->(#qN:e) # Weird macOS systems + /var/lib/pgsql/.s.PGSQL.<->(#qN:e) # Weird Linux systems + /var/lib/postgresql/.s.PGSQL.<->(#qN:e) # Weird Linux systems + ) + tmp=3D( ${(onu)tmp} ) + _wanted -2V ports expl 'PostgreSQL server port' compadd -a "$@" - tmp +} + +# Complete PostgreSQL special variables. This is brittle and = over-engineered, +# but it suits the purpose for now +# --pset =3D> complete \pset options +# --set =3D> complete \set options (default) +(( $+functions[__pgsql_variables] )) || +__pgsql_variables() { + local which tmp2 + local -a expl tmp + local -A opts + + zparseopts -A opts -D -E -- -pset -set + + if (( $+opts[--pset] )); then + which=3D--pset + else + which=3D--set + fi + + __pgsql_call_psql -f tmp help-variables '' --help=3Dvariables + tmp+=3D( '' ) + + # `psql --help=3Dvariables` produces three sections like this: + # psql variables: + # Usage: + # psql --set=3DNAME=3DVALUE + # or \set NAME VALUE inside psql + # + # AUTOCOMMIT ... + # Here, we strip up to the --set=3D line, then remove the next few = lines so they + # don't confuse us + tmp2=3D${${(F)tmp}#*[[:space:]]${which}=3D*$'\n'} + [[ $tmp2 =3D=3D [[:space:]]#or\ * ]] && tmp2=3D${tmp2#*$'\n'} + [[ $tmp2 =3D=3D [[:space:]]#$'\n'* ]] && tmp2=3D${tmp2#*$'\n'} + # Now we strip any following sections + tmp2=3D${tmp2%%$'\n\n'*} + # Now we extract the variable names + tmp=3D( ${(f)tmp2} ) + tmp=3D( ${(M)tmp:#\ \ [^[:space:]]##((#e)|[[:space:]]*)} ) + tmp=3D( ${(@)tmp#\ \ } ) + tmp=3D( ${(@)tmp%%[[:space:]]*} ) + + _wanted -x variables expl 'PostgreSQL special variable' \ + compadd -a "$@" - tmp +} + +# Complete PostgreSQL special variables (name=3Dvalue format) +(( $+functions[__pgsql_variables_values] )) || +__pgsql_cfg_variables_values() { + if compset -P '*=3D'; then + _message -e values 'PostgreSQL special-variable value' + else + compset -S '=3D*' + __pgsql_variables "$@" -qS=3D + fi +} + +# Complete PostgreSQL databases +(( $+functions[__pgsql_databases] )) || +__pgsql_databases() { + local conninfo + local -a expl tmp + + __pgsql_get_conninfo -O dbname + __pgsql_call_psql tmp databases "$conninfo" -c ' + SELECT datname + FROM pg_catalog.pg_database; + ' + # We can probably just assume that template0/1 will always exist; = it's useful + # for database creation, anyway + tmp+=3D( $PGDATABASE template0 template1 ) + + _wanted databases expl 'PostgreSQL database' compadd -a "$@" - tmp +} + +# Complete PostgreSQL indexes +(( $+functions[__pgsql_indexes] )) || +__pgsql_indexes() { + local conninfo + local -a expl tmp + + __pgsql_get_conninfo + __pgsql_call_psql tmp indexes "$conninfo" -c ' + SELECT indexname + FROM pg_catalog.pg_indexes; + ' + + _wanted -x indexes expl 'PostgreSQL index' compadd -a "$@" - tmp +} + +# Complete PostgreSQL roles/users +# -a =3D> include non-user (NOLOGIN) roles +(( $+functions[__pgsql_roles] )) || +__pgsql_roles() { + local conninfo which=3Drole where + local -a expl tmp + local -A opts + + zparseopts -A opts -D -E -- a + (( $+opts[-a] )) || { + which=3Duser + where=3D'WHERE rolcanlogin =3D true' + } + + __pgsql_get_conninfo -O user + __pgsql_call_psql tmp users "$conninfo" -c " + SELECT rolname + FROM pg_catalog.pg_roles + $where; + " + tmp+=3D( $PGUSER ) + + _wanted -x users expl "PostgreSQL $which" compadd -a "$@" - tmp +} + +# Complete PostgreSQL schemas +(( $+functions[__pgsql_schemas] )) || +__pgsql_schemas() { + local conninfo + local -a expl tmp + + __pgsql_get_conninfo + __pgsql_call_psql tmp schemas "$conninfo" -c " + SELECT nspname + FROM pg_catalog.pg_namespace + WHERE nspname NOT LIKE 'pg_%' + AND nspname !=3D 'information_schema'; + " + # Again, safe to assume this exists + tmp+=3D( public ) + + _wanted schemas expl 'PostgreSQL schema' compadd -a "$@" - tmp +} + +# Complete PostgreSQL tables +(( $+functions[__pgsql_tables] )) || +__pgsql_tables() { + local conninfo + local -a expl tmp + + __pgsql_get_conninfo + __pgsql_call_psql tmp tables "$conninfo" -c " + SELECT n.nspname || '.' || c.relname + FROM pg_catalog.pg_class AS c + LEFT JOIN pg_catalog.pg_namespace AS n + ON n.oid =3D c.relnamespace + WHERE c.relkind in ('r', '') + AND n.nspname !=3D 'pg_catalog' + AND n.nspname !=3D 'information_schema' + AND n.nspname NOT LIKE 'pg_toast%' + AND pg_catalog.pg_table_is_visible(c.oid); + " + + _wanted -x tables expl 'PostgreSQL table' compadd -a "$@" - tmp +} + +# Complete PostgreSQL tablespaces +(( $+functions[__pgsql_tablespaces] )) || +__pgsql_tablespaces() { + local conninfo + local -a expl tmp + + __pgsql_get_conninfo + __pgsql_call_psql tmp tablespaces "$conninfo" -c ' + SELECT spcname + FROM pg_catalog.pg_tablespace; + ' + # Again, safe to assume these exist + tmp+=3D( pg_default pg_global ) + + _wanted tablespaces expl 'PostgreSQL tablespace' compadd -a "$@" - = tmp +} + +# Complete PostgreSQL text-search configurations +(( $+functions[__pgsql_ts_configs] )) || +__pgsql_ts_configs() { + local conninfo + local -a expl tmp + + __pgsql_get_conninfo + __pgsql_call_psql tmp ts-configs "$conninfo" -c " + SELECT n.nspname || '.' || t.cfgname + FROM pg_catalog.pg_ts_config AS t + LEFT JOIN pg_catalog.pg_namespace AS n + ON t.cfgnamespace =3D n.oid; + " + # We'll assume these exist since this tends to be needed on cluster = init + tmp+=3D( pg_catalog.simple pg_catalog.english ) + + _wanted ts-configs expl 'PostgreSQL text-search configuration' \ + compadd -a "$@" - tmp +} + +# Complete clusterdb command +(( $+functions[_pgsql_clusterdb] )) || +_pgsql_clusterdb() { + (( CURRENT > 2 )) && local -a common_opts_excl=3D( '!---null' ) + local -a args=3D( + + x # Exclusive options + $common_opts_excl + + c # Connection options (not actually usable with --all) + $common_opts_connm + + '(d)' # Database connection options + '(a o)'{-d+,--dbname=3D}'[specify database name]: = :__pgsql_databases' + + C # Misc. common options + $common_opts_echo + # -q and -v are NOT exclusive + '(-q --quiet)'{-q,--quiet}'[do not display progress messages]' + '(-v --verbose)'{-v,--verbose}'[display detailed information during = processing]' + + a # --all-mode options + '(c d n -a --all)'{-a,--all}'[reindex all databases]' + + n # Normal-mode options + '(a)*'{-t+,--table=3D}'[cluster specified table only]: = :__pgsql_tables' + + o # Operands + '(a d)1: :__pgsql_databases' + ) + _arguments -s -S : $args +} + +# Complete createdb command +(( $+functions[_pgsql_createdb] )) || +_pgsql_createdb() { + (( CURRENT > 2 )) && local -a common_opts_excl=3D( '!---null' ) + local -a args=3D( + + x # Exclusive options + $common_opts_excl + + c # Connection options + $common_opts_connm + + l # Locale options + '(l)'{-l+,--locale=3D}'[specify locale (both LC_COLLATE and = LC_CTYPE)]: :_locales' + '(-l --locale)--lc-collate=3D[specify LC_COLLATE setting]: = :_locales' + '(-l --locale)--lc-ctype=3D[specify LC_CTYPE setting]: :_locales' + + o # Other arguments + $common_opts_echo + '(-D --tablespace)'{-D+,--tablespace=3D}'[specify default = tablespace]: :__pgsql_tablespaces' + '(-E --encoding)'{-E+,--encoding=3D}'[specify character encoding]: = :__pgsql_encodings' + '(-O --owner)'{-O+,--owner=3D}'[specify owner]: :__pgsql_roles -a' + '(-T --template)'{-T+,--template=3D}'[specify template database to = build from]: :__pgsql_databases' + # Possibly not useful to complete existing databases here + '1: :__pgsql_databases' + '2: :_guard "^-*" "database description"' + ) + _arguments -s -S : $args +} + +# Complete createuser command +(( $+functions[_pgsql_createuser] )) || +_pgsql_createuser() { + (( CURRENT > 2 )) && local -a common_opts_excl=3D( '!---null' ) + local -a args=3D( + + x # Exclusive options + $common_opts_excl + + c # Connection options + $common_opts_conn + + '(d)' # CREATEDB options + {-d,--createdb}'[grant ability to create new databases (CREATEDB)]' + {-D,--no-createdb}'[do not grant ability to create new databases = (NOCREATEDB)]' + + '(i)' # INHERIT options + {-i,--inherit}'[grant automatic privilege inheritance from role = memberships (INHERIT)]' + {-I,--no-inherit}'[do not grant automatic privilege inheritance = from role memberships (NOINHERIT)]' + + '(l)' # LOGIN options + {-l,--login}'[grant ability to log in as user (LOGIN)]' + {-L,--no-login}'[do not grant ability to log in as user (NOLOGIN)]' + + '(r)' # CREATEROLE options + {-r,--createrole}'[grant ability to create new roles (CREATEROLE)]' + {-R,--no-createrole}'[do not grant ability to create new roles = (NOCREATEROLE)]' + + '(R)' # REPLICATION options + '--replication[grant replication privileges (REPLICATION)]' + '--no-replication[do not grant replication privileges = (NOREPLICATION)]' + + '(s)' # SUPERUSER options + {-s,--superuser}'[grant super-user privileges (SUPERUSER)]' + {-S,--no-superuser}'[do not grant super-user privileges = (NOSUPERUSER)]' + + o # Other arguments + $common_opts_echo + '(-c --connection-limit)'{-c+,--connection-limit=3D}'[specify = connection limit for new role]:number of connections' + # No effect, kept for backwards compatibility + '!'{-E,--encrypted} + '*'{-g+,--role=3D}'[grant membership to specified role]: = :__pgsql_roles -a' + '--interactive[prompt for settings not specified on command line]' + '(-P --pwprompt)'{-P,--pwprompt}'[prompt for new user password]' + # Again, possibly not useful to complete these + '1: :__pgsql_roles' + ) + _arguments -s -S : $args +} + +# Complete dropdb command +(( $+functions[_pgsql_dropdb] )) || +_pgsql_dropdb() { + (( CURRENT > 2 )) && local -a common_opts_excl=3D( '!---null' ) + local -a args=3D( + + x # Exclusive options + $common_opts_excl + + c # Connection options + $common_opts_connm + + o # Other arguments + $common_opts_echo + '(-i --interactive)'{-i,--interactive}'[prompt for confirmation]' + '--if-exists[skip non-existent database]' + '1: :__pgsql_databases' + ) + _arguments -s -S : $args +} + +# Complete dropuser command +(( $+functions[_pgsql_dropuser] )) || +_pgsql_dropuser() { + (( CURRENT > 2 )) && local -a common_opts_excl=3D( '!---null' ) + local -a args=3D( + + x # Exclusive options + $common_opts_excl + + c # Connection options + $common_opts_conn + + o # Other arguments + $common_opts_echo + '(-i --interactive)'{-i,--interactive}'[prompt for confirmation = (and user name if not specified)]' + '--if-exists[skip non-existent user]' + # We could use -a here, but it seems questionable + '1: :__pgsql_roles' + ) + _arguments -s -S : $args +} + +# Complete initdb command +(( $+functions[_pgsql_initdb] )) || +_pgsql_initdb() { + (( CURRENT > 2 )) && local -a common_opts_excl=3D( '!---null' ) + local -a args=3D( + + x # Exclusive options + $common_opts_excl + + '(l)' # Locale options (general) + {-l+,--locale=3D}'[specify locale (all catgories)]: :_locales' + '--no-locale[equivalent to --locale=3DC]' + + lc # Locale options (specific) -- unlike createdb, NOT exclusive = with -l + '--lc-collate=3D[specify LC_COLLATE setting]: :_locales' + '--lc-ctype=3D[specify LC_CTYPE setting]: :_locales' + '--lc-messages=3D[specify LC_MESSAGES setting]: :_locales' + '--lc-monetary=3D[specify LC_MONETARY setting]: :_locales' + '--lc-numeric=3D[specify LC_NUMERIC setting]: :_locales' + '--lc-time=3D[specify LC_TIME setting]: :_locales' + + o # Other arguments + '(-A --auth)'{-A+,--auth=3D}'[specify authentication method (local = and host)]: :__pgsql_auth_methods' + '--auth-host=3D[specify host (TCP/IP) authentication method]: = :__pgsql_auth_methods' + '--auth-local=3D[specify local authentication method]: = :__pgsql_auth_methods' + '(-d --debug)'{-d,--debug}'[output debug information]' + '(1 -D --pgdata)'{-D+,--pgdata=3D}'[specify data directory]:data = directory:_directories' + '(-E --encoding)'{-E+,--encoding=3D}'[specify default character = encoding]: :__pgsql_encodings' + '(-k --data-checksums)'{-k,--data-checksums}'[enable checksums on = data pages]' + '-L+[specify input-file directory]:input-file = directory:_directories' + '(-n --no-clean)'{-n,--no-clean}'[do not clean up after errors]' + '(-N --no-sync)'{-N,--no-sync}'[do not wait for disk sync]' + '(-W --pwprompt)--pwfile=3D[read super-user password from specified = file]:password file:_files' + # This should be exclusive with everything but -D/1 + '(-S --sync-only)'{-S,--sync-only}'[safely write all database files = and exit]' + '(-T --text-search-config)'{-T+,--text-search-config=3D}'[specify = default text-search configuration]: :__pgsql_ts_configs' + # We could just use the OS user name here, idk + '(-U --username)'{-U+,--username=3D}'[specify super-user name]: = :__pgsql_roles' + '(-W --pwfile --pwprompt)'{-W,--pwprompt}'[prompt for super-user = password]' + '(-X --waldir)'{-X+,--waldir=3D}'[specify write-ahead log = directory]:write-ahead log directory:_directories' + '(-D --pgdata)1:database data directory:_directories' + ) + _arguments -s -S : $args +} + +# Complete pg_config command +(( $+functions[_pgsql_pg_config] )) || +_pgsql_pg_config() { + local -a args=3D( + + x # Exclusive options + ${(@M)common_opts_excl:#*(-\?|--help)*} + + o # Other options + ${(@)${(@M)common_opts_excl:#*--version*}#\(*\)} + '--bindir[display location of user executables]' + '--cc[display C compiler (CC) used during build]' + '--cflags[display C compiler flags (CFLAGS) used during build]' + '--cflags_sl[display C compiler flags for shared libraries = (CFLAGS_SL) used during build]' + '--configure[display configure options used during build]' + '--cppflags[display C preprocessor flags (CPPFLAGS) used during = build]' + '--docdir[display location of documentation files]' + '--htmldir[display location of HTML documentation files]' + '--includedir[display location of C header files for client = interfaces]' + '--includedir-server[display location of C header files for server = interfaces]' + '--ldflags[display linker flags (LDFLAGS) used during build]' + '--ldflags_ex[display linker flags used executables (LDFLAGS_EX) = used during build]' + '--ldflags_sl[display linker flags used shared libraries = (LDFLAGS_SL) used during build]' + '--libs[display linker flags for external libraries (LIBS) used = during build]' + '--libdir[display location of library object files]' + '--localedir[display location of locale support files]' + '--mandir[display location of manual pages]' + '--pgxs[display location of extension makefiles]' + '--pkgincludedir[display location of other C header files]' + '--pkglibdir[display location of module object files]' + '--sharedir[display location of architecture-independent support = files]' + '--sysconfdir[display location of system-wide configuration files]' + ) + _arguments -s -S : $args +} + +# Complete pg_ctl command +# @todo Exclusivity isn't great here -- it's annoying to handle = properly +# because pg_ctl accepts options interspersed with the sub-command name +(( $+functions[_pgsql_pg_ctl] )) || +_pgsql_pg_ctl() { + local -a cmds modes args + + (( CURRENT > 2 )) && local -a common_opts_excl=3D( '!---null' ) + + cmds=3D( + {init,initdb}'\:initialize database cluster' + 'kill\:kill process' + 'promote\:promote database server from stand-by to read/write mode' + 'reload\:reload database-server configuration' + 'restart\:restart database server' + 'start\:start database server' + 'status\:check status of database server' + 'stop\:stop database server' + ) + modes=3D( + {f,fast}'\:shut down cleanly, but without waiting for clients to = disconnect' + {i,immediate}'\:shut down immediately and uncleanly' + {s,smart}'\:shut down cleanly after waiting for clients to = disconnect' + ) + args=3D( + + x # Exclusive options + $common_opts_excl + + nk # Non-kill options + '(-D --pgdata)'{-D+,--pgdata=3D}'[specify data directory]:data = directory:_directories' + + nks # Non-kill/status options + '(-s --silent)'{-s,--silent}'[suppress informational messages]' + + ikprs # Wait options + '(-t -W --no-wait --timeout)'{-t+,--timeout=3D}'[specify time-out = interval (with -w)]:time-out interval (seconds)' + '(-w -W --no-wait --wait)'{-w,--wait}'[wait for operation to = complete]' + '(-t -w -W --no-wait --timeout --wait)'{-W,--no-wait}'[do not wait = for operation to complete]' + + isr # init/start/restart options + '*'{-o+,--options=3D}'[specify command-line options to = initdb/postgres]:initdb/postgres command-line options' + '-p+[specify path to initdb/postgres executable]:initdb/postgres = executable:_files -g "*(#q*)"' + + sr # start/restart options + '(-c --core-files)'{-c,--core-files}'[produce core files (where = supported)]' + '(-l --log)'{-l+,--log=3D}'[log to specified file]:log file:_files' + + tr # stop/restart options + '(-m --mode)'{-m+,--mode=3D}"[specify shut-down mode]:shut-down = mode:((${(j< >)${(@qq)modes}}))" + + o # Operands + "1:pg_ctl sub-command:((${(j< >)${(@qq)cmds}}))" + ) + [[ -n ${words[(r)*kill*]} ]] && args+=3D( '2: :_pids' ) + + _arguments -s -S : $args +} + +# Complete pg_dump/pg_dumpall commands +(( $+functions[_pgsql_pg_dump] )) || +_pgsql_pg_dump() { + local -a fmts args + + (( CURRENT > 2 )) && local -a common_opts_excl=3D( '!---null' ) + + fmts=3D( + {p,plain}'\:plain-text SQL script' + {c,custom}'\:custom-format archive' + {d,directory}'\:directory-format archive' + {t,tar}'\:tar-format archive' + ) + args+=3D( + + x # Exclusive options + $common_opts_excl + + c # Connection options + $common_opts_conn + '--role=3D[specify role used to create dump]: :__pgsql_roles -a' + ) + # pg_dump-specific connection options + [[ $service =3D=3D pg_dump ]] && args+=3D( + '(1 -d --dbname)'{-d+,--dbname=3D}'[specify database name]: = :__pgsql_databases' + # @todo Complete this properly + '(-d --dbname)1:PostgreSQL database name, conninfo string, or = URI:__pgsql_databases' + ) + # pg_dumpall-specific connection options + [[ $service =3D=3D pg_dumpall ]] && args+=3D( + # Despite the name, -d here this actually takes a conninfo string + # @todo Complete this + '(1 -d --dbname)'{-d+,--dbname=3D}'[specify conninfo = string]:conninfo string' + '(l --database)'{-l+,--database=3D}'[specify maintenance database = name]: :__pgsql_databases' + ) + args+=3D( + + '(ds)' # Data/schema options + '(-c --clean)'{-a,--data-only}'[dump only data (not = schema/definitions)]' + {-s,--schema-only}'[dump only schema/definitions (not data)]' + + '(in)' # Insert options + '(-o --oids)--column-inserts[output INSERT command with explicit = column names for each row]' + # Equivalent to above? + '!(-o --oids)--attribute-inserts' + '(-o --oids)--inserts[output INSERT command for each row]' + ) + [[ $service =3D=3D pg_dumpall ]] && args+=3D( + + '(grt)' # Globals/roles/tablespaces options + {-g,--globals-only}'[dump only roles and tablespaces (not = databases)]' + {-r,--roles-only}'[dump only roles (not databases or tablespaces)]' + {-t,--tablespaces-only}'[dump only tablespaces (not databases or = roles)]' + ) + # It would be nice to add '(with -Fp)' and so on where applicable, = but it's + # tedious because of pg_dumpall + args+=3D( + + o # Other options + '(-a -c --clean --data-only)'{-c,--clean}'[output commands to clean = objects before creating them]' + '(-o --oids in)'{-o,--oids}'[dump table object IDs]' + '(-O --no-owner)'{-O,--no-owner}'[do not output commands to set = ownership of objects]' + '(-S --superuser)'{-S+,--superuser=3D}'[specify super-user name]: = :__pgsql_roles' + '(-v --verbose)'{-v,--verbose}'[output verbosely]' + '(-x --no-acl --no-privileges)'{-x,--no-acl,--no-privileges}'[do = not dump access privileges]' + # Not meant for use by humans + '!--binary-upgrade' + '--disable-dollar-quoting[disable dollar-quoting of function = bodies]' + '--disable-triggers[output commands to disable triggers before = restoring (with -a)]' + '--if-exists[use conditional commands when cleaning objects (with = -c)]' + '--lock-wait-timeout=3D[specify table-lock time-out = interval]:time-out interval (milliseconds)' + '--no-publications[do not dump publications]' + '--no-security-labels[do not dump security labels]' + '--no-subscriptions[do not dump subscriptions]' + '--no-sync[do not wait for disk sync]' + '--no-tablespaces[do not output commands to select tablespaces]' + '--no-unlogged-table-data[do not dump data of unlogged tables]' + '--quote-all-identifiers[force quoting of all identifiers]' + '--use-set-session-authorization[output SET SESSION AUTHORIZATION = commands to set ownership of objects]' + ) + [[ $service =3D=3D pg_dump ]] && args+=3D( + # -b and -B are NOT exclusive + '(-b --blobs)'{-b,--blobs}'[dump large objects]' + '(-B --no-blobs)'{-B,--no-blobs}'[do not dump large objects]' + '(-C --create)'{-C,--create}'[output commands to create and = reconnect to database]' + '(-E --encoding)'{-E+,--encoding=3D}'[specify dump character = encoding]: :__pgsql_encodings' + '(-f --file)'{-f+,--file=3D}'[dump to specified file (or directory = with -Fd)]:dump file/directory:_files' + '(-F --format)'{-F+,--format=3D}"[dump using specified output = format]:output format:((${(j< >)${(@qq)fmts}}))" + '(-j --jobs)'{-j+,--jobs=3D}'[dump specified number of tables in = parallel (with -Fd)]:number of jobs/tables' + '*'{-n+,--schema=3D}'[dump only objects in schema matching = specified pattern]: :__pgsql_schemas' + '*'{-N+,--exclude-schema=3D}'[do not dump objects in schema = matching specified pattern]: :__pgsql_schemas' + # No effect, kept for backwards compatibility + '!'{-R,--no-reconnect} + '*'{-t+,--table=3D}'[dump only tables matching specified pattern]: = :__pgsql_tables' + '*'{-T+,--exclude-table=3D}'[do not dump tables matching specified = pattern]: :__pgsql_tables' + '(-Z --compress)'{-Z+,--compress=3D}"[specify output compression = level]:compression level:(${(j< >):-{0..9}})" + '--enable-row-security[dump with row security enabled]' + '*--exclude-table-data=3D[do not dump data for tables matching = specified pattern]: :__pgsql_tables' + '--no-synchronized-snapshots[support -j with pre-9.2 servers]' + '*--section=3D[dump only specified section]:section:(pre-data data = post-data)' + '--serializable-deferrable[dump using serializable transaction, = avoiding failure]' + # @todo Complete this + '--snapshot=3D[dump from specified snapshot]: :__pgsql_snapshots' + '--strict-names[require -n/-t patterns to match at least one = schema/table]' + ) + [[ $service =3D=3D pg_dumpall ]] && args+=3D( + '(-f --file)'{-f+,--file=3D}'[dump to specified file]:dump = file:_files' + '--no-role-passwords[do not dump passwords for roles]' + ) + _arguments -s -S : $args +} + +# Complete pg_isready command +(( $+functions[_pgsql_pg_isready] )) || +_pgsql_pg_isready() { + (( CURRENT > 2 )) && local -a common_opts_excl=3D( '!---null' ) + local -a args=3D( + + x # Exclusive options + $common_opts_excl + + c # Connection options + ${(@)common_opts_conn:#*--*password*} + # @todo Complete this properly + '(-d --dbname)'{-d+,--dbname=3D}'[specify database name, conninfo = string, or URI]:PostgreSQL database name, conninfo string, or = URI:__pgsql_databases' + '(-t --timeout)'{-t+,--timeout=3D}'[specify time-out = interval]:time-out interval (seconds)' + + C # Misc. common options + '(-q --quiet)'{-q,--quiet}'[suppress normal output]' + ) + _arguments -s -S : $args +} + +# Complete pg_restore command +(( $+functions[_pgsql_pg_restore] )) || +_pgsql_pg_restore() { + (( CURRENT > 2 )) && local -a common_opts_excl=3D( '!---null' ) + local -a fmts=3D( + # Plain-text is intentionally missing here + {c,custom}'\:custom-format archive' + {d,directory}'\:directory-format archive' + {t,tar}'\:tar-format archive' + ) + # It probably isn't that helpful to complete indexes, &c., from = existing + # databases, but oh well + local -a args=3D( + + x # Exclusive options + $common_opts_excl + + c # Connection options + $common_opts_conn + '(-d --dbname)'{-d+,--dbname=3D}'[restore to specified database]: = :__pgsql_databases' + '--role=3D[specify role used to perform restore]: :__pgsql_roles = -a' + + '(ds)' # Data/schema options + '(-c --clean)'{-a,--data-only}'[restore only data (not = schema/definitions)]' + {-s,--schema-only}'[restore only schema/definitions (not data)]' + + o # Other arguments + '(-1 --single-transaction)'{-1,--single-transaction}'[perform = restore as a single transaction]' + '(-a -c --clean --data-only)'{-c,--clean}'[clean objects before = creating them]' + '(-C --create)'{-C,--create}'[create database before restoring to = it]' + '(-e --exit-on-error)'{-e,--exit-error}'[exit immediately on = error]' + '(-f --file)'{-f+,--file=3D}'[specify output file for generated = script or listing]:output file:_files' + '(-F --format)'{-F+,--format=3D}"[specify archive format]:archive = format:((${(j< >)${(@qq)fmts}}))" + '*'{-I+,--index=3D}'[restore only definition of specified index]: = :__pgsql_indexes' + '(-j --jobs)'{-j+,--jobs=3D}'[restore in parallel with specified = number of jobs]:number of jobs' + '(-l --list)'{-l,--list}'[list archive table of contents]' + '(-L --use-list)'{-L+,--use-list=3D}'[restore only archive elements = in specified list file]:list file:_files' + '*'{-n+,--schema=3D}'[restore only objects in specified schema]: = :__pgsql_schemas' + '*'{-N+,--exclude-schema=3D}'[do not restore objects in specified = schema]: :__pgsql_schemas' + '(-O --no-owner)'{-O,--no-owner}'[do not restore ownership of = objects from archive]' + '*'{-P+,--function=3D}'[restore only the specified = function]:PostgreSQL function' + # No effect, kept for backwards compatibility + '!'{-R,--no-reconnect} + '(-S --superuser)'{-S+,--superuser=3D}'[specify super-user name]: = :__pgsql_roles' + '*'{-t+,--table=3D}'[restore only specified table]: = :__pgsql_tables' + '*'{-T+,--trigger=3D}'[restore only specified trigger]:PostgreSQL = trigger' + '(-v --verbose)'{-v,--verbose}'[output verbosely]' + '(-x --no-acl --no-privileges)'{-x,--no-acl,--no-privileges}'[do = not dump access privileges]' + '--disable-triggers[disable triggers before restoring (with -a)]' + '--enable-row-security[restore with row security enabled]' + '--if-exists[use conditional commands when cleaning objects (with = -c)]' + '--no-data-for-failed-tables[do not restore data if table creation = failed]' + '--no-publications[do not restore publications]' + '--no-security-labels[do not restore security labels]' + '--no-subscriptions[do not restore subscriptions]' + '--no-tablespaces[do not restore tablespaces]' + '*--section=3D[dump only specified section]:section:(pre-data data = post-data)' + '--strict-names[require -n/-t qualifiers to match at least one = schema/table]' + '--use-set-session-authorization[use SET SESSION AUTHORIZATION = commands to set ownership of objects]' + '1:archive file:_files' + ) + _arguments -s -S : $args +} + +# Complete pg_upgrade command +(( $+functions[_pgsql_pg_upgrade] )) || +_pgsql_pg_upgrade() { + (( CURRENT > 2 )) && local -a common_opts_excl=3D( '!---null' ) + local -a args=3D( + + x # Exclusive options + $common_opts_excl + + o # Other options + '(-b --old-bindir)'{-b+,--old-bindir=3D}'[specify old executable = directory]:old executable directory:_directories' + '(-B --new-bindir)'{-B+,--new-bindir=3D}'[specify new executable = directory]:new executable directory:_directories' + '(-c --check)'{-c,--check}"[check clusters only (don't change any = data)]" + '(-d --old-datadir)'{-d+,--old-datadir=3D}'[specify old data = directory]:old data directory:_directories' + '(-D --new-datadir)'{-D+,--new-datadir=3D}'[specify new data = directory]:new data directory:_directories' + '(-j --jobs)'{-j+,--jobs=3D}'[upgrade in parallel with specified = number of jobs]:number of jobs' + '(-k --link)'{-k,--link}'[use hard links instead of copying files = to new cluster]' + '*'{-o+,--old-options=3D}'[specify command-line options to old = postgres]:old postgres command-line options' + '*'{-O+,--new-options=3D}'[specify command-line options to new = postgres]:new postgres command-line options' + '(-p --old-port)'{-p+,--old-port=3D}'[specify old port number]:old = port number:__pgsql_ports' + '(-P --new-port)'{-P+,--new-port=3D}'[specify new port number]:new = port number:__pgsql_ports' + '(-r --retain)'{-r,--retain}'[retain SQL and log files even after = successful completion]' + '(-U --username)'{-U+,--username=3D}'[specify cluster install user = name]: :__pgsql_roles' + '(-v --verbose)'{-v,--verbose}'[log verbosely]' + ) + _arguments -s -S : $args +} + +# Complete postgres/postmaster commands +(( $+functions[_pgsql_postgres] )) || +_pgsql_postgres() { + local -a args + + (( CURRENT > 2 )) && local -a common_opts_excl=3D( '!---null' ) + args=3D( + + x # Exclusive options + $common_opts_excl + '--describe-config[dump internal configuration variables, = descriptions, and defaults]' + + o # Other options + '-B+[specify number of shared buffers used by server = processes]:number of shared buffers' + '*-c+[set specified run-time configuration parameter]: = :__pgsql_cfg_params_values' + '-C+[display value of specified run-time configuration parameter]: = :__pgsql_cfg_params' + '-d+[specify debug level]:debug level:(0 1 2 3 4 5)' + '-D+[specify configuration directory]:PostgreSQL configuration = directory:_directories' + '-e[set default date style to European (DMY)]' + '-F[disable fsync calls]' + '(-i)-h+[specify TCP/IP address to listen on]:listening = addresses:__pgsql_hosts_seq' + '(-h)-i[allow remote connections via TCP/IP]' + '-k+[specify directory of UNIX-domain socket to listen = on]:UNIX-domain socket directory:__pgsql_hosts_seq -/' + '-l[enable secure connections using SSL]' + '-N+[specify max number of client connections]:number of client = connections' + '*-o+[specify extra command-line options to pass down to = postgres]:postgres command-line options' + '-p+[specify TCP/IP port or UNIX-domain socket file extension to = listen on]: :__pgsql_ports' + '-s[display time information and other statistics after each = command]' + '-S+[specify amount of memory for sort/hash operations]:amount of = memory' + # These are 'semi-internal' options that we don't really complete, = but we'll + # account for them anyway + '!'{-f+,-n,-O,-P,-t+,-T,-v+,-W+} + ) + # --single must be the first argument on the command line + (( CURRENT =3D=3D 2 )) && args+=3D( + '--single[enter single-user mode]' + ) + (( CURRENT > 2 )) && [[ ${(Q)words[2]} =3D=3D --single ]] && args+=3D( + '-E[echo SQL commands to stdout]' + '-j[use semicolon followed by two newlines as command-entry = terminator]' + '-r+[send server log output to specified file]:log file:_files' + ) + + _arguments -s -S : $args +} + +# Complete psql command +(( $+functions[_pgsql_psql] )) || +_pgsql_psql() { + local -a args=3D( + + x # Exclusive options + ${(@M)common_opts_excl:#*version*} + '(: * -)'{-\?,--help=3D-}'[display help information]::help = topic:(commands options variables)' + + c # Connection options + ${(@)common_opts_conn/#\(-U/(2 -U} + '(1 -d --dbname)'{-d+,--dbname=3D}'[specify database name]: = :__pgsql_databases' + # @todo Complete this properly + '(-d --dbname)1:PostgreSQL database name, conninfo string, or = URI:__pgsql_databases' + # @todo This shouldn't be offered if the first operand isn't a = dbname + '(-U --username)2: :__pgsql_roles' + + '(e)' # Echo options (ECHO variable) + {-a,--echo-all}'[echo all non-empty input lines back to stdout]' + {-b,--echo-errors}'[echo failed SQL commands to stderr]' + {-e,--echo-queries}'[echo SQL commands to stdout]' + + '(f)' # Format options + '(x)'{-A,--no-align}'[display results in unaligned format]' + '(sf sr)'{-H,--html}'[display results in HTML table format]' + + '(sf)' # Field-separator options + '(-H --html x)'{-F+,--field-separator=3D}'[specify field separator = (with -A)]:field separator' + '(-H --html x)'{-z,--field-separator-zero}'[use NUL as field = separator (with -A)]' + + '(sr)' # Record-separator options + '(-H --html x)'{-R+,--record-separator=3D}'[specify record = separator (with -A)]:record separator' + '(-H --html x)'{-0,--record-separator-zero}'[use NUL as record = separator (with -A)]' + + '(t)' # HTML-table options + '(-A --no-align sf sr)'{-T+,--table-attr=3D}'[specify HTML table = attributes]:HTML attributes' + + '(x)' # Expanded-table-formatting options + '(-A --no-align sf sr)'{-x,--expanded}'[enable expanded table = formatting]' + + o # Other options + '(-1 --single-transaction)'{-1,--single-transaction}'[wrap all = commands in a single transaction (with -c/-f)]' + '*'{-c+,--command=3D}'[execute specified command string]:command = string' + '(-E --echo-hidden)'{-E,--echo-hidden}'[echo queries generated by = backslash commands]' + '*'{-f+,--file=3D}'[execute commands from specified file]:SQL = file:_files' + # The documentation says that all other 'non-connection' options = are ignored + # when this one is given... but it lies. There *are* several = options that + # get ignored, but it's irritating to enumerate them + '(-l --list)'{-l,--list}'[display available databases]' + '(-L --log-file)'{-L+,--log-file=3D}'[also log query output to = specified file]:log file:_files' + '(-n --no-readline)'{-n,--no-readline}'[do not use Readline for = line editing and history]' + '(-o --output)'{-o+,--output=3D}'[write query output to specified = file]:output file:_files' + '*'{-P+,--pset=3D}'[specify printing option]: = :__pgsql_cfg_variables_values --pset' + '(-q --quiet)'{-q,--quiet}'[suppress informational output]' + '(-s --single-step)'{-s,--single-step}'[prompt before executing = each command]' + '(-S --single-line)'{-S,--single-line}'[treat newlines as = semicolons]' + '(-t --tuples-only)'{-t,--tuples-only}'[do not output columns = names, row counts, etc.]' + '*'{-v+,--set=3D,--variable=3D}'[perform specified variable = assignment]: :__pgsql_cfg_variables_values --set' + '(-X --no-psqlrc)'{-X,--no-psqlrc}'[do not read start-up files]' + ) + _arguments -s -S : $args +} + +# Complete reindexdb command +(( $+functions[_pgsql_reindexdb] )) || +_pgsql_reindexdb() { + (( CURRENT > 2 )) && local -a common_opts_excl=3D( '!---null' ) + local -a args=3D( + + x # Exclusive options + $common_opts_excl + + c # Connection options (not actually usable with --all) + $common_opts_connm + + '(d)' # Database connection options + '(a o)'{-d+,--dbname=3D}'[specify database name]: = :__pgsql_databases' + + C # Misc. common options + $common_opts_echo + # -q and -v are NOT exclusive. -q only seems to affect --all mode + '(-q --quiet)'{-q,--quiet}'[do not display progress messages]' + '(-v --verbose)'{-v,--verbose}'[display detailed information during = processing]' + + a # --all-mode options + '(c d n o s -a --all)'{-a,--all}'[reindex all databases]' + + n # Normal-mode options + '(a s)*'{-i+,--index=3D}'[re-create specified index only]: = :__pgsql_indexes' + '(a s)*'{-S+,--schema=3D}'[reindex specified schema only]: = :__pgsql_schemas' + '(a s)*'{-t+,--table=3D}'[reindex specified table only]: = :__pgsql_tables' + + s # --system-mode options + '(a n -s --system)'{-s,--system}"[reindex database's system = catalogs]" + + o # Operands + '(a d)1: :__pgsql_databases' + ) + _arguments -s -S : $args +} + +# Complete vacuumdb command +(( $+functions[_pgsql_vacuumdb] )) || +_pgsql_vacuumdb() { + local -a args=3D( + + x # Exclusive options + $common_opts_excl + + c # Connection options (not actually usable with --all) + $common_opts_connm + + '(d)' # Database connection options + '(a o)'{-d+,--dbname=3D}'[specify database name]: = :__pgsql_databases' + + C # Misc. common options + $common_opts_echo + '(-j --jobs)'{-j+,--jobs=3D}'[run specified number of = vacuum/analyze commands in parallel]:number of jobs' + '--min-mxid-age=3D[specify minimum MXID age of tables to = vacuum]:minimum MXID age' + '--min-xid-age=3D[specify minimum XID age of tables to = vacuum]:minimum XID age' + '--skip-locked[skip relations that cannot be immediately locked]' + # -q and -v are NOT exclusive + '(-q --quiet)'{-q,--quiet}'[do not display progress messages]' + '(-v --verbose)'{-v,--verbose}'[display detailed information during = processing]' + + f # Options incompatible with analyse-only options + '(Z)--disable-page-skipping[disable all page-skipping behavior]' + '(Z -f --full)'{-f,--full}'[perform full vacuum]' + '(Z -F --freeze)'{-F,--freze}'[aggressively freeze tuples]' + + '(z)' # Analyse options + {-z,--analyze}'[also calculate statistics for use by optimizer]' + + '(Z)' # Analyse-only options + '(f)'{-Z,--analyze-only}'[only calculate statistics for use by = optimizer (no vacuum)]' + '(f)--analyze-in-stages[like -Z, but analyze in stages for faster = results]' + + a # --all-mode options + '(c d n -a --all)'{-a,--all}'[reindex all databases]' + + n # Normal-mode options + # @todo When used with -z, &al., this accepts a column name in = brackets. We + # don't complete that + '(a)*'{-t+,--table=3D}'[vacuum/analyze specified table(column) = only]: :__pgsql_tables' + + o # Operands + '(a d)1: :__pgsql_databases' + ) + _arguments -s -S : $args +} + +# Router +_postgresql() { + # Common exclusive options + local -a common_opts_excl=3D( + '(: * -)'{-\?,--help}'[display help information]' + '(: * -)'{-V,--version}'[display version information]' + ) + # Common connection options + local -a common_opts_conn=3D( + '(-h --host)'{-h+,--host=3D}'[specify database server host or = socket directory]: :__pgsql_hosts_seq -a' + '(-p --port)'{-p+,--port=3D}'[specify database server port]: = :__pgsql_ports' + '(-U --username)'{-U+,--username=3D}'[specify user name to connect = with]: :__pgsql_roles' + '(-w -W --no-password --password)'{-w,--no-password}'[never prompt = for password on connect]' + '(-w -W --no-password --password)'{-W,--password}'[force prompt for = password on connect]' + ) + # Common connection options + --maintenance-db + local -a common_opts_connm=3D( + $common_opts_conn + '--maintenance-db=3D[specify maintenance database name]: = :__pgsql_databases' + ) + # Common echo options + local -a common_opts_echo=3D( + '(-e --echo)'{-e,--echo}'[echo generated commands to stdout]' + ) + + # Special case: pg_dumpall is handled as pg_dump + if [[ $service =3D=3D pg_dumpall ]]; then + _pgsql_pg_dump "$@" + # Special case: postmaster is handled as postgres + elif [[ $service =3D=3D postmaster ]]; then + _pgsql_postgres "$@" + elif (( $+functions[_pgsql_$service] )); then + _pgsql_$service "$@" + else + _message "unsupported PostgreSQL service: $service" + _default + fi +} + +_postgresql "$@"