diff options
author | Peter Eisentraut <peter_e@gmx.net> | 2000-01-14 22:18:03 +0000 |
---|---|---|
committer | Peter Eisentraut <peter_e@gmx.net> | 2000-01-14 22:18:03 +0000 |
commit | 7c9390caa14ea2d5d99d69d2a34eee4d45d43b9c (patch) | |
tree | 7fdf1a26847ab31eee6ab32fc4d77138040971cf /src | |
parent | 4ceb2d0cb619bba2ecbf5d72a10c8fa7ba321366 (diff) | |
download | postgresql-7c9390caa14ea2d5d99d69d2a34eee4d45d43b9c.tar.gz postgresql-7c9390caa14ea2d5d99d69d2a34eee4d45d43b9c.zip |
Fixed psql variables vs array syntax, as well as minor psql enhancements
Diffstat (limited to 'src')
-rw-r--r-- | src/bin/psql/command.c | 272 | ||||
-rw-r--r-- | src/bin/psql/command.h | 13 | ||||
-rw-r--r-- | src/bin/psql/common.c | 312 | ||||
-rw-r--r-- | src/bin/psql/common.h | 9 | ||||
-rw-r--r-- | src/bin/psql/copy.c | 85 | ||||
-rw-r--r-- | src/bin/psql/copy.h | 2 | ||||
-rw-r--r-- | src/bin/psql/describe.c | 102 | ||||
-rw-r--r-- | src/bin/psql/describe.h | 18 | ||||
-rw-r--r-- | src/bin/psql/help.c | 15 | ||||
-rw-r--r-- | src/bin/psql/help.h | 2 | ||||
-rw-r--r-- | src/bin/psql/input.c | 27 | ||||
-rw-r--r-- | src/bin/psql/input.h | 2 | ||||
-rw-r--r-- | src/bin/psql/large_obj.c | 110 | ||||
-rw-r--r-- | src/bin/psql/large_obj.h | 9 | ||||
-rw-r--r-- | src/bin/psql/mainloop.c | 158 | ||||
-rw-r--r-- | src/bin/psql/mainloop.h | 4 | ||||
-rw-r--r-- | src/bin/psql/prompt.c | 49 | ||||
-rw-r--r-- | src/bin/psql/prompt.h | 2 | ||||
-rw-r--r-- | src/bin/psql/settings.h | 6 | ||||
-rw-r--r-- | src/bin/psql/startup.c | 180 |
20 files changed, 693 insertions, 684 deletions
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c index ba016120590..d658df1e572 100644 --- a/src/bin/psql/command.c +++ b/src/bin/psql/command.c @@ -1,4 +1,3 @@ -#include <config.h> #include <c.h> #include "command.h" @@ -26,6 +25,7 @@ #include "print.h" #include "describe.h" #include "input.h" +#include "variables.h" #ifdef WIN32 #define popen(x,y) _popen(x,y) @@ -38,16 +38,14 @@ static backslashResult exec_command(const char *cmd, char *const * options, const char *options_string, - PQExpBuffer query_buf, - PsqlSettings *pset); + PQExpBuffer query_buf); static bool do_edit(const char *filename_arg, PQExpBuffer query_buf); -static char * unescape(const char *source, PsqlSettings *pset); +static char * unescape(const char *source); static bool do_connect(const char *new_dbname, - const char *new_user, - PsqlSettings *pset); + const char *new_user); static bool do_shell(const char *command); @@ -79,8 +77,7 @@ static bool do_shell(const char *command); */ backslashResult -HandleSlashCmds(PsqlSettings *pset, - const char *line, +HandleSlashCmds(const char *line, PQExpBuffer query_buf, const char **end_of_cmd) { @@ -95,6 +92,12 @@ HandleSlashCmds(PsqlSettings *pset, const char *continue_parse = NULL; /* tell the mainloop where the * backslash command ended */ +#ifdef USE_ASSERT_CHECKING + assert(line); + assert(query_buf); + assert(end_of_cmd); +#endif + my_line = xstrdup(line); /* @@ -135,7 +138,7 @@ HandleSlashCmds(PsqlSettings *pset, switch (quote) { case '"': - options[i] = unescape(token, pset); + options[i] = unescape(token); break; case '\'': options[i] = xstrdup(token); @@ -144,7 +147,7 @@ HandleSlashCmds(PsqlSettings *pset, { bool error = false; FILE *fd = NULL; - char *file = unescape(token, pset); + char *file = unescape(token); PQExpBufferData output; char buf[512]; size_t result; @@ -200,8 +203,13 @@ HandleSlashCmds(PsqlSettings *pset, default: if (token[0] == '\\') continue_parse = options_string + pos; - else if (token[0] == '$') - options[i] = xstrdup(interpolate_var(token + 1, pset)); + else if (token[0] == '$') + { + const char * value = GetVariable(pset.vars, token+1); + if (!value) + value = ""; + options[i] = xstrdup(value); + } else options[i] = xstrdup(token); } @@ -216,7 +224,7 @@ HandleSlashCmds(PsqlSettings *pset, } cmd = my_line; - status = exec_command(cmd, options, options_string, query_buf, pset); + status = exec_command(cmd, options, options_string, query_buf); if (status == CMD_UNKNOWN) { @@ -238,15 +246,15 @@ HandleSlashCmds(PsqlSettings *pset, new_cmd[0] = cmd[0]; new_cmd[1] = '\0'; - status = exec_command(new_cmd, (char *const *) new_options, my_line + 2, query_buf, pset); + status = exec_command(new_cmd, (char *const *) new_options, my_line + 2, query_buf); } if (status == CMD_UNKNOWN) { - if (pset->cur_cmd_interactive) + 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); + fprintf(stderr, "%s: invalid command \\%s", pset.progname, cmd); status = CMD_ERROR; } @@ -254,13 +262,10 @@ HandleSlashCmds(PsqlSettings *pset, continue_parse += 2; - if (end_of_cmd) - { - if (continue_parse) - *end_of_cmd = line + (continue_parse - my_line); - else - *end_of_cmd = NULL; - } + if (continue_parse) + *end_of_cmd = line + (continue_parse - my_line); + else + *end_of_cmd = line + strlen(line); /* clean up */ for (i = 0; i < NR_OPTIONS && options[i]; i++) @@ -278,12 +283,11 @@ static backslashResult exec_command(const char *cmd, char *const * options, const char *options_string, - PQExpBuffer query_buf, - PsqlSettings *pset) + PQExpBuffer query_buf) { bool success = true; /* indicate here if the command ran ok or * failed */ - bool quiet = GetVariableBool(pset->vars, "quiet"); + bool quiet = QUIET(); backslashResult status = CMD_SKIP_LINE; @@ -291,16 +295,16 @@ exec_command(const char *cmd, /* \a -- toggle field alignment This makes little sense but we keep it around. */ if (strcmp(cmd, "a") == 0) { - if (pset->popt.topt.format != PRINT_ALIGNED) - success = do_pset("format", "aligned", &pset->popt, quiet); + if (pset.popt.topt.format != PRINT_ALIGNED) + success = do_pset("format", "aligned", &pset.popt, quiet); else - success = do_pset("format", "unaligned", &pset->popt, quiet); + success = do_pset("format", "unaligned", &pset.popt, quiet); } /* \C -- override table title (formerly change HTML caption) */ else if (strcmp(cmd, "C") == 0) - success = do_pset("title", options[0], &pset->popt, quiet); + success = do_pset("title", options[0], &pset.popt, quiet); /*---------- @@ -316,25 +320,25 @@ exec_command(const char *cmd, { if (options[1]) /* gave username */ - success = do_connect(options[0], options[1], pset); + success = do_connect(options[0], options[1]); else { if (options[0]) /* gave database name */ - success = do_connect(options[0], "", pset); /* empty string is same - * username as before, - * NULL would mean libpq - * default */ + success = do_connect(options[0], ""); /* empty string is same + * username as before, + * NULL would mean libpq + * default */ else /* connect to default db as default user */ - success = do_connect(NULL, NULL, pset); + success = do_connect(NULL, NULL); } } /* \copy */ - else if (strcmp(cmd, "copy") == 0) - success = do_copy(options_string, pset); + else if (strcasecmp(cmd, "copy") == 0) + success = do_copy(options_string); /* \copyright */ else if (strcmp(cmd, "copyright") == 0) @@ -350,31 +354,31 @@ exec_command(const char *cmd, case '\0': case '?': if (options[0]) - success = describeTableDetails(options[0], pset, show_verbose); + success = describeTableDetails(options[0], show_verbose); else /* standard listing of interesting things */ - success = listTables("tvs", NULL, pset, show_verbose); + success = listTables("tvs", NULL, show_verbose); break; case 'a': - success = describeAggregates(options[0], pset); + success = describeAggregates(options[0]); break; case 'd': - success = objectDescription(options[0], pset); + success = objectDescription(options[0]); break; case 'f': - success = describeFunctions(options[0], pset, show_verbose); + success = describeFunctions(options[0], show_verbose); break; case 'l': - success = do_lo_list(pset); + success = do_lo_list(); break; case 'o': - success = describeOperators(options[0], pset); + success = describeOperators(options[0]); break; case 'p': - success = permissionsList(options[0], pset); + success = permissionsList(options[0]); break; case 'T': - success = describeTypes(options[0], pset, show_verbose); + success = describeTypes(options[0], show_verbose); break; case 't': case 'v': @@ -382,9 +386,9 @@ exec_command(const char *cmd, case 's': case 'S': if (cmd[1] == 'S' && cmd[2] == '\0') - success = listTables("Stvs", NULL, pset, show_verbose); + success = listTables("Stvs", NULL, show_verbose); else - success = listTables(&cmd[1], options[0], pset, show_verbose); + success = listTables(&cmd[1], options[0], show_verbose); break; default: status = CMD_UNKNOWN; @@ -412,15 +416,15 @@ exec_command(const char *cmd, /* \f -- change field separator */ else if (strcmp(cmd, "f") == 0) - success = do_pset("fieldsep", options[0], &pset->popt, quiet); + success = do_pset("fieldsep", options[0], &pset.popt, quiet); /* \g means send query */ else if (strcmp(cmd, "g") == 0) { if (!options[0]) - pset->gfname = NULL; + pset.gfname = NULL; else - pset->gfname = xstrdup(options[0]); + pset.gfname = xstrdup(options[0]); status = CMD_SEND; } @@ -442,10 +446,10 @@ exec_command(const char *cmd, /* HTML mode */ else if (strcmp(cmd, "H") == 0 || strcmp(cmd, "html") == 0) { - if (pset->popt.topt.format != PRINT_HTML) - success = do_pset("format", "html", &pset->popt, quiet); + if (pset.popt.topt.format != PRINT_HTML) + success = do_pset("format", "html", &pset.popt, quiet); else - success = do_pset("format", "aligned", &pset->popt, quiet); + success = do_pset("format", "aligned", &pset.popt, quiet); } @@ -454,22 +458,22 @@ exec_command(const char *cmd, { if (!options[0]) { - if (pset->cur_cmd_interactive) + if (pset.cur_cmd_interactive) fprintf(stderr, "\\%s: missing required argument\n", cmd); else - fprintf(stderr, "%s: \\%s: missing required argument", pset->progname, cmd); + fprintf(stderr, "%s: \\%s: missing required argument", pset.progname, cmd); success = false; } else - success = process_file(options[0], pset); + success = process_file(options[0]); } /* \l is list databases */ else if (strcmp(cmd, "l") == 0 || strcmp(cmd, "list") == 0) - success = listAllDbs(pset, false); + success = listAllDbs(false); else if (strcmp(cmd, "l+") == 0 || strcmp(cmd, "list+") == 0) - success = listAllDbs(pset, true); + success = listAllDbs(true); /* large object things */ @@ -479,45 +483,45 @@ exec_command(const char *cmd, { if (!options[1]) { - if (pset->cur_cmd_interactive) + if (pset.cur_cmd_interactive) fprintf(stderr, "\\%s: missing required argument", cmd); else - fprintf(stderr, "%s: \\%s: missing required argument", pset->progname, cmd); + fprintf(stderr, "%s: \\%s: missing required argument", pset.progname, cmd); success = false; } else - success = do_lo_export(pset, options[0], options[1]); + success = do_lo_export(options[0], options[1]); } else if (strcmp(cmd + 3, "import") == 0) { if (!options[0]) { - if (pset->cur_cmd_interactive) + if (pset.cur_cmd_interactive) fprintf(stderr, "\\%s: missing required argument", cmd); else - fprintf(stderr, "%s: \\%s: missing required argument", pset->progname, cmd); + fprintf(stderr, "%s: \\%s: missing required argument", pset.progname, cmd); success = false; } else - success = do_lo_import(pset, options[0], options[1]); + success = do_lo_import(options[0], options[1]); } else if (strcmp(cmd + 3, "list") == 0) - success = do_lo_list(pset); + success = do_lo_list(); else if (strcmp(cmd + 3, "unlink") == 0) { if (!options[0]) { - if (pset->cur_cmd_interactive) + if (pset.cur_cmd_interactive) fprintf(stderr, "\\%s: missing required argument", cmd); else - fprintf(stderr, "%s: \\%s: missing required argument", pset->progname, cmd); + fprintf(stderr, "%s: \\%s: missing required argument", pset.progname, cmd); success = false; } else - success = do_lo_unlink(pset, options[0]); + success = do_lo_unlink(options[0]); } else @@ -526,7 +530,7 @@ exec_command(const char *cmd, /* \o -- set query output */ else if (strcmp(cmd, "o") == 0 || strcmp(cmd, "out") == 0) - success = setQFout(options[0], pset); + success = setQFout(options[0]); /* \p prints the current query buffer */ @@ -544,14 +548,14 @@ exec_command(const char *cmd, { if (!options[0]) { - if (pset->cur_cmd_interactive) + if (pset.cur_cmd_interactive) fprintf(stderr, "\\%s: missing required argument", cmd); else - fprintf(stderr, "%s: \\%s: missing required argument", pset->progname, cmd); + fprintf(stderr, "%s: \\%s: missing required argument", pset.progname, cmd); success = false; } else - success = do_pset(options[0], options[1], &pset->popt, quiet); + success = do_pset(options[0], options[1], &pset.popt, quiet); } /* \q or \quit */ @@ -564,8 +568,8 @@ exec_command(const char *cmd, int i; for (i = 0; i < 16 && options[i]; i++) - fputs(options[i], pset->queryFout); - fputs("\n", pset->queryFout); + fputs(options[i], pset.queryFout); + fputs("\n", pset.queryFout); } /* reset(clear) the buffer */ @@ -607,18 +611,21 @@ exec_command(const char *cmd, */ struct _variable *ptr; - for (ptr = pset->vars; ptr->next; ptr = ptr->next) + for (ptr = pset.vars; ptr->next; ptr = ptr->next) fprintf(stdout, "%s = '%s'\n", ptr->next->name, ptr->next->value); success = true; } else { - if (!SetVariable(pset->vars, options[0], options[1])) + const char * val = options[1]; + if (!val) + val = ""; + if (!SetVariable(pset.vars, options[0], val)) { - if (pset->cur_cmd_interactive) - fprintf(stderr, "\\%s: failed\n", cmd); + if (pset.cur_cmd_interactive) + fprintf(stderr, "\\%s: error\n", cmd); else - fprintf(stderr, "%s: \\%s: failed\n", pset->progname, cmd); + fprintf(stderr, "%s: \\%s: error\n", pset.progname, cmd); success = false; } @@ -627,13 +634,26 @@ exec_command(const char *cmd, /* \t -- turn off headers and row count */ else if (strcmp(cmd, "t") == 0) - success = do_pset("tuples_only", NULL, &pset->popt, quiet); + success = do_pset("tuples_only", NULL, &pset.popt, quiet); /* \T -- define html <table ...> attributes */ else if (strcmp(cmd, "T") == 0) - success = do_pset("tableattr", options[0], &pset->popt, quiet); + success = do_pset("tableattr", options[0], &pset.popt, quiet); + /* \unset */ + else if (strcmp(cmd, "unset") == 0) + { + 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); + + success = false; + } + } /* \w -- write query buffer to file */ else if (strcmp(cmd, "w") == 0 || strcmp(cmd, "write") == 0) @@ -643,10 +663,10 @@ exec_command(const char *cmd, if (!options[0]) { - if (pset->cur_cmd_interactive) + if (pset.cur_cmd_interactive) fprintf(stderr, "\\%s: missing required argument", cmd); else - fprintf(stderr, "%s: \\%s: missing required argument", pset->progname, cmd); + fprintf(stderr, "%s: \\%s: missing required argument", pset.progname, cmd); success = false; } else @@ -698,19 +718,19 @@ exec_command(const char *cmd, /* \x -- toggle expanded table representation */ else if (strcmp(cmd, "x") == 0) - success = do_pset("expanded", NULL, &pset->popt, quiet); + success = do_pset("expanded", NULL, &pset.popt, quiet); /* list table rights (grant/revoke) */ else if (strcmp(cmd, "z") == 0) - success = permissionsList(options[0], pset); + success = permissionsList(options[0]); else if (strcmp(cmd, "!") == 0) success = do_shell(options_string); else if (strcmp(cmd, "?") == 0) - slashUsage(pset); + slashUsage(); #ifdef NOT_USED @@ -748,7 +768,7 @@ exec_command(const char *cmd, * The return value is malloc()'ed. */ static char * -unescape(const char *source, PsqlSettings *pset) +unescape(const char *source) { unsigned char *p; bool esc = false; /* Last character we saw was the escape @@ -831,8 +851,9 @@ unescape(const char *source, PsqlSettings *pset) len = strcspn(p + 2, "}"); copy = xstrdup(p + 2); copy[len] = '\0'; - value = interpolate_var(copy, pset); - + value = GetVariable(pset.vars, copy); + if (!value) + value = ""; length += strlen(value) - (len + 3); new = realloc(destination, length); if (!new) @@ -871,40 +892,42 @@ unescape(const char *source, PsqlSettings *pset) * * Connects to a database (new_dbname) as a certain user (new_user). * The new user can be NULL. A db name of "-" is the same as the old one. - * (That is, the one currently in pset. But pset->db can also be NULL. A NULL + * (That is, the one currently in pset. But pset.db can also be NULL. A NULL * dbname is handled by libpq.) * Returns true if all ok, false if the new connection couldn't be established * but the old one was set back. Otherwise it terminates the program. */ static bool -do_connect(const char *new_dbname, const char *new_user, PsqlSettings *pset) +do_connect(const char *new_dbname, const char *new_user) { - PGconn *oldconn = pset->db; + PGconn *oldconn = pset.db; const char *dbparam = NULL; const char *userparam = NULL; const char *pwparam = NULL; char *prompted_password = NULL; - char *prompted_user = NULL; bool need_pass; bool success = false; + /* Delete variables (in case we fail before setting them anew) */ + SetVariable(pset.vars, "DBNAME", NULL); + SetVariable(pset.vars, "USER", NULL); + SetVariable(pset.vars, "HOST", NULL); + SetVariable(pset.vars, "PORT", NULL); + /* If dbname is "-" then use old name, else new one (even if NULL) */ - if (new_dbname && PQdb(oldconn) && (strcmp(new_dbname, "-") == 0 || strcmp(new_dbname, PQdb(oldconn)) == 0)) + if (oldconn && new_dbname && PQdb(oldconn) && strcmp(new_dbname, "-") == 0) dbparam = PQdb(oldconn); else dbparam = new_dbname; - /* If user is "" or "-" then use the old one */ - if (new_user && PQuser(oldconn) && (strcmp(new_user, "") == 0 || strcmp(new_user, "-") == 0 || strcmp(new_user, PQuser(oldconn)) == 0)) + /* If user is "" then use the old one */ + if (new_user && PQuser(oldconn) && strcmp(new_user, "")==0) userparam = PQuser(oldconn); - /* If username is "?" then prompt */ - else if (new_user && strcmp(new_user, "?") == 0) - userparam = prompted_user = simple_prompt("Username: ", 100, true); /* save for free() */ else userparam = new_user; /* need to prompt for password? */ - if (pset->getPassword) + if (pset.getPassword) pwparam = prompted_password = simple_prompt("Password: ", 100, false); /* need to save for * free() */ @@ -912,7 +935,7 @@ do_connect(const char *new_dbname, const char *new_user, PsqlSettings *pset) * Use old password if no new one given (if you didn't have an old * one, fine) */ - if (!pwparam) + if (!pwparam && oldconn) pwparam = PQpass(oldconn); @@ -925,18 +948,18 @@ do_connect(const char *new_dbname, const char *new_user, PsqlSettings *pset) * the default PGCLIENTENCODING value. -- 1998/12/12 Tatsuo Ishii */ - if (!pset->has_client_encoding) + if (!pset.has_client_encoding) putenv("PGCLIENTENCODING="); #endif do { need_pass = false; - pset->db = PQsetdbLogin(PQhost(oldconn), PQport(oldconn), + pset.db = PQsetdbLogin(PQhost(oldconn), PQport(oldconn), NULL, NULL, dbparam, userparam, pwparam); - if (PQstatus(pset->db) == CONNECTION_BAD && - strcmp(PQerrorMessage(pset->db), "fe_sendauth: no password supplied\n") == 0) + if (PQstatus(pset.db) == CONNECTION_BAD && + strcmp(PQerrorMessage(pset.db), "fe_sendauth: no password supplied\n") == 0) { need_pass = true; free(prompted_password); @@ -946,40 +969,39 @@ do_connect(const char *new_dbname, const char *new_user, PsqlSettings *pset) } while (need_pass); free(prompted_password); - free(prompted_user); /* * If connection failed, try at least keep the old one. That's * probably more convenient than just kicking you out of the program. */ - if (!pset->db || PQstatus(pset->db) == CONNECTION_BAD) + if (!pset.db || PQstatus(pset.db) == CONNECTION_BAD) { - if (pset->cur_cmd_interactive) + if (pset.cur_cmd_interactive) { - fprintf(stderr, "\\connect: %s", PQerrorMessage(pset->db)); - PQfinish(pset->db); + fprintf(stderr, "%s", PQerrorMessage(pset.db)); + PQfinish(pset.db); if (oldconn) { fputs("Previous connection kept\n", stderr); - pset->db = oldconn; + pset.db = oldconn; } else - pset->db = NULL; + 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); + fprintf(stderr, "%s: \\connect: %s", pset.progname, PQerrorMessage(pset.db)); + PQfinish(pset.db); if (oldconn) PQfinish(oldconn); - pset->db = NULL; + pset.db = NULL; } } else { - if (!GetVariable(pset->vars, "quiet")) + if (!QUIET()) { if (userparam != new_user) /* no new user */ printf("You are now connected to database %s.\n", dbparam); @@ -987,7 +1009,7 @@ do_connect(const char *new_dbname, const char *new_user, PsqlSettings *pset) printf("You are now connected as new user %s.\n", new_user); else /* both new */ printf("You are now connected to database %s as user %s.\n", - PQdb(pset->db), PQuser(pset->db)); + PQdb(pset.db), PQuser(pset.db)); } if (oldconn) @@ -996,6 +1018,12 @@ do_connect(const char *new_dbname, const char *new_user, PsqlSettings *pset) success = true; } + /* Update variables */ + SetVariable(pset.vars, "DBNAME", PQdb(pset.db)); + SetVariable(pset.vars, "USER", PQuser(pset.db)); + SetVariable(pset.vars, "HOST", PQhost(pset.db)); + SetVariable(pset.vars, "PORT", PQport(pset.db)); + return success; } @@ -1191,7 +1219,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, PsqlSettings *pset) +process_file(const char *filename) { FILE *fd; int result; @@ -1207,11 +1235,13 @@ process_file(const char *filename, PsqlSettings *pset) if (!fd) { + if (!pset.cur_cmd_interactive) + fprintf(stderr, "%s: ", pset.progname); perror(filename); return false; } - result = MainLoop(pset, fd); + result = MainLoop(fd); fclose(fd); return (result == EXIT_SUCCESS); } diff --git a/src/bin/psql/command.h b/src/bin/psql/command.h index 029937e3371..a8cc220e7c9 100644 --- a/src/bin/psql/command.h +++ b/src/bin/psql/command.h @@ -24,19 +24,18 @@ typedef enum _backslashResult -backslashResult HandleSlashCmds(PsqlSettings *pset, - const char *line, +backslashResult +HandleSlashCmds(const char *line, PQExpBuffer query_buf, const char **end_of_cmd); -bool process_file(const char *filename, - PsqlSettings *pset); +bool +process_file(const char *filename); - -bool do_pset(const char *param, +bool +do_pset(const char *param, const char *value, printQueryOpt * popt, bool quiet); - #endif diff --git a/src/bin/psql/common.c b/src/bin/psql/common.c index 584a8bf1c26..8133faa467a 100644 --- a/src/bin/psql/common.c +++ b/src/bin/psql/common.c @@ -1,7 +1,7 @@ -#include <config.h> #include <c.h> #include "common.h" +#include <errno.h> #include <stdlib.h> #include <stdio.h> #include <string.h> @@ -12,7 +12,6 @@ #include <strdup.h> #endif #include <signal.h> -#include <assert.h> #ifndef WIN32 #include <unistd.h> /* for write() */ #else @@ -73,64 +72,46 @@ xstrdup(const char *string) * Upon failure, sets stdout and returns false. */ bool -setQFout(const char *fname, PsqlSettings *pset) +setQFout(const char *fname) { bool status = true; -#ifdef USE_ASSERT_CHECKING - assert(pset); -#else - if (!pset) - return false; -#endif - /* Close old file/pipe */ - if (pset->queryFout && pset->queryFout != stdout && pset->queryFout != stderr) + if (pset.queryFout && pset.queryFout != stdout && pset.queryFout != stderr) { - if (pset->queryFoutPipe) - pclose(pset->queryFout); + if (pset.queryFoutPipe) + pclose(pset.queryFout); else - fclose(pset->queryFout); + fclose(pset.queryFout); } /* If no filename, set stdout */ if (!fname || fname[0] == '\0') { - pset->queryFout = stdout; - pset->queryFoutPipe = false; + pset.queryFout = stdout; + pset.queryFoutPipe = false; } else if (*fname == '|') { - const char *pipename = fname + 1; - - -#ifndef __CYGWIN32__ - pset->queryFout = popen(pipename, "w"); -#else - pset->queryFout = popen(pipename, "wb"); -#endif - pset->queryFoutPipe = true; + pset.queryFout = popen(fname + 1, "w"); + pset.queryFoutPipe = true; } else { -#ifndef __CYGWIN32__ - pset->queryFout = fopen(fname, "w"); -#else - pset->queryFout = fopen(fname, "wb"); -#endif - pset->queryFoutPipe = false; + pset.queryFout = fopen(fname, "w"); + pset.queryFoutPipe = false; } - if (!pset->queryFout) + if (!(pset.queryFout)) { - perror(fname); - pset->queryFout = stdout; - pset->queryFoutPipe = false; + fprintf(stderr, "%s: %s: %s\n", pset.progname, fname, strerror(errno)); + pset.queryFout = stdout; + pset.queryFoutPipe = false; status = false; } /* Direct signals */ - if (pset->queryFoutPipe) + if (pset.queryFoutPipe) pqsignal(SIGPIPE, SIG_IGN); else pqsignal(SIGPIPE, SIG_DFL); @@ -212,93 +193,6 @@ simple_prompt(const char *prompt, int maxlen, bool echo) /* - * interpolate_var() - * - * The idea here is that certain variables have a "magic" meaning, such as - * LastOid. However, you can assign to those variables, but that will shadow - * the magic meaning, until you unset it. If nothing matches, the value of - * the environment variable is used. - * - * This function only returns NULL if you feed in NULL's (don't do that). - * Otherwise, the return value is ready for immediate consumption. - */ -const char * -interpolate_var(const char *name, PsqlSettings *pset) -{ - const char *var; - -#ifdef USE_ASSERT_CHECKING - assert(name); - assert(pset); -#else - if (!name || !pset) - return NULL; -#endif - - var = GetVariable(pset->vars, name); - if (var) - return var; - - /* otherwise return magic variable */ - - /* - * (by convention these should be capitalized (but not all caps), to - * not be shadowed by regular vars or to shadow env vars) - */ - if (strcmp(name, "Version") == 0) - return PG_VERSION_STR; - - if (strcmp(name, "Database") == 0) - { - if (PQdb(pset->db)) - return PQdb(pset->db); - else - return ""; - } - - if (strcmp(name, "User") == 0) - { - if (PQuser(pset->db)) - return PQuser(pset->db); - else - return ""; - } - - if (strcmp(name, "Host") == 0) - { - if (PQhost(pset->db)) - return PQhost(pset->db); - else - return ""; - } - - if (strcmp(name, "Port") == 0) - { - if (PQport(pset->db)) - return PQport(pset->db); - else - return ""; - } - - if (strcmp(name, "LastOid") == 0) - { - static char buf[24]; - if (pset->lastOid == InvalidOid) - return ""; - sprintf(buf, "%u", pset->lastOid); - return buf; - } - - /* env vars */ - if ((var = getenv(name))) - return var; - - return ""; -} - - - -/* * Code to support query cancellation * * Before we start a query, we enable a SIGINT signal catcher that sends a @@ -333,21 +227,21 @@ handle_sigint(SIGNAL_ARGS) * PSQLexec * * This is the way to send "backdoor" queries (those not directly entered - * by the user). It is subject to -E (echo_secret) but not -e (echo). + * by the user). It is subject to -E but not -e. */ PGresult * -PSQLexec(PsqlSettings *pset, const char *query) +PSQLexec(const char *query) { PGresult *res; const char *var; - if (!pset->db) + if (!pset.db) { fputs("You are currently not connected to a database.\n", stderr); return NULL; } - var = GetVariable(pset->vars, "echo_secret"); + var = GetVariable(pset.vars, "ECHO_HIDDEN"); if (var) { printf("********* QUERY *********\n%s\n*************************\n\n", query); @@ -357,50 +251,50 @@ PSQLexec(PsqlSettings *pset, const char *query) if (var && strcmp(var, "noexec") == 0) return NULL; - cancelConn = pset->db; + cancelConn = pset.db; pqsignal(SIGINT, handle_sigint); /* control-C => cancel */ - res = PQexec(pset->db, query); + res = PQexec(pset.db, query); pqsignal(SIGINT, SIG_DFL); /* now control-C is back to normal */ - if (PQstatus(pset->db) == CONNECTION_OK) + if (PQstatus(pset.db) == CONNECTION_BAD) { - if (res && (PQresultStatus(res) == PGRES_COMMAND_OK || - PQresultStatus(res) == PGRES_TUPLES_OK || - PQresultStatus(res) == PGRES_COPY_IN || - PQresultStatus(res) == PGRES_COPY_OUT) - ) - return res; /* Normal success case... */ - /* Normal failure case --- display error and return NULL */ - fputs(PQerrorMessage(pset->db), pset->queryFout); - PQclear(res); - return NULL; + 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) + { + fputs("Failed.\n", stderr); + PQfinish(pset.db); + PQclear(res); + pset.db = NULL; + SetVariable(pset.vars, "DBNAME", NULL); + SetVariable(pset.vars, "HOST", NULL); + SetVariable(pset.vars, "PORT", NULL); + SetVariable(pset.vars, "USER", NULL); + return NULL; + } + else + fputs("Succeeded.\n", stderr); } - /* Lost connection. Report whatever libpq has to say, - * then consider recovery. - */ - fputs(PQerrorMessage(pset->db), pset->queryFout); - PQclear(res); - if (!pset->cur_cmd_interactive) - { - fprintf(stderr, "%s: connection to server was lost\n", - pset->progname); - exit(EXIT_BADCONN); - } - fputs("The connection to the server was lost. Attempting reset: ", stderr); - fflush(stderr); - PQreset(pset->db); - if (PQstatus(pset->db) == CONNECTION_BAD) + if (res && (PQresultStatus(res) == PGRES_COMMAND_OK || + PQresultStatus(res) == PGRES_TUPLES_OK || + PQresultStatus(res) == PGRES_COPY_IN || + PQresultStatus(res) == PGRES_COPY_OUT) + ) + return res; + else { - fputs("Failed.\n", stderr); - PQfinish(pset->db); - pset->db = NULL; + fputs(PQerrorMessage(pset.db), stderr); + PQclear(res); + return NULL; } - else - fputs("Succeeded.\n", stderr); - return NULL; } @@ -418,19 +312,19 @@ PSQLexec(PsqlSettings *pset, const char *query) * Returns true if the query executed successfully, false otherwise. */ bool -SendQuery(PsqlSettings *pset, const char *query) +SendQuery(const char *query) { bool success = false; PGresult *results; PGnotify *notify; - if (!pset->db) + if (!pset.db) { fputs("You are currently not connected to a database.\n", stderr); return false; } - if (GetVariableBool(pset->vars, "singlestep")) + if (GetVariableBool(pset.vars, "SINGLESTEP")) { char buf[3]; @@ -443,17 +337,23 @@ SendQuery(PsqlSettings *pset, const char *query) if (buf[0] == 'x') return false; } + else + { + const char * var = GetVariable(pset.vars, "ECHO"); + if (var && strcmp(var, "brief")==0) + puts(query); + } - cancelConn = pset->db; + cancelConn = pset.db; pqsignal(SIGINT, handle_sigint); - results = PQexec(pset->db, query); + results = PQexec(pset.db, query); pqsignal(SIGINT, SIG_DFL); if (results == NULL) { - fputs(PQerrorMessage(pset->db), pset->queryFout); + fputs(PQerrorMessage(pset.db), pset.queryFout); success = false; } else @@ -461,24 +361,30 @@ SendQuery(PsqlSettings *pset, const char *query) switch (PQresultStatus(results)) { case PGRES_TUPLES_OK: - if (pset->gfname) + /* write output to \g argument, if any */ + if (pset.gfname) { - PsqlSettings settings_copy = *pset; + FILE * queryFout_copy = pset.queryFout; + bool queryFoutPipe_copy = pset.queryFoutPipe; + pset.queryFout = NULL; /* so it doesn't get closed */ - settings_copy.queryFout = stdout; - if (!setQFout(pset->gfname, &settings_copy)) + /* open file/pipe */ + if (!setQFout(pset.gfname)) { success = false; break; } - printQuery(results, &settings_copy.popt, settings_copy.queryFout); + printQuery(results, &pset.popt, pset.queryFout); /* close file/pipe */ - setQFout(NULL, &settings_copy); + setQFout(NULL); - free(pset->gfname); - pset->gfname = NULL; + free(pset.gfname); + pset.gfname = NULL; + + pset.queryFout = queryFout_copy; + pset.queryFoutPipe = queryFoutPipe_copy; success = true; break; @@ -486,77 +392,83 @@ SendQuery(PsqlSettings *pset, const char *query) else { success = true; - printQuery(results, &pset->popt, pset->queryFout); + printQuery(results, &pset.popt, pset.queryFout); } break; case PGRES_EMPTY_QUERY: success = true; break; case PGRES_COMMAND_OK: + { + char buf[10]; + success = true; - pset->lastOid = PQoidValue(results); - if (!GetVariableBool(pset->vars, "quiet")) - fprintf(pset->queryFout, "%s\n", PQcmdStatus(results)); + sprintf(buf, "%u", (unsigned int)PQoidValue(results)); + if (!QUIET()) + fprintf(pset.queryFout, "%s\n", PQcmdStatus(results)); + SetVariable(pset.vars, "LASTOID", buf); break; - + } case PGRES_COPY_OUT: - success = handleCopyOut(pset->db, pset->queryFout); + success = handleCopyOut(pset.db, pset.queryFout); break; case PGRES_COPY_IN: - if (pset->cur_cmd_interactive && !GetVariable(pset->vars, "quiet")) + if (pset.cur_cmd_interactive && !QUIET()) puts("Enter data to be copied followed by a newline.\n" "End with a backslash and a period on a line by itself."); - success = handleCopyIn(pset->db, pset->cur_cmd_source, - pset->cur_cmd_interactive ? get_prompt(pset, PROMPT_COPY) : NULL); + success = handleCopyIn(pset.db, pset.cur_cmd_source, + pset.cur_cmd_interactive ? get_prompt(PROMPT_COPY) : NULL); break; case PGRES_NONFATAL_ERROR: case PGRES_FATAL_ERROR: case PGRES_BAD_RESPONSE: success = false; - fputs(PQerrorMessage(pset->db), stderr); + fputs(PQerrorMessage(pset.db), stderr); break; } - fflush(pset->queryFout); + fflush(pset.queryFout); - if (PQstatus(pset->db) == CONNECTION_BAD) + if (PQstatus(pset.db) == CONNECTION_BAD) { - if (!pset->cur_cmd_interactive) + if (!pset.cur_cmd_interactive) { - fprintf(stderr, "%s: connection to server was lost\n", - pset->progname); + fprintf(stderr, "%s: connection to server was lost", pset.progname); exit(EXIT_BADCONN); } fputs("The connection to the server was lost. Attempting reset: ", stderr); - fflush(stderr); - PQreset(pset->db); - if (PQstatus(pset->db) == CONNECTION_BAD) + PQreset(pset.db); + if (PQstatus(pset.db) == CONNECTION_BAD) { fputs("Failed.\n", stderr); - PQfinish(pset->db); - pset->db = NULL; + PQfinish(pset.db); PQclear(results); + pset.db = NULL; + SetVariable(pset.vars, "DBNAME", NULL); + SetVariable(pset.vars, "HOST", NULL); + SetVariable(pset.vars, "PORT", NULL); + SetVariable(pset.vars, "USER", NULL); return false; } else fputs("Succeeded.\n", stderr); } - + /* check for asynchronous notification returns */ - while ((notify = PQnotifies(pset->db)) != NULL) + while ((notify = PQnotifies(pset.db)) != NULL) { - fprintf(pset->queryFout, "Asynchronous NOTIFY '%s' from backend with pid '%d' received.\n", + fprintf(pset.queryFout, "Asynchronous NOTIFY '%s' from backend with pid '%d' received.\n", notify->relname, notify->be_pid); free(notify); - fflush(pset->queryFout); + fflush(pset.queryFout); } if (results) PQclear(results); - } + } return success; } diff --git a/src/bin/psql/common.h b/src/bin/psql/common.h index e3924e9d92d..7d285d01ccd 100644 --- a/src/bin/psql/common.h +++ b/src/bin/psql/common.h @@ -8,18 +8,15 @@ char * xstrdup(const char *string); bool - setQFout(const char *fname, PsqlSettings *pset); + setQFout(const char *fname); char * simple_prompt(const char *prompt, int maxlen, bool echo); -const char * - interpolate_var(const char *name, PsqlSettings *pset); - PGresult * - PSQLexec(PsqlSettings *pset, const char *query); + PSQLexec(const char *query); bool - SendQuery(PsqlSettings *pset, const char *query); + SendQuery(const char *query); #endif /* COMMON_H */ diff --git a/src/bin/psql/copy.c b/src/bin/psql/copy.c index 800a8f41eda..66449873346 100644 --- a/src/bin/psql/copy.c +++ b/src/bin/psql/copy.c @@ -1,4 +1,3 @@ -#include <config.h> #include <c.h> #include "copy.h" @@ -36,7 +35,7 @@ struct copy_options { char *table; - char *file; + char *file; /* NULL = stdin/stdout */ bool from; bool binary; bool oids; @@ -59,7 +58,7 @@ free_copy_options(struct copy_options * ptr) static struct copy_options * -parse_slash_copy(const char *args, PsqlSettings *pset) +parse_slash_copy(const char *args) { struct copy_options *result; char *line; @@ -132,17 +131,15 @@ parse_slash_copy(const char *args, PsqlSettings *pset) if (!error) { - token = strtokx(NULL, " \t", "'", '\\', NULL, NULL); + token = strtokx(NULL, " \t", "'", '\\', "e, NULL); if (!token) error = true; - else + else if (!quote && (strcasecmp(token, "stdin")==0 || strcasecmp(token, "stdout")==0)) + result->file = NULL; + else result->file = xstrdup(token); } -#ifdef USE_ASSERT_CHECKING - assert(error || result->file); -#endif - if (!error) { token = strtokx(NULL, " \t", NULL, '\\', NULL, NULL); @@ -194,8 +191,8 @@ parse_slash_copy(const char *args, PsqlSettings *pset) if (error) { - if (!pset->cur_cmd_interactive) - fprintf(stderr, "%s: ", pset->progname); + if (!pset.cur_cmd_interactive) + fprintf(stderr, "%s: ", pset.progname); fputs("\\copy: parse error at ", stderr); if (!token) fputs("end of line", stderr); @@ -217,7 +214,7 @@ parse_slash_copy(const char *args, PsqlSettings *pset) * file or route its response into the file. */ bool -do_copy(const char *args, PsqlSettings *pset) +do_copy(const char *args) { char query[128 + NAMEDATALEN]; FILE *copystream; @@ -226,7 +223,7 @@ do_copy(const char *args, PsqlSettings *pset) bool success; /* parse options */ - options = parse_slash_copy(args, pset); + options = parse_slash_copy(args); if (!options) return false; @@ -242,9 +239,9 @@ do_copy(const char *args, PsqlSettings *pset) strcat(query, "WITH OIDS "); if (options->from) - strcat(query, "FROM stdin"); + strcat(query, "FROM STDIN"); else - strcat(query, "TO stdout"); + strcat(query, "TO STDOUT"); if (options->delim) @@ -254,24 +251,32 @@ do_copy(const char *args, PsqlSettings *pset) strcat(query, "'"); } + if (options->null) + { + strcat(query, " WITH NULL AS '"); + strcat(query, options->null); + strcat(query, "'"); + } if (options->from) -#ifndef __CYGWIN32__ - copystream = fopen(options->file, "r"); -#else - copystream = fopen(options->file, "rb"); -#endif + { + if (options->file) + copystream = fopen(options->file, "r"); + else + copystream = stdin; + } else -#ifndef __CYGWIN32__ - copystream = fopen(options->file, "w"); -#else - copystream = fopen(options->file, "wb"); -#endif + { + if (options->file) + copystream = fopen(options->file, "w"); + else + copystream = stdout; + } if (!copystream) { - if (!pset->cur_cmd_interactive) - fprintf(stderr, "%s: ", pset->progname); + if (!pset.cur_cmd_interactive) + fprintf(stderr, "%s: ", pset.progname); fprintf(stderr, "unable to open file %s: %s\n", options->file, strerror(errno)); @@ -279,40 +284,40 @@ do_copy(const char *args, PsqlSettings *pset) return false; } - result = PSQLexec(pset, query); + result = PSQLexec(query); switch (PQresultStatus(result)) { case PGRES_COPY_OUT: - success = handleCopyOut(pset->db, copystream); + success = handleCopyOut(pset.db, copystream); break; case PGRES_COPY_IN: - success = handleCopyIn(pset->db, copystream, NULL); + success = handleCopyIn(pset.db, copystream, NULL); break; case PGRES_NONFATAL_ERROR: case PGRES_FATAL_ERROR: case PGRES_BAD_RESPONSE: success = false; - fputs(PQerrorMessage(pset->db), stderr); + fputs(PQerrorMessage(pset.db), stderr); break; default: success = false; - if (!pset->cur_cmd_interactive) - fprintf(stderr, "%s: ", pset->progname); + if (!pset.cur_cmd_interactive) + fprintf(stderr, "%s: ", pset.progname); fprintf(stderr, "\\copy: unexpected response (%d)\n", PQresultStatus(result)); } PQclear(result); - if (!GetVariable(pset->vars, "quiet")) + if (!success) { - if (success) - puts("Successfully copied"); - else - puts("Copy failed"); + if (!pset.cur_cmd_interactive) + fprintf(stderr, "%s: ", pset.progname); + fprintf(stderr, "\\copy failed\n"); } - fclose(copystream); + if (copystream != stdout && copystream != stdin) + fclose(copystream); free_copy_options(options); return success; } @@ -396,7 +401,7 @@ handleCopyIn(PGconn *conn, FILE *copystream, const char *prompt) while (!copydone) { /* for each input line ... */ - if (prompt && isatty(fileno(stdin))) + if (prompt && isatty(fileno(copystream))) { fputs(prompt, stdout); fflush(stdout); diff --git a/src/bin/psql/copy.h b/src/bin/psql/copy.h index 6e01c5457d1..840fb27fe12 100644 --- a/src/bin/psql/copy.h +++ b/src/bin/psql/copy.h @@ -8,7 +8,7 @@ /* handler for \copy */ bool - do_copy(const char *args, PsqlSettings *pset); + do_copy(const char *args); /* lower level processors for copy in/out streams */ diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c index f4ac7f1bcd3..1d544837546 100644 --- a/src/bin/psql/describe.c +++ b/src/bin/psql/describe.c @@ -31,11 +31,11 @@ * takes an optional regexp to match specific aggregates by name */ bool -describeAggregates(const char *name, PsqlSettings *pset) +describeAggregates(const char *name) { char buf[384 + 2 * REGEXP_CUTOFF]; PGresult *res; - printQueryOpt myopt = pset->popt; + printQueryOpt myopt = pset.popt; /* * There are two kinds of aggregates: ones that work on particular @@ -72,14 +72,14 @@ describeAggregates(const char *name, PsqlSettings *pset) strcat(buf, "ORDER BY \"Name\", \"Type\""); - res = PSQLexec(pset, buf); + res = PSQLexec(buf); if (!res) return false; myopt.nullPrint = NULL; myopt.title = "List of aggregates"; - printQuery(res, &myopt, pset->queryFout); + printQuery(res, &myopt, pset.queryFout); PQclear(res); return true; @@ -90,11 +90,11 @@ describeAggregates(const char *name, PsqlSettings *pset) * Takes an optional regexp to narrow down the function name */ bool -describeFunctions(const char *name, PsqlSettings *pset, bool verbose) +describeFunctions(const char *name, bool verbose) { char buf[384 + REGEXP_CUTOFF]; PGresult *res; - printQueryOpt myopt = pset->popt; + printQueryOpt myopt = pset.popt; /* * we skip in/out funcs by excluding functions that take some @@ -125,14 +125,14 @@ describeFunctions(const char *name, PsqlSettings *pset, bool verbose) } strcat(buf, "ORDER BY \"Function\", \"Result\", \"Arguments\""); - res = PSQLexec(pset, buf); + res = PSQLexec(buf); if (!res) return false; myopt.nullPrint = NULL; myopt.title = "List of functions"; - printQuery(res, &myopt, pset->queryFout); + printQuery(res, &myopt, pset.queryFout); PQclear(res); return true; @@ -145,11 +145,11 @@ describeFunctions(const char *name, PsqlSettings *pset, bool verbose) * describe types */ bool -describeTypes(const char *name, PsqlSettings *pset, bool verbose) +describeTypes(const char *name, bool verbose) { char buf[256 + REGEXP_CUTOFF]; PGresult *res; - printQueryOpt myopt = pset->popt; + printQueryOpt myopt = pset.popt; strcpy(buf, "SELECT t.typname AS \"Type\""); if (verbose) @@ -169,14 +169,14 @@ describeTypes(const char *name, PsqlSettings *pset, bool verbose) } strcat(buf, "ORDER BY t.typname;"); - res = PSQLexec(pset, buf); + res = PSQLexec(buf); if (!res) return false; myopt.nullPrint = NULL; myopt.title = "List of types"; - printQuery(res, &myopt, pset->queryFout); + printQuery(res, &myopt, pset.queryFout); PQclear(res); return true; @@ -187,11 +187,11 @@ describeTypes(const char *name, PsqlSettings *pset, bool verbose) /* \do */ bool -describeOperators(const char *name, PsqlSettings *pset) +describeOperators(const char *name) { char buf[1536 + 3 * REGEXP_CUTOFF]; PGresult *res; - printQueryOpt myopt = pset->popt; + printQueryOpt myopt = pset.popt; strcpy(buf, "SELECT o.oprname AS \"Op\",\n" @@ -251,14 +251,14 @@ describeOperators(const char *name, PsqlSettings *pset) } strcat(buf, "\nORDER BY \"Op\", \"Left arg\", \"Right arg\", \"Result\""); - res = PSQLexec(pset, buf); + res = PSQLexec(buf); if (!res) return false; myopt.nullPrint = NULL; myopt.title = "List of operators"; - printQuery(res, &myopt, pset->queryFout); + printQuery(res, &myopt, pset.queryFout); PQclear(res); return true; @@ -271,11 +271,11 @@ describeOperators(const char *name, PsqlSettings *pset) * for \l, \list, and -l switch */ bool -listAllDbs(PsqlSettings *pset, bool desc) +listAllDbs(bool desc) { PGresult *res; char buf[512]; - printQueryOpt myopt = pset->popt; + printQueryOpt myopt = pset.popt; strcpy(buf, "SELECT pg_database.datname as \"Database\",\n" @@ -306,14 +306,14 @@ listAllDbs(PsqlSettings *pset, bool desc) strcat(buf, "ORDER BY \"Database\""); - res = PSQLexec(pset, buf); + res = PSQLexec(buf); if (!res) return false; myopt.nullPrint = NULL; myopt.title = "List of databases"; - printQuery(res, &myopt, pset->queryFout); + printQuery(res, &myopt, pset.queryFout); PQclear(res); return true; @@ -325,11 +325,11 @@ listAllDbs(PsqlSettings *pset, bool desc) * */ bool -permissionsList(const char *name, PsqlSettings *pset) +permissionsList(const char *name) { char descbuf[256 + REGEXP_CUTOFF]; PGresult *res; - printQueryOpt myopt = pset->popt; + printQueryOpt myopt = pset.popt; descbuf[0] = '\0'; /* Currently, we ignore indexes since they have no meaningful rights */ @@ -346,15 +346,15 @@ permissionsList(const char *name, PsqlSettings *pset) } strcat(descbuf, "ORDER BY relname"); - res = PSQLexec(pset, descbuf); + res = PSQLexec(descbuf); if (!res) return false; myopt.nullPrint = NULL; - sprintf(descbuf, "Access permissions for database \"%s\"", PQdb(pset->db)); + 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; @@ -371,11 +371,11 @@ permissionsList(const char *name, PsqlSettings *pset) * lists of things, there are other \d? commands. */ bool -objectDescription(const char *object, PsqlSettings *pset) +objectDescription(const char *object) { char descbuf[2048 + 7 * REGEXP_CUTOFF]; PGresult *res; - printQueryOpt myopt = pset->popt; + printQueryOpt myopt = pset.popt; descbuf[0] = '\0'; @@ -466,7 +466,7 @@ objectDescription(const char *object, PsqlSettings *pset) strcat(descbuf, "\nORDER BY \"Name\""); - res = PSQLexec(pset, descbuf); + res = PSQLexec(descbuf); if (!res) return false; @@ -474,7 +474,7 @@ objectDescription(const char *object, PsqlSettings *pset) myopt.nullPrint = NULL; myopt.title = "Object descriptions"; - printQuery(res, &myopt, pset->queryFout); + printQuery(res, &myopt, pset.queryFout); PQclear(res); return true; @@ -507,11 +507,11 @@ xmalloc(size_t size) bool -describeTableDetails(const char *name, PsqlSettings *pset, bool desc) +describeTableDetails(const char *name, bool desc) { char buf[512 + INDEX_MAX_KEYS * NAMEDATALEN]; PGresult *res = NULL; - printTableOpt myopt = pset->popt.topt; + printTableOpt myopt = pset.popt.topt; int i; const char *view_def = NULL; const char *headers[5]; @@ -536,14 +536,14 @@ describeTableDetails(const char *name, PsqlSettings *pset, bool desc) "SELECT relhasindex, relkind, relchecks, reltriggers, relhasrules\n" "FROM pg_class WHERE relname='%s'", name); - res = PSQLexec(pset, buf); + res = PSQLexec(buf); if (!res) return false; /* Did we get anything? */ if (PQntuples(res) == 0) { - if (!GetVariableBool(pset->vars, "quiet")) + if (!QUIET()) fprintf(stderr, "Did not find any relation named \"%s\".\n", name); PQclear(res); return false; @@ -587,7 +587,7 @@ describeTableDetails(const char *name, PsqlSettings *pset, bool desc) strcat(buf, "'\n AND a.attnum > 0 AND a.attrelid = c.oid AND a.atttypid = t.oid\n" "ORDER BY a.attnum"); - res = PSQLexec(pset, buf); + res = PSQLexec(buf); if (!res) return false; @@ -595,7 +595,7 @@ describeTableDetails(const char *name, PsqlSettings *pset, bool desc) if (tableinfo.hasrules) { PGresult *result; sprintf(buf, "SELECT definition FROM pg_views WHERE viewname = '%s'", name); - result = PSQLexec(pset, buf); + result = PSQLexec(buf); if (!result) { PQclear(res); @@ -655,7 +655,7 @@ describeTableDetails(const char *name, PsqlSettings *pset, bool desc) "WHERE c.relname = '%s' AND c.oid = d.adrelid AND d.adnum = %s", name, PQgetvalue(res, i, 6)); - result = PSQLexec(pset, buf); + result = PSQLexec(buf); if (!result) error = true; else @@ -710,7 +710,7 @@ describeTableDetails(const char *name, PsqlSettings *pset, bool desc) "WHERE i.indexrelid = c.oid AND c.relname = '%s' AND c.relam = a.oid", name); - result = PSQLexec(pset, buf); + result = PSQLexec(buf); if (!result) error = true; else @@ -750,7 +750,7 @@ describeTableDetails(const char *name, PsqlSettings *pset, bool desc) "WHERE c.relname = '%s' AND c.oid = i.indrelid AND i.indexrelid = c2.oid\n" "ORDER BY c2.relname", name); - result1 = PSQLexec(pset, buf); + result1 = PSQLexec(buf); if (!result1) error = true; else @@ -764,7 +764,7 @@ describeTableDetails(const char *name, PsqlSettings *pset, bool desc) "FROM pg_relcheck r, pg_class c\n" "WHERE c.relname='%s' AND c.oid = r.rcrelid", name); - result2 = PSQLexec(pset, buf); + result2 = PSQLexec(buf); if (!result2) error = true; else @@ -779,7 +779,7 @@ describeTableDetails(const char *name, PsqlSettings *pset, bool desc) "FROM pg_rewrite r, pg_class c\n" "WHERE c.relname='%s' AND c.oid = r.ev_class", name); - result3 = PSQLexec(pset, buf); + result3 = PSQLexec(buf); if (!result3) error = true; else @@ -794,7 +794,7 @@ describeTableDetails(const char *name, PsqlSettings *pset, bool desc) "FROM pg_trigger t, pg_class c\n" "WHERE c.relname='%s' AND c.oid = t.tgrelid", name); - result4 = PSQLexec(pset, buf); + result4 = PSQLexec(buf); if (!result4) error = true; else @@ -863,7 +863,7 @@ describeTableDetails(const char *name, PsqlSettings *pset, bool desc) if (!error) { myopt.tuples_only = false; - printTable(title, headers, (const char**)cells, (const char**)footers, "llll", &myopt, pset->queryFout); + printTable(title, headers, (const char**)cells, (const char**)footers, "llll", &myopt, pset.queryFout); } /* clean up */ @@ -906,7 +906,7 @@ describeTableDetails(const char *name, PsqlSettings *pset, bool desc) * 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) +listTables(const char *infotype, const char *name, bool desc) { bool showTables = strchr(infotype, 't') != NULL; bool showIndices = strchr(infotype, 'i') != NULL; @@ -916,7 +916,7 @@ listTables(const char *infotype, const char *name, PsqlSettings *pset, bool desc char buf[3072 + 8 * REGEXP_CUTOFF]; PGresult *res; - printQueryOpt myopt = pset->popt; + printQueryOpt myopt = pset.popt; buf[0] = '\0'; @@ -1093,20 +1093,24 @@ listTables(const char *infotype, const char *name, PsqlSettings *pset, bool desc strcat(buf, "\nORDER BY \"Name\""); - res = PSQLexec(pset, buf); + res = PSQLexec(buf); if (!res) return false; - if (PQntuples(res) == 0) - fprintf(pset->queryFout, "No matching relations found.\n"); - + if (PQntuples(res) == 0 && !QUIET()) + { + if (name) + fprintf(pset.queryFout, "No matching relations found.\n"); + else + fprintf(pset.queryFout, "No relations found.\n"); + } else { myopt.topt.tuples_only = false; myopt.nullPrint = NULL; myopt.title = "List of relations"; - printQuery(res, &myopt, pset->queryFout); + printQuery(res, &myopt, pset.queryFout); } PQclear(res); diff --git a/src/bin/psql/describe.h b/src/bin/psql/describe.h index 960942f52ff..834375b252f 100644 --- a/src/bin/psql/describe.h +++ b/src/bin/psql/describe.h @@ -5,30 +5,30 @@ #include "settings.h" /* \da */ -bool describeAggregates(const char *name, PsqlSettings *pset); +bool describeAggregates(const char *name); /* \df */ -bool describeFunctions(const char *name, PsqlSettings *pset, bool verbose); +bool describeFunctions(const char *name, bool verbose); /* \dT */ -bool describeTypes(const char *name, PsqlSettings *pset, bool verbose); +bool describeTypes(const char *name, bool verbose); /* \do */ -bool describeOperators(const char *name, PsqlSettings *pset); +bool describeOperators(const char *name); /* \z (or \dp) */ -bool permissionsList(const char *name, PsqlSettings *pset); +bool permissionsList(const char *name); /* \dd */ -bool objectDescription(const char *object, PsqlSettings *pset); +bool objectDescription(const char *object); /* \d foo */ -bool describeTableDetails(const char *name, PsqlSettings *pset, bool desc); +bool describeTableDetails(const char *name, bool desc); /* \l */ -bool listAllDbs(PsqlSettings *pset, bool desc); +bool listAllDbs(bool desc); /* \dt, \di, \ds, \dS, etc. */ -bool listTables(const char *infotype, const char *name, PsqlSettings *pset, bool desc); +bool listTables(const char *infotype, const char *name, bool desc); #endif /* DESCRIBE_H */ diff --git a/src/bin/psql/help.c b/src/bin/psql/help.c index c108743deb2..47fc0d8fc51 100644 --- a/src/bin/psql/help.c +++ b/src/bin/psql/help.c @@ -149,7 +149,7 @@ struct winsize #endif void -slashUsage(PsqlSettings *pset) +slashUsage(void) { bool usePipe = false; const char *pagerenv; @@ -157,7 +157,7 @@ slashUsage(PsqlSettings *pset) struct winsize screen_size; #ifdef TIOCGWINSZ - if (pset->notty == 0 && + if (pset.notty == 0 && (ioctl(fileno(stdout), TIOCGWINSZ, &screen_size) == -1 || screen_size.ws_col == 0 || screen_size.ws_row == 0)) @@ -169,7 +169,7 @@ slashUsage(PsqlSettings *pset) } #endif - if (pset->notty == 0 && + if (pset.notty == 0 && (pagerenv = getenv("PAGER")) && (pagerenv[0] != '\0') && screen_size.ws_row <= 36 && @@ -184,7 +184,7 @@ slashUsage(PsqlSettings *pset) /* if you add/remove a line here, change the row test above */ fprintf(fout, " \\? help\n"); fprintf(fout, " \\c[onnect] [dbname|- [user|?]]\n" - " connect to new database (currently '%s')\n", PQdb(pset->db)); + " 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"); @@ -209,9 +209,10 @@ slashUsage(PsqlSettings *pset) 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, " \\set <var> <value> set internal variable\n"); + fprintf(fout, " \\t don't show table headers or footers (currently %s)\n", ON(pset.popt.topt.tuples_only)); + fprintf(fout, " \\unset <var> unset (delete) internal variable\n"); + 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"); diff --git a/src/bin/psql/help.h b/src/bin/psql/help.h index 791e0313ca1..db709268568 100644 --- a/src/bin/psql/help.h +++ b/src/bin/psql/help.h @@ -5,7 +5,7 @@ void usage(void); -void slashUsage(PsqlSettings *pset); +void slashUsage(void); void helpSQL(const char *topic); diff --git a/src/bin/psql/input.c b/src/bin/psql/input.c index 1775dffb834..6607d7f162b 100644 --- a/src/bin/psql/input.c +++ b/src/bin/psql/input.c @@ -29,6 +29,10 @@ char * gets_interactive(const char *prompt) { char *s; +#ifdef USE_HISTORY + const char *var; + static char * prev_hist = NULL; +#endif #ifdef USE_READLINE if (useReadline) @@ -44,8 +48,19 @@ gets_interactive(const char *prompt) #endif #ifdef USE_HISTORY - if (useHistory && s && s[0] != '\0') - add_history(s); + if (useHistory && s && s[0] != '\0') + { + var = GetVariable(pset.vars, "HISTCONTROL"); + if (!var || (var + && !((strcmp(var, "ignorespace") == 0 || strcmp(var, "ignoreboth") ==0) && s[0] == ' ' ) + && !((strcmp(var, "ignoredups") == 0 || strcmp(var, "ignoreboth") ==0) && prev_hist && strcmp(s, prev_hist) == 0) + )) + { + free(prev_hist); + prev_hist = strdup(s); + add_history(s); + } + } #endif return s; @@ -93,14 +108,14 @@ gets_fromFile(FILE *source) * The only "flag" right now is 1 for use readline & history. */ void -initializeInput(int flags, PsqlSettings *pset) +initializeInput(int flags) { #ifdef USE_READLINE if (flags == 1) { useReadline = true; rl_readline_name = "psql"; - initialize_readline(&(pset->db)); + initialize_readline(&(pset.db)); } #endif @@ -110,6 +125,7 @@ initializeInput(int flags, PsqlSettings *pset) const char *home; useHistory = true; + SetVariable(pset.vars, "HISTSIZE", "500"); using_history(); home = getenv("HOME"); if (home) @@ -166,6 +182,9 @@ finishInput(void) psql_history = (char *) malloc(strlen(home) + 20); if (psql_history) { + const char * var = GetVariable(pset.vars, "HISTSIZE"); + if (var) + stifle_history(atoi(var)); sprintf(psql_history, "%s/.psql_history", home); write_history(psql_history); free(psql_history); diff --git a/src/bin/psql/input.h b/src/bin/psql/input.h index 938170ee83b..675953efb4e 100644 --- a/src/bin/psql/input.h +++ b/src/bin/psql/input.h @@ -42,7 +42,7 @@ char * gets_interactive(const char *prompt); char * gets_fromFile(FILE *source); -void initializeInput(int flags, PsqlSettings *pset); +void initializeInput(int flags); bool saveHistory(const char *fname); diff --git a/src/bin/psql/large_obj.c b/src/bin/psql/large_obj.c index befa4c452c3..d1b3af044f4 100644 --- a/src/bin/psql/large_obj.c +++ b/src/bin/psql/large_obj.c @@ -1,4 +1,3 @@ -#include <config.h> #include <c.h> #include "large_obj.h" @@ -33,9 +32,9 @@ _my_notice_handler(void *arg, const char *message) static bool -handle_transaction(PsqlSettings *pset) +handle_transaction(void) { - const char *var = GetVariable(pset->vars, "lo_transaction"); + const char *var = GetVariable(pset.vars, "LO_TRANSACTION"); PGresult *res; bool commit; PQnoticeProcessor old_notice_hook; @@ -46,9 +45,9 @@ handle_transaction(PsqlSettings *pset) commit = (var && strcmp(var, "commit") == 0); notice[0] = '\0'; - old_notice_hook = PQsetNoticeProcessor(pset->db, _my_notice_handler, NULL); + old_notice_hook = PQsetNoticeProcessor(pset.db, _my_notice_handler, NULL); - res = PSQLexec(pset, commit ? "COMMIT" : "ROLLBACK"); + res = PSQLexec(commit ? "COMMIT" : "ROLLBACK"); if (!res) return false; @@ -58,7 +57,7 @@ handle_transaction(PsqlSettings *pset) (commit && strcmp(notice, "NOTICE: EndTransactionBlock and not inprogress/abort state\n") != 0)) fputs(notice, stderr); } - else if (!GetVariableBool(pset->vars, "quiet")) + else if (!QUIET()) { if (commit) puts("Warning: Your transaction in progress has been committed."); @@ -66,7 +65,7 @@ handle_transaction(PsqlSettings *pset) puts("Warning: Your transaction in progress has been rolled back."); } - PQsetNoticeProcessor(pset->db, old_notice_hook, NULL); + PQsetNoticeProcessor(pset.db, old_notice_hook, NULL); return true; } @@ -78,43 +77,43 @@ handle_transaction(PsqlSettings *pset) * Write a large object to a file */ bool -do_lo_export(PsqlSettings *pset, const char *loid_arg, const char *filename_arg) +do_lo_export(const char *loid_arg, const char *filename_arg) { PGresult *res; int status; bool own_transaction = true; - const char *var = GetVariable(pset->vars, "lo_transaction"); + const char *var = GetVariable(pset.vars, "LO_TRANSACTION"); if (var && strcmp(var, "nothing") == 0) own_transaction = false; - if (!pset->db) + if (!pset.db) { - if (!pset->cur_cmd_interactive) - fprintf(stderr, "%s: ", pset->progname); + if (!pset.cur_cmd_interactive) + fprintf(stderr, "%s: ", pset.progname); fputs("\\lo_export: not connected to a database\n", stderr); return false; } if (own_transaction) { - if (!handle_transaction(pset)) + if (!handle_transaction()) return false; - if (!(res = PSQLexec(pset, "BEGIN"))) + if (!(res = PSQLexec("BEGIN"))) return false; PQclear(res); } - status = lo_export(pset->db, atol(loid_arg), (char *) filename_arg); + status = lo_export(pset.db, atol(loid_arg), (char *) filename_arg); if (status != 1) { /* of course this status is documented * nowhere :( */ - fputs(PQerrorMessage(pset->db), stderr); + fputs(PQerrorMessage(pset.db), stderr); if (own_transaction) { - res = PQexec(pset->db, "ROLLBACK"); + res = PQexec(pset.db, "ROLLBACK"); PQclear(res); } return false; @@ -122,9 +121,9 @@ do_lo_export(PsqlSettings *pset, const char *loid_arg, const char *filename_arg) if (own_transaction) { - if (!(res = PSQLexec(pset, "COMMIT"))) + if (!(res = PSQLexec("COMMIT"))) { - res = PQexec(pset->db, "ROLLBACK"); + res = PQexec(pset.db, "ROLLBACK"); PQclear(res); return false; } @@ -132,7 +131,7 @@ do_lo_export(PsqlSettings *pset, const char *loid_arg, const char *filename_arg) PQclear(res); } - fprintf(pset->queryFout, "lo_export\n"); + fprintf(pset.queryFout, "lo_export\n"); return true; } @@ -145,44 +144,44 @@ do_lo_export(PsqlSettings *pset, const char *loid_arg, const char *filename_arg) * Copy large object from file to database */ bool -do_lo_import(PsqlSettings *pset, const char *filename_arg, const char *comment_arg) +do_lo_import(const char *filename_arg, const char *comment_arg) { PGresult *res; Oid loid; char buf[1024]; unsigned int i; bool own_transaction = true; - const char *var = GetVariable(pset->vars, "lo_transaction"); + const char *var = GetVariable(pset.vars, "LO_TRANSACTION"); if (var && strcmp(var, "nothing") == 0) own_transaction = false; - if (!pset->db) + if (!pset.db) { - if (!pset->cur_cmd_interactive) - fprintf(stderr, "%s: ", pset->progname); + if (!pset.cur_cmd_interactive) + fprintf(stderr, "%s: ", pset.progname); fputs("\\lo_import: not connected to a database\n", stderr); return false; } if (own_transaction) { - if (!handle_transaction(pset)) + if (!handle_transaction()) return false; - if (!(res = PSQLexec(pset, "BEGIN"))) + if (!(res = PSQLexec("BEGIN"))) return false; PQclear(res); } - loid = lo_import(pset->db, (char *) filename_arg); + loid = lo_import(pset.db, (char *) filename_arg); if (loid == InvalidOid) { - fputs(PQerrorMessage(pset->db), stderr); + fputs(PQerrorMessage(pset.db), stderr); if (own_transaction) { - res = PQexec(pset->db, "ROLLBACK"); + res = PQexec(pset.db, "ROLLBACK"); PQclear(res); } return false; @@ -199,11 +198,11 @@ do_lo_import(PsqlSettings *pset, const char *filename_arg, const char *comment_a strncat(buf, &comment_arg[i], 1); strcat(buf, "')"); - if (!(res = PSQLexec(pset, buf))) + if (!(res = PSQLexec(buf))) { if (own_transaction) { - res = PQexec(pset->db, "ROLLBACK"); + res = PQexec(pset.db, "ROLLBACK"); PQclear(res); } return false; @@ -212,9 +211,9 @@ do_lo_import(PsqlSettings *pset, const char *filename_arg, const char *comment_a if (own_transaction) { - if (!(res = PSQLexec(pset, "COMMIT"))) + if (!(res = PSQLexec("COMMIT"))) { - res = PQexec(pset->db, "ROLLBACK"); + res = PQexec(pset.db, "ROLLBACK"); PQclear(res); return false; } @@ -223,8 +222,9 @@ do_lo_import(PsqlSettings *pset, const char *filename_arg, const char *comment_a } - fprintf(pset->queryFout, "lo_import %d\n", loid); - pset->lastOid = loid; + fprintf(pset.queryFout, "lo_import %d\n", loid); + sprintf(buf, "%u", (unsigned int)loid); + SetVariable(pset.vars, "LASTOID", buf); return true; } @@ -237,44 +237,44 @@ do_lo_import(PsqlSettings *pset, const char *filename_arg, const char *comment_a * removes a large object out of the database */ bool -do_lo_unlink(PsqlSettings *pset, const char *loid_arg) +do_lo_unlink(const char *loid_arg) { PGresult *res; int status; Oid loid = (Oid) atol(loid_arg); char buf[256]; bool own_transaction = true; - const char *var = GetVariable(pset->vars, "lo_transaction"); + const char *var = GetVariable(pset.vars, "LO_TRANSACTION"); if (var && strcmp(var, "nothing") == 0) own_transaction = false; - if (!pset->db) + if (!pset.db) { - if (!pset->cur_cmd_interactive) - fprintf(stderr, "%s: ", pset->progname); + if (!pset.cur_cmd_interactive) + fprintf(stderr, "%s: ", pset.progname); fputs("\\lo_unlink: not connected to a database\n", stderr); return false; } if (own_transaction) { - if (!handle_transaction(pset)) + if (!handle_transaction()) return false; - if (!(res = PSQLexec(pset, "BEGIN"))) + if (!(res = PSQLexec("BEGIN"))) return false; PQclear(res); } - status = lo_unlink(pset->db, loid); + status = lo_unlink(pset.db, loid); if (status == -1) { - fputs(PQerrorMessage(pset->db), stderr); + fputs(PQerrorMessage(pset.db), stderr); if (own_transaction) { - res = PQexec(pset->db, "ROLLBACK"); + res = PQexec(pset.db, "ROLLBACK"); PQclear(res); } return false; @@ -282,11 +282,11 @@ do_lo_unlink(PsqlSettings *pset, const char *loid_arg) /* remove the comment as well */ sprintf(buf, "DELETE FROM pg_description WHERE objoid = %d", loid); - if (!(res = PSQLexec(pset, buf))) + if (!(res = PSQLexec(buf))) { if (own_transaction) { - res = PQexec(pset->db, "ROLLBACK"); + res = PQexec(pset.db, "ROLLBACK"); PQclear(res); } return false; @@ -295,9 +295,9 @@ do_lo_unlink(PsqlSettings *pset, const char *loid_arg) if (own_transaction) { - if (!(res = PSQLexec(pset, "COMMIT"))) + if (!(res = PSQLexec("COMMIT"))) { - res = PQexec(pset->db, "ROLLBACK"); + res = PQexec(pset.db, "ROLLBACK"); PQclear(res); return false; } @@ -305,7 +305,7 @@ do_lo_unlink(PsqlSettings *pset, const char *loid_arg) } - fprintf(pset->queryFout, "lo_unlink %d\n", loid); + fprintf(pset.queryFout, "lo_unlink %d\n", loid); return true; } @@ -318,11 +318,11 @@ do_lo_unlink(PsqlSettings *pset, const char *loid_arg) * Show all large objects in database with comments */ bool -do_lo_list(PsqlSettings *pset) +do_lo_list(void) { PGresult *res; char buf[1024]; - printQueryOpt myopt = pset->popt; + printQueryOpt myopt = pset.popt; strcpy(buf, "SELECT usename as \"Owner\", substring(relname from 5) as \"ID\",\n" @@ -336,7 +336,7 @@ do_lo_list(PsqlSettings *pset) "WHERE not exists (select 1 from pg_user where usesysid = relowner) AND relkind = 'l'\n" "ORDER BY \"ID\""); - res = PSQLexec(pset, buf); + res = PSQLexec(buf); if (!res) return false; @@ -344,7 +344,7 @@ do_lo_list(PsqlSettings *pset) myopt.nullPrint = NULL; myopt.title = "Large objects"; - printQuery(res, &myopt, pset->queryFout); + printQuery(res, &myopt, pset.queryFout); PQclear(res); return true; diff --git a/src/bin/psql/large_obj.h b/src/bin/psql/large_obj.h index 3ddb2206bbb..baf1222d8c7 100644 --- a/src/bin/psql/large_obj.h +++ b/src/bin/psql/large_obj.h @@ -2,11 +2,10 @@ #define LARGE_OBJ_H #include <c.h> -#include "settings.h" -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 do_lo_export(const char *loid_arg, const char *filename_arg); +bool do_lo_import(const char *filename_arg, const char *comment_arg); +bool do_lo_unlink(const char *loid_arg); +bool do_lo_list(void); #endif /* LARGE_OBJ_H */ diff --git a/src/bin/psql/mainloop.c b/src/bin/psql/mainloop.c index cb9232d7147..919025cb5c4 100644 --- a/src/bin/psql/mainloop.c +++ b/src/bin/psql/mainloop.c @@ -1,4 +1,3 @@ -#include <config.h> #include <c.h> #include "mainloop.h" @@ -26,7 +25,7 @@ * FIXME: rewrite this whole thing with flex */ int -MainLoop(PsqlSettings *pset, FILE *source) +MainLoop(FILE *source) { PQExpBuffer query_buf; /* buffer for query being accumulated */ PQExpBuffer previous_buf; /* if there isn't anything in the new buffer @@ -36,13 +35,14 @@ MainLoop(PsqlSettings *pset, FILE *source) int successResult = EXIT_SUCCESS; backslashResult slashCmdStatus; - bool eof = false; /* end of our command input? */ bool success; char in_quote; /* == 0 for no in_quote */ bool was_bslash; /* backslash */ bool xcomment; /* in extended comment */ int paren_level; unsigned int query_start; + int count_eof; + const char *var; int i, prevlen, @@ -56,12 +56,12 @@ MainLoop(PsqlSettings *pset, FILE *source) /* Save old settings */ - prev_cmd_source = pset->cur_cmd_source; - prev_cmd_interactive = pset->cur_cmd_interactive; + prev_cmd_source = pset.cur_cmd_source; + prev_cmd_interactive = pset.cur_cmd_interactive; /* Establish new source */ - pset->cur_cmd_source = source; - pset->cur_cmd_interactive = ((source == stdin) && !pset->notty); + pset.cur_cmd_source = source; + pset.cur_cmd_interactive = ((source == stdin) && !pset.notty); query_buf = createPQExpBuffer(); @@ -79,7 +79,7 @@ MainLoop(PsqlSettings *pset, FILE *source) /* main loop to get queries and execute them */ - while (!eof) + while (1) { if (slashCmdStatus == CMD_NEWEDIT) { @@ -102,7 +102,7 @@ MainLoop(PsqlSettings *pset, FILE *source) * otherwise, set interactive prompt if necessary and get * another line */ - if (pset->cur_cmd_interactive) + if (pset.cur_cmd_interactive) { int prompt_status; @@ -117,7 +117,7 @@ MainLoop(PsqlSettings *pset, FILE *source) else prompt_status = PROMPT_READY; - line = gets_interactive(get_prompt(pset, prompt_status)); + line = gets_interactive(get_prompt(prompt_status)); } else line = gets_fromFile(source); @@ -125,7 +125,7 @@ MainLoop(PsqlSettings *pset, FILE *source) /* Setting this will not have effect until next line. */ - die_on_error = GetVariableBool(pset->vars, "die_on_error"); + die_on_error = GetVariableBool(pset.vars, "EXIT_ON_ERROR"); /* * query_buf holds query already accumulated. line is the @@ -137,14 +137,47 @@ MainLoop(PsqlSettings *pset, FILE *source) /* No more input. Time to quit, or \i done */ if (line == NULL) { - if (GetVariableBool(pset->vars, "echo") && !GetVariableBool(pset->vars, "quiet")) - puts("EOF"); - else if (pset->cur_cmd_interactive) - putc('\n', stdout); /* just newline */ + if (pset.cur_cmd_interactive) + { + bool getout = true; + + /* This tries to mimic bash's IGNOREEOF feature. */ + const char * val = GetVariable(pset.vars, "IGNOREEOF"); + if (val) + { + long int maxeof; + char * endptr; + + if (*val == '\0') + maxeof = 10; + else + { + maxeof = strtol(val, &endptr, 0); + if (*endptr != '\0') /* string not valid as a number */ + maxeof = 10; + } + + if (count_eof++ != maxeof) + getout = false; /* not quite there yet */ + } - eof = true; - continue; + if (getout) + { + putc('\n', stdout); /* just newline */ + break; + } + else + { + if (!QUIET()) + printf("Use \"\\q\" to leave %s.\n", pset.progname); + continue; + } + } + else /* not interactive */ + break; } + else + count_eof = 0; /* strip trailing backslashes, they don't have a clear meaning */ while (1) @@ -164,11 +197,11 @@ MainLoop(PsqlSettings *pset, FILE *source) continue; } - - /* echo back if input is from file and flag is set */ - if (!pset->cur_cmd_interactive && GetVariableBool(pset->vars, "echo")) - puts(line); - + /* echo back if flag is set */ + var = GetVariable(pset.vars, "ECHO"); + if (var && strcmp(var, "full")==0) + puts(line); + fflush(stdout); len = strlen(line); query_start = 0; @@ -236,8 +269,7 @@ MainLoop(PsqlSettings *pset, FILE *source) /* colon -> substitute variable */ /* we need to be on the watch for the '::' operator */ else if (line[i] == ':' && !was_bslash && - strspn(line+i+thislen, VALID_VARIABLE_CHARS)>0 && - (prevlen > 0 && line[i-prevlen]!=':') + strspn(line+i+thislen, VALID_VARIABLE_CHARS)>0 ) { size_t in_length, @@ -250,24 +282,35 @@ MainLoop(PsqlSettings *pset, FILE *source) in_length = strspn(&line[i + thislen], VALID_VARIABLE_CHARS); after = line[i + thislen + in_length]; line[i + thislen + in_length] = '\0'; - value = interpolate_var(&line[i + thislen], pset); - out_length = strlen(value); - - new = malloc(len + out_length - (1 + in_length) + 1); - if (!new) - { - perror("malloc"); - exit(EXIT_FAILURE); - } - - sprintf(new, "%.*s%s%c", i, line, value, after); - if (after) - strcat(new, line + i + 1 + in_length + 1); - free(line); - line = new; - len = strlen(new); - continue; /* reparse the just substituted */ + /* if the variable doesn't exist we'll leave the string as is */ + value = GetVariable(pset.vars, &line[i + thislen]); + if (value) + { + out_length = strlen(value); + + new = malloc(len + out_length - (1 + in_length) + 1); + if (!new) + { + perror("malloc"); + exit(EXIT_FAILURE); + } + + sprintf(new, "%.*s%s%c", i, line, value, after); + if (after) + strcat(new, line + i + 1 + in_length + 1); + + free(line); + line = new; + len = strlen(new); + continue; /* reparse the just substituted */ + } + else + { + /* restore overwritten character */ + line[i + thislen + in_length] = after; + /* move on ... */ + } } /* semicolon? then send query */ @@ -288,7 +331,7 @@ MainLoop(PsqlSettings *pset, FILE *source) } /* execute query */ - success = SendQuery(pset, query_buf->data); + success = SendQuery(query_buf->data); slashCmdStatus = success ? CMD_SEND : CMD_ERROR; resetPQExpBuffer(previous_buf); @@ -314,7 +357,7 @@ MainLoop(PsqlSettings *pset, FILE *source) paren_level = 0; line[i - prevlen] = '\0'; /* overwrites backslash */ - /* is there anything else on the line? */ + /* is there anything else on the line for the command? */ if (line[query_start + strspn(line + query_start, " \t")] != '\0') { /* @@ -328,7 +371,7 @@ MainLoop(PsqlSettings *pset, FILE *source) } /* handle backslash command */ - slashCmdStatus = HandleSlashCmds(pset, &line[i], + slashCmdStatus = HandleSlashCmds(&line[i], query_buf->len>0 ? query_buf : previous_buf, &end_of_cmd); @@ -342,7 +385,7 @@ MainLoop(PsqlSettings *pset, FILE *source) if (slashCmdStatus == CMD_SEND) { - success = SendQuery(pset, query_buf->data); + success = SendQuery(query_buf->data); query_start = i + thislen; resetPQExpBuffer(previous_buf); @@ -350,14 +393,9 @@ MainLoop(PsqlSettings *pset, FILE *source) resetPQExpBuffer(query_buf); } - /* is there anything left after the backslash command? */ - if (end_of_cmd) - { - i += end_of_cmd - &line[i]; - query_start = i; - } - else - break; + /* process anything left after the backslash command */ + i += end_of_cmd - &line[i]; + query_start = i; } @@ -387,9 +425,9 @@ MainLoop(PsqlSettings *pset, FILE *source) /* In single line mode, send off the query if any */ - if (query_buf->data[0] != '\0' && GetVariableBool(pset->vars, "singleline")) + if (query_buf->data[0] != '\0' && GetVariableBool(pset.vars, "SINGLELINE")) { - success = SendQuery(pset, query_buf->data); + success = SendQuery(query_buf->data); slashCmdStatus = success ? CMD_SEND : CMD_ERROR; resetPQExpBuffer(previous_buf); appendPQExpBufferStr(previous_buf, query_buf->data); @@ -397,7 +435,7 @@ MainLoop(PsqlSettings *pset, FILE *source) } - if (!success && die_on_error && !pset->cur_cmd_interactive) + if (!success && die_on_error && !pset.cur_cmd_interactive) { successResult = EXIT_USER; break; @@ -405,18 +443,18 @@ MainLoop(PsqlSettings *pset, FILE *source) /* Have we lost the db connection? */ - if (pset->db == NULL && !pset->cur_cmd_interactive) + if (pset.db == NULL && !pset.cur_cmd_interactive) { successResult = EXIT_BADCONN; break; } - } /* while !EOF */ + } /* while !endofprogram */ destroyPQExpBuffer(query_buf); destroyPQExpBuffer(previous_buf); - pset->cur_cmd_source = prev_cmd_source; - pset->cur_cmd_interactive = prev_cmd_interactive; + pset.cur_cmd_source = prev_cmd_source; + pset.cur_cmd_interactive = prev_cmd_interactive; return successResult; } /* MainLoop() */ diff --git a/src/bin/psql/mainloop.h b/src/bin/psql/mainloop.h index b2b05d7d11b..439703d0404 100644 --- a/src/bin/psql/mainloop.h +++ b/src/bin/psql/mainloop.h @@ -2,9 +2,7 @@ #define MAINLOOP_H #include <stdio.h> -#include "settings.h" -int - MainLoop(PsqlSettings *pset, FILE *source); +int MainLoop(FILE *source); #endif /* MAINLOOP_H */ diff --git a/src/bin/psql/prompt.c b/src/bin/psql/prompt.c index dd41ba54015..d93f5611ced 100644 --- a/src/bin/psql/prompt.c +++ b/src/bin/psql/prompt.c @@ -1,4 +1,3 @@ -#include <config.h> #include <c.h> #include "prompt.h" @@ -10,6 +9,7 @@ #include "settings.h" #include "common.h" +#include "variables.h" #ifdef WIN32 #define popen(x,y) _popen(x,y) @@ -22,7 +22,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: @@ -46,8 +46,7 @@ * * %`command` - The result of executing command in /bin/sh with trailing * newline stripped. - * %$name$ - The value of the psql/environment/magic varible 'name' - * (same rules as for, e.g., \echo $foo) + * %$name$ - The value of the psql variable 'name' * (those will not be rescanned for more escape sequences!) * * @@ -56,7 +55,7 @@ *-------------------------- */ const char * -get_prompt(PsqlSettings *pset, promptStatus_t status) +get_prompt(promptStatus_t status) { #define MAX_PROMPT_SIZE 256 static char destination[MAX_PROMPT_SIZE + 1]; @@ -66,11 +65,11 @@ get_prompt(PsqlSettings *pset, promptStatus_t status) const char *prompt_string; if (status == PROMPT_READY) - prompt_string = GetVariable(pset->vars, "prompt1"); + prompt_string = GetVariable(pset.vars, "PROMPT1"); else if (status == PROMPT_CONTINUE || status == PROMPT_SINGLEQUOTE || status == PROMPT_DOUBLEQUOTE || status == PROMPT_COMMENT) - prompt_string = GetVariable(pset->vars, "prompt2"); + prompt_string = GetVariable(pset.vars, "PROMPT2"); else if (status == PROMPT_COPY) - prompt_string = GetVariable(pset->vars, "prompt3"); + prompt_string = GetVariable(pset.vars, "PROMPT3"); else prompt_string = "? "; @@ -92,31 +91,31 @@ get_prompt(PsqlSettings *pset, promptStatus_t status) /* Current database */ case '/': - if (pset->db) - strncpy(buf, PQdb(pset->db), MAX_PROMPT_SIZE); + if (pset.db) + strncpy(buf, PQdb(pset.db), MAX_PROMPT_SIZE); break; case '~': { const char *var; - if (pset->db) + if (pset.db) { - if (strcmp(PQdb(pset->db), PQuser(pset->db)) == 0 || - ((var = getenv("PGDATABASE")) && strcmp(var, PQdb(pset->db)) == 0)) + if (strcmp(PQdb(pset.db), PQuser(pset.db)) == 0 || + ((var = getenv("PGDATABASE")) && strcmp(var, PQdb(pset.db)) == 0)) strcpy(buf, "~"); else - strncpy(buf, PQdb(pset->db), MAX_PROMPT_SIZE); + strncpy(buf, PQdb(pset.db), MAX_PROMPT_SIZE); } break; } /* DB server hostname (long/short) */ case 'M': case 'm': - if (pset->db) + if (pset.db) { - if (PQhost(pset->db)) + if (PQhost(pset.db)) { - strncpy(buf, PQhost(pset->db), MAX_PROMPT_SIZE); + strncpy(buf, PQhost(pset.db), MAX_PROMPT_SIZE); if (*p == 'm') buf[strcspn(buf, ".")] = '\0'; } @@ -126,13 +125,13 @@ get_prompt(PsqlSettings *pset, promptStatus_t status) break; /* DB server port number */ case '>': - if (pset->db && PQport(pset->db)) - strncpy(buf, PQport(pset->db), MAX_PROMPT_SIZE); + if (pset.db && PQport(pset.db)) + strncpy(buf, PQport(pset.db), MAX_PROMPT_SIZE); break; /* DB server user name */ case 'n': - if (pset->db) - strncpy(buf, PQuser(pset->db), MAX_PROMPT_SIZE); + if (pset.db) + strncpy(buf, PQuser(pset.db), MAX_PROMPT_SIZE); break; case '0': @@ -159,9 +158,9 @@ get_prompt(PsqlSettings *pset, promptStatus_t status) switch (status) { case PROMPT_READY: - if (!pset->db) + if (!pset.db) buf[0] = '!'; - else if (!GetVariableBool(pset->vars, "singleline")) + else if (!GetVariableBool(pset.vars, "SINGLELINE")) buf[0] = '='; else buf[0] = '^'; @@ -189,7 +188,7 @@ get_prompt(PsqlSettings *pset, promptStatus_t status) case '#': { - if (pset->db && strcmp(PQuser(pset->db), "postgres") == 0) + if (pset.db && strcmp(PQuser(pset.db), "postgres") == 0) buf[0] = '#'; else buf[0] = '>'; @@ -230,7 +229,7 @@ get_prompt(PsqlSettings *pset, promptStatus_t status) name = strdup(p + 1); nameend = strcspn(name, "$"); name[nameend] = '\0'; - val = interpolate_var(name, pset); + val = GetVariable(pset.vars, name); if (val) strncpy(buf, val, MAX_PROMPT_SIZE); free(name); diff --git a/src/bin/psql/prompt.h b/src/bin/psql/prompt.h index e4c1242deb7..d98116395ad 100644 --- a/src/bin/psql/prompt.h +++ b/src/bin/psql/prompt.h @@ -14,7 +14,7 @@ typedef enum _promptStatus } promptStatus_t; const char * - get_prompt(PsqlSettings *pset, promptStatus_t status); + get_prompt(promptStatus_t status); #endif /* PROMPT_H */ diff --git a/src/bin/psql/settings.h b/src/bin/psql/settings.h index 774c54b4594..21f138bd37d 100644 --- a/src/bin/psql/settings.h +++ b/src/bin/psql/settings.h @@ -43,11 +43,13 @@ typedef struct _psqlSettings bool has_client_encoding; /* was PGCLIENTENCODING set on * startup? */ - Oid lastOid; /* saves oid from insert command - because people want it so badly */ char *progname; /* in case you renamed psql */ } PsqlSettings; +extern PsqlSettings pset; + + +#define QUIET() (GetVariableBool(pset.vars, "QUIET")) #ifndef EXIT_SUCCESS diff --git a/src/bin/psql/startup.c b/src/bin/psql/startup.c index 35f4ddce05c..2599a42199a 100644 --- a/src/bin/psql/startup.c +++ b/src/bin/psql/startup.c @@ -1,4 +1,3 @@ -#include <config.h> #include <c.h> #include <signal.h> @@ -34,10 +33,10 @@ #include "print.h" #include "describe.h" - +PsqlSettings pset; static void -process_psqlrc(PsqlSettings *pset); +process_psqlrc(void); static void showVersion(void); @@ -67,7 +66,7 @@ struct adhoc_opts }; static void -parse_options(int argc, char *argv[], PsqlSettings *pset, struct adhoc_opts * options); +parse_options(int argc, char *argv[], struct adhoc_opts * options); @@ -79,7 +78,6 @@ parse_options(int argc, char *argv[], PsqlSettings *pset, struct adhoc_opts * op int main(int argc, char **argv) { - PsqlSettings settings; struct adhoc_opts options; int successResult; @@ -87,64 +85,65 @@ main(int argc, char **argv) char *password = NULL; bool need_pass; - memset(&settings, 0, sizeof settings); + memset(&pset, 0, sizeof pset); if (!strrchr(argv[0], SEP_CHAR)) - settings.progname = argv[0]; + pset.progname = argv[0]; else - settings.progname = strrchr(argv[0], SEP_CHAR) + 1; + pset.progname = strrchr(argv[0], SEP_CHAR) + 1; - settings.cur_cmd_source = stdin; - settings.cur_cmd_interactive = false; + pset.cur_cmd_source = stdin; + pset.cur_cmd_interactive = false; - settings.vars = CreateVariableSpace(); - settings.popt.topt.format = PRINT_ALIGNED; - settings.queryFout = stdout; - settings.popt.topt.fieldSep = strdup(DEFAULT_FIELD_SEP); - settings.popt.topt.border = 1; - settings.popt.topt.pager = 1; + pset.vars = CreateVariableSpace(); + pset.popt.topt.format = PRINT_ALIGNED; + pset.queryFout = stdout; + pset.popt.topt.fieldSep = strdup(DEFAULT_FIELD_SEP); + pset.popt.topt.border = 1; + pset.popt.topt.pager = 1; - SetVariable(settings.vars, "prompt1", DEFAULT_PROMPT1); - SetVariable(settings.vars, "prompt2", DEFAULT_PROMPT2); - SetVariable(settings.vars, "prompt3", DEFAULT_PROMPT3); + SetVariable(pset.vars, "PROMPT1", DEFAULT_PROMPT1); + SetVariable(pset.vars, "PROMPT2", DEFAULT_PROMPT2); + SetVariable(pset.vars, "PROMPT3", DEFAULT_PROMPT3); + SetVariable(pset.vars, "VERSION", PG_VERSION_STR); - settings.notty = (!isatty(fileno(stdin)) || !isatty(fileno(stdout))); + pset.notty = (!isatty(fileno(stdin)) || !isatty(fileno(stdout))); /* This is obsolete and will be removed very soon. */ #ifdef PSQL_ALWAYS_GET_PASSWORDS - settings.getPassword = true; + pset.getPassword = true; #else - settings.getPassword = false; + pset.getPassword = false; #endif #ifdef MULTIBYTE - settings.has_client_encoding = (getenv("PGCLIENTENCODING") != NULL); + pset.has_client_encoding = (getenv("PGCLIENTENCODING") != NULL); #endif - parse_options(argc, argv, &settings, &options); + parse_options(argc, argv, &options); if (options.action == ACT_LIST_DB) options.dbname = "template1"; if (options.username) { - if (strcmp(options.username, "?") == 0) + if (strcmp(options.username, "\001") == 0) username = simple_prompt("Username: ", 100, true); else username = strdup(options.username); } - if (settings.getPassword) + if (pset.getPassword) password = simple_prompt("Password: ", 100, false); /* loop until we have a password if requested by backend */ do { need_pass = false; - settings.db = PQsetdbLogin(options.host, options.port, NULL, NULL, options.dbname, username, password); + pset.db = PQsetdbLogin(options.host, options.port, NULL, NULL, options.dbname, username, password); - if (PQstatus(settings.db) == CONNECTION_BAD && - strcmp(PQerrorMessage(settings.db), "fe_sendauth: no password supplied\n") == 0) + if (PQstatus(pset.db) == CONNECTION_BAD && + strcmp(PQerrorMessage(pset.db), "fe_sendauth: no password supplied\n") == 0) { need_pass = true; free(password); @@ -156,58 +155,61 @@ main(int argc, char **argv) free(username); free(password); - if (PQstatus(settings.db) == CONNECTION_BAD) + if (PQstatus(pset.db) == CONNECTION_BAD) { - fprintf(stderr, "%s: connection to database '%s' failed.\n%s", - settings.progname, PQdb(settings.db), - PQerrorMessage(settings.db)); - PQfinish(settings.db); + fprintf(stderr, "%s: connection to database '%s' failed - %s", + pset.progname, PQdb(pset.db), PQerrorMessage(pset.db)); + PQfinish(pset.db); exit(EXIT_BADCONN); } if (options.action == ACT_LIST_DB) { - int success = listAllDbs(&settings, false); + int success = listAllDbs(false); - PQfinish(settings.db); + PQfinish(pset.db); exit(!success); } + SetVariable(pset.vars, "DBNAME", PQdb(pset.db)); + SetVariable(pset.vars, "USER", PQuser(pset.db)); + SetVariable(pset.vars, "HOST", PQhost(pset.db)); + SetVariable(pset.vars, "PORT", PQport(pset.db)); - if (!GetVariable(settings.vars, "quiet") && !settings.notty && !options.action) + if (!QUIET() && !pset.notty && !options.action) { 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); + " \\q to quit\n", pset.progname); } - process_psqlrc(&settings); - - initializeInput(options.no_readline ? 0 : 1, &settings); - /* Now find something to do */ /* process file given by -f */ if (options.action == ACT_FILE) - successResult = process_file(options.action_string, &settings) ? 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(&settings, options.action_string, NULL, NULL) != 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(&settings, options.action_string) ? 0 : 1; + successResult = SendQuery( options.action_string) ? 0 : 1; /* or otherwise enter interactive main loop */ else - successResult = MainLoop(&settings, stdin); + { + process_psqlrc(); + initializeInput(options.no_readline ? 0 : 1); + successResult = MainLoop(stdin); + finishInput(); + } /* clean up */ - finishInput(); - PQfinish(settings.db); - setQFout(NULL, &settings); - DestroyVariableSpace(settings.vars); + PQfinish(pset.db); + setQFout(NULL); + DestroyVariableSpace(pset.vars); return successResult; } @@ -225,7 +227,7 @@ int getopt(int, char *const[], const char *); #endif static void -parse_options(int argc, char *argv[], PsqlSettings *pset, struct adhoc_opts * options) +parse_options(int argc, char *argv[], struct adhoc_opts * options) { #ifdef HAVE_GETOPT_LONG static struct option long_options[] = { @@ -234,9 +236,7 @@ parse_options(int argc, char *argv[], PsqlSettings *pset, struct adhoc_opts * op {"database", required_argument, NULL, 'd'}, {"dbname", required_argument, NULL, 'd'}, {"echo", no_argument, NULL, 'e'}, - {"echo-queries", no_argument, NULL, 'e'}, - {"echo-all", no_argument, NULL, 'E'}, - {"echo-all-queries", no_argument, NULL, 'E'}, + {"echo-hidden", no_argument, NULL, 'E'}, {"file", required_argument, NULL, 'f'}, {"field-separator", required_argument, NULL, 'F'}, {"host", required_argument, NULL, 'h'}, @@ -261,12 +261,12 @@ parse_options(int argc, char *argv[], PsqlSettings *pset, struct adhoc_opts * op }; int optindex; - #endif extern char *optarg; extern int optind; int c; + bool used_old_u_option = false; memset(options, 0, sizeof *options); @@ -284,7 +284,7 @@ parse_options(int argc, char *argv[], PsqlSettings *pset, struct adhoc_opts * op switch (c) { case 'A': - pset->popt.topt.format = PRINT_UNALIGNED; + pset.popt.topt.format = PRINT_UNALIGNED; break; case 'c': options->action_string = optarg; @@ -297,23 +297,23 @@ parse_options(int argc, char *argv[], PsqlSettings *pset, struct adhoc_opts * op options->dbname = optarg; break; case 'e': - SetVariable(pset->vars, "echo", ""); + SetVariable(pset.vars, "ECHO", "full"); break; case 'E': - SetVariable(pset->vars, "echo_secret", ""); + SetVariable(pset.vars, "ECHO_HIDDEN", ""); break; case 'f': options->action = ACT_FILE; options->action_string = optarg; break; case 'F': - pset->popt.topt.fieldSep = strdup(optarg); + pset.popt.topt.fieldSep = strdup(optarg); break; case 'h': options->host = optarg; break; case 'H': - pset->popt.topt.format = PRINT_HTML; + pset.popt.topt.format = PRINT_HTML; break; case 'l': options->action = ACT_LIST_DB; @@ -322,7 +322,7 @@ parse_options(int argc, char *argv[], PsqlSettings *pset, struct adhoc_opts * op options->no_readline = true; break; case 'o': - setQFout(optarg, pset); + setQFout(optarg); break; case 'p': options->port = optarg; @@ -336,16 +336,16 @@ parse_options(int argc, char *argv[], PsqlSettings *pset, struct adhoc_opts * op value = xstrdup(optarg); equal_loc = strchr(value, '='); if (!equal_loc) - result = do_pset(value, NULL, &pset->popt, true); + result = do_pset(value, NULL, &pset.popt, true); else { *equal_loc = '\0'; - result = do_pset(value, equal_loc + 1, &pset->popt, true); + result = do_pset(value, equal_loc + 1, &pset.popt, true); } if (!result) { - fprintf(stderr, "Couldn't set printing paramter %s.\n", value); + fprintf(stderr, "%s: couldn't set printing parameter %s\n", pset.progname, value); exit(EXIT_FAILURE); } @@ -353,29 +353,31 @@ parse_options(int argc, char *argv[], PsqlSettings *pset, struct adhoc_opts * op break; } case 'q': - SetVariable(pset->vars, "quiet", ""); + SetVariable(pset.vars, "QUIET", ""); break; case 's': - SetVariable(pset->vars, "singlestep", ""); + SetVariable(pset.vars, "SINGLESTEP", ""); break; case 'S': - SetVariable(pset->vars, "singleline", ""); + SetVariable(pset.vars, "SINGLELINE", ""); break; case 't': - pset->popt.topt.tuples_only = true; + pset.popt.topt.tuples_only = true; break; case 'T': - pset->popt.topt.tableAttr = xstrdup(optarg); + pset.popt.topt.tableAttr = xstrdup(optarg); break; case 'u': - pset->getPassword = true; - options->username = "?"; + pset.getPassword = true; + options->username = "\001"; /* hopefully nobody has that username */ + /* this option is out */ + used_old_u_option = true; break; case 'U': options->username = optarg; break; case 'x': - pset->popt.topt.expanded = true; + pset.popt.topt.expanded = true; break; case 'v': { @@ -386,20 +388,20 @@ parse_options(int argc, char *argv[], PsqlSettings *pset, struct adhoc_opts * op equal_loc = strchr(value, '='); if (!equal_loc) { - if (!DeleteVariable(pset->vars, value)) + if (!DeleteVariable(pset.vars, value)) { fprintf(stderr, "%s: could not delete variable %s\n", - pset->progname, value); + pset.progname, value); exit(EXIT_FAILURE); } } else { *equal_loc = '\0'; - if (!SetVariable(pset->vars, value, equal_loc + 1)) + if (!SetVariable(pset.vars, value, equal_loc + 1)) { - fprintf(stderr, "%s: Couldn't set variable %s to %s\n", - pset->progname, value, equal_loc); + fprintf(stderr, "%s: could not set variable %s\n", + pset.progname, value); exit(EXIT_FAILURE); } } @@ -411,7 +413,7 @@ parse_options(int argc, char *argv[], PsqlSettings *pset, struct adhoc_opts * op showVersion(); exit(EXIT_SUCCESS); case 'W': - pset->getPassword = true; + pset.getPassword = true; break; case '?': usage(); @@ -420,7 +422,7 @@ parse_options(int argc, char *argv[], PsqlSettings *pset, struct adhoc_opts * op #ifndef HAVE_GETOPT_LONG case '-': fprintf(stderr, "%s was compiled without support for long options.\n" - "Use -? for help on invocation options.\n", pset->progname); + "Use -? for help on invocation options.\n", pset.progname); exit(EXIT_FAILURE); break; #endif @@ -441,12 +443,16 @@ parse_options(int argc, char *argv[], PsqlSettings *pset, struct adhoc_opts * op options->dbname = argv[optind]; else if (!options->username) options->username = argv[optind]; - else + else if (!QUIET()) fprintf(stderr, "%s: warning: extra option %s ignored\n", - pset->progname, argv[optind]); + pset.progname, argv[optind]); optind++; } + + if (used_old_u_option && !QUIET()) + fprintf(stderr, "%s: Warning: The -u option is deprecated. Use -U.\n", pset.progname); + } @@ -455,7 +461,7 @@ parse_options(int argc, char *argv[], PsqlSettings *pset, struct adhoc_opts * op * Load /etc/psqlrc or .psqlrc file, if found. */ static void -process_psqlrc(PsqlSettings *pset) +process_psqlrc(void) { char *psqlrc; char *home; @@ -466,9 +472,9 @@ process_psqlrc(PsqlSettings *pset) /* 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, pset); + process_file("/etc/psqlrc-" PG_RELEASE "." PG_VERSION "." PG_SUBVERSION); else if (access("/etc/psqlrc", R_OK) == 0) - process_file("/etc/psqlrc", pset); + process_file("/etc/psqlrc"); /* Look for one in the home dir */ home = getenv("HOME"); @@ -484,12 +490,12 @@ process_psqlrc(PsqlSettings *pset) sprintf(psqlrc, "%s/.psqlrc-" PG_RELEASE "." PG_VERSION "." PG_SUBVERSION, home); if (access(psqlrc, R_OK) == 0) - process_file(psqlrc, pset); + process_file(psqlrc); else { sprintf(psqlrc, "%s/.psqlrc", home); if (access(psqlrc, R_OK) == 0) - process_file(psqlrc, pset); + process_file(psqlrc); } free(psqlrc); } @@ -529,7 +535,7 @@ showVersion(void) #else #define _Feature #endif - fputs("multibyte"); + fputs("multibyte", stdout); #endif #undef _Feature |