psql backslash commands are schema-aware. Pattern matching behavior
follows recent pghackers discussion. This commit includes all the relevant fixes from Greg Mullane's patch of 24-June.
This commit is contained in:
parent
6ce4a4e3e1
commit
039cb47988
@ -1,5 +1,5 @@
|
||||
<!--
|
||||
$Header: /cvsroot/pgsql/doc/src/sgml/ref/grant.sgml,v 1.26 2002/05/14 18:47:58 tgl Exp $
|
||||
$Header: /cvsroot/pgsql/doc/src/sgml/ref/grant.sgml,v 1.27 2002/08/10 03:56:23 tgl Exp $
|
||||
PostgreSQL documentation
|
||||
-->
|
||||
|
||||
@ -249,16 +249,17 @@ GRANT { { CREATE | USAGE } [,...] | ALL [ PRIVILEGES ] }
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Use <xref linkend="app-psql">'s <command>\z</command> command
|
||||
Use <xref linkend="app-psql">'s <command>\dp</command> command
|
||||
to obtain information about existing privileges, for example:
|
||||
<programlisting>
|
||||
lusitania=> \z mytable
|
||||
Access privileges for database "lusitania"
|
||||
Table | Access privileges
|
||||
---------+---------------------------------------
|
||||
mytable | {=r,miriam=arwdRxt,"group todos=arw"}
|
||||
lusitania=> \dp mytable
|
||||
Access privileges for database "lusitania"
|
||||
Schema | Table | Access privileges
|
||||
--------+---------+---------------------------------------
|
||||
public | mytable | {=r,miriam=arwdRxt,"group todos=arw"}
|
||||
(1 row)
|
||||
</programlisting>
|
||||
The entries shown by <command>\z</command> are interpreted thus:
|
||||
The entries shown by <command>\dp</command> are interpreted thus:
|
||||
<programlisting>
|
||||
=xxxx -- privileges granted to PUBLIC
|
||||
uname=xxxx -- privileges granted to a user
|
||||
|
@ -1,5 +1,5 @@
|
||||
<!--
|
||||
$Header: /cvsroot/pgsql/doc/src/sgml/ref/psql-ref.sgml,v 1.69 2002/07/28 15:22:21 petere Exp $
|
||||
$Header: /cvsroot/pgsql/doc/src/sgml/ref/psql-ref.sgml,v 1.70 2002/08/10 03:56:23 tgl Exp $
|
||||
PostgreSQL documentation
|
||||
-->
|
||||
|
||||
@ -538,7 +538,7 @@ testdb=>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
To include whitespace into an argument you must quote it with a
|
||||
To include whitespace into an argument you may quote it with a
|
||||
single quote. To include a single quote into such an argument,
|
||||
precede it by a backslash. Anything contained in single quotes is
|
||||
furthermore subject to C-like substitutions for
|
||||
@ -551,25 +551,24 @@ testdb=>
|
||||
|
||||
<para>
|
||||
If an unquoted argument begins with a colon (<literal>:</literal>),
|
||||
it is taken as a variable and the value of the variable is taken as
|
||||
the argument instead.
|
||||
it is taken as a <application>psql</> variable and the value of the
|
||||
variable is used as the argument instead.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Arguments that are quoted in <quote>backticks</quote>
|
||||
(<literal>`</literal>) are taken as a command line that is passed to
|
||||
the shell. The output of the command (with a trailing newline
|
||||
the shell. The output of the command (with any trailing newline
|
||||
removed) is taken as the argument value. The above escape sequences
|
||||
also apply in backticks.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Some commands take the name of an <acronym>SQL</acronym> identifier
|
||||
Some commands take an <acronym>SQL</acronym> identifier
|
||||
(such as a table name) as argument. These arguments follow the
|
||||
syntax rules of <acronym>SQL</acronym> regarding double quotes: an
|
||||
identifier without double quotes is coerced to lower-case. For all
|
||||
other commands double quotes are not special and will become part of
|
||||
the argument.
|
||||
identifier without double quotes is coerced to lower-case, while
|
||||
whitespace within double quotes is included in the argument.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
@ -732,18 +731,17 @@ testdb=>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><literal>\d</literal> <replaceable class="parameter">relation</replaceable> </term>
|
||||
<term><literal>\d</literal> [ <replaceable class="parameter">pattern</replaceable> ]</term>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
Shows all columns of <replaceable
|
||||
class="parameter">relation</replaceable> (which could be a
|
||||
table, view, index, or sequence), their types, and any special
|
||||
For each relation (table, view, index, or sequence) matching the
|
||||
<replaceable class="parameter">pattern</replaceable>, show all
|
||||
columns, their types, and any special
|
||||
attributes such as <literal>NOT NULL</literal> or defaults, if
|
||||
any. If the relation is, in fact, a table, any defined indices,
|
||||
primary keys, unique constraints and check constraints are also
|
||||
listed. If the relation is a view, the view definition is also
|
||||
shown.
|
||||
any. Associated indexes, constraints, rules, and triggers are
|
||||
also shown, as is the view definition if the relation is a view.
|
||||
(<quote>Matching the pattern</> is defined below.)
|
||||
</para>
|
||||
|
||||
<para>
|
||||
@ -753,7 +751,8 @@ testdb=>
|
||||
|
||||
<note>
|
||||
<para>
|
||||
If <command>\d</command> is called without any arguments, it is
|
||||
If <command>\d</command> is used without a
|
||||
<replaceable class="parameter">pattern</replaceable> argument, it is
|
||||
equivalent to <command>\dtvs</command> which will show a list of
|
||||
all tables, views, and sequences. This is purely a convenience
|
||||
measure.
|
||||
@ -776,34 +775,35 @@ testdb=>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><literal>\dd</literal> [ <replaceable class="parameter">object</replaceable> ]</term>
|
||||
<term><literal>\dd</literal> [ <replaceable class="parameter">pattern</replaceable> ]</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Shows the descriptions of <replaceable
|
||||
class="parameter">object</replaceable> (which can be a regular
|
||||
expression), or of all objects if no argument is given.
|
||||
Shows the descriptions of objects matching the <replaceable
|
||||
class="parameter">pattern</replaceable>, or of all visible objects if
|
||||
no argument is given. But in either case, only objects that have
|
||||
a description are listed.
|
||||
(<quote>Object</quote> covers aggregates, functions, operators,
|
||||
types, relations (tables, views, indexes, sequences, large
|
||||
objects), rules, and triggers.) For example:
|
||||
<programlisting>
|
||||
=> <userinput>\dd version</userinput>
|
||||
Object descriptions
|
||||
Name | What | Description
|
||||
---------+----------+---------------------------
|
||||
version | function | PostgreSQL version string
|
||||
Object descriptions
|
||||
Schema | Name | Object | Description
|
||||
------------+---------+----------+---------------------------
|
||||
pg_catalog | version | function | PostgreSQL version string
|
||||
(1 row)
|
||||
</programlisting>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Descriptions for objects can be generated with the
|
||||
Descriptions for objects can be created with the
|
||||
<command>COMMENT ON</command> <acronym>SQL</acronym> command.
|
||||
</para>
|
||||
|
||||
<note>
|
||||
<para>
|
||||
<productname>PostgreSQL</productname> stores the object
|
||||
descriptions in the pg_description system table.
|
||||
descriptions in the <structname>pg_description</> system table.
|
||||
</para>
|
||||
</note>
|
||||
|
||||
@ -816,7 +816,7 @@ testdb=>
|
||||
<listitem>
|
||||
<para>
|
||||
Lists all available domains (derived types). If <replaceable
|
||||
class="parameter">pattern</replaceable> (a regular expression)
|
||||
class="parameter">pattern</replaceable>
|
||||
is specified, only matching domains are shown.
|
||||
</para>
|
||||
</listitem>
|
||||
@ -830,7 +830,7 @@ testdb=>
|
||||
<para>
|
||||
Lists available functions, together with their argument and
|
||||
return types. If <replaceable
|
||||
class="parameter">pattern</replaceable> (a regular expression)
|
||||
class="parameter">pattern</replaceable>
|
||||
is specified, only matching functions are shown. If the form
|
||||
<literal>\df+</literal> is used, additional information about
|
||||
each function, including language and description, is shown.
|
||||
@ -844,18 +844,17 @@ testdb=>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
This is not the actual command name: The letters i, s, t, v, S
|
||||
This is not the actual command name: the letters i, s, t, v, S
|
||||
stand for index, sequence, table, view, and system table,
|
||||
respectively. You can specify any or all of them in any order to
|
||||
obtain a listing of them, together with who the owner is.
|
||||
respectively. You can specify any or all of these letters, in any
|
||||
order, to obtain a listing of all the matching objects.
|
||||
If <quote>+</quote> is appended to the command name, each object is
|
||||
listed with its associated description, if any.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
If <replaceable class="parameter">pattern</replaceable> is
|
||||
specified, it is a regular expression that restricts the listing
|
||||
to those objects whose name matches. If one appends a
|
||||
<quote>+</quote> to the command name, each object is listed with
|
||||
its associated description, if any.
|
||||
If a <replaceable class="parameter">pattern</replaceable> is
|
||||
specified, only objects whose name matches the pattern are listed.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
@ -873,12 +872,12 @@ testdb=>
|
||||
|
||||
|
||||
<varlistentry>
|
||||
<term><literal>\do [ <replaceable class="parameter">name</replaceable> ]</literal></term>
|
||||
<term><literal>\do [ <replaceable class="parameter">pattern</replaceable> ]</literal></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Lists available operators with their operand and return types.
|
||||
If <replaceable class="parameter">name</replaceable> is
|
||||
specified, only operators with that name will be shown.
|
||||
If a <replaceable class="parameter">pattern</replaceable> is
|
||||
specified, only operators whose name matches the pattern are listed.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
@ -888,9 +887,17 @@ testdb=>
|
||||
<term><literal>\dp</literal> [ <replaceable class="parameter">pattern</replaceable> ]</term>
|
||||
<listitem>
|
||||
<para>
|
||||
This is an alias for <command>\z</command> which was included
|
||||
for its greater mnemonic value (<quote>display
|
||||
permissions</quote>).
|
||||
Produces a list of all available tables with their
|
||||
associated access permissions.
|
||||
If a <replaceable class="parameter">pattern</replaceable> is
|
||||
specified, only tables whose name matches the pattern are listed.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The commands <xref linkend="SQL-GRANT"> and
|
||||
<xref linkend="SQL-REVOKE">
|
||||
are used to set access permissions. See <xref linkend="SQL-GRANT">
|
||||
for more information.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
@ -912,7 +919,7 @@ testdb=>
|
||||
<term><literal>\du [ <replaceable class="parameter">pattern</replaceable> ]</literal></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Lists all configured users or only those that match <replaceable
|
||||
Lists all database users, or only those that match <replaceable
|
||||
class="parameter">pattern</replaceable>.
|
||||
</para>
|
||||
</listitem>
|
||||
@ -1608,57 +1615,23 @@ lo_import 152801
|
||||
<term><literal>\z</literal> [ <replaceable class="parameter">pattern</replaceable> ]</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Produces a list of all tables in the database with their
|
||||
appropriate access permissions listed. If an argument is given
|
||||
it is taken as a regular expression which limits the listing to
|
||||
those tables which match it.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<programlisting>
|
||||
test=> <userinput>\z</userinput>
|
||||
Access permissions for database "test"
|
||||
Relation | Access permissions
|
||||
----------+-------------------------------------
|
||||
my_table | {"=r","joe=arwR", "group staff=ar"}
|
||||
(1 row )
|
||||
</programlisting>
|
||||
Read this as follows:
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>"=r"</literal>: <literal>PUBLIC</literal> has read
|
||||
(<command>SELECT</command>) permission on the table.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>"joe=arwR"</literal>: User <literal>joe</literal> has
|
||||
read, write (<command>UPDATE</command>,
|
||||
<command>DELETE</command>), <quote>append</quote>
|
||||
(<command>INSERT</command>) permissions, and permission to
|
||||
create rules on the table.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>"group staff=ar"</literal>: Group
|
||||
<literal>staff</literal> has <command>SELECT</command> and
|
||||
<command>INSERT</command> permission.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
Produces a list of all available tables with their
|
||||
associated access permissions.
|
||||
If a <replaceable class="parameter">pattern</replaceable> is
|
||||
specified, only tables whose name matches the pattern are listed.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The commands <xref linkend="SQL-GRANT"> and
|
||||
<xref linkend="SQL-REVOKE">
|
||||
are used to set access permissions.
|
||||
are used to set access permissions. See <xref linkend="SQL-GRANT">
|
||||
for more information.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
This is an alias for <command>\dp</command> (<quote>display
|
||||
permissions</quote>).
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
@ -1688,6 +1661,46 @@ Access permissions for database "test"
|
||||
|
||||
</variablelist>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The various <literal>\d</> commands accept a <replaceable
|
||||
class="parameter">pattern</replaceable> parameter to specify the
|
||||
object name(s) to be displayed. Patterns are interpreted similarly
|
||||
to SQL identifiers, in that unquoted letters are forced to lowercase,
|
||||
while double quotes (<literal>"</>) protect letters from case conversion
|
||||
and allow incorporation of whitespace into the identifier. Within
|
||||
double quotes, paired double quotes reduce to a single double quote in
|
||||
the resulting name. For example, <literal>FOO"BAR"BAZ</> is interpreted
|
||||
as <literal>fooBARbaz</>, and <literal>"A weird"" name"</> becomes
|
||||
<literal>A weird" name</>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
More interestingly, <literal>\d</> patterns allow the use of
|
||||
<literal>*</> to mean <quote>any sequence of characters</>, and
|
||||
<literal>?</> to mean <quote>any single character</>. (This notation
|
||||
is comparable to Unix shell filename patterns.) Advanced users can
|
||||
also use regular-expression notations such as character classes, for
|
||||
example <literal>[0-9]</> to match <quote>any digit</>. To make any of
|
||||
these pattern-matching characters be interpreted literally, surround it
|
||||
with double quotes.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
A pattern that contains an (unquoted) dot is interpreted as a schema
|
||||
name pattern followed by an object name pattern. For example,
|
||||
<literal> \dt foo*.bar*</> displays all tables in schemas whose name
|
||||
starts with <literal>foo</> and whose table name
|
||||
starts with <literal>bar</>. If no dot appears, then the pattern
|
||||
matches only objects that are visible in the current schema search path.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Whenever the <replaceable class="parameter">pattern</replaceable> parameter
|
||||
is omitted completely, the <literal>\d</> commands display all objects
|
||||
that are visible in the current schema search path. To see all objects
|
||||
in the database, use the pattern <literal>*.*</>.
|
||||
</para>
|
||||
</refsect2>
|
||||
|
||||
<refsect2>
|
||||
@ -2402,11 +2415,12 @@ $ ./configure --with-includes=/opt/gnu/include --with-libs=/opt/gnu/lib ...
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
In some earlier life <application>psql</application> allowed the
|
||||
first argument to start directly after the (single-letter)
|
||||
command. For compatibility this is still supported to some extent
|
||||
In an earlier life <application>psql</application> allowed the
|
||||
first argument of a single-letter backslash command to start
|
||||
directly after the command, without intervening whitespace. For
|
||||
compatibility this is still supported to some extent,
|
||||
but I am not going to explain the details here as this use is
|
||||
discouraged. But if you get strange messages, keep this in mind.
|
||||
discouraged. If you get strange messages, keep this in mind.
|
||||
For example
|
||||
<programlisting>
|
||||
testdb=> <userinput>\foo</userinput>
|
||||
@ -2421,7 +2435,8 @@ Field separator is "oo",
|
||||
<application>psql</application> only works smoothly with servers
|
||||
of the same version. That does not mean other combinations will
|
||||
fail outright, but subtle and not-so-subtle problems might come
|
||||
up.
|
||||
up. Backslash commands are particularly likely to fail if the
|
||||
server is of a different version.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
/*
|
||||
* psql - the PostgreSQL interactive terminal
|
||||
*
|
||||
* Copyright 2000 by PostgreSQL Global Development Group
|
||||
* Copyright 2000-2002 by PostgreSQL Global Development Group
|
||||
*
|
||||
* $Header: /cvsroot/pgsql/src/bin/psql/command.c,v 1.74 2002/07/18 02:02:30 ishii Exp $
|
||||
* $Header: /cvsroot/pgsql/src/bin/psql/command.c,v 1.75 2002/08/10 03:56:23 tgl Exp $
|
||||
*/
|
||||
#include "postgres_fe.h"
|
||||
#include "command.h"
|
||||
@ -54,7 +54,7 @@ enum option_type
|
||||
OT_NORMAL, /* normal case */
|
||||
OT_SQLID, /* treat as SQL identifier */
|
||||
OT_SQLIDHACK, /* SQL identifier, but don't downcase */
|
||||
OT_FILEPIPE /* it's a file or pipe */
|
||||
OT_FILEPIPE /* it's a filename or pipe */
|
||||
};
|
||||
|
||||
static char *scan_option(char **string, enum option_type type,
|
||||
@ -328,10 +328,11 @@ exec_command(const char *cmd,
|
||||
/* \d* commands */
|
||||
else if (cmd[0] == 'd')
|
||||
{
|
||||
char *name;
|
||||
char *pattern;
|
||||
bool show_verbose;
|
||||
|
||||
name = scan_option(&string, OT_SQLID, NULL, true);
|
||||
/* We don't do SQLID reduction on the pattern yet */
|
||||
pattern = scan_option(&string, OT_NORMAL, NULL, true);
|
||||
|
||||
show_verbose = strchr(cmd, '+') ? true : false;
|
||||
|
||||
@ -339,51 +340,53 @@ exec_command(const char *cmd,
|
||||
{
|
||||
case '\0':
|
||||
case '+':
|
||||
if (name)
|
||||
success = describeTableDetails(name, show_verbose);
|
||||
if (pattern)
|
||||
success = describeTableDetails(pattern, show_verbose);
|
||||
else
|
||||
/* standard listing of interesting things */
|
||||
success = listTables("tvs", NULL, show_verbose);
|
||||
break;
|
||||
case 'a':
|
||||
success = describeAggregates(name);
|
||||
success = describeAggregates(pattern, show_verbose);
|
||||
break;
|
||||
case 'd':
|
||||
success = objectDescription(name);
|
||||
success = objectDescription(pattern);
|
||||
break;
|
||||
case 'f':
|
||||
success = describeFunctions(name, show_verbose);
|
||||
success = describeFunctions(pattern, show_verbose);
|
||||
break;
|
||||
case 'l':
|
||||
success = do_lo_list();
|
||||
break;
|
||||
case 'o':
|
||||
success = describeOperators(name);
|
||||
success = describeOperators(pattern);
|
||||
break;
|
||||
case 'p':
|
||||
success = permissionsList(name);
|
||||
success = permissionsList(pattern);
|
||||
break;
|
||||
case 'T':
|
||||
success = describeTypes(name, show_verbose);
|
||||
success = describeTypes(pattern, show_verbose);
|
||||
break;
|
||||
case 't':
|
||||
case 'v':
|
||||
case 'i':
|
||||
case 's':
|
||||
case 'S':
|
||||
success = listTables(&cmd[1], name, show_verbose);
|
||||
success = listTables(&cmd[1], pattern, show_verbose);
|
||||
break;
|
||||
case 'u':
|
||||
success = describeUsers(name);
|
||||
success = describeUsers(pattern);
|
||||
break;
|
||||
case 'D':
|
||||
success = listDomains(name);
|
||||
success = listDomains(pattern);
|
||||
break;
|
||||
|
||||
default:
|
||||
status = CMD_UNKNOWN;
|
||||
}
|
||||
free(name);
|
||||
|
||||
if (pattern)
|
||||
free(pattern);
|
||||
}
|
||||
|
||||
|
||||
@ -815,13 +818,14 @@ exec_command(const char *cmd,
|
||||
success = do_pset("expanded", NULL, &pset.popt, quiet);
|
||||
|
||||
|
||||
/* \z -- list table rights (grant/revoke) */
|
||||
/* \z -- list table rights (equivalent to \dp) */
|
||||
else if (strcmp(cmd, "z") == 0)
|
||||
{
|
||||
char *opt = scan_option(&string, OT_SQLID, NULL, true);
|
||||
char *pattern = scan_option(&string, OT_NORMAL, NULL, true);
|
||||
|
||||
success = permissionsList(opt);
|
||||
free(opt);
|
||||
success = permissionsList(pattern);
|
||||
if (pattern)
|
||||
free(pattern);
|
||||
}
|
||||
|
||||
/* \! -- shell escape */
|
||||
@ -881,11 +885,27 @@ exec_command(const char *cmd,
|
||||
|
||||
/*
|
||||
* scan_option()
|
||||
*
|
||||
* *string points to possible option string on entry; on exit, it's updated
|
||||
* to point past the option string (if any).
|
||||
*
|
||||
* type tells what processing, if any, to perform on the option string;
|
||||
* for example, if it's a SQL identifier, we want to downcase any unquoted
|
||||
* letters.
|
||||
*
|
||||
* if quote is not NULL, *quote is set to 0 if no quoting was found, else
|
||||
* the quote symbol.
|
||||
*
|
||||
* if semicolon is true, trailing semicolon(s) that would otherwise be taken
|
||||
* as part of the option string will be stripped.
|
||||
*
|
||||
* Return value is NULL if no option found, else a malloc'd copy of the
|
||||
* processed option value.
|
||||
*/
|
||||
static char *
|
||||
scan_option(char **string, enum option_type type, char *quote, bool semicolon)
|
||||
{
|
||||
unsigned int pos = 0;
|
||||
unsigned int pos;
|
||||
char *options_string;
|
||||
char *return_val;
|
||||
|
||||
@ -897,82 +917,27 @@ scan_option(char **string, enum option_type type, char *quote, bool semicolon)
|
||||
|
||||
options_string = *string;
|
||||
/* skip leading whitespace */
|
||||
pos += strspn(options_string + pos, " \t\n\r");
|
||||
pos = strspn(options_string, " \t\n\r");
|
||||
|
||||
switch (options_string[pos])
|
||||
{
|
||||
/*
|
||||
* Double quoted string
|
||||
* End of line: no option present
|
||||
*/
|
||||
case '"':
|
||||
{
|
||||
unsigned int jj;
|
||||
unsigned short int bslash_count = 0;
|
||||
case '\0':
|
||||
*string = &options_string[pos];
|
||||
return NULL;
|
||||
|
||||
/* scan for end of quote */
|
||||
for (jj = pos + 1; options_string[jj]; jj += PQmblen(&options_string[jj], pset.encoding))
|
||||
{
|
||||
if (options_string[jj] == '"' && bslash_count % 2 == 0)
|
||||
break;
|
||||
|
||||
if (options_string[jj] == '\\')
|
||||
bslash_count++;
|
||||
else
|
||||
bslash_count = 0;
|
||||
}
|
||||
|
||||
if (options_string[jj] == 0)
|
||||
{
|
||||
psql_error("parse error at the end of line\n");
|
||||
*string = &options_string[jj];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return_val = malloc(jj - pos + 2);
|
||||
if (!return_val)
|
||||
{
|
||||
psql_error("out of memory\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/*
|
||||
* If this is expected to be an SQL identifier like option
|
||||
* then we strip out the double quotes
|
||||
*/
|
||||
|
||||
if (type == OT_SQLID || type == OT_SQLIDHACK)
|
||||
{
|
||||
unsigned int k,
|
||||
cc;
|
||||
|
||||
bslash_count = 0;
|
||||
cc = 0;
|
||||
for (k = pos + 1; options_string[k]; k += PQmblen(&options_string[k], pset.encoding))
|
||||
{
|
||||
if (options_string[k] == '"' && bslash_count % 2 == 0)
|
||||
break;
|
||||
|
||||
if (options_string[jj] == '\\')
|
||||
bslash_count++;
|
||||
else
|
||||
bslash_count = 0;
|
||||
|
||||
return_val[cc++] = options_string[k];
|
||||
}
|
||||
return_val[cc] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
strncpy(return_val, &options_string[pos], jj - pos + 1);
|
||||
return_val[jj - pos + 1] = '\0';
|
||||
}
|
||||
|
||||
*string = options_string + jj + 1;
|
||||
if (quote)
|
||||
*quote = '"';
|
||||
|
||||
return return_val;
|
||||
}
|
||||
/*
|
||||
* Next command: treat like end of line
|
||||
*
|
||||
* XXX this means we can't conveniently accept options that
|
||||
* start with a backslash; therefore, option processing that
|
||||
* encourages use of backslashes is rather broken.
|
||||
*/
|
||||
case '\\':
|
||||
*string = &options_string[pos];
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* A single quote has a psql internal meaning, such as for
|
||||
@ -1015,7 +980,7 @@ scan_option(char **string, enum option_type type, char *quote, bool semicolon)
|
||||
case '`':
|
||||
{
|
||||
bool error = false;
|
||||
FILE *fd = NULL;
|
||||
FILE *fd;
|
||||
char *file;
|
||||
PQExpBufferData output;
|
||||
char buf[512];
|
||||
@ -1040,10 +1005,10 @@ scan_option(char **string, enum option_type type, char *quote, bool semicolon)
|
||||
error = true;
|
||||
}
|
||||
|
||||
initPQExpBuffer(&output);
|
||||
|
||||
if (!error)
|
||||
{
|
||||
initPQExpBuffer(&output);
|
||||
|
||||
do
|
||||
{
|
||||
result = fread(buf, 1, 512, fd);
|
||||
@ -1056,27 +1021,26 @@ scan_option(char **string, enum option_type type, char *quote, bool semicolon)
|
||||
appendBinaryPQExpBuffer(&output, buf, result);
|
||||
} while (!feof(fd));
|
||||
appendPQExpBufferChar(&output, '\0');
|
||||
}
|
||||
|
||||
if (pclose(fd) == -1)
|
||||
{
|
||||
psql_error("%s: %s\n", file, strerror(errno));
|
||||
error = true;
|
||||
}
|
||||
if (fd && pclose(fd) == -1)
|
||||
{
|
||||
psql_error("%s: %s\n", file, strerror(errno));
|
||||
error = true;
|
||||
}
|
||||
|
||||
if (!error)
|
||||
{
|
||||
if (output.data[strlen(output.data) - 1] == '\n')
|
||||
output.data[strlen(output.data) - 1] = '\0';
|
||||
}
|
||||
|
||||
if (!error)
|
||||
return_val = output.data;
|
||||
}
|
||||
else
|
||||
{
|
||||
return_val = xstrdup("");
|
||||
termPQExpBuffer(&output);
|
||||
}
|
||||
|
||||
options_string[pos + 1 + len] = '`';
|
||||
*string = options_string + pos + len + 2;
|
||||
if (quote)
|
||||
@ -1084,13 +1048,6 @@ scan_option(char **string, enum option_type type, char *quote, bool semicolon)
|
||||
return return_val;
|
||||
}
|
||||
|
||||
/*
|
||||
* end of line
|
||||
*/
|
||||
case 0:
|
||||
*string = &options_string[pos];
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* Variable substitution
|
||||
*/
|
||||
@ -1109,17 +1066,10 @@ scan_option(char **string, enum option_type type, char *quote, bool semicolon)
|
||||
return_val = xstrdup(value);
|
||||
options_string[pos + token_end + 1] = save_char;
|
||||
*string = &options_string[pos + token_end + 1];
|
||||
/* XXX should we set *quote to ':' here? */
|
||||
return return_val;
|
||||
}
|
||||
|
||||
/*
|
||||
* Next command
|
||||
*/
|
||||
case '\\':
|
||||
*string = options_string + pos;
|
||||
return NULL;
|
||||
break;
|
||||
|
||||
/*
|
||||
* | could be the beginning of a pipe if so, take rest of line
|
||||
* as command
|
||||
@ -1127,49 +1077,135 @@ scan_option(char **string, enum option_type type, char *quote, bool semicolon)
|
||||
case '|':
|
||||
if (type == OT_FILEPIPE)
|
||||
{
|
||||
*string += strlen(options_string + pos);
|
||||
*string += strlen(*string);
|
||||
return xstrdup(options_string + pos);
|
||||
break;
|
||||
}
|
||||
/* fallthrough for other option types */
|
||||
|
||||
/*
|
||||
* A normal word
|
||||
* Default case: token extends to next whitespace, except that
|
||||
* whitespace within double quotes doesn't end the token.
|
||||
*
|
||||
* If we are processing the option as a SQL identifier, then
|
||||
* downcase unquoted letters and remove double-quotes --- but
|
||||
* doubled double-quotes become output double-quotes, per spec.
|
||||
*
|
||||
* Note that a string like FOO"BAR"BAZ will be converted to
|
||||
* fooBARbaz; this is somewhat inconsistent with the SQL spec,
|
||||
* which would have us parse it as several identifiers. But
|
||||
* for psql's purposes, we want a string like "foo"."bar" to
|
||||
* be treated as one option, so there's little choice.
|
||||
*/
|
||||
default:
|
||||
{
|
||||
size_t token_end;
|
||||
bool inquotes = false;
|
||||
size_t token_len;
|
||||
char *cp;
|
||||
|
||||
token_end = strcspn(&options_string[pos], " \t\n\r");
|
||||
return_val = malloc(token_end + 1);
|
||||
/* Find end of option */
|
||||
|
||||
cp = &options_string[pos];
|
||||
for (;;)
|
||||
{
|
||||
/* Find next quote, whitespace, or end of string */
|
||||
cp += strcspn(cp, "\" \t\n\r");
|
||||
if (inquotes)
|
||||
{
|
||||
if (*cp == '\0')
|
||||
{
|
||||
psql_error("parse error at the end of line\n");
|
||||
*string = cp;
|
||||
return NULL;
|
||||
}
|
||||
if (*cp == '"')
|
||||
inquotes = false;
|
||||
cp++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (*cp != '"')
|
||||
break; /* whitespace or end of string */
|
||||
if (quote)
|
||||
*quote = '"';
|
||||
inquotes = true;
|
||||
cp++;
|
||||
}
|
||||
}
|
||||
|
||||
*string = cp;
|
||||
|
||||
/* Copy the option */
|
||||
token_len = cp - &options_string[pos];
|
||||
|
||||
return_val = malloc(token_len + 1);
|
||||
if (!return_val)
|
||||
{
|
||||
psql_error("out of memory\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
strncpy(return_val, &options_string[pos], token_end);
|
||||
return_val[token_end] = 0;
|
||||
|
||||
/* Strip any trailing semi-colons for some types */
|
||||
memcpy(return_val, &options_string[pos], token_len);
|
||||
return_val[token_len] = '\0';
|
||||
|
||||
/* Strip any trailing semi-colons if requested */
|
||||
if (semicolon)
|
||||
{
|
||||
int i;
|
||||
int i;
|
||||
|
||||
for (i = strlen(return_val) - 1; i && return_val[i] == ';'; i--);
|
||||
if (i < strlen(return_val) - 1)
|
||||
for (i = token_len - 1;
|
||||
i >= 0 && return_val[i] == ';';
|
||||
i--)
|
||||
/* skip */;
|
||||
|
||||
if (i < 0)
|
||||
{
|
||||
/* nothing left after stripping the semicolon... */
|
||||
free(return_val);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (i < token_len - 1)
|
||||
return_val[i + 1] = '\0';
|
||||
}
|
||||
|
||||
if (type == OT_SQLID)
|
||||
for (cp = return_val; *cp; cp += PQmblen(cp, pset.encoding))
|
||||
if (isupper((unsigned char) *cp))
|
||||
*cp = tolower((unsigned char) *cp);
|
||||
/*
|
||||
* If SQL identifier processing was requested,
|
||||
* then we strip out excess double quotes and downcase
|
||||
* unquoted letters.
|
||||
*/
|
||||
if (type == OT_SQLID || type == OT_SQLIDHACK)
|
||||
{
|
||||
inquotes = false;
|
||||
cp = return_val;
|
||||
|
||||
while (*cp)
|
||||
{
|
||||
if (*cp == '"')
|
||||
{
|
||||
if (inquotes && cp[1] == '"')
|
||||
{
|
||||
/* Keep the first quote, remove the second */
|
||||
cp++;
|
||||
}
|
||||
inquotes = !inquotes;
|
||||
/* Collapse out quote at *cp */
|
||||
memmove(cp, cp+1, strlen(cp));
|
||||
/* do not advance cp */
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!inquotes && type == OT_SQLID)
|
||||
{
|
||||
if (isupper((unsigned char) *cp))
|
||||
*cp = tolower((unsigned char) *cp);
|
||||
}
|
||||
cp += PQmblen(cp, pset.encoding);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*string = &options_string[pos + token_end];
|
||||
return return_val;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -1429,7 +1465,7 @@ test_superuser(const char *username)
|
||||
return false;
|
||||
|
||||
initPQExpBuffer(&buf);
|
||||
printfPQExpBuffer(&buf, "SELECT usesuper FROM pg_user WHERE usename = '%s'", username);
|
||||
printfPQExpBuffer(&buf, "SELECT usesuper FROM pg_catalog.pg_user WHERE usename = '%s'", username);
|
||||
res = PSQLexec(buf.data);
|
||||
termPQExpBuffer(&buf);
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,9 +1,9 @@
|
||||
/*
|
||||
* psql - the PostgreSQL interactive terminal
|
||||
*
|
||||
* Copyright 2000 by PostgreSQL Global Development Group
|
||||
* Copyright 2000-2002 by PostgreSQL Global Development Group
|
||||
*
|
||||
* $Header: /cvsroot/pgsql/src/bin/psql/describe.h,v 1.16 2002/03/19 02:32:21 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/bin/psql/describe.h,v 1.17 2002/08/10 03:56:24 tgl Exp $
|
||||
*/
|
||||
#ifndef DESCRIBE_H
|
||||
#define DESCRIBE_H
|
||||
@ -11,36 +11,36 @@
|
||||
#include "settings.h"
|
||||
|
||||
/* \da */
|
||||
bool describeAggregates(const char *name);
|
||||
bool describeAggregates(const char *pattern, bool verbose);
|
||||
|
||||
/* \df */
|
||||
bool describeFunctions(const char *name, bool verbose);
|
||||
bool describeFunctions(const char *pattern, bool verbose);
|
||||
|
||||
/* \dT */
|
||||
bool describeTypes(const char *name, bool verbose);
|
||||
bool describeTypes(const char *pattern, bool verbose);
|
||||
|
||||
/* \do */
|
||||
bool describeOperators(const char *name);
|
||||
bool describeOperators(const char *pattern);
|
||||
|
||||
/* \du */
|
||||
bool describeUsers(const char *name);
|
||||
bool describeUsers(const char *pattern);
|
||||
|
||||
/* \z (or \dp) */
|
||||
bool permissionsList(const char *name);
|
||||
bool permissionsList(const char *pattern);
|
||||
|
||||
/* \dd */
|
||||
bool objectDescription(const char *object);
|
||||
bool objectDescription(const char *pattern);
|
||||
|
||||
/* \d foo */
|
||||
bool describeTableDetails(const char *name, bool desc);
|
||||
bool describeTableDetails(const char *pattern, bool verbose);
|
||||
|
||||
/* \l */
|
||||
bool listAllDbs(bool desc);
|
||||
|
||||
/* \dt, \di, \ds, \dS, etc. */
|
||||
bool listTables(const char *infotype, const char *name, bool desc);
|
||||
bool listTables(const char *tabtypes, const char *pattern, bool verbose);
|
||||
|
||||
/* \dD */
|
||||
bool listDomains(const char *name);
|
||||
bool listDomains(const char *pattern);
|
||||
|
||||
#endif /* DESCRIBE_H */
|
||||
|
@ -1,9 +1,9 @@
|
||||
/*
|
||||
* psql - the PostgreSQL interactive terminal
|
||||
*
|
||||
* Copyright 2000 by PostgreSQL Global Development Group
|
||||
* Copyright 2000-2002 by PostgreSQL Global Development Group
|
||||
*
|
||||
* $Header: /cvsroot/pgsql/src/bin/psql/large_obj.c,v 1.19 2002/03/06 06:10:31 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/bin/psql/large_obj.c,v 1.20 2002/08/10 03:56:24 tgl Exp $
|
||||
*/
|
||||
#include "postgres_fe.h"
|
||||
#include "large_obj.h"
|
||||
@ -209,9 +209,10 @@ do_lo_import(const char *filename_arg, const char *comment_arg)
|
||||
return false;
|
||||
}
|
||||
sprintf(cmdbuf,
|
||||
"INSERT INTO pg_description VALUES ('%u', "
|
||||
"(SELECT oid FROM pg_class WHERE relname = 'pg_largeobject'),"
|
||||
" 0, '", loid);
|
||||
"INSERT INTO pg_catalog.pg_description VALUES ('%u', "
|
||||
"'pg_catalog.pg_largeobject'::regclass, "
|
||||
"0, '",
|
||||
loid);
|
||||
bufptr = cmdbuf + strlen(cmdbuf);
|
||||
for (i = 0; i < slen; i++)
|
||||
{
|
||||
@ -310,8 +311,8 @@ do_lo_unlink(const char *loid_arg)
|
||||
/* XXX ought to replace this with some kind of COMMENT command */
|
||||
if (pset.issuper)
|
||||
{
|
||||
sprintf(buf, "DELETE FROM pg_description WHERE objoid = '%u' "
|
||||
"AND classoid = (SELECT oid FROM pg_class WHERE relname = 'pg_largeobject')",
|
||||
sprintf(buf, "DELETE FROM pg_catalog.pg_description WHERE objoid = '%u' "
|
||||
"AND classoid = 'pg_catalog.pg_largeobject'::regclass",
|
||||
loid);
|
||||
if (!(res = PSQLexec(buf)))
|
||||
{
|
||||
@ -356,8 +357,8 @@ do_lo_list(void)
|
||||
printQueryOpt myopt = pset.popt;
|
||||
|
||||
snprintf(buf, sizeof(buf),
|
||||
"SELECT loid as \"ID\", obj_description(loid, 'pg_largeobject') as \"%s\"\n"
|
||||
"FROM (SELECT DISTINCT loid FROM pg_largeobject) x\n"
|
||||
"SELECT loid as \"ID\", pg_catalog.obj_description(loid, 'pg_largeobject') as \"%s\"\n"
|
||||
"FROM (SELECT DISTINCT loid FROM pg_catalog.pg_largeobject) x\n"
|
||||
"ORDER BY \"ID\"",
|
||||
gettext("Description"));
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
/*
|
||||
* psql - the PostgreSQL interactive terminal
|
||||
*
|
||||
* Copyright 2000 by PostgreSQL Global Development Group
|
||||
* Copyright 2000-2002 by PostgreSQL Global Development Group
|
||||
*
|
||||
* $Header: /cvsroot/pgsql/src/bin/psql/tab-complete.c,v 1.55 2002/08/04 05:01:57 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/bin/psql/tab-complete.c,v 1.56 2002/08/10 03:56:24 tgl Exp $
|
||||
*/
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
@ -118,11 +118,20 @@ initialize_readline(void)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Queries to get lists of names of various kinds of things, possibly
|
||||
* restricted to names matching a partially entered name. In these queries,
|
||||
* the %s will be replaced by the text entered so far, the %d by its length.
|
||||
*/
|
||||
|
||||
#define Query_for_list_of_tables "SELECT relname FROM pg_catalog.pg_class WHERE (relkind='r' or relkind='v') and substr(relname,1,%d)='%s' and pg_catalog.pg_table_is_visible(oid)"
|
||||
#define Query_for_list_of_indexes "SELECT relname FROM pg_catalog.pg_class WHERE relkind='i' and substr(relname,1,%d)='%s' and pg_catalog.pg_table_is_visible(oid)"
|
||||
#define Query_for_list_of_databases "SELECT datname FROM pg_catalog.pg_database WHERE substr(datname,1,%d)='%s'"
|
||||
#define Query_for_list_of_attributes "SELECT a.attname FROM pg_catalog.pg_attribute a, pg_catalog.pg_class c WHERE c.oid = a.attrelid and a.attnum>0 and not a.attisdropped and substr(a.attname,1,%d)='%s' and c.relname='%s' and pg_catalog.pg_table_is_visible(c.oid)"
|
||||
#define Query_for_list_of_users "SELECT usename FROM pg_catalog.pg_user WHERE substr(usename,1,%d)='%s'"
|
||||
|
||||
/* This is a list of all "things" in Pgsql, which can show up after CREATE or
|
||||
DROP; and there is also a query to get a list of them.
|
||||
The %s will be replaced by the text entered so far, the %d by its length.
|
||||
If you change the order here or insert things, make sure to also adjust the
|
||||
referencing macros below.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
@ -131,37 +140,29 @@ typedef struct
|
||||
} pgsql_thing_t;
|
||||
|
||||
pgsql_thing_t words_after_create[] = {
|
||||
{"AGGREGATE", "SELECT distinct proname FROM pg_catalog.pg_proc WHERE proisagg AND substr(proname,1,%d)='%s'"},
|
||||
{"DATABASE", "SELECT datname FROM pg_catalog.pg_database WHERE substr(datname,1,%d)='%s'"},
|
||||
{"FUNCTION", "SELECT distinct proname FROM pg_catalog.pg_proc WHERE substr(proname,1,%d)='%s'"},
|
||||
{"AGGREGATE", "SELECT DISTINCT proname FROM pg_catalog.pg_proc WHERE proisagg AND substr(proname,1,%d)='%s'"},
|
||||
{"DATABASE", Query_for_list_of_databases},
|
||||
{"FUNCTION", "SELECT DISTINCT proname FROM pg_catalog.pg_proc WHERE substr(proname,1,%d)='%s'"},
|
||||
{"GROUP", "SELECT groname FROM pg_catalog.pg_group WHERE substr(groname,1,%d)='%s'"},
|
||||
{"INDEX", "SELECT relname FROM pg_catalog.pg_class WHERE relkind='i' and substr(relname,1,%d)='%s'"},
|
||||
{"INDEX", Query_for_list_of_indexes},
|
||||
{"OPERATOR", NULL}, /* Querying for this is probably not such a good idea. */
|
||||
{"RULE", "SELECT rulename FROM pg_catalog.pg_rules WHERE substr(rulename,1,%d)='%s'"},
|
||||
{"SCHEMA", "SELECT nspname FROM pg_catalog.pg_namespace WHERE substr(nspname,1,%d)='%s'"},
|
||||
{"SEQUENCE", "SELECT relname FROM pg_catalog.pg_class WHERE relkind='S' and substr(relname,1,%d)='%s'"},
|
||||
{"TABLE", "SELECT relname FROM pg_catalog.pg_class WHERE (relkind='r' or relkind='v') and substr(relname,1,%d)='%s'"},
|
||||
{"TABLE", Query_for_list_of_tables},
|
||||
{"TEMP", NULL}, /* for CREATE TEMP TABLE ... */
|
||||
{"TRIGGER", "SELECT tgname FROM pg_catalog.pg_trigger WHERE substr(tgname,1,%d)='%s'"},
|
||||
{"TYPE", "SELECT typname FROM pg_catalog.pg_type WHERE substr(typname,1,%d)='%s'"},
|
||||
{"UNIQUE", NULL}, /* for CREATE UNIQUE INDEX ... */
|
||||
{"USER", "SELECT usename FROM pg_catalog.pg_user WHERE substr(usename,1,%d)='%s'"},
|
||||
{"USER", Query_for_list_of_users},
|
||||
{"VIEW", "SELECT viewname FROM pg_catalog.pg_views WHERE substr(viewname,1,%d)='%s'"},
|
||||
{NULL, NULL} /* end of list */
|
||||
};
|
||||
|
||||
|
||||
/* The query to get a list of tables and a list of indexes, which are used at
|
||||
various places. */
|
||||
#define Query_for_list_of_tables words_after_create[9].query
|
||||
#define Query_for_list_of_indexes words_after_create[4].query
|
||||
#define Query_for_list_of_databases words_after_create[1].query
|
||||
#define Query_for_list_of_attributes "SELECT a.attname FROM pg_catalog.pg_attribute a, pg_catalog.pg_class c WHERE c.oid = a.attrelid and a.attnum>0 and not a.attisdropped and substr(a.attname,1,%d)='%s' and c.relname='%s'"
|
||||
#define Query_for_list_of_users words_after_create[14].query
|
||||
|
||||
/* A couple of macros to ease typing. You can use these to complete the given
|
||||
string with
|
||||
1) The results from a query you pass it. (Perhaps one of those right above?)
|
||||
1) The results from a query you pass it. (Perhaps one of those above?)
|
||||
2) The items from a null-pointer-terminated list.
|
||||
3) A string constant
|
||||
4) The list of attributes to the given table.
|
||||
@ -375,7 +376,7 @@ psql_completion(char *text, int start, int end)
|
||||
* queries. */
|
||||
|
||||
if (snprintf(query_buffer, BUF_SIZE,
|
||||
"SELECT c1.relname FROM pg_catalog.pg_class c1, pg_catalog.pg_class c2, pg_catalog.pg_index i WHERE c1.oid=i.indrelid and i.indexrelid=c2.oid and c2.relname='%s'",
|
||||
"SELECT c1.relname FROM pg_catalog.pg_class c1, pg_catalog.pg_class c2, pg_catalog.pg_index i WHERE c1.oid=i.indrelid and i.indexrelid=c2.oid and c2.relname='%s' and pg_catalog.pg_table_is_visible(c2.oid)",
|
||||
prev2_wd) == -1)
|
||||
ERROR_QUERY_TOO_LONG;
|
||||
else
|
||||
@ -389,7 +390,8 @@ psql_completion(char *text, int start, int end)
|
||||
{
|
||||
char *list_COMMENT[] =
|
||||
{"DATABASE", "INDEX", "RULE", "SCHEMA", "SEQUENCE", "TABLE", "TYPE", "VIEW",
|
||||
"COLUMN", "AGGREGATE", "FUNCTION", "OPERATOR", "TRIGGER", NULL};
|
||||
"COLUMN", "AGGREGATE", "FUNCTION", "OPERATOR", "TRIGGER", "CONSTRAINT",
|
||||
"DOMAIN", NULL};
|
||||
|
||||
COMPLETE_WITH_LIST(list_COMMENT);
|
||||
}
|
||||
@ -440,7 +442,7 @@ psql_completion(char *text, int start, int end)
|
||||
/* Complete USING with an index method */
|
||||
else if (strcasecmp(prev_wd, "USING") == 0)
|
||||
{
|
||||
char *index_mth[] = {"BTREE", "RTREE", "HASH", NULL};
|
||||
char *index_mth[] = {"BTREE", "RTREE", "HASH", "GIST", NULL};
|
||||
|
||||
COMPLETE_WITH_LIST(index_mth);
|
||||
}
|
||||
@ -553,7 +555,7 @@ psql_completion(char *text, int start, int end)
|
||||
/* Complete GRANT/REVOKE with a list of privileges */
|
||||
else if (strcasecmp(prev_wd, "GRANT") == 0 || strcasecmp(prev_wd, "REVOKE") == 0)
|
||||
{
|
||||
char *list_privileg[] = {"SELECT", "INSERT", "UPDATE", "DELETE", "RULE", "ALL", NULL};
|
||||
char *list_privileg[] = {"SELECT", "INSERT", "UPDATE", "DELETE", "RULE", "REFERENCES", "TRIGGER", "CREATE", "TEMPORARY", "EXECUTE", "USAGE", "ALL", NULL};
|
||||
|
||||
COMPLETE_WITH_LIST(list_privileg);
|
||||
}
|
||||
@ -563,14 +565,15 @@ psql_completion(char *text, int start, int end)
|
||||
|
||||
/*
|
||||
* Complete GRANT/REVOKE <sth> ON with a list of tables, views,
|
||||
* schema, sequences, and indexes
|
||||
* sequences, and indexes
|
||||
*
|
||||
* XXX should also offer DATABASE, FUNCTION, LANGUAGE, SCHEMA here
|
||||
*/
|
||||
else if ((strcasecmp(prev3_wd, "GRANT") == 0 || strcasecmp(prev3_wd, "REVOKE") == 0) &&
|
||||
strcasecmp(prev_wd, "ON") == 0)
|
||||
COMPLETE_WITH_QUERY("SELECT relname FROM pg_catalog.pg_class "
|
||||
"WHERE relkind in ('r','i','S','v') AND "
|
||||
"substr(relname,1,%d)='%s' UNION "
|
||||
"SELECT nspname FROM pg_catalog.pg_namespace;");
|
||||
"substr(relname,1,%d)='%s' AND pg_catalog.pg_table_is_visible(oid)");
|
||||
/* Complete "GRANT * ON * " with "TO" */
|
||||
else if (strcasecmp(prev4_wd, "GRANT") == 0 && strcasecmp(prev2_wd, "ON") == 0)
|
||||
COMPLETE_WITH_CONST("TO");
|
||||
@ -745,7 +748,7 @@ psql_completion(char *text, int start, int end)
|
||||
|
||||
/* UNLISTEN */
|
||||
else if (strcasecmp(prev_wd, "UNLISTEN") == 0)
|
||||
COMPLETE_WITH_QUERY("SELECT relname FROM pg_catalog.pg_listener WHERE substr(relname,1,%d)='%s' UNION SELECT '*'::text");
|
||||
COMPLETE_WITH_QUERY("SELECT relname FROM pg_catalog.pg_listener WHERE substr(relname,1,%d)='%s' UNION SELECT '*'::name");
|
||||
|
||||
/* UPDATE */
|
||||
/* If prev. word is UPDATE suggest a list of tables */
|
||||
@ -765,7 +768,7 @@ psql_completion(char *text, int start, int end)
|
||||
|
||||
/* VACUUM */
|
||||
else if (strcasecmp(prev_wd, "VACUUM") == 0)
|
||||
COMPLETE_WITH_QUERY("SELECT relname FROM pg_catalog.pg_class WHERE relkind='r' and substr(relname,1,%d)='%s' UNION SELECT 'FULL'::text UNION SELECT 'ANALYZE'::text");
|
||||
COMPLETE_WITH_QUERY("SELECT relname FROM pg_catalog.pg_class WHERE relkind='r' and substr(relname,1,%d)='%s' and pg_catalog.pg_table_is_visible(oid) UNION SELECT 'FULL'::name UNION SELECT 'ANALYZE'::name");
|
||||
else if (strcasecmp(prev2_wd, "VACUUM") == 0 && (strcasecmp(prev_wd, "FULL") == 0 || strcasecmp(prev_wd, "ANALYZE") == 0))
|
||||
COMPLETE_WITH_QUERY(Query_for_list_of_tables);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user