From f6689a328f07fe579d57c1a419fd8b53db7499c7 Mon Sep 17 00:00:00 2001 From: Peter Eisentraut <peter_e@gmx.net> Date: Wed, 12 Jan 2000 19:36:36 +0000 Subject: [PATCH] Fixed a few "fixes" and bugs. Adjusted messages and options to GNU suggestions. --- doc/src/sgml/ref/createuser.sgml | 4 +- doc/src/sgml/ref/dropuser.sgml | 4 +- doc/src/sgml/ref/psql-ref.sgml | 89 ++--------- src/bin/psql/command.c | 109 ++++++++----- src/bin/psql/common.c | 10 +- src/bin/psql/copy.c | 75 ++++++--- src/bin/psql/describe.c | 253 ++++++++++++++++++------------- src/bin/psql/describe.h | 8 +- src/bin/psql/help.c | 140 +++++++++-------- src/bin/psql/large_obj.c | 31 ++-- src/bin/psql/large_obj.h | 2 +- src/bin/psql/mainloop.c | 8 +- src/bin/psql/print.c | 2 +- src/bin/psql/prompt.c | 15 +- src/bin/psql/settings.h | 1 + src/bin/psql/startup.c | 139 +++++++---------- src/bin/psql/tab-complete.c | 20 +-- src/bin/scripts/createdb | 37 ++--- src/bin/scripts/createlang.sh | 67 ++++---- src/bin/scripts/createuser | 39 +++-- src/bin/scripts/dropdb | 26 ++-- src/bin/scripts/droplang | 50 +++--- src/bin/scripts/dropuser | 23 ++- src/bin/scripts/vacuumdb | 53 ++++--- 24 files changed, 613 insertions(+), 592 deletions(-) diff --git a/doc/src/sgml/ref/createuser.sgml b/doc/src/sgml/ref/createuser.sgml index dc0eeb8edce..cf8ff8dfee2 100644 --- a/doc/src/sgml/ref/createuser.sgml +++ b/doc/src/sgml/ref/createuser.sgml @@ -1,5 +1,5 @@ <!-- -$Header: /cvsroot/pgsql/doc/src/sgml/ref/createuser.sgml,v 1.7 1999/12/07 22:41:41 momjian Exp $ +$Header: /cvsroot/pgsql/doc/src/sgml/ref/createuser.sgml,v 1.8 2000/01/12 19:36:34 petere Exp $ Postgres documentation --> @@ -177,7 +177,7 @@ createuser [ <replaceable class="parameter">options</replaceable> ] [ <replaceab </varlistentry> <varlistentry> - <term><computeroutput>createuser: Creation of user "<replaceable class="parameter">username</replaceable>" failed.</computeroutput></term> + <term><computeroutput>createuser: creation of user "<replaceable class="parameter">username</replaceable>" failed</computeroutput></term> <listitem> <para> Something went wrong. The user was not created. diff --git a/doc/src/sgml/ref/dropuser.sgml b/doc/src/sgml/ref/dropuser.sgml index 80a2a715762..398bde28e1c 100644 --- a/doc/src/sgml/ref/dropuser.sgml +++ b/doc/src/sgml/ref/dropuser.sgml @@ -1,5 +1,5 @@ <!-- -$Header: /cvsroot/pgsql/doc/src/sgml/ref/dropuser.sgml,v 1.2 1999/12/07 22:41:41 momjian Exp $ +$Header: /cvsroot/pgsql/doc/src/sgml/ref/dropuser.sgml,v 1.3 2000/01/12 19:36:34 petere Exp $ Postgres documentation --> @@ -127,7 +127,7 @@ dropuser [ <replaceable class="parameter">options</replaceable> ] [ <replaceable </varlistentry> <varlistentry> - <term><computeroutput>dropuser: Deletion of user "<replaceable class="parameter">username</replaceable>" failed.</computeroutput></term> + <term><computeroutput>dropuser: deletion of user "<replaceable class="parameter">username</replaceable>" failed</computeroutput></term> <listitem> <para> Something went wrong. The user was not removed. diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml index b24acf0e4f7..5c92e5fbd1b 100644 --- a/doc/src/sgml/ref/psql-ref.sgml +++ b/doc/src/sgml/ref/psql-ref.sgml @@ -1,5 +1,5 @@ <!-- -$Header: /cvsroot/pgsql/doc/src/sgml/ref/psql-ref.sgml,v 1.18 1999/11/26 04:24:16 momjian Exp $ +$Header: /cvsroot/pgsql/doc/src/sgml/ref/psql-ref.sgml,v 1.19 2000/01/12 19:36:34 petere Exp $ Postgres documentation --> @@ -352,7 +352,7 @@ testdb=> </para> <para> - The command form <literal>\d?</literal> is identical, but any comments + The command form <literal>\d+</literal> is identical, but any comments associated with the table columns are shown as well. </para> @@ -375,10 +375,6 @@ testdb=> Lists all available aggregate functions, together with the data type they operate on. If <replaceable class="parameter">pattern</replaceable> (a regular expression) is specified, only matching aggregates are shown. - If the alternative command form <literal>\da?</literal> is used, - comments are listed for each function as well. The command form - <literal>\da+</literal> will show more information about each aggregate - function, which is usually not of general interest. </para> </listitem> </varlistentry> @@ -426,8 +422,7 @@ testdb=> If <replaceable class="parameter">pattern</replaceable> (a regular expression) is specified, only matching functions are shown. If the form <literal>\df+</literal> is used, additional information about - each function is shown. Comments for each function can be shown with - the <literal>\df?</literal> form. + each function, including language and description is shown. </para> </listitem> </varlistentry> @@ -447,7 +442,7 @@ testdb=> <para> If <replaceable class="parameter">pattern</replaceable> is specified, it is a regular expression restricts the listing to those objects - whose name matches. If one appends a <quote>?</quote> to the command name, + whose name matches. If one appends a <quote>+</quote> to the command name, each object is listed with its associated description, if any. </para> </listitem> @@ -476,10 +471,6 @@ testdb=> interpretation of the backslash as a new command, you might also wish to quote the argument.) </para> - <para> - If the form <literal>\do?</literal> is used, comments are listed for - each operator. - </para> </listitem> </varlistentry> @@ -500,8 +491,7 @@ testdb=> <listitem> <para> Lists all data types or only those that match <replaceable class="parameter">pattern</replaceable>. - The command forms <literal>\dT+</literal> and <literal>\dT?</literal> show extra information - and the associated descriptions of the types, respectively. + The command form <literal>\dT+</literal> shows extra information. </para> </listitem> </varlistentry> @@ -648,7 +638,7 @@ Tue Oct 26 21:40:57 CEST 1999 <listitem> <para> List all the databases in the server as well as their owners. Append a - <quote>?</quote> (question mark) to the command name to see any descriptions + <quote>+</quote> to the command name to see any descriptions for the databases as well. If your <productname>PostgreSQL</productname> installation was compiled with multibyte encoding support, the encoding scheme of each @@ -723,8 +713,6 @@ lo_import 152801 <para> Shows a list of all <productname>PostgreSQL</productname> <quote>large objects</quote> currently stored in the database along with their owners. - Append a question mark to the command name (<literal>\lo_list?</literal>) to - see the the associated comments as well. </para> </listitem> </varlistentry> @@ -1203,11 +1191,9 @@ Access permissions for database "test" <para> If so configured, <application>psql</application> understands both standard - Unix short options, and <acronym>GNU</acronym>-style long options. Since the - latter are not available on all systems, you are advised to consider carefully - whether to use them, if you are writing scripts, etc. For support on the - <productname>PostgreSQL</productname> mailing lists, you are asked to only - use the standard short options. + Unix short options, and <acronym>GNU</acronym>-style long options. The latter + are not available on all systems, so you are advised to consider carefully + whether to use them. </para> <para> @@ -1301,7 +1287,7 @@ Access permissions for database "test" <varlistentry> - <term>-F, --field-sep <replaceable class="parameter">separator</replaceable></term> + <term>-F, --field-separator <replaceable class="parameter">separator</replaceable></term> <listitem> <para> Use <replaceable class="parameter">separator</replaceable> as the field separator. @@ -1358,7 +1344,7 @@ Access permissions for database "test" <varlistentry> - <term>-o, --out <replaceable class="parameter">filename</replaceable></term> + <term>-o, --output <replaceable class="parameter">filename</replaceable></term> <listitem> <para> Put all query output into file <replaceable class="parameter">filename</replaceable>. @@ -1400,8 +1386,7 @@ Access permissions for database "test" <listitem> <para> Specifies that <application>psql</application> should do its work quietly. - By default, it prints welcome messages, various informational output and - prompts for each query. + By default, it prints welcome messages and various informational output. If this option is used, none of this happens. This is useful with the <option>-c</option> option. Within <application>psql</application> you can also set the <envar>quiet</envar> variable to achieve the same effect. @@ -1511,35 +1496,7 @@ Access permissions for database "test" <term>-V, --version</term> <listitem> <para> - Shows version information about <application>psql</application> and your - <productname>PostgreSQL</productname> database server, if it could be reached. - </para> - - <para> - The output looks similar to this: -<programlisting> -~$ <userinput>psql -V</userinput> -Server: PostgreSQL 6.5.2 on i586-pc-linux-gnu, compiled by egcs -psql 6.6.0 on i586-pc-linux-gnu, compiled by gcc 2.8.1 (Oct 27 1999 15:15:04), long options, -readline, history, locale, assert checks -</programlisting> - The <quote>Server</quote> line is identical to the one returned by the - backend function <function>version()</function> and thus might vary - if you query different servers by using different connection - options. - </para> - - <para> - The <quote>psql</quote> line is compiled into the <application>psql</application> - binary. It shows you which <productname>PostgreSQL</productname> release - it was distributed with and what optional features were compiled into it. - Although in general (as in the example above) you can use <application>psql</application> - and database servers from different versions (if they don't differ too much) - this is not recommended or - even necessary. The optional features indicate only <application>psql</application>'s - capabilities but if <application>psql</application> was configured with - the same source tree as the rest of the distribution, it gives you an - indication about other parts of the installation as well. + Shows the <application>psql</application> version. </para> </listitem> </varlistentry> @@ -2149,26 +2106,6 @@ Field separator is "oo". </refsect2> - <refsect2> - <title>History and Lineage</title> - - <para> - <application>psql</application> first appeared in <productname>Postgres95</productname> - to complement and later replace the <application>monitor</application> program. (You see this - name here or there in really old files. The author has never had the pleasure to use this - program though.) An uncountable number of people have added features since to reflect - the enhancements in the actual database server. - </para> - - <para> - The present version is the result of a major clean-up and re-write in 1999 by - <ulink URL="mailto:peter_e@gmx.net">Peter Eisentraut</ulink> in preparation for release 7.0. - Many people had again contributed their ideas. A bunch of features were stolen - from various shells (in case you hadn't noticed), in particular - <application>tcsh</application>. - </para> - </refsect2> - <refsect2> <title><acronym>GNU</acronym> readline</title> diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c index 9489a8e2af6..ba016120590 100644 --- a/src/bin/psql/command.c +++ b/src/bin/psql/command.c @@ -243,7 +243,10 @@ HandleSlashCmds(PsqlSettings *pset, if (status == CMD_UNKNOWN) { - fprintf(stderr, "Unrecognized command: \\%s. Try \\? for help.\n", cmd); + if (pset->cur_cmd_interactive) + fprintf(stderr, "Invalid command \\%s. Try \\? for help.\n", cmd); + else + fprintf(stderr, "%s: invalid command \\%s", pset->progname, cmd); status = CMD_ERROR; } @@ -341,38 +344,37 @@ exec_command(const char *cmd, else if (cmd[0] == 'd') { bool show_verbose = strchr(cmd, '+') ? true : false; - bool show_desc = strchr(cmd, '?') ? true : false; switch (cmd[1]) { case '\0': case '?': if (options[0]) - success = describeTableDetails(options[0], pset, show_desc); + success = describeTableDetails(options[0], pset, show_verbose); else /* standard listing of interesting things */ - success = listTables("tvs", NULL, pset, show_desc); + success = listTables("tvs", NULL, pset, show_verbose); break; case 'a': - success = describeAggregates(options[0], pset, show_verbose, show_desc); + success = describeAggregates(options[0], pset); break; case 'd': success = objectDescription(options[0], pset); break; case 'f': - success = describeFunctions(options[0], pset, show_verbose, show_desc); + success = describeFunctions(options[0], pset, show_verbose); break; case 'l': - success = do_lo_list(pset, show_desc); + success = do_lo_list(pset); break; case 'o': - success = describeOperators(options[0], pset, show_verbose, show_desc); + success = describeOperators(options[0], pset); break; case 'p': success = permissionsList(options[0], pset); break; case 'T': - success = describeTypes(options[0], pset, show_verbose, show_desc); + success = describeTypes(options[0], pset, show_verbose); break; case 't': case 'v': @@ -380,9 +382,9 @@ exec_command(const char *cmd, case 's': case 'S': if (cmd[1] == 'S' && cmd[2] == '\0') - success = listTables("Stvs", NULL, pset, show_desc); + success = listTables("Stvs", NULL, pset, show_verbose); else - success = listTables(&cmd[1], options[0], pset, show_desc); + success = listTables(&cmd[1], options[0], pset, show_verbose); break; default: status = CMD_UNKNOWN; @@ -452,7 +454,10 @@ exec_command(const char *cmd, { if (!options[0]) { - fputs("Usage: \\i <filename>\n", stderr); + if (pset->cur_cmd_interactive) + fprintf(stderr, "\\%s: missing required argument\n", cmd); + else + fprintf(stderr, "%s: \\%s: missing required argument", pset->progname, cmd); success = false; } else @@ -463,7 +468,7 @@ exec_command(const char *cmd, /* \l is list databases */ else if (strcmp(cmd, "l") == 0 || strcmp(cmd, "list") == 0) success = listAllDbs(pset, false); - else if (strcmp(cmd, "l?") == 0 || strcmp(cmd, "list?") == 0) + else if (strcmp(cmd, "l+") == 0 || strcmp(cmd, "list+") == 0) success = listAllDbs(pset, true); @@ -474,7 +479,10 @@ exec_command(const char *cmd, { if (!options[1]) { - fputs("Usage: \\lo_export <loid> <filename>\n", stderr); + if (pset->cur_cmd_interactive) + fprintf(stderr, "\\%s: missing required argument", cmd); + else + fprintf(stderr, "%s: \\%s: missing required argument", pset->progname, cmd); success = false; } else @@ -485,7 +493,10 @@ exec_command(const char *cmd, { if (!options[0]) { - fputs("Usage: \\lo_import <filename> [<description>]\n", stderr); + if (pset->cur_cmd_interactive) + fprintf(stderr, "\\%s: missing required argument", cmd); + else + fprintf(stderr, "%s: \\%s: missing required argument", pset->progname, cmd); success = false; } else @@ -493,15 +504,16 @@ exec_command(const char *cmd, } else if (strcmp(cmd + 3, "list") == 0) - success = do_lo_list(pset, false); - else if (strcmp(cmd + 3, "list?") == 0) - success = do_lo_list(pset, true); + success = do_lo_list(pset); else if (strcmp(cmd + 3, "unlink") == 0) { if (!options[0]) { - fputs("Usage: \\lo_unlink <loid>\n", stderr); + if (pset->cur_cmd_interactive) + fprintf(stderr, "\\%s: missing required argument", cmd); + else + fprintf(stderr, "%s: \\%s: missing required argument", pset->progname, cmd); success = false; } else @@ -522,7 +534,7 @@ exec_command(const char *cmd, { if (query_buf && query_buf->len > 0) puts(query_buf->data); - else if (!GetVariableBool(pset->vars, "quiet")) + else if (!quiet) puts("Query buffer is empty."); fflush(stdout); } @@ -532,7 +544,10 @@ exec_command(const char *cmd, { if (!options[0]) { - fputs("Usage: \\pset <parameter> [<value>]\n", stderr); + if (pset->cur_cmd_interactive) + fprintf(stderr, "\\%s: missing required argument", cmd); + else + fprintf(stderr, "%s: \\%s: missing required argument", pset->progname, cmd); success = false; } else @@ -600,7 +615,11 @@ exec_command(const char *cmd, { if (!SetVariable(pset->vars, options[0], options[1])) { - fprintf(stderr, "Set variable failed.\n"); + if (pset->cur_cmd_interactive) + fprintf(stderr, "\\%s: failed\n", cmd); + else + fprintf(stderr, "%s: \\%s: failed\n", pset->progname, cmd); + success = false; } } @@ -624,7 +643,10 @@ exec_command(const char *cmd, if (!options[0]) { - fprintf(stderr, "Usage: \\%s <filename>\n", cmd); + if (pset->cur_cmd_interactive) + fprintf(stderr, "\\%s: missing required argument", cmd); + else + fprintf(stderr, "%s: \\%s: missing required argument", pset->progname, cmd); success = false; } else @@ -932,20 +954,27 @@ do_connect(const char *new_dbname, const char *new_user, PsqlSettings *pset) */ if (!pset->db || PQstatus(pset->db) == CONNECTION_BAD) { - fprintf(stderr, "Could not establish database connection.\n%s", PQerrorMessage(pset->db)); - PQfinish(pset->db); - if (!oldconn || !pset->cur_cmd_interactive) - { /* we don't want unpredictable things to - * happen in scripting mode */ - fputs("Terminating.\n", stderr); + if (pset->cur_cmd_interactive) + { + fprintf(stderr, "\\connect: %s", PQerrorMessage(pset->db)); + PQfinish(pset->db); + if (oldconn) + { + fputs("Previous connection kept\n", stderr); + pset->db = oldconn; + } + else + pset->db = NULL; + } + else + { + /* we don't want unpredictable things to + * happen in scripting mode */ + fprintf(stderr, "%s: \\connect: %s", pset->progname, PQerrorMessage(pset->db)); + PQfinish(pset->db); if (oldconn) PQfinish(oldconn); - pset->db = NULL; - } - else - { - fputs("Keeping old connection.\n", stderr); - pset->db = oldconn; + pset->db = NULL; } } else @@ -956,8 +985,7 @@ do_connect(const char *new_dbname, const char *new_user, PsqlSettings *pset) printf("You are now connected to database %s.\n", dbparam); else if (dbparam != new_dbname) /* no new db */ printf("You are now connected as new user %s.\n", new_user); - else -/* both new */ + else /* both new */ printf("You are now connected to database %s as user %s.\n", PQdb(pset->db), PQuser(pset->db)); } @@ -1020,7 +1048,7 @@ editFile(const char *fname) static bool do_edit(const char *filename_arg, PQExpBuffer query_buf) { - char fnametmp[64]; + char fnametmp[MAXPGPATH]; FILE *stream; const char *fname; bool error = false; @@ -1047,8 +1075,11 @@ do_edit(const char *filename_arg, PQExpBuffer query_buf) /* make a temp file to edit */ #ifndef WIN32 mode_t oldumask; + const char *tmpdirenv = getenv("TMPDIR"); - sprintf(fnametmp, "/tmp/psql.edit.%ld.%ld", (long) geteuid(), (long) getpid()); + sprintf(fnametmp, "%s/psql.edit.%ld.%ld", + tmpdirenv ? tmpdirenv : "/tmp", + (long) geteuid(), (long) getpid()); #else GetTempFileName(".", "psql", 0, fnametmp); #endif diff --git a/src/bin/psql/common.c b/src/bin/psql/common.c index 6bbf663733c..fd52d4de8b8 100644 --- a/src/bin/psql/common.c +++ b/src/bin/psql/common.c @@ -491,9 +491,6 @@ SendQuery(PsqlSettings *pset, const char *query) break; case PGRES_COPY_OUT: - if (pset->cur_cmd_interactive && !GetVariableBool(pset->vars, "quiet")) - puts("Copy command returns:"); - success = handleCopyOut(pset->db, pset->queryFout); break; @@ -510,7 +507,7 @@ SendQuery(PsqlSettings *pset, const char *query) case PGRES_FATAL_ERROR: case PGRES_BAD_RESPONSE: success = false; - fputs(PQerrorMessage(pset->db), pset->queryFout); + fputs(PQerrorMessage(pset->db), stderr); break; } @@ -518,6 +515,11 @@ SendQuery(PsqlSettings *pset, const char *query) if (PQstatus(pset->db) == CONNECTION_BAD) { + if (!pset->cur_cmd_interactive) + { + fprintf(stderr, "%s: connection to server was lost", pset->progname); + exit(EXIT_BADCONN); + } fputs("The connection to the server was lost. Attempting reset: ", stderr); PQreset(pset->db); if (PQstatus(pset->db) == CONNECTION_BAD) diff --git a/src/bin/psql/copy.c b/src/bin/psql/copy.c index 1d2a24c39f7..800a8f41eda 100644 --- a/src/bin/psql/copy.c +++ b/src/bin/psql/copy.c @@ -27,7 +27,7 @@ * parse_slash_copy * -- parses \copy command line * - * Accepted syntax: \copy [binary] table|"table" [with oids] from|to filename|'filename' using delimiters ['<char>'] + * Accepted syntax: \copy [binary] table|"table" [with oids] from|to filename|'filename' using delimiters ['<char>'] [ with null as 'string' ] * (binary is not here yet) * * returns a malloc'ed structure with the options, or NULL on parsing error @@ -41,6 +41,7 @@ struct copy_options bool binary; bool oids; char *delim; + char *null; }; @@ -52,12 +53,13 @@ free_copy_options(struct copy_options * ptr) free(ptr->table); free(ptr->file); free(ptr->delim); + free(ptr->null); free(ptr); } static struct copy_options * -parse_slash_copy(const char *args) +parse_slash_copy(const char *args, PsqlSettings *pset) { struct copy_options *result; char *line; @@ -78,7 +80,9 @@ parse_slash_copy(const char *args) error = true; else { - if (!quote && strcasecmp(token, "binary") == 0) +#ifdef NOT_USED + /* this is not implemented yet */ + if (!quote && strcasecmp(token, "binary") == 0) { result->binary = true; token = strtokx(NULL, " \t", "\"", '\\', "e, NULL); @@ -86,6 +90,7 @@ parse_slash_copy(const char *args) error = true; } if (token) +#endif result->table = xstrdup(token); } @@ -143,9 +148,7 @@ parse_slash_copy(const char *args) token = strtokx(NULL, " \t", NULL, '\\', NULL, NULL); if (token) { - if (strcasecmp(token, "using") != 0) - error = true; - else + if (strcasecmp(token, "using") == 0) { token = strtokx(NULL, " \t", NULL, '\\', NULL, NULL); if (!token || strcasecmp(token, "delimiters") != 0) @@ -154,11 +157,36 @@ parse_slash_copy(const char *args) { token = strtokx(NULL, " \t", "'", '\\', NULL, NULL); if (token) + { result->delim = xstrdup(token); + token = strtokx(NULL, " \t", NULL, '\\', NULL, NULL); + } else error = true; } } + + if (!error && token) + { + if (strcasecmp(token, "with") == 0) + { + token = strtokx(NULL, " \t", NULL, '\\', NULL, NULL); + if (!token || strcasecmp(token, "null") != 0) + error = true; + else + { + token = strtokx(NULL, " \t", NULL, '\\', NULL, NULL); + if (!token || strcasecmp(token, "as") != 0) + error = true; + else + { + token = strtokx(NULL, " \t", "'", '\\', NULL, NULL); + if (token) + result->null = xstrdup(token); + } + } + } + } } } @@ -166,11 +194,13 @@ parse_slash_copy(const char *args) if (error) { - fputs("Parse error at ", stderr); + if (!pset->cur_cmd_interactive) + fprintf(stderr, "%s: ", pset->progname); + fputs("\\copy: parse error at ", stderr); if (!token) - fputs("end of line.", stderr); + fputs("end of line", stderr); else - fprintf(stderr, "'%s'.", token); + fprintf(stderr, "'%s'", token); fputs("\n", stderr); free(result); return NULL; @@ -196,15 +226,14 @@ do_copy(const char *args, PsqlSettings *pset) bool success; /* parse options */ - options = parse_slash_copy(args); + options = parse_slash_copy(args, pset); if (!options) return false; strcpy(query, "COPY "); if (options->binary) - fputs("Warning: \\copy binary is not implemented. Resorting to text output.\n", stderr); -/* strcat(query, "BINARY "); */ + strcat(query, "BINARY "); strcat(query, "\""); strncat(query, options->table, NAMEDATALEN); @@ -220,13 +249,7 @@ do_copy(const char *args, PsqlSettings *pset) if (options->delim) { - - /* - * backend copy only uses the first character here, but that might - * be the escape backslash (makes me wonder though why it's called - * delimiterS) - */ - strncat(query, " USING DELIMITERS '", 2); + strcat(query, " USING DELIMITERS '"); strcat(query, options->delim); strcat(query, "'"); } @@ -247,9 +270,11 @@ do_copy(const char *args, PsqlSettings *pset) if (!copystream) { + if (!pset->cur_cmd_interactive) + fprintf(stderr, "%s: ", pset->progname); fprintf(stderr, - "Unable to open file %s which to copy: %s\n", - options->from ? "from" : "to", strerror(errno)); + "unable to open file %s: %s\n", + options->file, strerror(errno)); free_copy_options(options); return false; } @@ -272,7 +297,9 @@ do_copy(const char *args, PsqlSettings *pset) break; default: success = false; - fprintf(stderr, "Unexpected response (%d)\n", PQresultStatus(result)); + if (!pset->cur_cmd_interactive) + fprintf(stderr, "%s: ", pset->progname); + fprintf(stderr, "\\copy: unexpected response (%d)\n", PQresultStatus(result)); } PQclear(result); @@ -280,9 +307,9 @@ do_copy(const char *args, PsqlSettings *pset) if (!GetVariable(pset->vars, "quiet")) { if (success) - puts("Successfully copied."); + puts("Successfully copied"); else - puts("Copy failed."); + puts("Copy failed"); } fclose(copystream); diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c index 728866fa3c2..f4ac7f1bcd3 100644 --- a/src/bin/psql/describe.c +++ b/src/bin/psql/describe.c @@ -18,10 +18,7 @@ * Handlers for various slash commands displaying some sort of list * of things in the database. * - * If you add something here, consider this: - * - If (and only if) the variable "description" is set, the description/ - * comment for the object should be displayed. - * - Try to format the query to look nice in -E output. + * If you add something here, try to format the query to look nice in -E output. *---------------- */ @@ -34,7 +31,7 @@ * takes an optional regexp to match specific aggregates by name */ bool -describeAggregates(const char *name, PsqlSettings *pset, bool verbose, bool desc) +describeAggregates(const char *name, PsqlSettings *pset) { char buf[384 + 2 * REGEXP_CUTOFF]; PGresult *res; @@ -45,17 +42,11 @@ describeAggregates(const char *name, PsqlSettings *pset, bool verbose, bool desc * types ones that work on all */ strcpy(buf, - "SELECT a.aggname AS \"Name\", t.typname AS \"Type\""); - if (verbose) - strcat(buf, " ,u.usename as \"Owner\""); - if (desc) - strcat(buf, ",\n obj_description(a.oid) as \"Description\""); - strcat(buf, !verbose ? - ("\nFROM pg_aggregate a, pg_type t\n" - "WHERE a.aggbasetype = t.oid\n") : - ("\nFROM pg_aggregate a, pg_type t, pg_user u\n" - "WHERE a.aggbasetype = t.oid AND a.aggowner = u.usesysid\n") - ); + "SELECT a.aggname AS \"Name\", t.typname AS \"Type\",\n" + " obj_description(a.oid) as \"Description\"\n" + "FROM pg_aggregate a, pg_type t\n" + "WHERE a.aggbasetype = t.oid\n" + ); if (name) { @@ -66,18 +57,12 @@ describeAggregates(const char *name, PsqlSettings *pset, bool verbose, bool desc strcat(buf, "UNION\n" - "SELECT a.aggname AS \"Name\", '(all types)' as \"Type\""); - if (verbose) - strcat(buf, " ,u.usename as \"Owner\""); - if (desc) - strcat(buf, - ",\n obj_description(a.oid) as \"Description\""); - strcat(buf, !verbose ? - ("\nFROM pg_aggregate a\n" - "WHERE a.aggbasetype = 0\n") : - ("\nFROM pg_aggregate a, pg_user u\n" - "WHERE a.aggbasetype = 0 AND a.aggowner = u.usesysid\n") - ); + "SELECT a.aggname AS \"Name\", '(all types)' as \"Type\",\n" + " obj_description(a.oid) as \"Description\"\n" + "FROM pg_aggregate a\n" + "WHERE a.aggbasetype = 0\n" + ); + if (name) { strcat(buf, " AND a.aggname ~* '"); @@ -91,7 +76,6 @@ describeAggregates(const char *name, PsqlSettings *pset, bool verbose, bool desc if (!res) return false; - myopt.topt.tuples_only = false; myopt.nullPrint = NULL; myopt.title = "List of aggregates"; @@ -106,7 +90,7 @@ describeAggregates(const char *name, PsqlSettings *pset, bool verbose, bool desc * Takes an optional regexp to narrow down the function name */ bool -describeFunctions(const char *name, PsqlSettings *pset, bool verbose, bool desc) +describeFunctions(const char *name, PsqlSettings *pset, bool verbose) { char buf[384 + REGEXP_CUTOFF]; PGresult *res; @@ -117,12 +101,11 @@ describeFunctions(const char *name, PsqlSettings *pset, bool verbose, bool desc) * arguments, but have no types defined for those arguments */ strcpy(buf, - "SELECT t.typname as \"Result\", p.proname as \"Function\",\n" + "SELECT t.typname as \"Result\", p.proname as \"Function\",\n" " oidvectortypes(p.proargtypes) as \"Arguments\""); if (verbose) - strcat(buf, ",\n u.usename as \"Owner\", l.lanname as \"Language\", p.prosrc as \"Source\""); - if (desc) - strcat(buf, ",\n obj_description(p.oid) as \"Description\""); + strcat(buf, ",\n u.usename as \"Owner\", l.lanname as \"Language\", p.prosrc as \"Source\",\n" + " obj_description(p.oid) as \"Description\""); if (!verbose) strcat(buf, @@ -146,7 +129,6 @@ describeFunctions(const char *name, PsqlSettings *pset, bool verbose, bool desc) if (!res) return false; - myopt.topt.tuples_only = false; myopt.nullPrint = NULL; myopt.title = "List of functions"; @@ -163,7 +145,7 @@ describeFunctions(const char *name, PsqlSettings *pset, bool verbose, bool desc) * describe types */ bool -describeTypes(const char *name, PsqlSettings *pset, bool verbose, bool desc) +describeTypes(const char *name, PsqlSettings *pset, bool verbose) { char buf[256 + REGEXP_CUTOFF]; PGresult *res; @@ -171,25 +153,13 @@ describeTypes(const char *name, PsqlSettings *pset, bool verbose, bool desc) strcpy(buf, "SELECT t.typname AS \"Type\""); if (verbose) - strcat(buf, - ",\n (CASE WHEN t.typlen=-1 THEN 'var'::text ELSE t.typlen::text END) as \"Length\"" - ",\n u.usename as \"Owner\"" - ); - /* - * Let's always show descriptions for this. There is room. - * bjm 1999/12/31 - */ - strcat(buf, ",\n obj_description(t.oid) as \"Description\""); + strcat(buf, ",\n (CASE WHEN t.typlen = -1 THEN 'var'::text ELSE t.typlen::text END) as \"Size\""); + strcat(buf, ",\n obj_description(t.oid) as \"Description\""); /* * do not include array types (start with underscore), * do not include user relations (typrelid!=0) */ - strcat(buf, !verbose ? - ("\nFROM pg_type t\n" - "WHERE t.typrelid = 0 AND t.typname !~ '^_.*'\n") : - ("\nFROM pg_type t, pg_user u\n" - "WHERE t.typrelid = 0 AND t.typname !~ '^_.*' AND t.typowner = u.usesysid\n") - ); + strcat(buf, "\nFROM pg_type t\nWHERE t.typrelid = 0 AND t.typname !~ '^_.*'\n"); if (name) { @@ -203,7 +173,6 @@ describeTypes(const char *name, PsqlSettings *pset, bool verbose, bool desc) if (!res) return false; - myopt.topt.tuples_only = false; myopt.nullPrint = NULL; myopt.title = "List of types"; @@ -218,26 +187,19 @@ describeTypes(const char *name, PsqlSettings *pset, bool verbose, bool desc) /* \do */ bool -describeOperators(const char *name, PsqlSettings *pset, bool verbose, bool desc) +describeOperators(const char *name, PsqlSettings *pset) { char buf[1536 + 3 * REGEXP_CUTOFF]; PGresult *res; printQueryOpt myopt = pset->popt; - /* Not used right now. Maybe later. */ - (void)verbose; - - /* FIXME: Use outer joins here when ready */ - strcpy(buf, - "SELECT o.oprname AS \"Op\",\n" + "SELECT o.oprname AS \"Op\",\n" " t1.typname AS \"Left arg\",\n" " t2.typname AS \"Right arg\",\n" - " t0.typname AS \"Result\""); - if (desc) - strcat(buf, ",\n obj_description(p.oid) as \"Description\""); - strcat(buf, - "\nFROM pg_proc p, pg_type t0,\n" + " t0.typname AS \"Result\",\n" + " obj_description(p.oid) as \"Description\"\n" + "FROM pg_proc p, pg_type t0,\n" " pg_type t1, pg_type t2,\n" " pg_operator o\n" "WHERE p.prorettype = t0.oid AND\n" @@ -256,10 +218,9 @@ describeOperators(const char *name, PsqlSettings *pset, bool verbose, bool desc) "SELECT o.oprname as \"Op\",\n" " ''::name AS \"Left arg\",\n" " t1.typname AS \"Right arg\",\n" - " t0.typname AS \"Result\""); - if (desc) - strcat(buf, ",\n obj_description(p.oid) as \"Description\""); - strcat(buf, "\nFROM pg_operator o, pg_proc p, pg_type t0, pg_type t1\n" + " t0.typname AS \"Result\",\n" + " obj_description(p.oid) as \"Description\"\n" + "FROM pg_operator o, pg_proc p, pg_type t0, pg_type t1\n" "WHERE RegprocToOid(o.oprcode) = p.oid AND\n" " o.oprresult = t0.oid AND\n" " o.oprkind = 'l' AND\n" @@ -275,10 +236,9 @@ describeOperators(const char *name, PsqlSettings *pset, bool verbose, bool desc) "SELECT o.oprname as \"Op\",\n" " t1.typname AS \"Left arg\",\n" " ''::name AS \"Right arg\",\n" - " t0.typname AS \"Result\""); - if (desc) - strcat(buf, ",\n obj_description(p.oid) as \"Description\""); - strcat(buf, "\nFROM pg_operator o, pg_proc p, pg_type t0, pg_type t1\n" + " t0.typname AS \"Result\",\n" + " obj_description(p.oid) as \"Description\"\n" + "FROM pg_operator o, pg_proc p, pg_type t0, pg_type t1\n" "WHERE RegprocToOid(o.oprcode) = p.oid AND\n" " o.oprresult = t0.oid AND\n" " o.oprkind = 'r' AND\n" @@ -295,7 +255,6 @@ describeOperators(const char *name, PsqlSettings *pset, bool verbose, bool desc) if (!res) return false; - myopt.topt.tuples_only = false; myopt.nullPrint = NULL; myopt.title = "List of operators"; @@ -315,11 +274,11 @@ bool listAllDbs(PsqlSettings *pset, bool desc) { PGresult *res; - char buf[256]; + char buf[512]; printQueryOpt myopt = pset->popt; strcpy(buf, - "SELECT pg_database.datname as \"Database\",\n" + "SELECT pg_database.datname as \"Database\",\n" " pg_user.usename as \"Owner\""); #ifdef MULTIBYTE strcat(buf, @@ -328,14 +287,29 @@ listAllDbs(PsqlSettings *pset, bool desc) if (desc) strcat(buf, ",\n obj_description(pg_database.oid) as \"Description\"\n"); strcat(buf, "FROM pg_database, pg_user\n" - "WHERE pg_database.datdba = pg_user.usesysid\n" - "ORDER BY \"Database\""); + "WHERE pg_database.datdba = pg_user.usesysid\n"); + + /* Also include databases that have no valid owner. */ + strcat(buf, "\nUNION\n\n"); + + strcat(buf, + "SELECT pg_database.datname as \"Database\",\n" + " NULL as \"Owner\""); +#ifdef MULTIBYTE + strcat(buf, + ",\n pg_database.encoding as \"Encoding\""); +#endif + if (desc) + strcat(buf, ",\n obj_description(pg_database.oid) as \"Description\"\n"); + strcat(buf, "FROM pg_database\n" + "WHERE pg_database.datdba NOT IN (SELECT usesysid FROM pg_user)\n"); + + strcat(buf, "ORDER BY \"Database\""); res = PSQLexec(pset, buf); if (!res) return false; - myopt.topt.tuples_only = false; myopt.nullPrint = NULL; myopt.title = "List of databases"; @@ -376,17 +350,11 @@ permissionsList(const char *name, PsqlSettings *pset) if (!res) return false; - if (PQntuples(res) == 0) - fputs("Couldn't find any tables.\n", pset->queryFout); - else - { - myopt.topt.tuples_only = false; - myopt.nullPrint = NULL; - sprintf(descbuf, "Access permissions for database \"%s\"", PQdb(pset->db)); - myopt.title = descbuf; + myopt.nullPrint = NULL; + sprintf(descbuf, "Access permissions for database \"%s\"", PQdb(pset->db)); + myopt.title = descbuf; - printQuery(res, &myopt, pset->queryFout); - } + printQuery(res, &myopt, pset->queryFout); PQclear(res); return true; @@ -394,7 +362,6 @@ permissionsList(const char *name, PsqlSettings *pset) - /* * Get object comments * @@ -413,7 +380,7 @@ objectDescription(const char *object, PsqlSettings *pset) descbuf[0] = '\0'; /* Aggregate descriptions */ - strcat(descbuf, "SELECT DISTINCT a.aggname as \"Name\", 'aggregate'::text as \"What\", d.description as \"Description\"\n" + strcat(descbuf, "SELECT DISTINCT a.aggname as \"Name\", 'aggregate'::text as \"Object\", d.description as \"Description\"\n" "FROM pg_aggregate a, pg_description d\n" "WHERE a.oid = d.objoid\n"); if (object) @@ -425,7 +392,7 @@ objectDescription(const char *object, PsqlSettings *pset) /* Function descriptions (except in/outs for datatypes) */ strcat(descbuf, "\nUNION ALL\n\n"); - strcat(descbuf, "SELECT DISTINCT p.proname as \"Name\", 'function'::text as \"What\", d.description as \"Description\"\n" + strcat(descbuf, "SELECT DISTINCT p.proname as \"Name\", 'function'::text as \"Object\", d.description as \"Description\"\n" "FROM pg_proc p, pg_description d\n" "WHERE p.oid = d.objoid AND (p.pronargs = 0 or oidvectortypes(p.proargtypes) != '')\n"); if (object) @@ -437,7 +404,7 @@ objectDescription(const char *object, PsqlSettings *pset) /* Operator descriptions */ strcat(descbuf, "\nUNION ALL\n\n"); - strcat(descbuf, "SELECT DISTINCT o.oprname as \"Name\", 'operator'::text as \"What\", d.description as \"Description\"\n" + strcat(descbuf, "SELECT DISTINCT o.oprname as \"Name\", 'operator'::text as \"Object\", d.description as \"Description\"\n" "FROM pg_operator o, pg_description d\n" /* must get comment via associated function */ "WHERE RegprocToOid(o.oprcode) = d.objoid\n"); @@ -450,7 +417,7 @@ objectDescription(const char *object, PsqlSettings *pset) /* Type description */ strcat(descbuf, "\nUNION ALL\n\n"); - strcat(descbuf, "SELECT DISTINCT t.typname as \"Name\", 'type'::text as \"What\", d.description as \"Description\"\n" + strcat(descbuf, "SELECT DISTINCT t.typname as \"Name\", 'type'::text as \"Object\", d.description as \"Description\"\n" "FROM pg_type t, pg_description d\n" "WHERE t.oid = d.objoid\n"); if (object) @@ -462,7 +429,7 @@ objectDescription(const char *object, PsqlSettings *pset) /* Relation (tables, views, indices, sequences) descriptions */ strcat(descbuf, "\nUNION ALL\n\n"); - strcat(descbuf, "SELECT DISTINCT c.relname as \"Name\", 'relation'::text||'('||c.relkind||')' as \"What\", d.description as \"Description\"\n" + strcat(descbuf, "SELECT DISTINCT c.relname as \"Name\", 'relation'::text||'('||c.relkind||')' as \"Object\", d.description as \"Description\"\n" "FROM pg_class c, pg_description d\n" "WHERE c.oid = d.objoid\n"); if (object) @@ -474,7 +441,7 @@ objectDescription(const char *object, PsqlSettings *pset) /* Rule description (ignore rules for views) */ strcat(descbuf, "\nUNION ALL\n\n"); - strcat(descbuf, "SELECT DISTINCT r.rulename as \"Name\", 'rule'::text as \"What\", d.description as \"Description\"\n" + strcat(descbuf, "SELECT DISTINCT r.rulename as \"Name\", 'rule'::text as \"Object\", d.description as \"Description\"\n" "FROM pg_rewrite r, pg_description d\n" "WHERE r.oid = d.objoid AND r.rulename !~ '^_RET'\n"); if (object) @@ -486,7 +453,7 @@ objectDescription(const char *object, PsqlSettings *pset) /* Trigger description */ strcat(descbuf, "\nUNION ALL\n\n"); - strcat(descbuf, "SELECT DISTINCT t.tgname as \"Name\", 'trigger'::text as \"What\", d.description as \"Description\"\n" + strcat(descbuf, "SELECT DISTINCT t.tgname as \"Name\", 'trigger'::text as \"Object\", d.description as \"Description\"\n" "FROM pg_trigger t, pg_description d\n" "WHERE t.oid = d.objoid\n"); if (object) @@ -518,11 +485,12 @@ objectDescription(const char *object, PsqlSettings *pset) /* * describeTableDetails (for \d) * - * Unfortunately, the information presented here is so complicated that it + * Unfortunately, the information presented here is so complicated that it cannot * be done in a single query. So we have to assemble the printed table by hand * and pass it to the underlying printTable() function. * */ + static void * xmalloc(size_t size) { @@ -576,7 +544,7 @@ describeTableDetails(const char *name, PsqlSettings *pset, bool desc) if (PQntuples(res) == 0) { if (!GetVariableBool(pset->vars, "quiet")) - fprintf(stdout, "Did not find any relation named \"%s\".\n", name); + fprintf(stderr, "Did not find any relation named \"%s\".\n", name); PQclear(res); return false; } @@ -932,6 +900,10 @@ describeTableDetails(const char *name, PsqlSettings *pset, bool desc) * s - sequences * S - systems tables (~ '^pg_') * (any order of the above is fine) + * + * Note: For some reason it always happens to people that their tables have owners + * that are no longer in pg_user; consequently they wouldn't show up here. The code + * tries to fix this the painful way, hopefully outer joins will be done sometime. */ bool listTables(const char *infotype, const char *name, PsqlSettings *pset, bool desc) @@ -942,7 +914,7 @@ listTables(const char *infotype, const char *name, PsqlSettings *pset, bool desc bool showSeq = strchr(infotype, 's') != NULL; bool showSystem = strchr(infotype, 'S') != NULL; - char buf[1536 + 4 * REGEXP_CUTOFF]; + char buf[3072 + 8 * REGEXP_CUTOFF]; PGresult *res; printQueryOpt myopt = pset->popt; @@ -964,6 +936,22 @@ listTables(const char *infotype, const char *name, PsqlSettings *pset, bool desc strncat(buf, name, REGEXP_CUTOFF); strcat(buf, "'\n"); } + + strcat(buf, "UNION\n"); + strcat(buf, "SELECT c.relname as \"Name\", 'table'::text as \"Type\", NULL as \"Owner\""); + if (desc) + strcat(buf, ", obj_description(c.oid) as \"Description\""); + strcat(buf, "\nFROM pg_class c\n" + "WHERE c.relkind = 'r'\n" + " AND not exists (select 1 from pg_views where viewname = c.relname)\n" + " AND not exists (select 1 from pg_user where usesysid = c.relowner)\n"); + strcat(buf, showSystem ? " AND c.relname ~ '^pg_'\n" : " AND c.relname !~ '^pg_'\n"); + if (name) + { + strcat(buf, " AND c.relname ~ '"); + strncat(buf, name, REGEXP_CUTOFF); + strcat(buf, "'\n"); + } } /* views */ @@ -985,6 +973,22 @@ listTables(const char *infotype, const char *name, PsqlSettings *pset, bool desc strncat(buf, name, REGEXP_CUTOFF); strcat(buf, "'\n"); } + + strcat(buf, "UNION\n"); + strcat(buf, "SELECT c.relname as \"Name\", 'view'::text as \"Type\", NULL as \"Owner\""); + if (desc) + strcat(buf, ", obj_description(c.oid) as \"Description\""); + strcat(buf, "\nFROM pg_class c\n" + "WHERE c.relkind = 'r'\n" + " AND exists (select 1 from pg_views where viewname = c.relname)\n" + " AND not exists (select 1 from pg_user where usesysid = c.relowner)\n"); + strcat(buf, showSystem ? " AND c.relname ~ '^pg_'\n" : " AND c.relname !~ '^pg_'\n"); + if (name) + { + strcat(buf, " AND c.relname ~ '"); + strncat(buf, name, REGEXP_CUTOFF); + strcat(buf, "'\n"); + } } /* indices, sequences */ @@ -1010,6 +1014,36 @@ listTables(const char *infotype, const char *name, PsqlSettings *pset, bool desc strcat(buf, "'S'"); strcat(buf, ")\n"); + /* ignore large-obj indices */ + if (showIndices) + strcat(buf, " AND (c.relkind != 'i' OR c.relname !~ '^xinx')\n"); + + strcat(buf, showSystem ? " AND c.relname ~ '^pg_'\n" : " AND c.relname !~ '^pg_'\n"); + if (name) + { + strcat(buf, " AND c.relname ~ '"); + strncat(buf, name, REGEXP_CUTOFF); + strcat(buf, "'\n"); + } + + strcat(buf, "UNION\n"); + strcat(buf, + "SELECT c.relname as \"Name\",\n" + " (CASE WHEN relkind = 'S' THEN 'sequence'::text ELSE 'index'::text END) as \"Type\",\n" + " NULL as \"Owner\"" + ); + if (desc) + strcat(buf, ", obj_description(c.oid) as \"Description\""); + strcat(buf, "\nFROM pg_class c\n" + "WHERE not exists (select 1 from pg_user where usesysid = c.relowner) AND relkind in ("); + if (showIndices && showSeq) + strcat(buf, "'i', 'S'"); + else if (showIndices) + strcat(buf, "'i'"); + else + strcat(buf, "'S'"); + strcat(buf, ")\n"); + /* ignore large-obj indices */ if (showIndices) strcat(buf, " AND (c.relkind != 'i' OR c.relname !~ '^xinx')\n"); @@ -1023,13 +1057,13 @@ listTables(const char *infotype, const char *name, PsqlSettings *pset, bool desc } } - /* real system catalogue tables */ + /* special system tables */ if (showSystem && showTables) { if (buf[0]) strcat(buf, "\nUNION\n\n"); - strcat(buf, "SELECT c.relname as \"Name\", 'system'::text as \"Type\", u.usename as \"Owner\""); + strcat(buf, "SELECT c.relname as \"Name\", 'special'::text as \"Type\", u.usename as \"Owner\""); if (desc) strcat(buf, ", obj_description(c.oid) as \"Description\""); strcat(buf, "\nFROM pg_class c, pg_user u\n" @@ -1040,6 +1074,20 @@ listTables(const char *infotype, const char *name, PsqlSettings *pset, bool desc strncat(buf, name, REGEXP_CUTOFF); strcat(buf, "'\n"); } + + strcat(buf, "UNION\n"); + strcat(buf, "SELECT c.relname as \"Name\", 'special'::text as \"Type\", NULL as \"Owner\""); + if (desc) + strcat(buf, ", obj_description(c.oid) as \"Description\""); + strcat(buf, "\nFROM pg_class c\n" + "WHERE c.relkind = 's'\n" + " AND not exists (select 1 from pg_user where usesysid = c.relowner)"); + if (name) + { + strcat(buf, " AND c.relname ~ '"); + strncat(buf, name, REGEXP_CUTOFF); + strcat(buf, "'\n"); + } } strcat(buf, "\nORDER BY \"Name\""); @@ -1064,6 +1112,3 @@ listTables(const char *infotype, const char *name, PsqlSettings *pset, bool desc PQclear(res); return true; } - - -/* end of file */ diff --git a/src/bin/psql/describe.h b/src/bin/psql/describe.h index 164c7044e70..960942f52ff 100644 --- a/src/bin/psql/describe.h +++ b/src/bin/psql/describe.h @@ -5,16 +5,16 @@ #include "settings.h" /* \da */ -bool describeAggregates(const char *name, PsqlSettings *pset, bool verbose, bool desc); +bool describeAggregates(const char *name, PsqlSettings *pset); /* \df */ -bool describeFunctions(const char *name, PsqlSettings *pset, bool verbose, bool desc); +bool describeFunctions(const char *name, PsqlSettings *pset, bool verbose); /* \dT */ -bool describeTypes(const char *name, PsqlSettings *pset, bool verbose, bool desc); +bool describeTypes(const char *name, PsqlSettings *pset, bool verbose); /* \do */ -bool describeOperators(const char *name, PsqlSettings *pset, bool verbose, bool desc); +bool describeOperators(const char *name, PsqlSettings *pset); /* \z (or \dp) */ bool permissionsList(const char *name, PsqlSettings *pset); diff --git a/src/bin/psql/help.c b/src/bin/psql/help.c index e200f391390..c108743deb2 100644 --- a/src/bin/psql/help.c +++ b/src/bin/psql/help.c @@ -30,7 +30,7 @@ /* * usage * - * print out command line arguments and exit + * print out command line arguments */ #define ON(var) (var ? "on" : "off") @@ -63,61 +63,67 @@ usage(void) #endif } -/* If string begins " here, then it ought to end there to fit on an 80 column terminal> > > > > > > " */ - fprintf(stderr, "Usage: psql [options] [dbname [username]] \n"); - fprintf(stderr, " -A Unaligned table output mode (-P format=unaligned)\n"); - fprintf(stderr, " -c query Run single query (slash commands, too) and exit\n"); +/* If this " is the start of the string then it ought to end there to fit in 80 columns >> " */ + puts( "This is psql, the PostgreSQL interactive terminal."); + puts( "\nUsage:"); + puts( " psql [options] [dbname [username]]"); + puts( "\nOptions:"); + puts( " -A Unaligned table output mode (-P format=unaligned"); + puts( " -c query Run only single query (or slash command) and exit"); /* Display default database */ env = getenv("PGDATABASE"); if (!env) env = user; - fprintf(stderr, " -d dbname Specify database name to connect to (default: %s)\n", env); + printf(" -d dbname Specify database name to connect to (default: %s)\n", env); - fprintf(stderr, " -e Echo all input in non-interactive mode\n"); - fprintf(stderr, " -E Display queries that internal commands generate\n"); - fprintf(stderr, " -f filename Execute queries from file, then exit\n"); - fprintf(stderr, " -F sep Set field separator (default: '" DEFAULT_FIELD_SEP "') (-P fieldsep=)\n"); + puts( " -e Echo all input in non-interactive mode"); + puts( " -E Display queries that internal commands generate"); + puts( " -f filename Execute queries from file, then exit"); + puts( " -F sep Set field separator (default: \"" DEFAULT_FIELD_SEP "\") (-P fieldsep=)"); /* Display default host */ env = getenv("PGHOST"); - fprintf(stderr, " -h host Specify database server host (default: "); + printf(" -h host Specify database server host (default: "); if (env) - fprintf(stderr, env); + fputs(env, stdout); else - fprintf(stderr, "domain socket"); - fprintf(stderr, ")\n"); + fputs("domain socket", stdout); + puts(")"); - fprintf(stderr, " -H HTML table output mode (-P format=html)\n"); - fprintf(stderr, " -l List available databases, then exit\n"); - fprintf(stderr, " -n Do not use readline and history\n"); - fprintf(stderr, " -o filename Send query output to filename (or |pipe)\n"); + puts( " -H HTML table output mode (-P format=html)"); + puts( " -l List available databases, then exit"); + puts( " -n Do not use readline or history"); + puts( " -o filename Send query output to filename (or |pipe)"); /* Display default port */ env = getenv("PGPORT"); - fprintf(stderr, " -p port Specify database server port (default: %s)\n", - env ? env : "hardwired"); + printf(" -p port Specify database server port (default: %s)\n", + env ? env : "hardwired"); - fprintf(stderr, " -P var[=arg] Set printing option 'var' to 'arg'. (see \\pset command)\n"); - fprintf(stderr, " -q Run quietly (no messages, no prompts)\n"); - fprintf(stderr, " -s Single step mode (confirm each query)\n"); - fprintf(stderr, " -S Single line mode (newline sends query)\n"); - fprintf(stderr, " -t Don't print headings and row count (-P tuples_only)\n"); - fprintf(stderr, " -T text Set HTML table tag options (e.g., width, border)\n"); - fprintf(stderr, " -u Prompt for username and password (same as \"-U ? -W\")\n"); + puts( " -P var[=arg] Set printing option 'var' to 'arg' (see \\pset command)"); + puts( " -q Run quietly (no messages, only query output)"); + puts( " -s Single step mode (confirm each query)"); + puts( " -S Single line mode (newline terminates query)"); + puts( " -t Don't print headings and row count (-P tuples_only)"); + puts( " -T text Set HTML table tag options (width, border) (-P tableattr=)"); /* Display default user */ env = getenv("PGUSER"); if (!env) env = user; - fprintf(stderr, " -U [username] Specifiy username, \"?\"=prompt (default user: %s)\n", env); + printf(" -U [username] Specifiy username, \"?\"=prompt (default user: %s)\n", env); - fprintf(stderr, " -x Turn on expanded table output (-P expanded)\n"); - fprintf(stderr, " -v name=val Set psql variable 'name' to 'value'\n"); - fprintf(stderr, " -V Show version information and exit\n"); - fprintf(stderr, " -W Prompt for password (should happen automatically)\n"); + puts( " -x Turn on expanded table output (-P expanded)"); + puts( " -v name=val Set psql variable 'name' to 'value'"); + puts( " -V Show version information and exit"); + puts( " -W Prompt for password (should happen automatically)"); - fprintf(stderr, "Consult the documentation for the complete details.\n"); + puts( "\nFor more information, type \"\\?\" (for internal commands) or \"\\help\""); + puts( "(for SQL commands) from within psql, or consult the psql section in the"); + puts( "PostgreSQL manual, which accompanies the distribution and is also available at"); + puts( "<http://www.postgresql.org>."); + puts( "Report bugs to <bugs@postgresql.org>."); #ifndef WIN32 if (pw) @@ -176,37 +182,39 @@ slashUsage(PsqlSettings *pset) fout = stdout; /* if you add/remove a line here, change the row test above */ - fprintf(fout, " \\? -- help\n"); - fprintf(fout, " \\c[onnect] [dbname|- [user|?]] -- connect to new database (now '%s')\n", PQdb(pset->db)); - fprintf(fout, " \\copy [binary] <table> [with oids] {from|to} <fname>[using delimiters '<char>']\n"); - fprintf(fout, " \\copyright -- show PostgreSQL copyright\n"); - fprintf(fout, " \\d <table> -- describe table (or view, index, sequence)\n"); - fprintf(fout, " \\d{i|s|t|v|S}-- list only indices/sequences/tables/views/system tables\n"); - fprintf(fout, " \\da -- list aggregates\n"); - fprintf(fout, " \\dd [object] -- list comment for table, type, function, or operator\n"); - fprintf(fout, " \\df -- list functions\n"); - fprintf(fout, " \\do -- list operators\n"); - fprintf(fout, " \\dT -- list data types\n"); - fprintf(fout, " \\e [fname] -- edit the current query buffer or <fname> with external editor\n"); - fprintf(fout, " \\echo <text> -- write text to stdout\n"); - fprintf(fout, " \\g [fname] -- send query to backend (and results in <fname> or |pipe)\n"); - fprintf(fout, " \\h [cmd] -- help on syntax of sql commands, * for all commands\n"); - fprintf(fout, " \\i <fname> -- read and execute queries from filename\n"); - fprintf(fout, " \\l -- list all databases\n"); - fprintf(fout, " \\lo_export, \\lo_import, \\lo_list, \\lo_unlink -- large object operations\n"); - fprintf(fout, " \\o [fname] -- send all query results to <fname>, or |pipe\n"); - fprintf(fout, " \\p -- print the content of the current query buffer\n"); - fprintf(fout, " \\pset -- set table output options\n"); - fprintf(fout, " \\q -- quit\n"); - fprintf(fout, " \\qecho <text>-- write text to query output stream (see \\o)\n"); - fprintf(fout, " \\r -- reset (clear) the query buffer\n"); - fprintf(fout, " \\s [fname] -- print history or save it in <fname>\n"); - fprintf(fout, " \\set <var> [value] -- set/unset internal variable\n"); - fprintf(fout, " \\t -- don't show table headers or footers (now %s)\n", ON(pset->popt.topt.tuples_only)); - fprintf(fout, " \\x -- toggle expanded output (now %s)\n", ON(pset->popt.topt.expanded)); - fprintf(fout, " \\w <fname> -- write current query buffer to a file\n"); - fprintf(fout, " \\z -- list table access permissions\n"); - fprintf(fout, " \\! [cmd] -- shell escape or command\n"); + fprintf(fout, " \\? help\n"); + fprintf(fout, " \\c[onnect] [dbname|- [user|?]]\n" + " connect to new database (currently '%s')\n", PQdb(pset->db)); + fprintf(fout, " \\copy ... perform SQL COPY with data stream to the client machine"); + fprintf(fout, " \\copyright show PostgreSQL usage and distribution terms\n"); + fprintf(fout, " \\d <table> describe table (or view, index, sequence)\n"); + fprintf(fout, " \\d{i|s|t|v|S} list only indices/sequences/tables/views/system tables\n"); + fprintf(fout, " \\da list aggregates\n"); + fprintf(fout, " \\dd [object] list comment for table, type, function, or operator\n"); + fprintf(fout, " \\df list functions\n"); + fprintf(fout, " \\do list operators\n"); + fprintf(fout, " \\dT list data types\n"); + fprintf(fout, " \\e [fname] edit the current query buffer or <fname> with external editor\n"); + fprintf(fout, " \\echo <text> write text to stdout\n"); + fprintf(fout, " \\g [fname] send query to backend (and results in <fname> or |pipe)\n"); + fprintf(fout, " \\h [cmd] help on syntax of sql commands, * for all commands\n"); + fprintf(fout, " \\i <fname> read and execute queries from filename\n"); + fprintf(fout, " \\l list all databases\n"); + fprintf(fout, " \\lo_export, \\lo_import, \\lo_list, \\lo_unlink\n" + " large object operations\n"); + fprintf(fout, " \\o [fname] send all query results to <fname>, or |pipe\n"); + fprintf(fout, " \\p show the content of the current query buffer\n"); + fprintf(fout, " \\pset [opt] set table output options\n"); + fprintf(fout, " \\q quit psql\n"); + fprintf(fout, " \\qecho <text> write text to query output stream (see \\o)\n"); + fprintf(fout, " \\r reset (clear) the query buffer\n"); + fprintf(fout, " \\s [fname] print history or save it in <fname>\n"); + fprintf(fout, " \\set <var> [value] set/unset internal variable\n"); + fprintf(fout, " \\t don't show table headers or footers (currently %s)\n", ON(pset->popt.topt.tuples_only)); + fprintf(fout, " \\x toggle expanded output (currently %s)\n", ON(pset->popt.topt.expanded)); + fprintf(fout, " \\w <fname> write current query buffer to a file\n"); + fprintf(fout, " \\z list table access permissions\n"); + fprintf(fout, " \\! [cmd] shell escape or command\n"); if (usePipe) { @@ -229,7 +237,7 @@ helpSQL(const char *topic) char left_center_right; /* Which column we're displaying */ int i; /* Index into QL_HELP[] */ - puts("Syntax: \\h <cmd> or \\help <cmd>, where <cmd> is one of the following:"); + puts("Available help:"); left_center_right = 'L';/* Start with left column */ i = 0; @@ -254,10 +262,8 @@ helpSQL(const char *topic) } if (left_center_right != 'L') puts("\n"); - puts("Or type \\h * for a complete description of all commands."); } - else { int i; diff --git a/src/bin/psql/large_obj.c b/src/bin/psql/large_obj.c index 5358528833d..befa4c452c3 100644 --- a/src/bin/psql/large_obj.c +++ b/src/bin/psql/large_obj.c @@ -90,7 +90,9 @@ do_lo_export(PsqlSettings *pset, const char *loid_arg, const char *filename_arg) if (!pset->db) { - fputs("You are not connected to a database.\n", stderr); + if (!pset->cur_cmd_interactive) + fprintf(stderr, "%s: ", pset->progname); + fputs("\\lo_export: not connected to a database\n", stderr); return false; } @@ -157,7 +159,9 @@ do_lo_import(PsqlSettings *pset, const char *filename_arg, const char *comment_a if (!pset->db) { - fputs("You are not connected to a database.\n", stderr); + if (!pset->cur_cmd_interactive) + fprintf(stderr, "%s: ", pset->progname); + fputs("\\lo_import: not connected to a database\n", stderr); return false; } @@ -247,7 +251,9 @@ do_lo_unlink(PsqlSettings *pset, const char *loid_arg) if (!pset->db) { - fputs("You are not connected to a database.\n", stderr); + if (!pset->cur_cmd_interactive) + fprintf(stderr, "%s: ", pset->progname); + fputs("\\lo_unlink: not connected to a database\n", stderr); return false; } @@ -309,20 +315,25 @@ do_lo_unlink(PsqlSettings *pset, const char *loid_arg) /* * do_lo_list() * - * Show all large objects in database, with comments if desired + * Show all large objects in database with comments */ bool -do_lo_list(PsqlSettings *pset, bool desc) +do_lo_list(PsqlSettings *pset) { PGresult *res; - char buf[512]; + char buf[1024]; printQueryOpt myopt = pset->popt; - strcpy(buf, "SELECT usename as \"Owner\", substring(relname from 5) as \"ID\""); - if (desc) - strcat(buf, ",\n obj_description(pg_class.oid) as \"Description\""); - strcat(buf, "\nFROM pg_class, pg_user\n" + strcpy(buf, + "SELECT usename as \"Owner\", substring(relname from 5) as \"ID\",\n" + " obj_description(pg_class.oid) as \"Description\"\n" + "FROM pg_class, pg_user\n" "WHERE usesysid = relowner AND relkind = 'l'\n" + "UNION\n" + "SELECT NULL as \"Owner\", substring(relname from 5) as \"ID\",\n" + " obj_description(pg_class.oid) as \"Description\"\n" + "FROM pg_class\n" + "WHERE not exists (select 1 from pg_user where usesysid = relowner) AND relkind = 'l'\n" "ORDER BY \"ID\""); res = PSQLexec(pset, buf); diff --git a/src/bin/psql/large_obj.h b/src/bin/psql/large_obj.h index bb06867a2ec..3ddb2206bbb 100644 --- a/src/bin/psql/large_obj.h +++ b/src/bin/psql/large_obj.h @@ -7,6 +7,6 @@ bool do_lo_export(PsqlSettings *pset, const char *loid_arg, const char *filename_arg); bool do_lo_import(PsqlSettings *pset, const char *filename_arg, const char *comment_arg); bool do_lo_unlink(PsqlSettings *pset, const char *loid_arg); -bool do_lo_list(PsqlSettings *pset, bool desc); +bool do_lo_list(PsqlSettings *pset); #endif /* LARGE_OBJ_H */ diff --git a/src/bin/psql/mainloop.c b/src/bin/psql/mainloop.c index 76da5417365..cb9232d7147 100644 --- a/src/bin/psql/mainloop.c +++ b/src/bin/psql/mainloop.c @@ -124,10 +124,7 @@ MainLoop(PsqlSettings *pset, FILE *source) } - /* Setting this will not have effect until next line. (Faster. - Also think about what happens if there is an error processing - _this_ command.) - */ + /* Setting this will not have effect until next line. */ die_on_error = GetVariableBool(pset->vars, "die_on_error"); /* @@ -143,7 +140,7 @@ MainLoop(PsqlSettings *pset, FILE *source) if (GetVariableBool(pset->vars, "echo") && !GetVariableBool(pset->vars, "quiet")) puts("EOF"); else if (pset->cur_cmd_interactive) - puts(""); /* just newline */ + putc('\n', stdout); /* just newline */ eof = true; continue; @@ -269,6 +266,7 @@ MainLoop(PsqlSettings *pset, FILE *source) free(line); line = new; + len = strlen(new); continue; /* reparse the just substituted */ } diff --git a/src/bin/psql/print.c b/src/bin/psql/print.c index 15d40a806a9..156cdf6c653 100644 --- a/src/bin/psql/print.c +++ b/src/bin/psql/print.c @@ -204,7 +204,7 @@ print_aligned_text(const char *title, const char * const * headers, if (opt_border == 0) total_w = col_count - 1; else if (opt_border == 1) - total_w = col_count * 3 - 2; + total_w = col_count * 3 - 1; else total_w = col_count * 3 + 1; diff --git a/src/bin/psql/prompt.c b/src/bin/psql/prompt.c index 22ca579351c..dd41ba54015 100644 --- a/src/bin/psql/prompt.c +++ b/src/bin/psql/prompt.c @@ -52,8 +52,7 @@ * * * If the application-wide prompts became NULL somehow, the returned string - * will be empty (not NULL!). Do not free() the result of this function unless - * you want trouble. + * will be empty (not NULL!). *-------------------------- */ const char * @@ -66,9 +65,6 @@ get_prompt(PsqlSettings *pset, promptStatus_t status) const char *p; const char *prompt_string; - if (GetVariable(pset->vars, "quiet")) - return ""; - if (status == PROMPT_READY) prompt_string = GetVariable(pset->vars, "prompt1"); else if (status == PROMPT_CONTINUE || status == PROMPT_SINGLEQUOTE || status == PROMPT_DOUBLEQUOTE || status == PROMPT_COMMENT) @@ -130,13 +126,8 @@ get_prompt(PsqlSettings *pset, promptStatus_t status) break; /* DB server port number */ case '>': - if (pset->db) - { - if (PQhost(pset->db)) - strncpy(buf, PQport(pset->db), MAX_PROMPT_SIZE); - else - buf[0] = '.'; - } + if (pset->db && PQport(pset->db)) + strncpy(buf, PQport(pset->db), MAX_PROMPT_SIZE); break; /* DB server user name */ case 'n': diff --git a/src/bin/psql/settings.h b/src/bin/psql/settings.h index 85cf9dcb7f3..774c54b4594 100644 --- a/src/bin/psql/settings.h +++ b/src/bin/psql/settings.h @@ -45,6 +45,7 @@ typedef struct _psqlSettings * startup? */ Oid lastOid; /* saves oid from insert command because people want it so badly */ + char *progname; /* in case you renamed psql */ } PsqlSettings; diff --git a/src/bin/psql/startup.c b/src/bin/psql/startup.c index 62011b53d22..61613898418 100644 --- a/src/bin/psql/startup.c +++ b/src/bin/psql/startup.c @@ -40,7 +40,7 @@ static void process_psqlrc(PsqlSettings *pset); static void -showVersion(PsqlSettings *pset); +showVersion(void); /* Structures to pass information between the option parsing routine @@ -51,7 +51,6 @@ enum _actions ACT_NOTHING = 0, ACT_SINGLE_SLASH, ACT_LIST_DB, - ACT_SHOW_VER, ACT_SINGLE_QUERY, ACT_FILE }; @@ -90,6 +89,11 @@ main(int argc, char **argv) memset(&settings, 0, sizeof settings); + if (!strrchr(argv[0], SEP_CHAR)) + settings.progname = argv[0]; + else + settings.progname = strrchr(argv[0], SEP_CHAR) + 1; + settings.cur_cmd_source = stdin; settings.cur_cmd_interactive = false; @@ -119,7 +123,7 @@ main(int argc, char **argv) parse_options(argc, argv, &settings, &options); - if (options.action == ACT_LIST_DB || options.action == ACT_SHOW_VER) + if (options.action == ACT_LIST_DB) options.dbname = "template1"; if (options.username) @@ -152,9 +156,10 @@ main(int argc, char **argv) free(username); free(password); - if (PQstatus(settings.db) == CONNECTION_BAD && options.action != ACT_SHOW_VER) + if (PQstatus(settings.db) == CONNECTION_BAD) { - fprintf(stderr, "Connection to database '%s' failed.\n%s\n", PQdb(settings.db), PQerrorMessage(settings.db)); + fprintf(stderr, "%s: connection to database '%s' failed - %s", + settings.progname, PQdb(settings.db), PQerrorMessage(settings.db)); PQfinish(settings.db); exit(EXIT_BADCONN); } @@ -167,22 +172,15 @@ main(int argc, char **argv) exit(!success); } - if (options.action == ACT_SHOW_VER) - { - showVersion(&settings); - PQfinish(settings.db); - exit(EXIT_SUCCESS); - } - if (!GetVariable(settings.vars, "quiet") && !settings.notty && !options.action) { - puts("Welcome to psql, the PostgreSQL interactive terminal.\n\n" - "Type: \\copyright for distribution terms\n" - " \\h for help with SQL commands\n" - " \\? for help on internal slash commands\n" - " \\g or terminate with semicolon to execute query\n" - " \\q to quit\n"); + printf("Welcome to %s, the PostgreSQL interactive terminal.\n\n" + "Type: \\copyright for distribution terms\n" + " \\h for help with SQL commands\n" + " \\? for help on internal slash commands\n" + " \\g or terminate with semicolon to execute query\n" + " \\q to quit\n", settings.progname); } process_psqlrc(&settings); @@ -239,13 +237,12 @@ parse_options(int argc, char *argv[], PsqlSettings *pset, struct adhoc_opts * op {"echo-all", no_argument, NULL, 'E'}, {"echo-all-queries", no_argument, NULL, 'E'}, {"file", required_argument, NULL, 'f'}, - {"field-sep", required_argument, NULL, 'F'}, + {"field-separator", required_argument, NULL, 'F'}, {"host", required_argument, NULL, 'h'}, {"html", no_argument, NULL, 'H'}, {"list", no_argument, NULL, 'l'}, {"no-readline", no_argument, NULL, 'n'}, - {"out", required_argument, NULL, 'o'}, - {"to-file", required_argument, NULL, 'o'}, + {"output", required_argument, NULL, 'o'}, {"port", required_argument, NULL, 'p'}, {"pset", required_argument, NULL, 'P'}, {"quiet", no_argument, NULL, 'q'}, @@ -390,7 +387,8 @@ parse_options(int argc, char *argv[], PsqlSettings *pset, struct adhoc_opts * op { if (!DeleteVariable(pset->vars, value)) { - fprintf(stderr, "Couldn't delete variable %s.\n", value); + fprintf(stderr, "%s: could not delete variable %s\n", + pset->progname, value); exit(EXIT_FAILURE); } } @@ -399,7 +397,8 @@ parse_options(int argc, char *argv[], PsqlSettings *pset, struct adhoc_opts * op *equal_loc = '\0'; if (!SetVariable(pset->vars, value, equal_loc + 1)) { - fprintf(stderr, "Couldn't set variable %s to %s.\n", value, equal_loc); + fprintf(stderr, "%s: Couldn't set variable %s to %s\n", + pset->progname, value, equal_loc); exit(EXIT_FAILURE); } } @@ -408,8 +407,8 @@ parse_options(int argc, char *argv[], PsqlSettings *pset, struct adhoc_opts * op break; } case 'V': - options->action = ACT_SHOW_VER; - break; + showVersion(); + exit(EXIT_SUCCESS); case 'W': pset->getPassword = true; break; @@ -419,8 +418,8 @@ parse_options(int argc, char *argv[], PsqlSettings *pset, struct adhoc_opts * op break; #ifndef HAVE_GETOPT_LONG case '-': - fprintf(stderr, "This version of psql was compiled without support for long options.\n" - "Use -? for help on invocation options.\n"); + fprintf(stderr, "%s was compiled without support for long options.\n" + "Use -? for help on invocation options.\n", pset->progname); exit(EXIT_FAILURE); break; #endif @@ -442,7 +441,8 @@ parse_options(int argc, char *argv[], PsqlSettings *pset, struct adhoc_opts * op else if (!options->username) options->username = argv[optind]; else - fprintf(stderr, "Warning: extra option %s ignored.\n", argv[optind]); + fprintf(stderr, "%s: warning: extra option %s ignored\n", + pset->progname, argv[optind]); optind++; } @@ -498,73 +498,46 @@ process_psqlrc(PsqlSettings *pset) /* showVersion * - * Displays the database backend version. - * Also checks against the version psql was compiled for and makes - * sure that there are no problems. - * - * Returns false if there was a problem retrieving the information - * or a mismatch was detected. + * This output format is intended to match GNU standards. */ static void -showVersion(PsqlSettings *pset) +showVersion(void) { - PGresult *res = NULL; - const char *versionstr = NULL; - long int release = 0, - version = 0, - subversion = 0; - - /* get backend version */ - if (pset->db && PQstatus(pset->db) == CONNECTION_OK) { - res = PSQLexec(pset, "SELECT version()"); - if (PQresultStatus(res) == PGRES_TUPLES_OK) - versionstr = PQgetvalue(res, 0, 0); - } - - if (versionstr && strncmp(versionstr, "PostgreSQL ", 11) == 0) - { - char *tmp; - - release = strtol(&versionstr[11], &tmp, 10); - version = strtol(tmp + 1, &tmp, 10); - subversion = strtol(tmp + 1, &tmp, 10); - } + puts("psql (PostgreSQL) " PG_RELEASE "." PG_VERSION "." PG_SUBVERSION); - printf("Server: %s\npsql", versionstr ? versionstr : "(could not connect)"); +#if defined(USE_READLINE) || defined (USE_HISTORY) || defined(MULTIBYTE) + fputs("contains ", stdout); - if (!versionstr || strcmp(versionstr, PG_VERSION_STR) != 0) - printf(&PG_VERSION_STR[strcspn(PG_VERSION_STR, " ")]); - printf(" (" __DATE__ " " __TIME__ ")"); - -#ifdef MULTIBYTE - printf(", multibyte"); -#endif -#ifdef HAVE_GETOPT_LONG - printf(", long options"); -#endif #ifdef USE_READLINE - printf(", readline"); + fputs("readline", stdout); +#define _Feature #endif + #ifdef USE_HISTORY - printf(", history"); +#ifdef _Feature + fputs(", ", stdout); +#else +#define _Feature #endif -#ifdef USE_LOCALE - printf(", locale"); + fputs("history", stdout); #endif -#ifdef PSQL_ALWAYS_GET_PASSWORDS - printf(", always password"); + +#ifdef MULTIBYTE +#ifdef _Feature + fputs(", ", stdout); +#else +#define _Feature #endif -#ifdef USE_ASSERT_CHECKING - printf(", assert checks"); + fputs("multibyte"); #endif + +#undef _Feature - puts(""); - - if (versionstr && (release < 6 || (release == 6 && version < 5))) - puts("\nWarning: The server you are connected to is potentially too old for this client\n" - "version. You should ideally be using clients and servers from the same\n" - "distribution."); + puts(" support"); +#endif - if (res) - PQclear(res); + puts("Copyright (C) 2000 PostgreSQL Global Development Team"); + puts("Copyright (C) 1996 Regents of the University of California"); + puts("Read the file COPYING or use the command \\copyright to see the"); + puts("usage and distribution terms."); } diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c index 6ec503605c9..dbba754b9a0 100644 --- a/src/bin/psql/tab-complete.c +++ b/src/bin/psql/tab-complete.c @@ -97,14 +97,12 @@ void initialize_readline(PGconn ** conn) rl_readline_name = "psql"; rl_attempted_completion_function = psql_completion; - rl_filename_quoting_function = quote_file_name; - /*rl_filename_dequoting_function = dequote_file_name;*/ - rl_filename_quote_characters = "qwertyuioplkjhgfdsazxcvbnm"; - rl_special_prefixes = "()'"; rl_basic_word_break_characters = "\t\n\"'`@$><=;|&{ "; - completion_max_records = rl_completion_query_items + 1; + completion_max_records = 100; + /* There is a variable rl_completion_query_items for this but apparently + it's not defined everywhere. */ database_connection = conn; } @@ -203,8 +201,6 @@ char ** psql_completion(char *text, int start, int end) (void)end; /* not used */ - rl_completion_append_character = ' '; - /* Clear a few things. */ completion_charp = NULL; completion_charpp = NULL; @@ -721,8 +717,10 @@ PGresult * exec_query(char * query) result = PQexec(*database_connection, query); if (result != NULL && PQresultStatus(result) != PGRES_TUPLES_OK) { +#ifdef NOT_USED fprintf(stderr, "\nThe completion query \"%s\" failed thus: %s\n", query, PQresStatus(PQresultStatus(result))); +#endif PQclear(result); result = NULL; } @@ -777,6 +775,9 @@ char * previous_word(int point, int skip) { } + +#ifdef NOT_USED + /* Surround a string with single quotes. This works for both SQL and psql internal. Doesn't work so well yet. */ @@ -798,7 +799,7 @@ char * quote_file_name(char *text, int match_type, char * quote_pointer) } -#ifdef NOT_USED + static char * dequote_file_name(char *text, char quote_char) { char *s; @@ -814,6 +815,7 @@ static char * dequote_file_name(char *text, char quote_char) return s; } -#endif + +#endif /* NOT_USED */ #endif /* USE_READLINE */ diff --git a/src/bin/scripts/createdb b/src/bin/scripts/createdb index 7a7286c5751..490edb196e5 100644 --- a/src/bin/scripts/createdb +++ b/src/bin/scripts/createdb @@ -11,7 +11,7 @@ # # # IDENTIFICATION -# $Header: /cvsroot/pgsql/src/bin/scripts/Attic/createdb,v 1.5 2000/01/12 13:08:55 ishii Exp $ +# $Header: /cvsroot/pgsql/src/bin/scripts/Attic/createdb,v 1.6 2000/01/12 19:36:36 petere Exp $ # #------------------------------------------------------------------------- @@ -28,6 +28,7 @@ do case "$1" in --help|-\?) usage=t + break ;; # options passed on to psql --host|-h) @@ -89,7 +90,8 @@ do MB=`echo $1 | sed 's/^--encoding=//'` ;; -*) - echo "$CMDNAME: Unrecognized option: $1. Try -? for help." + echo "$CMDNAME: unrecognized option: $1" + echo "Try -? for help." exit 1 ;; *) @@ -104,20 +106,17 @@ do done if [ "$usage" ]; then - echo "" echo "Usage: $CMDNAME [options] dbname [description]" echo "" - echo " -h HOSTNAME, --host=HOSTNAME " - echo " -p PORT, --port=PORT " - echo " -U USERNAME, --username=USERNAME " - echo " -W, --password " - echo " -e, --echo " - echo " -q, --quiet " - echo " -D PATH, --location=PATH " - echo " -E ENCODING --encoding=ENCODING " - echo " -?, --help " - echo "" - exit 1 + echo " -D, --location=PATH Alternative place to store the database" + echo " -E, --encoding=ENCODING Multibyte encoding for the database" + echo " -h, --host=HOSTNAME Database server host" + echo " -p, --port=PORT Database server port" + echo " -U, --username=USERNAME Username to connect as" + echo " -W, --password Prompt for password" +#??? echo " -e, --echo " + echo " -q, --quiet Don't write any messages" + exit 0 fi @@ -126,17 +125,19 @@ then mbcode=`pg_encoding "$MB"` if [ -z "$mbcode" ] then - echo "$CMDNAME: \"$MB\" is not a valid encoding name." + echo "$CMDNAME: \"$MB\" is not a valid encoding name" exit 1 fi fi if [ -z "$dbname" ]; then - echo "$CMDNAME: Missing required argument database name. Try -? for help." + echo "$CMDNAME: missing required argument database name" + echo "Try -? for help." exit 1 fi +# escape the quotes dbpath=`echo $dbpath | sed "s/'/\\\\\'/g"` dbname=`echo $dbname | sed 's/\"/\\\"/g'` @@ -147,7 +148,7 @@ withstring= psql $PSQLOPT -d template1 -c "CREATE DATABASE \"$dbname\"$withstring" if [ $? -ne 0 ]; then - echo "$CMDNAME: Database creation failed." + echo "$CMDNAME: database creation failed" exit 1 fi @@ -158,7 +159,7 @@ dbcomment=`echo $dbcomment | sed "s/'/\\\\\'/g"` psql $PSQLOPT -d template1 -c "COMMENT ON DATABASE \"$dbname\" IS '$dbcomment'" if [ $? -ne 0 ]; then - echo "$CMDNAME: Comment creation failed. (Database was created.)" + echo "$CMDNAME: comment creation failed (database was created)" exit 1 fi diff --git a/src/bin/scripts/createlang.sh b/src/bin/scripts/createlang.sh index b5eac5762e2..404a8bd53a7 100644 --- a/src/bin/scripts/createlang.sh +++ b/src/bin/scripts/createlang.sh @@ -8,7 +8,7 @@ # # # IDENTIFICATION -# $Header: /cvsroot/pgsql/src/bin/scripts/Attic/createlang.sh,v 1.4 1999/12/17 18:05:32 momjian Exp $ +# $Header: /cvsroot/pgsql/src/bin/scripts/Attic/createlang.sh,v 1.5 2000/01/12 19:36:36 petere Exp $ # #------------------------------------------------------------------------- @@ -32,16 +32,6 @@ else fi -# ---------- -# Find the default PGLIB directory -# ---------- -postconfig_result="`sh -c postconfig 2>/dev/null`" -if [ "$postconfig_result" ]; then - set -a - eval "$postconfig_result" - set +a -fi - # ---------- # Get options, language name and dbname @@ -51,6 +41,7 @@ do case "$1" in --help|-\?) usage=t + break ;; --list|-l) list=t @@ -115,6 +106,11 @@ do PGLIB=`echo $1 | sed 's/^--pglib=//'` ;; + -*) + echo "$CMDNAME: unrecognized option: $1" + echo "Try -? for help." + exit 1 + ;; *) langname="$1" if [ "$2" ]; then @@ -130,18 +126,15 @@ if [ "$usage" ]; then echo "" echo "Usage: $CMDNAME [options] [langname [dbname]]" echo "" - echo " -h HOSTNAME, --host=HOSTNAME " - echo " -p PORT, --port=PORT " - echo " -U USERNAME, --username=USERNAME " - echo " -l, --list " - echo " -W, --password " - echo " -d DBNAME, --database=DBNAME " - echo " -e, --echo " - echo " -D PATH, --location=PATH " - echo " -L PGLIB --pglib=PGLIB " - echo " -?, --help " - echo "" - exit 1 + echo " -h, --host=HOSTNAME Database server host" + echo " -p, --port=PORT Database server port" + echo " -U, --username=USERNAME Username to connect as" + echo " -W, --password Prompt for password" + echo " -d, --dbname=DBNAME Database to install language in" + echo " -e, --echo Create some output about what is happening" + echo " -L, --pglib=PGLIB Find language interpreter in directory PGLIB" + echo " -l, --list Show a list of currently installed languages" + exit 0 fi if [ "$list" ]; then @@ -154,7 +147,8 @@ fi # Check that we have a database # ---------- if [ -z "$dbname" ]; then - echo "$CMDNAME: Missing required argument database name. Try -? for help." + echo "$CMDNAME: missing required argument database name" + echo "Try -? for help." exit 1 fi @@ -163,9 +157,10 @@ fi # Check that we have PGLIB # ---------- if [ -z "$PGLIB" ]; then - echo "Cannot determine the PostgreSQL lib directory (PGLIB). You must" - echo "identify it either with a --pglib option or by setting the PGLIB" - echo "environment variable." + echo "$CMDNAME: missing required argument PGLIB directory" + echo "(This is the directory where the interpreter for the procedural" + echo "language is stored. Traditionally, these are installed in whatever" + echo "'lib' directory was specified at configure time.)" exit 1 fi @@ -191,7 +186,7 @@ case "$langname" in trusted="TRUSTED " handler="pltcl_call_handler";; *) - echo "$CMDNAME: Unsupported language '$langname'." + echo "$CMDNAME: unsupported language '$langname'" echo "Supported languages are 'plpgsql' and 'pltcl'." exit 1 ;; @@ -203,7 +198,7 @@ esac # in PGLIB # ---------- if [ ! -f $PGLIB/${langname}__DLSUFFIX__ ]; then - echo "Cannot find the file $PGLIB/${langname}__DLSUFFIX__." + echo "$CMDNAME: cannot find the file $PGLIB/${langname}__DLSUFFIX__" echo "" echo "This file contains the call handler for $lancomp. By default," echo "only PL/pgSQL is built and installed; other languages must be" @@ -228,12 +223,12 @@ PSQL="psql -A -t $PSQLOPT -d $dbname -c" # ---------- res=`$PSQL "SELECT oid FROM pg_language WHERE lanname = '$langname'"` if [ $? -ne 0 ]; then - echo "Language installation failed." + echo "$CMDNAME: external error" exit 1 fi if [ "$res" ]; then - echo "The language '$langname' is already installed in database $dbname." - exit 2 + echo "$CMDNAME: '$langname' is already installed in database $dbname" + exit 1 fi # ---------- @@ -241,9 +236,7 @@ fi # ---------- res=`$PSQL "SELECT oid FROM pg_proc WHERE proname = '$handler'"` if [ ! -z "$res" ]; then - echo "The language $lancomp isn't created up to now but there is" - echo "already a function named '$handler' declared." - echo "Language installation aborted." + echo "$CMDNAME: A function named '$handler' already exists. Installation aborted." exit 1 fi @@ -252,12 +245,12 @@ fi # ---------- $PSQL "CREATE FUNCTION $handler () RETURNS OPAQUE AS '$PGLIB/${langname}__DLSUFFIX__' LANGUAGE 'C'" if [ $? -ne 0 ]; then - echo "Language installation failed." + echo "$CMDNAME: language installation failed" exit 1 fi $PSQL "CREATE ${trusted}PROCEDURAL LANGUAGE '$langname' HANDLER $handler LANCOMPILER '$lancomp'" if [ $? -ne 0 ]; then - echo "Language installation failed." + echo "$CMDNAME: language installation failed" exit 1 fi diff --git a/src/bin/scripts/createuser b/src/bin/scripts/createuser index ae4f3dff321..dd184c9a4e8 100644 --- a/src/bin/scripts/createuser +++ b/src/bin/scripts/createuser @@ -8,7 +8,7 @@ # # # IDENTIFICATION -# $Header: /cvsroot/pgsql/src/bin/scripts/Attic/createuser,v 1.4 1999/12/16 20:10:02 momjian Exp $ +# $Header: /cvsroot/pgsql/src/bin/scripts/Attic/createuser,v 1.5 2000/01/12 19:36:36 petere Exp $ # # Note - this should NOT be setuid. # @@ -41,6 +41,7 @@ do case "$1" in --help|-\?) usage=t + break ;; # options passed on to psql --host|-h) @@ -110,7 +111,8 @@ do PwPrompt=t ;; -*) - echo "$CMDNAME: Unrecognized option: $1. Try -? for help." + echo "$CMDNAME: unrecognized option: $1" + echo "Try -? for help." exit 1 ;; *) @@ -121,29 +123,26 @@ do done if [ "$usage" ]; then - echo "" echo "Usage: $CMDNAME [options] [username]" echo "" - echo " -h HOSTNAME, --host=HOSTNAME " - echo " -p PORT, --port=PORT " - echo " -d, --createdb " - echo " -D, --no-createdb " - echo " -a, --adduser " - echo " -A, --no-adduser " - echo " -i SYSID, --sysid=SYSID " - echo " -P, --pwprompt " - echo " -U USERNAME, --username=USERNAME (for connect to db)" - echo " -W, --password (for connect to db)" - echo " -e, --echo " - echo " -q, --quiet " - echo " -?, --help " - echo "" - exit 1 + echo " -d, --createdb User can create new databases" + echo " -D, --no-createdb User cannot create databases" + echo " -a, --adduser User can add new users" + echo " -A, --no-adduser User cannot add new users" + echo " -i, --sysid=SYSID Select sysid for new user" + echo " -P, --pwprompt Assign a password to new user" + echo " -h, --host=HOSTNAME Database server host" + echo " -p, --port=PORT Database server port" + echo " -U, --username=USERNAME Username to connect as (not the one to create)" + echo " -W, --password Prompt for password to connect" +#??? echo " -e, --echo " + echo " -q, --quiet Don't write any messages" + exit 0 fi if [ "$SysID" ]; then if [ "$SysID" != "`echo $SysID | sed 's/[^0-9]//g'`" ]; then - echo "$CMDNAME: User sysid must be a positive number." + echo "$CMDNAME: user sysid must be a positive number" exit 1 fi fi @@ -204,7 +203,7 @@ SUBQUERY= psql $PSQLOPT -d template1 -c "$QUERY" if [ $? -ne 0 ]; then - echo "$CMDNAME: Creation of user \"$NewUser\" failed." + echo "$CMDNAME: creation of user \"$NewUser\" failed" exit 1 fi diff --git a/src/bin/scripts/dropdb b/src/bin/scripts/dropdb index 58b4076ebb9..a8396103170 100644 --- a/src/bin/scripts/dropdb +++ b/src/bin/scripts/dropdb @@ -10,7 +10,7 @@ # # # IDENTIFICATION -# $Header: /cvsroot/pgsql/src/bin/scripts/Attic/dropdb,v 1.4 1999/12/16 20:10:02 momjian Exp $ +# $Header: /cvsroot/pgsql/src/bin/scripts/Attic/dropdb,v 1.5 2000/01/12 19:36:36 petere Exp $ # #------------------------------------------------------------------------- @@ -96,23 +96,21 @@ done if [ "$usage" ]; then - echo "" echo "Usage: $CMDNAME [options] dbname" echo "" - echo " -h HOSTNAME, --host=HOSTNAME " - echo " -p PORT, --port=PORT " - echo " -u USERNAME, --username=USERNAME " - echo " -W, --password " - echo " -e, --echo " - echo " -q, --quiet " - echo " -i, --interactive " - echo " -?, --help " - echo "" - exit 1 + echo " -h, --host=HOSTNAME Database server host" + echo " -p, --port=PORT Database server port" + echo " -U, --username=USERNAME Username to connect as" + echo " -W, --password Prompt for password" + echo " -i, --interactive Prompt before deleting anything" +#??? echo " -e, --echo " + echo " -q, --quiet Don't write any messages" + exit 0 fi if [ -z "$dbname" ]; then - echo "$CMDNAME: Missing required argument database name. Try -? for help." + echo "$CMDNAME: missing required argument database name" + echo "Try -? for help." exit 1 fi @@ -131,7 +129,7 @@ dbname=`echo $dbname | sed 's/\"/\\\"/g'` psql $PSQLOPT -d template1 -c "DROP DATABASE \"$dbname\"" if [ $? -ne 0 ]; then - echo "$CMDNAME: Database removal failed." + echo "$CMDNAME: database removal failed" exit 1 fi diff --git a/src/bin/scripts/droplang b/src/bin/scripts/droplang index 8fbfd3b9ec0..a6b6efd3631 100644 --- a/src/bin/scripts/droplang +++ b/src/bin/scripts/droplang @@ -8,7 +8,7 @@ # # # IDENTIFICATION -# $Header: /cvsroot/pgsql/src/bin/scripts/Attic/droplang,v 1.4 1999/12/16 20:10:02 momjian Exp $ +# $Header: /cvsroot/pgsql/src/bin/scripts/Attic/droplang,v 1.5 2000/01/12 19:36:36 petere Exp $ # #------------------------------------------------------------------------- @@ -40,6 +40,7 @@ do case "$1" in --help|-\?) usage=t + break ;; --list|-l) list=t @@ -94,6 +95,11 @@ do dbname=`echo $1 | sed 's/^--database=//'` ;; + -*) + echo "$CMDNAME: unrecognized option: $1" + echo "Try -? for help." + exit 1 + ;; *) langname="$1" if [ "$2" ]; then @@ -108,18 +114,16 @@ done if [ "$usage" ]; then echo "" - echo "Usage: $CMDNAME [options] [language [dbname]]" + echo "Usage: $CMDNAME [options] [langname [dbname]]" echo "" - echo " -h HOSTNAME, --host=HOSTNAME " - echo " -p PORT, --port=PORT " - echo " -u USERNAME, --username=USERNAME " - echo " -W, --password " - echo " -d DBNAME --database=DBNAME " - echo " -e, --echo " - echo " -q, --quiet " - echo " -?, --help " - echo "" - exit 1 + echo " -h, --host=HOSTNAME Database server host" + echo " -p, --port=PORT Database server port" + echo " -U, --username=USERNAME Username to connect as" + echo " -W, --password Prompt for password" + echo " -d, --dbname=DBNAME Database to remove language from" + echo " -e, --echo Create some output about what is happening" + echo " -l, --list Show a list of currently installed languages" + exit 0 fi @@ -133,7 +137,8 @@ fi # Check that we have a database # ---------- if [ -z "$dbname" ]; then - echo "$CMDNAME: Missing required argument database name. Try -? for help." + echo "$CMDNAME: missing required argument database name" + echo "Try -? for help." exit 1 fi @@ -159,8 +164,8 @@ case "$langname" in handler="pltcl_call_handler" ;; *) - echo "$CMDNAME: Unsupported language '$langname'." - echo " Supported languages are 'plpgsql' and 'pltcl'." + echo "$CMDNAME: unsupported language '$langname'" + echo "Supported languages are 'plpgsql' and 'pltcl'." exit 1 ;; esac @@ -180,11 +185,11 @@ PSQL="psql -A -t $PSQLOPT -d $dbname -c" # ---------- res=`$PSQL "SELECT oid FROM pg_language WHERE lanname = '$langname'"` if [ $? -ne 0 ]; then - echo "Language removal failed." + echo "$CMDNAME: external error" exit 1 fi if [ -z "$res" ]; then - echo "The language '$langname' isn't installed in database $dbname." + echo "$CMDNAME: '$langname' is not installed in database $dbname" exit 1 fi @@ -194,13 +199,12 @@ fi # ---------- res=`$PSQL "SELECT COUNT(proname) FROM pg_proc P, pg_language L WHERE P.prolang = L.oid AND L.lanname = '$langname'"` if [ $? -ne 0 ]; then - echo "Language removal failed." + echo "$CMDNAME: external error" exit 1 fi if [ $res -ne 0 ]; then - echo "There are $res functions/trigger procedures declared in language" - echo "$lancomp." - echo "Language not removed." + echo "$CMDNAME: There are $res functions/trigger procedures declared in language" + echo "$lancomp. Language not removed." exit 1 fi @@ -209,12 +213,12 @@ fi # ---------- $PSQL "DROP PROCEDURAL LANGUAGE '$langname'" if [ $? -ne 0 ]; then - echo "Language removal failed." + echo "$CMDNAME: language removal failed" exit 1 fi $PSQL "DROP FUNCTION $handler()" if [ $? -ne 0 ]; then - echo "Language removal failed." + echo "$CMDNAME: language removal failed" exit 1 fi diff --git a/src/bin/scripts/dropuser b/src/bin/scripts/dropuser index a5d743eadcd..add007290b0 100644 --- a/src/bin/scripts/dropuser +++ b/src/bin/scripts/dropuser @@ -8,7 +8,7 @@ # # # IDENTIFICATION -# $Header: /cvsroot/pgsql/src/bin/scripts/Attic/dropuser,v 1.4 1999/12/16 20:10:02 momjian Exp $ +# $Header: /cvsroot/pgsql/src/bin/scripts/Attic/dropuser,v 1.5 2000/01/12 19:36:36 petere Exp $ # # Note - this should NOT be setuid. # @@ -36,6 +36,7 @@ do case "$1" in --help|-\?) usage=t + break ;; # options passed on to psql --host|-h) @@ -99,16 +100,14 @@ if [ "$usage" ]; then echo "" echo "Usage: $CMDNAME [options] [username]" echo "" - echo " -h HOSTNAME, --host=HOSTNAME " - echo " -p PORT, --port=PORT " - echo " -u USERNAME, --username=USERNAME (for connect to db)" - echo " -W, --password " - echo " -e, --echo " - echo " -q, --quiet " - echo " -i, --interactive " - echo " -?, --help " - echo "" - exit 1 + echo " -h, --host=HOSTNAME Database server host" + echo " -p, --port=PORT Database server port" + echo " -U, --username=USERNAME Username to connect as (not the one to drop)" + echo " -W, --password Prompt for password to connect" + echo " -i, --interactive Prompt before deleting anything" +#??? echo " -e, --echo " + echo " -q, --quiet Don't write any messages" + exit 0 fi # Prompt for username if missing @@ -135,7 +134,7 @@ DelUser=`echo $DelUser | sed 's/\"/\\\"/g'` psql $PSQLOPT -d template1 -c "DROP USER \"$DelUser\"" if [ $? -ne 0 ]; then - echo "$CMDNAME: Deletion of user \"$DelUser\" failed." + echo "$CMDNAME: deletion of user \"$DelUser\" failed" exit 1 fi diff --git a/src/bin/scripts/vacuumdb b/src/bin/scripts/vacuumdb index 234a26b2caf..92c0ce9cc94 100644 --- a/src/bin/scripts/vacuumdb +++ b/src/bin/scripts/vacuumdb @@ -11,7 +11,7 @@ # # # IDENTIFICATION -# $Header: /cvsroot/pgsql/src/bin/scripts/Attic/vacuumdb,v 1.7 1999/12/18 08:46:44 momjian Exp $ +# $Header: /cvsroot/pgsql/src/bin/scripts/Attic/vacuumdb,v 1.8 2000/01/12 19:36:36 petere Exp $ # #------------------------------------------------------------------------- @@ -29,6 +29,7 @@ do case "$1" in --help|-\?) usage=t + break ;; # options passed on to psql --host|-h) @@ -86,7 +87,7 @@ do --analyze|-z) analyze="ANALYZE " ;; - --alldb|-a) + --all|-a) alldb=Y ;; --table|-t) @@ -103,7 +104,8 @@ do ;; -*) - echo "$CMDNAME: Unrecognized option: $1. Try -? for help." + echo "$CMDNAME: unrecognized option: $1" + echo "Try -? for help." exit 1 ;; *) @@ -114,42 +116,43 @@ do done if [ "$usage" ]; then - echo "" echo "Usage: $CMDNAME [options] [dbname]" echo "" - echo " -h HOSTNAME, --host=HOSTNAME " - echo " -p PORT, --port=PORT " - echo " -u USERNAME, --username=USERNAME " - echo " -W, --password " - echo " -d DBNAME, --database=DBNAME " - echo " -z, --analyze " - echo " -a, --alldb " - echo " -t TABLE[(columns)], --table=TABLE[(columns)]" - echo " -v, --verbose " - echo " -e, --echo " - echo " -q, --quiet " - echo " -?, --help " - echo "" - exit 1 + echo " -h, --host=HOSTNAME Database server host" + echo " -p, --port=PORT Database server port" + echo " -U, --username=USERNAME Username to connect as" + echo " -W, --password Prompt for password" + echo " -d, --dbname=DBNAME Database to vacuum" + echo " -a, --all Vacuum all databases" + echo " -z, --analyze Update optimizer hints" + echo " -t, --table='TABLE[(columns)]' Vacuum specific table only" + echo " -v, --verbose Write a lot of output" +#??? echo " -e, --echo " + echo " -q, --quiet Don't write any output" + exit 0 fi -if [ ! -z "$alldb" ]; then - dbname="`psql $PASSWDOPT $AUTHOPT $PGHOSTOPT $PGPORTOPT -q -t -A -d template1 -c 'SELECT datname FROM pg_database'`" +if [ "$alldb" ]; then + if [ "$dbname" -o "$table" ]; then + echo "$CMDNAME: cannot vacuum all databases and a specific one at the same time" + exit 1 + fi + dbname="`psql $PSQLOPT -q -t -A -d template1 -c 'SELECT datname FROM pg_database'`" fi if [ -z "$dbname" ]; then - echo "$CMDNAME: Missing required argument database name. Try -? for help." + echo "$CMDNAME: missing required argument database name" + echo "Try -? for help." exit 1 fi for db in $dbname do - psql $PASSWDOPT -tq $AUTHOPT $PGHOSTOPT $PGPORTOPT -c "vacuum $verbose $analyze $table" $db + psql $PSQLOPT -c "vacuum $verbose $analyze $table" -d $dbname done -if [ $? -ne 0 ] -then - echo "$CMDNAME: Vacuum failed." +if [ $? -ne 0 ]; then + echo "$CMDNAME: vacuum failed" exit 1 fi -- GitLab