diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml index 88a15fe631..4e3d555480 100644 --- a/doc/src/sgml/ref/psql-ref.sgml +++ b/doc/src/sgml/ref/psql-ref.sgml @@ -1,5 +1,5 @@ @@ -851,6 +851,16 @@ lo_import 152801 + + recordsep + + + Specifies the record (line) separator to use in unaligned output mode. The default + is a newline character. + + + + tuples_only (or t) @@ -1900,12 +1910,14 @@ testdb=> \set content `sed -e "s/'/\\\\\\'/g" < my_file.txt` %M - The hostname of the database server (or . if Unix domain socket). + The hostname of the database server (or . + if Unix domain socket). %m - The hostname of the database server truncated after the first dot. + The hostname of the database server truncated after the + first dot. @@ -1915,7 +1927,8 @@ testdb=> \set content `sed -e "s/'/\\\\\\'/g" < my_file.txt` %n - The username you are connected as (not your local system user name). + The username you are connected as (not your local system + user name). @@ -1925,37 +1938,39 @@ testdb=> \set content `sed -e "s/'/\\\\\\'/g" < my_file.txt` %~ - Like %/, but the output is ~ (tilde) if the database - is your default database. + Like %/, but the output is ~ + (tilde) if the database is your default database. %# - If the username is postgres, a #, otherwise a >. + If the username is postgres, a + #, otherwise a >. %R - In prompt 1 normally =, but ^ if in single-line mode, and - ! if the session is disconnected from the database (which can only - happen if \connect fails). - In prompt 2 the sequence is replaced by -, *, a single quote, - or a double quote, depending on whether psql expects more input - because the query wasn't terminated yet, because you are inside a /* ... */ - comment, or because you are inside a quote. - In prompt 3 the sequence doesn't resolve to anything. + In prompt 1 normally =, but ^ if in single-line + mode, and ! if the session is disconnected from the database + (which can happen if \connect fails). In prompt 2 the + sequence is replaced by -, *, a single quote, + or a double quote, depending on whether psql + expects more input because the query wasn't terminated yet, because you are + inside a /* ... */ comment, or because you are inside + a quote. In prompt 3 the sequence doesn't resolve to anything. %digits - If digits starts with 0x - the rest of the characters are interpreted at a hexadecimal digit and the - character with the corresponding code is subsituted. If the first digit is 0 - the characters are interpreted as on octal number and the corresponding character - is substituted. Otherwise a decimal number is assumed. + If digits starts with + 0x the rest of the characters are interpreted at a + hexadecimal digit and the character with the corresponding code is + subsituted. If the first digit is 0 the characters are + interpreted as on octal number and the corresponding character is + substituted. Otherwise a decimal number is assumed. diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index a17fadc566..d62f3ef61c 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.130 2000/01/18 19:08:13 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.131 2000/01/18 23:30:20 petere Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -854,6 +854,7 @@ AlterTableStmt: | ALTER TABLE relation_name opt_inh_star DROP CONSTRAINT name drop_behavior { AlterTableStmt *n = makeNode(AlterTableStmt); + n->subtype = 'X'; n->relname = $3; n->inh = $4; n->name = $7; diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c index 4ed0280c89..93be3d946c 100644 --- a/src/bin/psql/command.c +++ b/src/bin/psql/command.c @@ -1,6 +1,14 @@ +/* + * psql - the PostgreSQL interactive terminal + * + * Copyright 2000 by PostgreSQL Global Development Team + * + * $Header: /cvsroot/pgsql/src/bin/psql/command.c,v 1.13 2000/01/18 23:30:22 petere Exp $ + */ #include #include "command.h" +#include #include #include #include @@ -39,12 +47,11 @@ static backslashResult exec_command(const char *cmd, char *const * options, const char *options_string, - PQExpBuffer query_buf, - int encoding); + PQExpBuffer query_buf); static bool do_edit(const char *filename_arg, PQExpBuffer query_buf); -static char * unescape(const char *source, int encoding); +static char * unescape(const char *source); static bool do_connect(const char *new_dbname, const char *new_user); @@ -81,8 +88,7 @@ static bool do_shell(const char *command); backslashResult HandleSlashCmds(const char *line, PQExpBuffer query_buf, - const char **end_of_cmd, - int encoding) + const char **end_of_cmd) { backslashResult status = CMD_SKIP_LINE; char *my_line; @@ -134,14 +140,14 @@ HandleSlashCmds(const char *line, * whitespace */ i = 0; - token = strtokx(options_string, " \t", "\"'`", '\\', "e, &pos, encoding); + token = strtokx(options_string, " \t", "\"'`", '\\', "e, &pos, pset.encoding); for (i = 0; token && i < NR_OPTIONS; i++) { switch (quote) { case '"': - options[i] = unescape(token, encoding); + options[i] = unescape(token); break; case '\'': options[i] = xstrdup(token); @@ -150,7 +156,7 @@ HandleSlashCmds(const char *line, { bool error = false; FILE *fd = NULL; - char *file = unescape(token, encoding); + char *file = unescape(token); PQExpBufferData output; char buf[512]; size_t result; @@ -158,7 +164,7 @@ HandleSlashCmds(const char *line, fd = popen(file, "r"); if (!fd) { - perror(file); + psql_error("%s: %s\n", file, strerror(errno)); error = true; } @@ -171,7 +177,7 @@ HandleSlashCmds(const char *line, result = fread(buf, 1, 512, fd); if (ferror(fd)) { - perror(file); + psql_error("%s: %s\n", file, strerror(errno)); error = true; break; } @@ -181,7 +187,7 @@ HandleSlashCmds(const char *line, if (pclose(fd) == -1) { - perror(file); + psql_error("%s: %s\n", file, strerror(errno)); error = true; } } @@ -220,14 +226,14 @@ HandleSlashCmds(const char *line, if (continue_parse) break; - token = strtokx(NULL, " \t", "\"'`", '\\', "e, &pos, encoding); + token = strtokx(NULL, " \t", "\"'`", '\\', "e, &pos, pset.encoding); } /* for */ options[i] = NULL; } cmd = my_line; - status = exec_command(cmd, options, options_string, query_buf, encoding); + status = exec_command(cmd, options, options_string, query_buf); if (status == CMD_UNKNOWN) { @@ -249,7 +255,7 @@ HandleSlashCmds(const char *line, new_cmd[0] = cmd[0]; new_cmd[1] = '\0'; - status = exec_command(new_cmd, (char *const *) new_options, my_line + 2, query_buf, encoding); + status = exec_command(new_cmd, (char *const *) new_options, my_line + 2, query_buf); } if (status == CMD_UNKNOWN) @@ -257,7 +263,7 @@ HandleSlashCmds(const char *line, 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); + psql_error("invalid command \\%s\n", cmd); status = CMD_ERROR; } @@ -286,8 +292,7 @@ static backslashResult exec_command(const char *cmd, char *const * options, const char *options_string, - PQExpBuffer query_buf, - int encoding) + PQExpBuffer query_buf) { bool success = true; /* indicate here if the command ran ok or * failed */ @@ -342,7 +347,7 @@ exec_command(const char *cmd, /* \copy */ else if (strcasecmp(cmd, "copy") == 0) - success = do_copy(options_string, encoding); + success = do_copy(options_string); /* \copyright */ else if (strcmp(cmd, "copyright") == 0) @@ -461,15 +466,12 @@ exec_command(const char *cmd, else if (strcmp(cmd, "i") == 0 || strcmp(cmd, "include") == 0) { if (!options[0]) - { - if (pset.cur_cmd_interactive) - fprintf(stderr, "\\%s: missing required argument\n", cmd); - else - fprintf(stderr, "%s: \\%s: missing required argument", pset.progname, cmd); + { + psql_error("\\%s: missing required argument\n", cmd); success = false; } else - success = process_file(options[0], encoding); + success = process_file(options[0]); } @@ -487,10 +489,7 @@ exec_command(const char *cmd, { if (!options[1]) { - if (pset.cur_cmd_interactive) - fprintf(stderr, "\\%s: missing required argument", cmd); - else - fprintf(stderr, "%s: \\%s: missing required argument", pset.progname, cmd); + psql_error("\\%s: missing required argument\n", cmd); success = false; } else @@ -501,10 +500,7 @@ exec_command(const char *cmd, { if (!options[0]) { - if (pset.cur_cmd_interactive) - fprintf(stderr, "\\%s: missing required argument", cmd); - else - fprintf(stderr, "%s: \\%s: missing required argument", pset.progname, cmd); + psql_error("\\%s: missing required argument\n", cmd); success = false; } else @@ -518,10 +514,7 @@ exec_command(const char *cmd, { if (!options[0]) { - if (pset.cur_cmd_interactive) - fprintf(stderr, "\\%s: missing required argument", cmd); - else - fprintf(stderr, "%s: \\%s: missing required argument", pset.progname, cmd); + psql_error("\\%s: missing required argument\n", cmd); success = false; } else @@ -552,10 +545,7 @@ exec_command(const char *cmd, { if (!options[0]) { - if (pset.cur_cmd_interactive) - fprintf(stderr, "\\%s: missing required argument", cmd); - else - fprintf(stderr, "%s: \\%s: missing required argument", pset.progname, cmd); + psql_error("\\%s: missing required argument\n", cmd); success = false; } else @@ -626,11 +616,7 @@ exec_command(const char *cmd, val = ""; if (!SetVariable(pset.vars, options[0], val)) { - if (pset.cur_cmd_interactive) - fprintf(stderr, "\\%s: error\n", cmd); - else - fprintf(stderr, "%s: \\%s: error\n", pset.progname, cmd); - + psql_error("\\%s: error\n", cmd); success = false; } } @@ -650,10 +636,7 @@ exec_command(const char *cmd, { if (!SetVariable(pset.vars, options[0], NULL)) { - if (pset.cur_cmd_interactive) - fprintf(stderr, "\\%s: error\n", cmd); - else - fprintf(stderr, "%s: \\%s: error\n", pset.progname, cmd); + psql_error("\\%s: error\n", cmd); success = false; } @@ -667,10 +650,7 @@ exec_command(const char *cmd, if (!options[0]) { - if (pset.cur_cmd_interactive) - fprintf(stderr, "\\%s: missing required argument", cmd); - else - fprintf(stderr, "%s: \\%s: missing required argument", pset.progname, cmd); + psql_error("\\%s: missing required argument\n", cmd); success = false; } else @@ -678,24 +658,16 @@ exec_command(const char *cmd, if (options[0][0] == '|') { pipe = true; -#ifndef __CYGWIN32__ fd = popen(&options[0][1], "w"); -#else - fd = popen(&options[0][1], "wb"); -#endif } else { -#ifndef __CYGWIN32__ fd = fopen(options[0], "w"); -#else - fd = fopen(options[0], "wb"); -#endif } if (!fd) { - perror(options[0]); + psql_error("%s: %s\n", options[0], strerror(errno)); success = false; } } @@ -714,7 +686,7 @@ exec_command(const char *cmd, if (result == EOF) { - perror("close"); + psql_error("%s: %s\n", options[0], strerror(errno)); success = false; } } @@ -737,9 +709,8 @@ exec_command(const char *cmd, slashUsage(); -#ifdef NOT_USED - - /* +#if 0 + /* * These commands don't do anything. I just use them to test the * parser. */ @@ -772,7 +743,7 @@ exec_command(const char *cmd, * The return value is malloc()'ed. */ static char * -unescape(const char *source, int encoding) +unescape(const char *source) { unsigned char *p; bool esc = false; /* Last character we saw was the escape @@ -790,11 +761,11 @@ unescape(const char *source, int encoding) tmp = destination = (char *) malloc(length); if (!tmp) { - perror("malloc"); + psql_error("out of memory\n"); exit(EXIT_FAILURE); } - for (p = (char *) source; *p; p += PQmblen(p, encoding)) + for (p = (char *) source; *p; p += PQmblen(p, pset.encoding)) { if (esc) { @@ -866,7 +837,7 @@ unescape(const char *source, int encoding) new = realloc(destination, length); if (!new) { - perror("realloc"); + psql_error("out of memory\n"); exit(EXIT_FAILURE); } tmp = new + (tmp - destination); @@ -946,20 +917,6 @@ do_connect(const char *new_dbname, const char *new_user) if (!pwparam && oldconn) pwparam = PQpass(oldconn); - -#ifdef MULTIBYTE - - /* - * PGCLIENTENCODING may be set by the previous connection. if a user - * does not explicitly set PGCLIENTENCODING, we should discard - * PGCLIENTENCODING so that libpq could get the backend encoding as - * the default PGCLIENTENCODING value. -- 1998/12/12 Tatsuo Ishii - */ - - if (!pset.has_client_encoding) - putenv("PGCLIENTENCODING="); -#endif - do { need_pass = false; @@ -986,7 +943,7 @@ do_connect(const char *new_dbname, const char *new_user) { if (pset.cur_cmd_interactive) { - fprintf(stderr, "%s", PQerrorMessage(pset.db)); + psql_error("%s", PQerrorMessage(pset.db)); PQfinish(pset.db); if (oldconn) { @@ -1000,7 +957,7 @@ do_connect(const char *new_dbname, const char *new_user) { /* we don't want unpredictable things to * happen in scripting mode */ - fprintf(stderr, "%s: \\connect: %s", pset.progname, PQerrorMessage(pset.db)); + psql_error("\\connect: %s", PQerrorMessage(pset.db)); PQfinish(pset.db); if (oldconn) PQfinish(oldconn); @@ -1026,6 +983,9 @@ do_connect(const char *new_dbname, const char *new_user) success = true; } + PQsetNoticeProcessor(pset.db, NoticeProcessor, NULL); + pset.encoding = PQclientencoding(pset.db); + /* Update variables */ SetVariable(pset.vars, "DBNAME", PQdb(pset.db)); SetVariable(pset.vars, "USER", PQuser(pset.db)); @@ -1072,8 +1032,10 @@ editFile(const char *fname) return false; sprintf(sys, "exec %s %s", editorName, fname); result = system(sys); - if (result == -1 || result == 127) - perror(sys); + if (result == -1) + psql_error("could not start editor\n"); + else if (result == 127) + psql_error("could not start /bin/sh\n"); free(sys); return result == 0; @@ -1131,7 +1093,7 @@ do_edit(const char *filename_arg, PQExpBuffer query_buf) if (!stream) { - perror(fname); + psql_error("couldn't open temp file %s: %s\n", fname, strerror(errno)); error = true; } else @@ -1146,7 +1108,7 @@ do_edit(const char *filename_arg, PQExpBuffer query_buf) if (fwrite(query_buf->data, 1, ql, stream) != ql) { - perror(fname); + psql_error("%s: %s\n", fname, strerror(errno)); fclose(stream); remove(fname); error = true; @@ -1159,7 +1121,7 @@ do_edit(const char *filename_arg, PQExpBuffer query_buf) #ifndef WIN32 if (!error && stat(fname, &before) != 0) { - perror(fname); + psql_error("%s: %s\n", fname, strerror(errno)); error = true; } #endif @@ -1171,7 +1133,7 @@ do_edit(const char *filename_arg, PQExpBuffer query_buf) #ifndef WIN32 if (!error && stat(fname, &after) != 0) { - perror(fname); + psql_error("%s: %s\n", fname, strerror(errno)); error = true; } @@ -1184,7 +1146,7 @@ do_edit(const char *filename_arg, PQExpBuffer query_buf) stream = fopen(fname, "r"); if (!stream) { - perror(fname); + psql_error("%s: %s\n", fname, strerror(errno)); error = true; } else @@ -1199,7 +1161,7 @@ do_edit(const char *filename_arg, PQExpBuffer query_buf) result = fread(line, 1, 1024, stream); if (ferror(stream)) { - perror(fname); + psql_error("%s: %s\n", fname, strerror(errno)); error = true; break; } @@ -1212,9 +1174,14 @@ do_edit(const char *filename_arg, PQExpBuffer query_buf) /* remove temp file */ if (!filename_arg) - remove(fname); - } - + { + if (remove(fname)==-1) + { + psql_error("%s: %s\n", fname, strerror(errno)); + error=true; + } + } + } return !error; } @@ -1227,7 +1194,7 @@ do_edit(const char *filename_arg, PQExpBuffer query_buf) * Handler for \i, but can be used for other things as well. */ bool -process_file(const char *filename, int encoding) +process_file(char *filename) { FILE *fd; int result; @@ -1243,13 +1210,12 @@ process_file(const char *filename, int encoding) if (!fd) { - if (!pset.cur_cmd_interactive) - fprintf(stderr, "%s: ", pset.progname); - perror(filename); + psql_error("%s: %s\n", filename, strerror(errno)); return false; } - result = MainLoop(fd, encoding); + pset.inputfile = filename; + result = MainLoop(fd); fclose(fd); return (result == EXIT_SUCCESS); } @@ -1315,7 +1281,7 @@ do_pset(const char *param, const char *value, printQueryOpt * popt, bool quiet) popt->topt.format = PRINT_LATEX; else { - fprintf(stderr, "Allowed formats are unaligned, aligned, html, latex.\n"); + psql_error("\\pset: allowed formats are unaligned, aligned, html, latex\n"); return false; } @@ -1362,7 +1328,23 @@ do_pset(const char *param, const char *value, printQueryOpt * popt, bool quiet) popt->topt.fieldSep = xstrdup(value); } if (!quiet) - printf("Field separator is \"%s\".\n", popt->topt.fieldSep); + printf("Field separator is '%s'.\n", popt->topt.fieldSep); + } + + /* record separator for unaligned text */ + else if (strcmp(param, "recordsep") == 0) + { + if (value) + { + free(popt->topt.recordSep); + popt->topt.recordSep = xstrdup(value); + } + if (!quiet) { + if (strcmp(popt->topt.recordSep, "\n")==0) + printf("Record separator is ."); + else + printf("Record separator is '%s'.\n", popt->topt.recordSep); + } } /* toggle between full and barebones format */ @@ -1430,7 +1412,7 @@ do_pset(const char *param, const char *value, printQueryOpt * popt, bool quiet) else { - fprintf(stderr, "Unknown option: %s\n", param); + psql_error("\\pset: unknown option: %s\n", param); return false; } @@ -1456,8 +1438,13 @@ do_shell(const char *command) shellName = DEFAULT_SHELL; sys = malloc(strlen(shellName) + 16); - if (!sys) - return false; + if (!sys) { + psql_error("out of memory\n"); + if (pset.cur_cmd_interactive) + return false; + else + exit(EXIT_FAILURE); + } sprintf(sys, "exec %s", shellName); result = system(sys); free(sys); @@ -1467,7 +1454,7 @@ do_shell(const char *command) if (result == 127 || result == -1) { - perror("system"); + psql_error("\\!: failed\n"); return false; } return true; diff --git a/src/bin/psql/command.h b/src/bin/psql/command.h index 5543cbe9c2..f3a7b4d36a 100644 --- a/src/bin/psql/command.h +++ b/src/bin/psql/command.h @@ -1,7 +1,13 @@ +/* + * psql - the PostgreSQL interactive terminal + * + * Copyright 2000 by PostgreSQL Global Development Team + * + * $Header: /cvsroot/pgsql/src/bin/psql/command.h,v 1.6 2000/01/18 23:30:23 petere Exp $ + */ #ifndef COMMAND_H #define COMMAND_H -#include #include #include @@ -10,7 +16,6 @@ #include "print.h" - typedef enum _backslashResult { CMD_UNKNOWN = 0, /* not done parsing yet (internal only) */ @@ -23,14 +28,13 @@ typedef enum _backslashResult } backslashResult; - backslashResult HandleSlashCmds(const char *line, PQExpBuffer query_buf, - const char **end_of_cmd, int encoding); + const char **end_of_cmd); bool -process_file(const char *filename, int encoding); +process_file(char *filename); bool do_pset(const char *param, @@ -38,4 +42,4 @@ do_pset(const char *param, printQueryOpt * popt, bool quiet); -#endif +#endif /* COMMAND_H */ diff --git a/src/bin/psql/common.c b/src/bin/psql/common.c index b1241bd53d..0565d0cac2 100644 --- a/src/bin/psql/common.c +++ b/src/bin/psql/common.c @@ -1,3 +1,10 @@ +/* + * psql - the PostgreSQL interactive terminal + * + * Copyright 2000 by PostgreSQL Global Development Team + * + * $Header: /cvsroot/pgsql/src/bin/psql/common.c,v 1.9 2000/01/18 23:30:23 petere Exp $ + */ #include #include "common.h" @@ -5,6 +12,7 @@ #include #include #include +#include #ifdef HAVE_TERMIOS_H #include #endif @@ -49,13 +57,13 @@ xstrdup(const char *string) if (!string) { - fprintf(stderr, "xstrdup: Cannot duplicate null pointer.\n"); + fprintf(stderr, "%s: xstrdup: cannot duplicate null pointer\n", pset.progname); exit(EXIT_FAILURE); } tmp = strdup(string); if (!tmp) { - perror("strdup"); + psql_error("out of memory\n"); exit(EXIT_FAILURE); } return tmp; @@ -104,7 +112,7 @@ setQFout(const char *fname) if (!(pset.queryFout)) { - fprintf(stderr, "%s: %s: %s\n", pset.progname, fname, strerror(errno)); + psql_error("%s: %s\n", fname, strerror(errno)); pset.queryFout = stdout; pset.queryFoutPipe = false; status = false; @@ -123,6 +131,38 @@ setQFout(const char *fname) +/* + * Error reporting for scripts. Errors should look like + * filename:lineno: message + * + */ +void +psql_error(const char *fmt, ...) +{ + va_list ap; + + fflush(stdout); + if (pset.queryFout!=stdout) + fflush(pset.queryFout); + + if (pset.inputfile) + fprintf(stderr, "%s:%u: ", pset.inputfile ? pset.inputfile : pset.progname, pset.lineno); + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); +} + +/* for backend NOTICES */ + +void +NoticeProcessor(void * arg, const char * message) +{ + (void)arg; /* not used */ + psql_error("%s", message); +} + + + /* * simple_prompt * @@ -239,7 +279,7 @@ PSQLexec(const char *query) if (!pset.db) { - fputs("You are currently not connected to a database.\n", stderr); + psql_error("You are currently not connected to a database.\n"); return NULL; } @@ -268,7 +308,7 @@ PSQLexec(const char *query) { if (!pset.cur_cmd_interactive) { - fprintf(stderr, "%s: connection to server was lost", pset.progname); + psql_error("connection to server was lost"); exit(EXIT_BADCONN); } fputs("The connection to the server was lost. Attempting reset: ", stderr); @@ -297,7 +337,7 @@ PSQLexec(const char *query) return res; else { - fputs(PQerrorMessage(pset.db), stderr); + psql_error("%s", PQerrorMessage(pset.db)); PQclear(res); return NULL; } @@ -326,7 +366,7 @@ SendQuery(const char *query) if (!pset.db) { - fputs("You are currently not connected to a database.\n", stderr); + psql_error("you are currently not connected to a database.\n"); return false; } @@ -436,7 +476,7 @@ SendQuery(const char *query) case PGRES_FATAL_ERROR: case PGRES_BAD_RESPONSE: success = false; - fputs(PQerrorMessage(pset.db), stderr); + psql_error("%s", PQerrorMessage(pset.db)); break; } @@ -446,7 +486,7 @@ SendQuery(const char *query) { if (!pset.cur_cmd_interactive) { - fprintf(stderr, "%s: connection to server was lost", pset.progname); + psql_error("connection to server was lost"); exit(EXIT_BADCONN); } fputs("The connection to the server was lost. Attempting reset: ", stderr); diff --git a/src/bin/psql/common.h b/src/bin/psql/common.h index 7d285d01cc..08519f5a40 100644 --- a/src/bin/psql/common.h +++ b/src/bin/psql/common.h @@ -1,22 +1,33 @@ +/* + * psql - the PostgreSQL interactive terminal + * + * Copyright 2000 by PostgreSQL Global Development Team + * + * $Header: /cvsroot/pgsql/src/bin/psql/common.h,v 1.4 2000/01/18 23:30:23 petere Exp $ + */ #ifndef COMMON_H #define COMMON_H #include -#include "settings.h" +#include -char * - xstrdup(const char *string); +char * xstrdup(const char *string); -bool - setQFout(const char *fname); +bool setQFout(const char *fname); -char * - simple_prompt(const char *prompt, int maxlen, bool echo); +#ifndef __GNUC__ +void psql_error(const char *fmt, ...); +#else +/* This checks the format string for consistency. */ +void psql_error(const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); +#endif -PGresult * - PSQLexec(const char *query); +void NoticeProcessor(void * arg, const char * message); -bool - SendQuery(const char *query); +char * simple_prompt(const char *prompt, int maxlen, bool echo); + +PGresult * PSQLexec(const char *query); + +bool SendQuery(const char *query); #endif /* COMMON_H */ diff --git a/src/bin/psql/copy.c b/src/bin/psql/copy.c index 8e64c80b98..8f46e65b4c 100644 --- a/src/bin/psql/copy.c +++ b/src/bin/psql/copy.c @@ -1,3 +1,10 @@ +/* + * psql - the PostgreSQL interactive terminal + * + * Copyright 2000 by PostgreSQL Global Development Team + * + * $Header: /cvsroot/pgsql/src/bin/psql/copy.c,v 1.6 2000/01/18 23:30:23 petere Exp $ + */ #include #include "copy.h" @@ -58,7 +65,7 @@ free_copy_options(struct copy_options * ptr) static struct copy_options * -parse_slash_copy(const char *args, int encoding) +parse_slash_copy(const char *args) { struct copy_options *result; char *line; @@ -70,11 +77,11 @@ parse_slash_copy(const char *args, int encoding) if (!(result = calloc(1, sizeof(struct copy_options)))) { - perror("calloc"); + psql_error("out of memory\n"); exit(EXIT_FAILURE); } - token = strtokx(line, " \t", "\"", '\\', "e, NULL, encoding); + token = strtokx(line, " \t", "\"", '\\', "e, NULL, pset.encoding); if (!token) error = true; else @@ -84,7 +91,7 @@ parse_slash_copy(const char *args, int encoding) if (!quote && strcasecmp(token, "binary") == 0) { result->binary = true; - token = strtokx(NULL, " \t", "\"", '\\', "e, NULL, encoding); + token = strtokx(NULL, " \t", "\"", '\\', "e, NULL, pset.encoding); if (!token) error = true; } @@ -99,14 +106,14 @@ parse_slash_copy(const char *args, int encoding) if (!error) { - token = strtokx(NULL, " \t", NULL, '\\', NULL, NULL, encoding); + token = strtokx(NULL, " \t", NULL, '\\', NULL, NULL, pset.encoding); if (!token) error = true; else { if (strcasecmp(token, "with") == 0) { - token = strtokx(NULL, " \t", NULL, '\\', NULL, NULL, encoding); + token = strtokx(NULL, " \t", NULL, '\\', NULL, NULL, pset.encoding); if (!token || strcasecmp(token, "oids") != 0) error = true; else @@ -114,7 +121,7 @@ parse_slash_copy(const char *args, int encoding) if (!error) { - token = strtokx(NULL, " \t", NULL, '\\', NULL, NULL, encoding); + token = strtokx(NULL, " \t", NULL, '\\', NULL, NULL, pset.encoding); if (!token) error = true; } @@ -131,7 +138,7 @@ parse_slash_copy(const char *args, int encoding) if (!error) { - token = strtokx(NULL, " \t", "'", '\\', "e, NULL, encoding); + token = strtokx(NULL, " \t", "'", '\\', "e, NULL, pset.encoding); if (!token) error = true; else if (!quote && (strcasecmp(token, "stdin")==0 || strcasecmp(token, "stdout")==0)) @@ -142,21 +149,21 @@ parse_slash_copy(const char *args, int encoding) if (!error) { - token = strtokx(NULL, " \t", NULL, '\\', NULL, NULL, encoding); + token = strtokx(NULL, " \t", NULL, '\\', NULL, NULL, pset.encoding); if (token) { if (strcasecmp(token, "using") == 0) { - token = strtokx(NULL, " \t", NULL, '\\', NULL, NULL, encoding); + token = strtokx(NULL, " \t", NULL, '\\', NULL, NULL, pset.encoding); if (!token || strcasecmp(token, "delimiters") != 0) error = true; else { - token = strtokx(NULL, " \t", "'", '\\', NULL, NULL, encoding); + token = strtokx(NULL, " \t", "'", '\\', NULL, NULL, pset.encoding); if (token) { result->delim = xstrdup(token); - token = strtokx(NULL, " \t", NULL, '\\', NULL, NULL, encoding); + token = strtokx(NULL, " \t", NULL, '\\', NULL, NULL, pset.encoding); } else error = true; @@ -167,17 +174,17 @@ parse_slash_copy(const char *args, int encoding) { if (strcasecmp(token, "with") == 0) { - token = strtokx(NULL, " \t", NULL, '\\', NULL, NULL, encoding); + token = strtokx(NULL, " \t", NULL, '\\', NULL, NULL, pset.encoding); if (!token || strcasecmp(token, "null") != 0) error = true; else { - token = strtokx(NULL, " \t", NULL, '\\', NULL, NULL, encoding); + token = strtokx(NULL, " \t", NULL, '\\', NULL, NULL, pset.encoding); if (!token || strcasecmp(token, "as") != 0) error = true; else { - token = strtokx(NULL, " \t", "'", '\\', NULL, NULL, encoding); + token = strtokx(NULL, " \t", "'", '\\', NULL, NULL, pset.encoding); if (token) result->null = xstrdup(token); } @@ -191,15 +198,11 @@ parse_slash_copy(const char *args, int encoding) if (error) { - if (!pset.cur_cmd_interactive) - fprintf(stderr, "%s: ", pset.progname); - fputs("\\copy: parse error at ", stderr); - if (!token) - fputs("end of line", stderr); - else - fprintf(stderr, "'%s'", token); - fputs("\n", stderr); - free(result); + psql_error("\\copy: parse error at %s%s%s\n", + token ? "'" : "", + token ? token : "end of line", + token ? "'" : ""); + free_copy_options(result); return NULL; } else @@ -214,7 +217,7 @@ parse_slash_copy(const char *args, int encoding) * file or route its response into the file. */ bool -do_copy(const char *args, int encoding) +do_copy(const char *args) { char query[128 + NAMEDATALEN]; FILE *copystream; @@ -223,7 +226,7 @@ do_copy(const char *args, int encoding) bool success; /* parse options */ - options = parse_slash_copy(args, encoding); + options = parse_slash_copy(args); if (!options) return false; @@ -275,11 +278,8 @@ do_copy(const char *args, int encoding) if (!copystream) { - if (!pset.cur_cmd_interactive) - fprintf(stderr, "%s: ", pset.progname); - fprintf(stderr, - "unable to open file %s: %s\n", - options->file, strerror(errno)); + psql_error("%s: %s\n", + options->file, strerror(errno)); free_copy_options(options); return false; } @@ -298,24 +298,15 @@ do_copy(const char *args, int encoding) case PGRES_FATAL_ERROR: case PGRES_BAD_RESPONSE: success = false; - fputs(PQerrorMessage(pset.db), stderr); + psql_error("\\copy: %s", PQerrorMessage(pset.db)); break; default: success = false; - if (!pset.cur_cmd_interactive) - fprintf(stderr, "%s: ", pset.progname); - fprintf(stderr, "\\copy: unexpected response (%d)\n", PQresultStatus(result)); + psql_error("\\copy: unexpected response (%d)\n", PQresultStatus(result)); } PQclear(result); - if (!success) - { - if (!pset.cur_cmd_interactive) - fprintf(stderr, "%s: ", pset.progname); - fprintf(stderr, "\\copy failed\n"); - } - if (copystream != stdout && copystream != stdin) fclose(copystream); free_copy_options(options); diff --git a/src/bin/psql/copy.h b/src/bin/psql/copy.h index 6258fcb280..4710a623eb 100644 --- a/src/bin/psql/copy.h +++ b/src/bin/psql/copy.h @@ -1,22 +1,23 @@ +/* + * psql - the PostgreSQL interactive terminal + * + * Copyright 2000 by PostgreSQL Global Development Team + * + * $Header: /cvsroot/pgsql/src/bin/psql/copy.h,v 1.5 2000/01/18 23:30:23 petere Exp $ + */ #ifndef COPY_H #define COPY_H #include #include #include -#include "settings.h" /* handler for \copy */ -bool - do_copy(const char *args, int encoding); - +bool do_copy(const char *args); /* lower level processors for copy in/out streams */ -bool - handleCopyOut(PGconn *conn, FILE *copystream); - -bool - handleCopyIn(PGconn *conn, FILE *copystream, const char *prompt); +bool handleCopyOut(PGconn *conn, FILE *copystream); +bool handleCopyIn(PGconn *conn, FILE *copystream, const char *prompt); #endif diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c index 1ddc9b2ffc..9fad95f1cd 100644 --- a/src/bin/psql/describe.c +++ b/src/bin/psql/describe.c @@ -1,4 +1,10 @@ -#include +/* + * psql - the PostgreSQL interactive terminal + * + * Copyright 2000 by PostgreSQL Global Development Team + * + * $Header: /cvsroot/pgsql/src/bin/psql/describe.c,v 1.13 2000/01/18 23:30:23 petere Exp $ + */ #include #include "describe.h" @@ -470,7 +476,6 @@ objectDescription(const char *object) if (!res) return false; - myopt.topt.tuples_only = false; myopt.nullPrint = NULL; myopt.title = "Object descriptions"; @@ -861,10 +866,8 @@ describeTableDetails(const char *name, bool desc) PQclear(result4); } - if (!error) { - myopt.tuples_only = false; - printTable(title, headers, (const char**)cells, (const char**)footers, "llll", &myopt, pset.queryFout); - } + if (!error) + printTable(title, headers, (const char**)cells, (const char**)footers, "llll", &myopt, pset.queryFout); /* clean up */ free(title); @@ -1106,7 +1109,6 @@ listTables(const char *infotype, const char *name, bool desc) } else { - myopt.topt.tuples_only = false; myopt.nullPrint = NULL; myopt.title = "List of relations"; diff --git a/src/bin/psql/describe.h b/src/bin/psql/describe.h index 834375b252..7c87baa06d 100644 --- a/src/bin/psql/describe.h +++ b/src/bin/psql/describe.h @@ -1,3 +1,10 @@ +/* + * psql - the PostgreSQL interactive terminal + * + * Copyright 2000 by PostgreSQL Global Development Team + * + * $Header: /cvsroot/pgsql/src/bin/psql/describe.h,v 1.6 2000/01/18 23:30:23 petere Exp $ + */ #ifndef DESCRIBE_H #define DESCRIBE_H diff --git a/src/bin/psql/help.c b/src/bin/psql/help.c index 18f41e84fc..04690a1303 100644 --- a/src/bin/psql/help.c +++ b/src/bin/psql/help.c @@ -1,4 +1,10 @@ -#include +/* + * psql - the PostgreSQL interactive terminal + * + * Copyright 2000 by PostgreSQL Global Development Team + * + * $Header: /cvsroot/pgsql/src/bin/psql/help.c,v 1.11 2000/01/18 23:30:23 petere Exp $ + */ #include #include "help.h" @@ -68,23 +74,23 @@ usage(void) 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"); + puts( " -A Unaligned table output mode (-P format=unaligned)"); + puts( " -c Run only single query (or slash command) and exit"); /* Display default database */ env = getenv("PGDATABASE"); if (!env) env = user; - printf(" -d dbname Specify database name to connect to (default: %s)\n", env); + printf(" -d Specify database name to connect to (default: %s)\n", env); 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=)"); + puts( " -f Execute queries from file, then exit"); + puts( " -F Set field separator (default: \"" DEFAULT_FIELD_SEP "\") (-P fieldsep=)"); /* Display default host */ env = getenv("PGHOST"); - printf(" -h host Specify database server host (default: "); + printf(" -h Specify database server host (default: "); if (env) fputs(env, stdout); else @@ -94,11 +100,11 @@ usage(void) 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)"); + puts( " -o Send query output to filename (or |pipe)"); /* Display default port */ env = getenv("PGPORT"); - printf(" -p port Specify database server port (default: %s)\n", + printf(" -p Specify database server port (default: %s)\n", env ? env : "hardwired"); puts( " -P var[=arg] Set printing option 'var' to 'arg' (see \\pset command)"); @@ -112,7 +118,7 @@ usage(void) env = getenv("PGUSER"); if (!env) env = user; - printf(" -U [username] Specifiy username, \"?\"=prompt (default user: %s)\n", env); + printf(" -U Specifiy username, \"?\"=prompt (default user: %s)\n", env); puts( " -x Turn on expanded table output (-P expanded)"); puts( " -v name=val Set psql variable 'name' to 'value'"); @@ -120,9 +126,9 @@ usage(void) puts( " -W Prompt for password (should happen automatically)"); 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( "."); + puts( "(for SQL commands) from within psql, or consult the psql section in"); + puts( "the PostgreSQL manual, which accompanies the distribution and is also"); + puts( "available at ."); puts( "Report bugs to ."); #ifndef WIN32 diff --git a/src/bin/psql/help.h b/src/bin/psql/help.h index db70926856..45e02cc2a9 100644 --- a/src/bin/psql/help.h +++ b/src/bin/psql/help.h @@ -1,7 +1,14 @@ +/* + * psql - the PostgreSQL interactive terminal + * + * Copyright 2000 by PostgreSQL Global Development Team + * + * $Header: /cvsroot/pgsql/src/bin/psql/help.h,v 1.4 2000/01/18 23:30:23 petere Exp $ + */ #ifndef HELP_H #define HELP_H -#include "settings.h" +#include void usage(void); @@ -11,5 +18,4 @@ void helpSQL(const char *topic); void print_copyright(void); - #endif diff --git a/src/bin/psql/input.c b/src/bin/psql/input.c index 6607d7f162..9aa5628437 100644 --- a/src/bin/psql/input.c +++ b/src/bin/psql/input.c @@ -1,4 +1,10 @@ -#include +/* + * psql - the PostgreSQL interactive terminal + * + * Copyright 2000 by PostgreSQL Global Development Team + * + * $Header: /cvsroot/pgsql/src/bin/psql/input.c,v 1.7 2000/01/18 23:30:23 petere Exp $ + */ #include #include "input.h" @@ -115,7 +121,7 @@ initializeInput(int flags) { useReadline = true; rl_readline_name = "psql"; - initialize_readline(&(pset.db)); + initialize_readline(); } #endif diff --git a/src/bin/psql/input.h b/src/bin/psql/input.h index 675953efb4..b8e7082900 100644 --- a/src/bin/psql/input.h +++ b/src/bin/psql/input.h @@ -1,51 +1,47 @@ +/* + * psql - the PostgreSQL interactive terminal + * + * Copyright 2000 by PostgreSQL Global Development Team + * + * $Header: /cvsroot/pgsql/src/bin/psql/input.h,v 1.5 2000/01/18 23:30:23 petere Exp $ + */ #ifndef INPUT_H #define INPUT_H -#include #include #include -#include "settings.h" - -/* If some other file needs to have access to readline/history, include this +/* + * If some other file needs to have access to readline/history, include this * file and save yourself all this work. * * USE_READLINE and USE_HISTORY are the definite pointers regarding existence or not. */ #ifdef HAVE_LIBREADLINE -#ifdef HAVE_READLINE_H -#include -#define USE_READLINE 1 -#else -#if defined(HAVE_READLINE_READLINE_H) -#include -#define USE_READLINE 1 -#endif -#endif +# ifdef HAVE_READLINE_H +# include +# define USE_READLINE 1 +# elif defined(HAVE_READLINE_READLINE_H) +# include +# define USE_READLINE 1 +# endif #endif #if defined(HAVE_LIBHISTORY) || (defined(HAVE_LIBREADLINE) && defined(HAVE_HISTORY_IN_READLINE)) -#if defined(HAVE_HISTORY_H) -#include -#define USE_HISTORY 1 -#else -#if defined(HAVE_READLINE_HISTORY_H) -#include -#define USE_HISTORY 1 +# ifdef HAVE_HISTORY_H +# include +# define USE_HISTORY 1 +# elif defined(HAVE_READLINE_HISTORY_H) +# include +# define USE_HISTORY 1 +# endif #endif -#endif -#endif - char * gets_interactive(const char *prompt); - char * gets_fromFile(FILE *source); - void initializeInput(int flags); - bool saveHistory(const char *fname); - void finishInput(void); -#endif +#endif /* INPUT_H */ diff --git a/src/bin/psql/large_obj.c b/src/bin/psql/large_obj.c index d1b3af044f..cdc2c24c06 100644 --- a/src/bin/psql/large_obj.c +++ b/src/bin/psql/large_obj.c @@ -1,3 +1,10 @@ +/* + * psql - the PostgreSQL interactive terminal + * + * Copyright 2000 by PostgreSQL Global Development Team + * + * $Header: /cvsroot/pgsql/src/bin/psql/large_obj.c,v 1.6 2000/01/18 23:30:23 petere Exp $ + */ #include #include "large_obj.h" diff --git a/src/bin/psql/large_obj.h b/src/bin/psql/large_obj.h index baf1222d8c..26de0e147f 100644 --- a/src/bin/psql/large_obj.h +++ b/src/bin/psql/large_obj.h @@ -1,3 +1,10 @@ +/* + * psql - the PostgreSQL interactive terminal + * + * Copyright 2000 by PostgreSQL Global Development Team + * + * $Header: /cvsroot/pgsql/src/bin/psql/large_obj.h,v 1.6 2000/01/18 23:30:23 petere Exp $ + */ #ifndef LARGE_OBJ_H #define LARGE_OBJ_H diff --git a/src/bin/psql/mainloop.c b/src/bin/psql/mainloop.c index 29db0d0610..be8f16fdf8 100644 --- a/src/bin/psql/mainloop.c +++ b/src/bin/psql/mainloop.c @@ -1,3 +1,10 @@ +/* + * psql - the PostgreSQL interactive terminal + * + * Copyright 2000 by PostgreSQL Global Development Team + * + * $Header: /cvsroot/pgsql/src/bin/psql/mainloop.c,v 1.15 2000/01/18 23:30:23 petere Exp $ + */ #include #include "mainloop.h" @@ -25,7 +32,7 @@ * FIXME: rewrite this whole thing with flex */ int -MainLoop(FILE *source, int encoding) +MainLoop(FILE *source) { PQExpBuffer query_buf; /* buffer for query being accumulated */ PQExpBuffer previous_buf; /* if there isn't anything in the new buffer @@ -52,6 +59,7 @@ MainLoop(FILE *source, int encoding) FILE *prev_cmd_source; bool prev_cmd_interactive; + unsigned int prev_lineno; bool die_on_error; @@ -68,7 +76,7 @@ MainLoop(FILE *source, int encoding) previous_buf = createPQExpBuffer(); if (!query_buf || !previous_buf) { - perror("createPQExpBuffer"); + psql_error("out of memory"); exit(EXIT_FAILURE); } @@ -76,6 +84,8 @@ MainLoop(FILE *source, int encoding) in_quote = 0; paren_level = 0; slashCmdStatus = CMD_UNKNOWN; /* set default */ + prev_lineno = pset.lineno; + pset.lineno = 0; /* main loop to get queries and execute them */ @@ -163,7 +173,10 @@ MainLoop(FILE *source, int encoding) if (getout) { - putc('\n', stdout); /* just newline */ + if (QUIET()) + putc('\n', stdout); + else + puts("\\q"); break; } else @@ -179,6 +192,8 @@ MainLoop(FILE *source, int encoding) else count_eof = 0; + pset.lineno++; + /* strip trailing backslashes, they don't have a clear meaning */ while (1) { @@ -201,7 +216,7 @@ MainLoop(FILE *source, int encoding) var = GetVariable(pset.vars, "ECHO"); if (var && strcmp(var, "full")==0) puts(line); - fflush(stdout); + fflush(stdout); len = strlen(line); query_start = 0; @@ -212,10 +227,10 @@ MainLoop(FILE *source, int encoding) * The current character is at line[i], the prior character at line[i * - prevlen], the next character at line[i + thislen]. */ -#define ADVANCE_1 (prevlen = thislen, i += thislen, thislen = PQmblen(line+i, encoding)) +#define ADVANCE_1 (prevlen = thislen, i += thislen, thislen = PQmblen(line+i, pset.encoding)) success = true; - for (i = 0, prevlen = 0, thislen = (len > 0) ? PQmblen(line, encoding) : 0; + for (i = 0, prevlen = 0, thislen = (len > 0) ? PQmblen(line, pset.encoding) : 0; i < len; ADVANCE_1) { @@ -293,7 +308,7 @@ MainLoop(FILE *source, int encoding) new = malloc(len + out_length - (1 + in_length) + 1); if (!new) { - perror("malloc"); + psql_error("out of memory"); exit(EXIT_FAILURE); } @@ -374,7 +389,7 @@ MainLoop(FILE *source, int encoding) /* handle backslash command */ slashCmdStatus = HandleSlashCmds(&line[i], query_buf->len>0 ? query_buf : previous_buf, - &end_of_cmd, encoding); + &end_of_cmd); success = slashCmdStatus != CMD_ERROR; @@ -456,6 +471,7 @@ MainLoop(FILE *source, int encoding) pset.cur_cmd_source = prev_cmd_source; pset.cur_cmd_interactive = prev_cmd_interactive; + pset.lineno = prev_lineno; return successResult; } /* MainLoop() */ diff --git a/src/bin/psql/mainloop.h b/src/bin/psql/mainloop.h index f76db73328..8caa8c6c80 100644 --- a/src/bin/psql/mainloop.h +++ b/src/bin/psql/mainloop.h @@ -1,8 +1,15 @@ +/* + * psql - the PostgreSQL interactive terminal + * + * Copyright 2000 by PostgreSQL Global Development Team + * + * $Header: /cvsroot/pgsql/src/bin/psql/mainloop.h,v 1.5 2000/01/18 23:30:24 petere Exp $ + */ #ifndef MAINLOOP_H #define MAINLOOP_H #include -int MainLoop(FILE *source, int encoding); +int MainLoop(FILE *source); #endif /* MAINLOOP_H */ diff --git a/src/bin/psql/print.c b/src/bin/psql/print.c index 4676d4b506..af1172a21b 100644 --- a/src/bin/psql/print.c +++ b/src/bin/psql/print.c @@ -1,4 +1,10 @@ -#include +/* + * psql - the PostgreSQL interactive terminal + * + * Copyright 2000 by PostgreSQL Global Development Team + * + * $Header: /cvsroot/pgsql/src/bin/psql/print.c,v 1.8 2000/01/18 23:30:24 petere Exp $ + */ #include #include "print.h" @@ -30,19 +36,22 @@ static void print_unaligned_text(const char *title, const char * const * headers, const char * const * cells, const char * const * footers, - const char *opt_fieldsep, bool opt_barebones, + const char *opt_fieldsep, const char *opt_recordsep, bool opt_barebones, FILE *fout) { unsigned int col_count = 0; unsigned int i; const char * const * ptr; + bool need_recordsep = false; if (!opt_fieldsep) opt_fieldsep = ""; + if (!opt_recordsep) + opt_recordsep = ""; /* print title */ if (!opt_barebones && title) - fprintf(fout, "%s\n", title); + fprintf(fout, "%s%s", title, opt_recordsep); /* print headers and count columns */ for (ptr = headers; *ptr; ptr++) @@ -56,17 +65,22 @@ print_unaligned_text(const char *title, const char * const * headers, } } if (!opt_barebones) - fputs("\n", fout); + need_recordsep = true; /* print cells */ i = 0; for (ptr = cells; *ptr; ptr++) { + if (need_recordsep) + { + fputs(opt_recordsep, fout); + need_recordsep = false; + } fputs(*ptr, fout); if ((i + 1) % col_count) fputs(opt_fieldsep, fout); else - fputs("\n", fout); + need_recordsep = true; i++; } @@ -74,8 +88,19 @@ print_unaligned_text(const char *title, const char * const * headers, if (!opt_barebones && footers) for (ptr = footers; *ptr; ptr++) - fprintf(fout, "%s\n", *ptr); + { + if (need_recordsep) + { + fputs(opt_recordsep, fout); + need_recordsep = false; + } + fputs(*ptr, fout); + need_recordsep = true; + } + /* the last record needs to be concluded with a newline */ + if (need_recordsep) + fputc('\n', fout); } @@ -83,20 +108,21 @@ print_unaligned_text(const char *title, const char * const * headers, static void print_unaligned_vertical(const char *title, const char * const * headers, const char * const * cells, const char * const * footers, - const char *opt_fieldsep, bool opt_barebones, + const char *opt_fieldsep, const char *opt_recordsep, bool opt_barebones, FILE *fout) { unsigned int col_count = 0; unsigned int i; - unsigned int record = 1; const char * const * ptr; if (!opt_fieldsep) opt_fieldsep = ""; + if (!opt_recordsep) + opt_recordsep = ""; /* print title */ if (!opt_barebones && title) - fprintf(fout, "%s\n", title); + fputs(title, fout); /* count columns */ for (ptr = headers; *ptr; ptr++) @@ -105,24 +131,30 @@ print_unaligned_vertical(const char *title, const char * const * headers, /* print records */ for (i = 0, ptr = cells; *ptr; i++, ptr++) { - if (i % col_count == 0) - { - if (!opt_barebones) - fprintf(fout, "-- RECORD %d\n", record++); - else - fputc('\n', fout); - } - fprintf(fout, "%s%s%s\n", headers[i % col_count], opt_fieldsep, *ptr); + if (i!=0 || (!opt_barebones && title)) + { + fputs(opt_recordsep, fout); + if (i % col_count == 0) + fputs(opt_recordsep, fout); /* another one */ + } + + fputs(headers[i % col_count], fout); + fputs(opt_fieldsep, fout); + fputs(*ptr, fout); } /* print footers */ - - if (!opt_barebones && footers) + if (!opt_barebones && footers && *footers) { - fputs("--- END ---\n", fout); + fputs(opt_recordsep, fout); for (ptr = footers; *ptr; ptr++) - fprintf(fout, "%s\n", *ptr); + { + fputs(opt_recordsep, fout); + fputs(*ptr, fout); + } } + + fputc('\n', fout); } @@ -679,9 +711,9 @@ print_latex_text(const char *title, const char * const * headers, /* print title */ if (!opt_barebones && title) { - fputs("\begin{center}\n", fout); + fputs("\\begin{center}\n", fout); latex_escaped_print(title, fout); - fputs("\n\end{center}\n\n", fout); + fputs("\n\\end{center}\n\n", fout); } /* begin environment and set alignments and borders */ @@ -776,9 +808,9 @@ print_latex_vertical(const char *title, const char * const * headers, /* print title */ if (!opt_barebones && title) { - fputs("\begin{center}\n", fout); + fputs("\\begin{center}\n", fout); latex_escaped_print(title, fout); - fputs("\n\end{center}\n\n", fout); + fputs("\n\\end{center}\n\n", fout); } /* begin environment and set alignments and borders */ @@ -936,9 +968,9 @@ printTable(const char *title, { case PRINT_UNALIGNED: if (opt->expanded) - print_unaligned_vertical(title, headers, cells, footers, opt->fieldSep, opt->tuples_only, output); + print_unaligned_vertical(title, headers, cells, footers, opt->fieldSep, opt->recordSep, opt->tuples_only, output); else - print_unaligned_text(title, headers, cells, footers, opt->fieldSep, opt->tuples_only, output); + print_unaligned_text(title, headers, cells, footers, opt->fieldSep, opt->recordSep, opt->tuples_only, output); break; case PRINT_ALIGNED: if (opt->expanded) diff --git a/src/bin/psql/print.h b/src/bin/psql/print.h index 277441ee04..252236bf33 100644 --- a/src/bin/psql/print.h +++ b/src/bin/psql/print.h @@ -1,3 +1,10 @@ +/* + * psql - the PostgreSQL interactive terminal + * + * Copyright 2000 by PostgreSQL Global Development Team + * + * $Header: /cvsroot/pgsql/src/bin/psql/print.h,v 1.5 2000/01/18 23:30:24 petere Exp $ + */ #ifndef PRINT_H #define PRINT_H @@ -29,6 +36,7 @@ typedef struct _printTableOpt unsigned short int border; /* Print a border around the table. * 0=none, 1=dividing lines, 2=full */ char *fieldSep; /* field separator for unaligned text mode */ + char *recordSep; /* record separator for unaligned text mode */ char *tableAttr; /* attributes for HTML */ } printTableOpt; diff --git a/src/bin/psql/prompt.c b/src/bin/psql/prompt.c index d93f5611ce..f9d6cc098e 100644 --- a/src/bin/psql/prompt.c +++ b/src/bin/psql/prompt.c @@ -1,3 +1,10 @@ +/* + * psql - the PostgreSQL interactive terminal + * + * Copyright 2000 by PostgreSQL Global Development Team + * + * $Header: /cvsroot/pgsql/src/bin/psql/prompt.c,v 1.6 2000/01/18 23:30:24 petere Exp $ + */ #include #include "prompt.h" @@ -22,7 +29,7 @@ * get_prompt * * Returns a statically allocated prompt made by interpolating certain - * tcsh style escape sequences into pset->vars "PROMPT1|2|3". + * tcsh style escape sequences into pset.vars "PROMPT1|2|3". * (might not be completely multibyte safe) * * Defined interpolations are: @@ -49,7 +56,6 @@ * %$name$ - The value of the psql variable 'name' * (those will not be rescanned for more escape sequences!) * - * * If the application-wide prompts became NULL somehow, the returned string * will be empty (not NULL!). *-------------------------- diff --git a/src/bin/psql/prompt.h b/src/bin/psql/prompt.h index d98116395a..9134f8331c 100644 --- a/src/bin/psql/prompt.h +++ b/src/bin/psql/prompt.h @@ -1,7 +1,14 @@ +/* + * psql - the PostgreSQL interactive terminal + * + * Copyright 2000 by PostgreSQL Global Development Team + * + * $Header: /cvsroot/pgsql/src/bin/psql/prompt.h,v 1.4 2000/01/18 23:30:24 petere Exp $ + */ #ifndef PROMPT_H #define PROMPT_H -#include "settings.h" +#include typedef enum _promptStatus { @@ -13,8 +20,6 @@ typedef enum _promptStatus PROMPT_COPY } promptStatus_t; -const char * - get_prompt(promptStatus_t status); - +const char *get_prompt(promptStatus_t status); #endif /* PROMPT_H */ diff --git a/src/bin/psql/settings.h b/src/bin/psql/settings.h index 21f138bd37..6cfeca79b2 100644 --- a/src/bin/psql/settings.h +++ b/src/bin/psql/settings.h @@ -1,6 +1,13 @@ +/* + * psql - the PostgreSQL interactive terminal + * + * Copyright 2000 by PostgreSQL Global Development Team + * + * $Header: /cvsroot/pgsql/src/bin/psql/settings.h,v 1.7 2000/01/18 23:30:24 petere Exp $ + */ #ifndef SETTINGS_H #define SETTINGS_H -#include + #include #include @@ -13,6 +20,7 @@ #include "print.h" #define DEFAULT_FIELD_SEP "|" +#define DEFAULT_RECORD_SEP "\n" #define DEFAULT_EDITOR "vi" #define DEFAULT_PROMPT1 "%/%R%# " @@ -23,6 +31,7 @@ typedef struct _psqlSettings { PGconn *db; /* connection to backend */ + int encoding; FILE *queryFout; /* where to send the query results */ bool queryFoutPipe; /* queryFout is from a popen() */ @@ -41,9 +50,9 @@ typedef struct _psqlSettings * loop */ bool cur_cmd_interactive; - bool has_client_encoding; /* was PGCLIENTENCODING set on - * startup? */ char *progname; /* in case you renamed psql */ + char *inputfile; /* for error reporting */ + unsigned lineno; /* also for error reporting */ } PsqlSettings; extern PsqlSettings pset; diff --git a/src/bin/psql/startup.c b/src/bin/psql/startup.c index c1e9fa0219..1c31cb4756 100644 --- a/src/bin/psql/startup.c +++ b/src/bin/psql/startup.c @@ -1,3 +1,10 @@ +/* + * psql - the PostgreSQL interactive terminal + * + * Copyright 2000 by PostgreSQL Global Development Team + * + * $Header: /cvsroot/pgsql/src/bin/psql/startup.c,v 1.16 2000/01/18 23:30:24 petere Exp $ + */ #include #include @@ -94,13 +101,15 @@ main(int argc, char **argv) pset.cur_cmd_source = stdin; pset.cur_cmd_interactive = false; + pset.encoding = PQenv2encoding(); pset.vars = CreateVariableSpace(); pset.popt.topt.format = PRINT_ALIGNED; pset.queryFout = stdout; - pset.popt.topt.fieldSep = strdup(DEFAULT_FIELD_SEP); + pset.popt.topt.fieldSep = xstrdup(DEFAULT_FIELD_SEP); + pset.popt.topt.recordSep = xstrdup(DEFAULT_RECORD_SEP); pset.popt.topt.border = 1; - pset.popt.topt.pager = 1; + pset.popt.topt.pager = true; SetVariable(pset.vars, "PROMPT1", DEFAULT_PROMPT1); SetVariable(pset.vars, "PROMPT2", DEFAULT_PROMPT2); @@ -116,10 +125,6 @@ main(int argc, char **argv) pset.getPassword = false; #endif -#ifdef MULTIBYTE - pset.has_client_encoding = (getenv("PGCLIENTENCODING") != NULL); -#endif - parse_options(argc, argv, &options); if (options.action == ACT_LIST_DB) @@ -157,12 +162,19 @@ main(int argc, char **argv) if (PQstatus(pset.db) == CONNECTION_BAD) { - fprintf(stderr, "%s: connection to database '%s' failed.\n%s", - pset.progname, PQdb(pset.db), PQerrorMessage(pset.db)); + fprintf(stderr, "%s: connection to database \"%s\" failed - %s", + pset.progname, PQdb(pset.db), PQerrorMessage(pset.db)); PQfinish(pset.db); exit(EXIT_BADCONN); } + PQsetNoticeProcessor(pset.db, NoticeProcessor, NULL); + /* + * We need to save the encoding because we want to have it + * available even if the database connection goes bad. + */ + pset.encoding = PQclientencoding(pset.db); + if (options.action == ACT_LIST_DB) { int success = listAllDbs(false); @@ -190,10 +202,10 @@ main(int argc, char **argv) /* process file given by -f */ if (options.action == ACT_FILE) - successResult = process_file(options.action_string, PQclientencoding(pset.db)) ? 0 : 1; + successResult = process_file(options.action_string) ? 0 : 1; /* process slash command if one was given to -c */ else if (options.action == ACT_SINGLE_SLASH) - successResult = HandleSlashCmds(options.action_string, NULL, NULL, PQclientencoding(pset.db)) != CMD_ERROR ? 0 : 1; + successResult = HandleSlashCmds(options.action_string, NULL, NULL) != CMD_ERROR ? 0 : 1; /* If the query given to -c was a normal one, send it */ else if (options.action == ACT_SINGLE_QUERY) successResult = SendQuery( options.action_string) ? 0 : 1; @@ -202,7 +214,7 @@ main(int argc, char **argv) { process_psqlrc(); initializeInput(options.no_readline ? 0 : 1); - successResult = MainLoop(stdin, PQclientencoding(pset.db)); + successResult = MainLoop(stdin); finishInput(); } @@ -234,7 +246,6 @@ parse_options(int argc, char *argv[], struct adhoc_opts * options) static struct option long_options[] = { {"no-align", no_argument, NULL, 'A'}, {"command", required_argument, NULL, 'c'}, - {"database", required_argument, NULL, 'd'}, {"dbname", required_argument, NULL, 'd'}, {"echo", no_argument, NULL, 'e'}, {"echo-hidden", no_argument, NULL, 'E'}, @@ -417,8 +428,16 @@ parse_options(int argc, char *argv[], struct adhoc_opts * options) pset.getPassword = true; break; case '?': - usage(); - exit(EXIT_SUCCESS); + if (strcmp(argv[optind-1], "-?")==0) + { + usage(); + exit(EXIT_SUCCESS); + } + else + { + fputs("Try -? for help.\n", stderr); + exit(EXIT_FAILURE); + } break; #ifndef HAVE_GETOPT_LONG case '-': @@ -428,7 +447,7 @@ parse_options(int argc, char *argv[], struct adhoc_opts * options) break; #endif default: - usage(); + fputs("Try -? for help.\n", stderr); exit(EXIT_FAILURE); break; } @@ -466,20 +485,16 @@ process_psqlrc(void) { char *psqlrc; char *home; - int encoding; #ifdef WIN32 #define R_OK 0 #endif - /* get client side encoding from envrionment variable if any */ - encoding = PQenv2encoding(); - /* System-wide startup file */ if (access("/etc/psqlrc-" PG_RELEASE "." PG_VERSION "." PG_SUBVERSION, R_OK) == 0) - process_file("/etc/psqlrc-" PG_RELEASE "." PG_VERSION "." PG_SUBVERSION, encoding); + process_file("/etc/psqlrc-" PG_RELEASE "." PG_VERSION "." PG_SUBVERSION); else if (access("/etc/psqlrc", R_OK) == 0) - process_file("/etc/psqlrc", encoding); + process_file("/etc/psqlrc"); /* Look for one in the home dir */ home = getenv("HOME"); @@ -489,18 +504,18 @@ process_psqlrc(void) psqlrc = (char *) malloc(strlen(home) + 20); if (!psqlrc) { - perror("malloc"); + fprintf(stderr, "%s: out of memory\n", pset.progname); exit(EXIT_FAILURE); } sprintf(psqlrc, "%s/.psqlrc-" PG_RELEASE "." PG_VERSION "." PG_SUBVERSION, home); if (access(psqlrc, R_OK) == 0) - process_file(psqlrc, encoding); + process_file(psqlrc); else { sprintf(psqlrc, "%s/.psqlrc", home); if (access(psqlrc, R_OK) == 0) - process_file(psqlrc, encoding); + process_file(psqlrc); } free(psqlrc); } diff --git a/src/bin/psql/stringutils.c b/src/bin/psql/stringutils.c index 1421cf1360..c8cc603422 100644 --- a/src/bin/psql/stringutils.c +++ b/src/bin/psql/stringutils.c @@ -1,4 +1,10 @@ -#include +/* + * psql - the PostgreSQL interactive terminal + * + * Copyright 2000 by PostgreSQL Global Development Team + * + * $Header: /cvsroot/pgsql/src/bin/psql/stringutils.c,v 1.22 2000/01/18 23:30:24 petere Exp $ + */ #include #include "stringutils.h" diff --git a/src/bin/psql/stringutils.h b/src/bin/psql/stringutils.h index c9a161d88e..0a109b5639 100644 --- a/src/bin/psql/stringutils.h +++ b/src/bin/psql/stringutils.h @@ -1,3 +1,10 @@ +/* + * psql - the PostgreSQL interactive terminal + * + * Copyright 2000 by PostgreSQL Global Development Team + * + * $Header: /cvsroot/pgsql/src/bin/psql/stringutils.h,v 1.12 2000/01/18 23:30:24 petere Exp $ + */ #ifndef STRINGUTILS_H #define STRINGUTILS_H diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c index dbba754b9a..4bec69e615 100644 --- a/src/bin/psql/tab-complete.c +++ b/src/bin/psql/tab-complete.c @@ -1,3 +1,11 @@ +/* + * psql - the PostgreSQL interactive terminal + * + * Copyright 2000 by PostgreSQL Global Development Team + * + * $Header: /cvsroot/pgsql/src/bin/psql/tab-complete.c,v 1.7 2000/01/18 23:30:24 petere Exp $ + */ + /*----------- This file implements a somewhat more sophisticated readline "TAB completion" in psql. It is not intended to be AI, to replace learning SQL, or to relieve @@ -24,7 +32,6 @@ gracefully. -------------*/ -#include #include #include "tab-complete.h" @@ -44,17 +51,11 @@ #include #include "common.h" - +#include "settings.h" #define BUF_SIZE 2048 #define ERROR_QUERY_TOO_LONG /* empty */ -/* This pointer saves the place where psql stores its own pointer to the - currently active database connection. This is probably a less than ideal way - of passing this around, but this way I only had to make minimal changes to - psql.c. */ -static PGconn ** database_connection; - /* Forward declaration of functions */ static char ** psql_completion(char *text, int start, int end); @@ -80,21 +81,10 @@ char * completion_info_charp; /* if you need to pass another string */ static int completion_max_records; -static void * xmalloc(size_t length) -{ - void *tmp = malloc(length); - if (!tmp) { - perror("malloc"); - exit(EXIT_FAILURE); - } - return tmp; -} - - /* Initialize the readline library for our purposes. */ -void initialize_readline(PGconn ** conn) +void initialize_readline(void) { - rl_readline_name = "psql"; + rl_readline_name = pset.progname; rl_attempted_completion_function = psql_completion; rl_special_prefixes = "()'"; @@ -103,8 +93,6 @@ void initialize_readline(PGconn ** conn) completion_max_records = 100; /* There is a variable rl_completion_query_items for this but apparently it's not defined everywhere. */ - - database_connection = conn; } @@ -511,7 +499,8 @@ char ** psql_completion(char *text, int start, int end) COMPLETE_WITH_LIST(sql_commands); else if (strcmp(prev_wd, "\\pset")==0) { char * my_list[] = { "format", "border", "expanded", "null", "fieldsep", - "tuples_only", "title", "tableattr", "pager", NULL }; + "tuples_only", "title", "tableattr", "pager", + "recordsep", NULL }; COMPLETE_WITH_LIST(my_list); } else if( strcmp(prev_wd, "\\e")==0 || strcmp(prev_wd, "\\edit")==0 || @@ -703,7 +692,7 @@ PGresult * exec_query(char * query) PGresult * result; char query_buffer[BUF_SIZE]; - if (query == NULL || PQstatus(*database_connection) != CONNECTION_OK) + if (query == NULL || !pset.db || PQstatus(pset.db) != CONNECTION_OK) return NULL; #ifdef USE_ASSERT_CHECKING assert( query[strlen(query)-1] != ';' ); @@ -714,12 +703,12 @@ PGresult * exec_query(char * query) return NULL; } - result = PQexec(*database_connection, query); + result = PQexec(pset.db, 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))); +#if 0 + psql_error("tab completion: %s failed - %s", + query, PQresStatus(PQresultStatus(result))); #endif PQclear(result); result = NULL; @@ -767,7 +756,16 @@ char * previous_word(int point, int skip) { } /* make a copy */ - s = (char *)xmalloc(end-start+2); + s = (char *)malloc(end-start+2); + if (!s) + { + psql_error("out of memory\n"); + if (!pset.cur_cmd_interactive) + exit(EXIT_FAILURE); + else + return NULL; + } + strncpy(s, &rl_line_buffer[start], end-start+1); s[end-start+1] = '\0'; @@ -776,11 +774,13 @@ char * previous_word(int point, int skip) { -#ifdef NOT_USED +#if 0 -/* Surround a string with single quotes. This works for both SQL and - psql internal. Doesn't work so well yet. -*/ +/* + * Surround a string with single quotes. This works for both SQL and + * psql internal. Currently disable because it is reported not to + * cooperate with certain versions of readline. + */ char * quote_file_name(char *text, int match_type, char * quote_pointer) { char *s; @@ -789,7 +789,7 @@ char * quote_file_name(char *text, int match_type, char * quote_pointer) (void)quote_pointer; /* not used */ length = strlen(text) + ( match_type==SINGLE_MATCH ? 3 : 2 ); - s = xmalloc(length); + s = malloc(length); s[0] = '\''; strcpy(s+1, text); if (match_type==SINGLE_MATCH) @@ -809,13 +809,13 @@ static char * dequote_file_name(char *text, char quote_char) return xstrdup(text); length = strlen(text); - s = xmalloc(length-2+1); + s = malloc(length-2+1); strncpy(s, text+1, length-2); s[length] = '\0'; return s; } -#endif /* NOT_USED */ +#endif /* 0 */ #endif /* USE_READLINE */ diff --git a/src/bin/psql/tab-complete.h b/src/bin/psql/tab-complete.h index 04d5a8bcee..42fa6fe1b0 100644 --- a/src/bin/psql/tab-complete.h +++ b/src/bin/psql/tab-complete.h @@ -1,8 +1,13 @@ +/* + * psql - the PostgreSQL interactive terminal + * + * Copyright 2000 by PostgreSQL Global Development Team + * + * $Header: /cvsroot/pgsql/src/bin/psql/tab-complete.h,v 1.2 2000/01/18 23:30:24 petere Exp $ + */ #ifndef TAB_COMPLETE_H #define TAB_COMPLETE_H -#include - -void initialize_readline(PGconn ** conn); +void initialize_readline(void); #endif diff --git a/src/bin/psql/variables.c b/src/bin/psql/variables.c index c84363ea7f..0c559af7e6 100644 --- a/src/bin/psql/variables.c +++ b/src/bin/psql/variables.c @@ -1,4 +1,10 @@ -#include +/* + * psql - the PostgreSQL interactive terminal + * + * Copyright 2000 by PostgreSQL Global Development Team + * + * $Header: /cvsroot/pgsql/src/bin/psql/variables.c,v 1.4 2000/01/18 23:30:24 petere Exp $ + */ #include #include "variables.h" diff --git a/src/bin/psql/variables.h b/src/bin/psql/variables.h index 06493b49d8..d6b5fb7235 100644 --- a/src/bin/psql/variables.h +++ b/src/bin/psql/variables.h @@ -1,4 +1,13 @@ -/* This implements a sort of variable repository. One could also think of it +/* + * psql - the PostgreSQL interactive terminal + * + * Copyright 2000 by PostgreSQL Global Development Team + * + * $Header: /cvsroot/pgsql/src/bin/psql/variables.h,v 1.4 2000/01/18 23:30:24 petere Exp $ + */ + +/* + * This implements a sort of variable repository. One could also think of it * as cheap version of an associative array. In each one of these * datastructures you can store name/value pairs. *