diff options
author | Bruce Momjian <bruce@momjian.us> | 1999-11-04 23:14:30 +0000 |
---|---|---|
committer | Bruce Momjian <bruce@momjian.us> | 1999-11-04 23:14:30 +0000 |
commit | 0e6652e67357354e01f2466184343d0bc0ee2cab (patch) | |
tree | 0c06450508417e033f8a2b90241a7126cd54c4fe /src/bin/psql | |
parent | 2323b63631080b7d4c287872a83b0ea30bd7874a (diff) | |
download | postgresql-0e6652e67357354e01f2466184343d0bc0ee2cab.tar.gz |
psql cleanup
Diffstat (limited to 'src/bin/psql')
29 files changed, 5236 insertions, 8021 deletions
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c index 6bcf96c9cd..29df279262 100644 --- a/src/bin/psql/command.c +++ b/src/bin/psql/command.c @@ -7,9 +7,9 @@ #include <stdlib.h> #include <ctype.h> #ifndef WIN32 -#include <sys/types.h> /* for umask() */ -#include <sys/stat.h> /* for umask(), stat() */ -#include <unistd.h> /* for geteuid(), getpid(), stat() */ +#include <sys/types.h> /* for umask() */ +#include <sys/stat.h> /* for umask(), stat() */ +#include <unistd.h> /* for geteuid(), getpid(), stat() */ #endif #include <assert.h> @@ -35,21 +35,20 @@ /* functions for use in this file only */ -static backslashResult -exec_command(const char * cmd, - char * const * options, - const char * options_string, - PQExpBuffer query_buf, - PsqlSettings * pset); +static backslashResult exec_command(const char *cmd, + char *const * options, + const char *options_string, + PQExpBuffer query_buf, + PsqlSettings *pset); static bool -do_edit(const char *filename_arg, PQExpBuffer query_buf); + do_edit(const char *filename_arg, PQExpBuffer query_buf); static char * -unescape(const char * source, PsqlSettings * pset); + unescape(const char *source, PsqlSettings *pset); static bool -do_shell(const char *command); + do_shell(const char *command); @@ -72,538 +71,616 @@ do_shell(const char *command); backslashResult HandleSlashCmds(PsqlSettings *pset, - const char *line, - PQExpBuffer query_buf, - const char ** end_of_cmd) + const char *line, + PQExpBuffer query_buf, + const char **end_of_cmd) { - backslashResult status = CMD_SKIP_LINE; - char * my_line; - char * options[17] ={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; - char * token; - const char * options_string = NULL; - const char * cmd; - size_t blank_loc; - int i; - const char * continue_parse = NULL; /* tell the mainloop where the backslash command ended */ - - my_line = xstrdup(line); - - /* Find the first whitespace (or backslash) - line[blank_loc] will now be the whitespace character - or the \0 at the end */ - blank_loc = strcspn(my_line, " \t"); - - /* do we have an option string? */ - if (my_line[blank_loc] != '\0') { - options_string = &my_line[blank_loc+1]; - - my_line[blank_loc] = '\0'; - } - - if (options_string) { - char quote; - unsigned int pos; - options_string = &options_string[strspn(options_string, " \t")]; /* skip leading whitespace */ - - i = 0; - token = strtokx(options_string, " \t", "\"'`", '\\', "e, &pos); - - for (i = 0; token && i<16; i++) { - switch(quote) { - case '"': - options[i] = unescape(token, pset); - break; - case '\'': - options[i] = xstrdup(token); - break; - case '`': - { - bool error = false; - FILE * fd = NULL; - char * file = unescape(token, pset); - PQExpBufferData output; - char buf[512]; - size_t result; - - fd = popen(file, "r"); - if (!fd) { - perror(file); - error = true; - } + backslashResult status = CMD_SKIP_LINE; + char *my_line; + char *options[17] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + char *token; + const char *options_string = NULL; + const char *cmd; + size_t blank_loc; + int i; + const char *continue_parse = NULL; /* tell the mainloop where the + * backslash command ended */ + + my_line = xstrdup(line); + + /* + * Find the first whitespace (or backslash) line[blank_loc] will now + * be the whitespace character or the \0 at the end + */ + blank_loc = strcspn(my_line, " \t"); + + /* do we have an option string? */ + if (my_line[blank_loc] != '\0') + { + options_string = &my_line[blank_loc + 1]; - if (!error) { - initPQExpBuffer(&output); + my_line[blank_loc] = '\0'; + } - do { - result = fread(buf, 1, 512, fd); - if (ferror(fd)) { - perror(file); - error = true; - break; + if (options_string) + { + char quote; + unsigned int pos; + + options_string = &options_string[strspn(options_string, " \t")]; /* skip leading + * whitespace */ + + i = 0; + token = strtokx(options_string, " \t", "\"'`", '\\', "e, &pos); + + for (i = 0; token && i < 16; i++) + { + switch (quote) + { + case '"': + options[i] = unescape(token, pset); + break; + case '\'': + options[i] = xstrdup(token); + break; + case '`': + { + bool error = false; + FILE *fd = NULL; + char *file = unescape(token, pset); + PQExpBufferData output; + char buf[512]; + size_t result; + + fd = popen(file, "r"); + if (!fd) + { + perror(file); + error = true; + } + + if (!error) + { + initPQExpBuffer(&output); + + do + { + result = fread(buf, 1, 512, fd); + if (ferror(fd)) + { + perror(file); + error = true; + break; + } + appendBinaryPQExpBuffer(&output, buf, result); + } while (!feof(fd)); + appendPQExpBufferChar(&output, '\0'); + + if (pclose(fd) == -1) + { + perror(file); + error = true; + } + } + + if (!error) + { + if (output.data[strlen(output.data) - 1] == '\n') + output.data[strlen(output.data) - 1] = '\0'; + } + + free(file); + if (!error) + options[i] = output.data; + else + { + options[i] = xstrdup(""); + termPQExpBuffer(&output); + } + break; + } + case 0: + default: + if (token[0] == '\\') + continue_parse = options_string + pos; + else if (token[0] == '$') + options[i] = xstrdup(interpolate_var(token + 1, pset)); + else + options[i] = xstrdup(token); + break; } - appendBinaryPQExpBuffer(&output, buf, result); - } while (!feof(fd)); - appendPQExpBufferChar(&output, '\0'); - - if (pclose(fd) == -1) { - perror(file); - error = true; - } - } - if (!error) { - if (output.data[strlen(output.data)-1] == '\n') - output.data[strlen(output.data)-1] = '\0'; - } + if (continue_parse) + break; - free(file); - if (!error) - options[i] = output.data; - else { - options[i] = xstrdup(""); - termPQExpBuffer(&output); + token = strtokx(NULL, " \t", "\"'`", '\\', "e, &pos); } - break; - } - case 0: - default: - if (token[0] == '\\') - continue_parse = options_string + pos; - else if (token[0] == '$') - options[i] = xstrdup(interpolate_var(token+1, pset)); - else - options[i] = xstrdup(token); - break; - } - - if (continue_parse) - break; - - token = strtokx(NULL, " \t", "\"'`", '\\', "e, &pos); } - } - cmd = my_line; + cmd = my_line; - status = exec_command(cmd, options, options_string, query_buf, pset); + status = exec_command(cmd, options, options_string, query_buf, pset); - if (status == CMD_UNKNOWN) { - /* If the command was not recognized, try inserting a space after - the first letter and call again. The one letter commands - allow arguments to start immediately after the command, - but that is no longer encouraged. */ - const char * new_options[17]; - char new_cmd[2]; - int i; + if (status == CMD_UNKNOWN) + { - for (i=1; i<17; i++) - new_options[i] = options[i-1]; - new_options[0] = cmd+1; + /* + * If the command was not recognized, try inserting a space after + * the first letter and call again. The one letter commands allow + * arguments to start immediately after the command, but that is + * no longer encouraged. + */ + const char *new_options[17]; + char new_cmd[2]; + int i; - new_cmd[0] = cmd[0]; - new_cmd[1] = '\0'; + for (i = 1; i < 17; i++) + new_options[i] = options[i - 1]; + new_options[0] = cmd + 1; + + 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, pset); - } + if (status == CMD_UNKNOWN) + { + fprintf(stderr, "Unrecognized command: \\%s. Try \\? for help.\n", cmd); + status = CMD_ERROR; + } - if (status == CMD_UNKNOWN) { - fprintf(stderr, "Unrecognized command: \\%s. Try \\? for help.\n", cmd); - status = CMD_ERROR; - } - - if (continue_parse && *(continue_parse+1) == '\\') - continue_parse+=2; + if (continue_parse && *(continue_parse + 1) == '\\') + continue_parse += 2; - if (end_of_cmd) { - if (continue_parse) - *end_of_cmd = line + (continue_parse - my_line); - else - *end_of_cmd = NULL; - } + if (end_of_cmd) + { + if (continue_parse) + *end_of_cmd = line + (continue_parse - my_line); + else + *end_of_cmd = NULL; + } - /* clean up */ - for (i = 0; i<16 && options[i]; i++) - free(options[i]); + /* clean up */ + for (i = 0; i < 16 && options[i]; i++) + free(options[i]); - free(my_line); + free(my_line); - return status; + return status; } static backslashResult -exec_command(const char * cmd, - char * const * options, - const char * options_string, - PQExpBuffer query_buf, - PsqlSettings * pset) +exec_command(const char *cmd, + char *const * options, + const char *options_string, + PQExpBuffer query_buf, + PsqlSettings *pset) { - bool success = true; /* indicate here if the command ran ok or failed */ - bool quiet = GetVariableBool(pset->vars, "quiet"); + bool success = true; /* indicate here if the command ran ok or + * failed */ + bool quiet = GetVariableBool(pset->vars, "quiet"); - backslashResult status = CMD_SKIP_LINE; + backslashResult status = CMD_SKIP_LINE; - /* \a -- toggle field alignment - This is deprecated and makes no 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); - else - success = do_pset("format", "unaligned", &pset->popt, quiet); - } - - - /* \C -- override table title - (formerly change HTML caption) This is deprecated. */ - else if (strcmp(cmd, "C") == 0) - success = do_pset("title", options[0], &pset->popt, quiet); - - - - /* \c or \connect -- connect to new database or as different user - * - * \c foo bar : connect to db "foo" as user "bar" - * \c foo [-] : connect to db "foo" as current user - * \c - bar : connect to current db as user "bar" - * \c : connect to default db as default user - */ - else if (strcmp(cmd, "c")==0 || strcmp(cmd, "connect")==0) - { - if (options[1]) - /* gave username */ - success = do_connect(options[0], options[1], pset); - 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 */ - else - /* connect to default db as default user */ - success = do_connect(NULL, NULL, pset); + /* + * \a -- toggle field alignment This is deprecated and makes no 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); + else + success = do_pset("format", "unaligned", &pset->popt, quiet); } - } - - - /* \copy */ - else if (strcmp(cmd, "copy") == 0) - success = do_copy(options_string, pset); - - /* \copyright */ - else if (strcmp(cmd, "copyright") == 0) - print_copyright(); - - /* \d* commands */ - else if (cmd[0] == 'd') { - switch(cmd[1]) { - case '\0': - if (options[0]) - success = describeTableDetails(options[0], pset); - else - success = listTables("tvs", NULL, pset); /* standard listing of interesting things */ - break; - case 'a': - success = describeAggregates(options[0], pset); - break; - case 'd': - success = objectDescription(options[0], pset); - break; - case 'f': - success = describeFunctions(options[0], pset); - break; - case 'l': - success = do_lo_list(pset); - break; - case 'o': - success = describeOperators(options[0], pset); - break; - case 'p': - success = permissionsList(options[0], pset); - break; - case 'T': - success = describeTypes(options[0], pset); - break; - case 't': case 'v': case 'i': case 's': case 'S': - if (cmd[1] == 'S' && cmd[2] == '\0') - success = listTables("Stvs", NULL, pset); - else - success = listTables(&cmd[1], options[0], pset); - break; - default: - status = CMD_UNKNOWN; + + + /* + * \C -- override table title (formerly change HTML caption) This is + * deprecated. + */ + else if (strcmp(cmd, "C") == 0) + success = do_pset("title", options[0], &pset->popt, quiet); + + + + /* + * \c or \connect -- connect to new database or as different user + * + * \c foo bar : connect to db "foo" as user "bar" \c foo [-] : + * connect to db "foo" as current user \c - bar : connect to + * current db as user "bar" \c : connect to default db as + * default user + */ + else if (strcmp(cmd, "c") == 0 || strcmp(cmd, "connect") == 0) + { + if (options[1]) + /* gave username */ + success = do_connect(options[0], options[1], pset); + 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 */ + else + /* connect to default db as default user */ + success = do_connect(NULL, NULL, pset); + } } - } - /* \e or \edit -- edit the current query buffer (or a file and make it the - query buffer */ - else if (strcmp(cmd, "e") == 0 || strcmp(cmd, "edit") == 0) - status = do_edit(options[0], query_buf) ? CMD_NEWEDIT : CMD_ERROR; + /* \copy */ + else if (strcmp(cmd, "copy") == 0) + success = do_copy(options_string, pset); + /* \copyright */ + else if (strcmp(cmd, "copyright") == 0) + print_copyright(); - /* \echo */ - else if (strcmp(cmd, "echo") == 0) { - int i; - for (i=0; i<16 && options[i]; i++) - fputs(options[i], stdout); - fputs("\n", stdout); - } + /* \d* commands */ + else if (cmd[0] == 'd') + { + switch (cmd[1]) + { + case '\0': + if (options[0]) + success = describeTableDetails(options[0], pset); + else + success = listTables("tvs", NULL, pset); /* standard listing of + * interesting things */ + break; + case 'a': + success = describeAggregates(options[0], pset); + break; + case 'd': + success = objectDescription(options[0], pset); + break; + case 'f': + success = describeFunctions(options[0], pset); + break; + case 'l': + success = do_lo_list(pset); + break; + case 'o': + success = describeOperators(options[0], pset); + break; + case 'p': + success = permissionsList(options[0], pset); + break; + case 'T': + success = describeTypes(options[0], pset); + break; + case 't': + case 'v': + case 'i': + case 's': + case 'S': + if (cmd[1] == 'S' && cmd[2] == '\0') + success = listTables("Stvs", NULL, pset); + else + success = listTables(&cmd[1], options[0], pset); + break; + default: + status = CMD_UNKNOWN; + } + } - /* \f -- change field separator - (This is deprecated in favour of \pset.) */ - else if (strcmp(cmd, "f") == 0) - success = do_pset("fieldsep", options[0], &pset->popt, quiet); + /* + * \e or \edit -- edit the current query buffer (or a file and make it + * the query buffer + */ + else if (strcmp(cmd, "e") == 0 || strcmp(cmd, "edit") == 0) + status = do_edit(options[0], query_buf) ? CMD_NEWEDIT : CMD_ERROR; - /* \g means send query */ - else if (strcmp(cmd, "g") == 0) { - if (!options[0]) - pset->gfname = NULL; - else - pset->gfname = xstrdup(options[0]); - status = CMD_SEND; - } - /* help */ - else if (strcmp(cmd, "h") == 0 || strcmp(cmd, "help") == 0) - helpSQL(options_string); + /* \echo */ + else if (strcmp(cmd, "echo") == 0) + { + int i; + for (i = 0; i < 16 && options[i]; i++) + fputs(options[i], stdout); + fputs("\n", stdout); + } - /* HTML mode */ - else if (strcmp(cmd, "H") == 0 || strcmp(cmd, "html") == 0) - success = do_pset("format", "html", &pset->popt, quiet); + /* + * \f -- change field separator (This is deprecated in favour of + * \pset.) + */ + else if (strcmp(cmd, "f") == 0) + success = do_pset("fieldsep", options[0], &pset->popt, quiet); - /* \i is include file */ - else if (strcmp(cmd, "i") == 0 || strcmp(cmd, "include") == 0) - { - if (!options[0]) { - fputs("Usage: \\i <filename>\n", stderr); - success = false; + /* \g means send query */ + else if (strcmp(cmd, "g") == 0) + { + if (!options[0]) + pset->gfname = NULL; + else + pset->gfname = xstrdup(options[0]); + status = CMD_SEND; } - else - success = process_file(options[0], pset); - } - - /* \l is list databases */ - else if (strcmp(cmd, "l") == 0 || strcmp(cmd, "list") == 0) - success = listAllDbs(pset); - - - /* large object things */ - else if (strncmp(cmd, "lo_", 3)==0) { - if (strcmp(cmd+3, "export") == 0) { - if (!options[1]) { - fputs("Usage: \\lo_export <loid> <filename>\n", stderr); - success = false; - } - else - success = do_lo_export(pset, options[0], options[1]); + + /* help */ + else if (strcmp(cmd, "h") == 0 || strcmp(cmd, "help") == 0) + helpSQL(options_string); + + + /* HTML mode */ + else if (strcmp(cmd, "H") == 0 || strcmp(cmd, "html") == 0) + success = do_pset("format", "html", &pset->popt, quiet); + + + /* \i is include file */ + else if (strcmp(cmd, "i") == 0 || strcmp(cmd, "include") == 0) + { + if (!options[0]) + { + fputs("Usage: \\i <filename>\n", stderr); + success = false; + } + else + success = process_file(options[0], pset); } - else if (strcmp(cmd+3, "import") == 0) { - if (!options[0]) { - fputs("Usage: \\lo_import <filename> [<description>]\n", stderr); - success = false; - } - else - success = do_lo_import(pset, options[0], options[1]); + /* \l is list databases */ + else if (strcmp(cmd, "l") == 0 || strcmp(cmd, "list") == 0) + success = listAllDbs(pset); + + + /* large object things */ + else if (strncmp(cmd, "lo_", 3) == 0) + { + if (strcmp(cmd + 3, "export") == 0) + { + if (!options[1]) + { + fputs("Usage: \\lo_export <loid> <filename>\n", stderr); + success = false; + } + else + success = do_lo_export(pset, options[0], options[1]); + } + + else if (strcmp(cmd + 3, "import") == 0) + { + if (!options[0]) + { + fputs("Usage: \\lo_import <filename> [<description>]\n", stderr); + success = false; + } + else + success = do_lo_import(pset, options[0], options[1]); + } + + else if (strcmp(cmd + 3, "list") == 0) + success = do_lo_list(pset); + + else if (strcmp(cmd + 3, "unlink") == 0) + { + if (!options[0]) + { + fputs("Usage: \\lo_unlink <loid>\n", stderr); + success = false; + } + else + success = do_lo_unlink(pset, options[0]); + } + + else + status = CMD_UNKNOWN; } - else if (strcmp(cmd+3, "list") == 0) - success = do_lo_list(pset); + /* \o -- set query output */ + else if (strcmp(cmd, "o") == 0 || strcmp(cmd, "out") == 0) + success = setQFout(options[0], pset); - else if (strcmp(cmd+3, "unlink") == 0) { - if (!options[0]) { - fputs("Usage: \\lo_unlink <loid>\n", stderr); - success = false; - } - else - success = do_lo_unlink(pset, options[0]); + + /* \p prints the current query buffer */ + else if (strcmp(cmd, "p") == 0 || strcmp(cmd, "print") == 0) + { + if (query_buf && query_buf->len > 0) + puts(query_buf->data); + else if (!GetVariableBool(pset->vars, "quiet")) + puts("Query buffer is empty."); } - else - status = CMD_UNKNOWN; - } - - /* \o -- set query output */ - else if (strcmp(cmd, "o") == 0 || strcmp(cmd, "out") == 0) - success = setQFout(options[0], pset); - - - /* \p prints the current query buffer */ - else if (strcmp(cmd, "p") == 0 || strcmp(cmd, "print") == 0 ) - { - if (query_buf && query_buf->len > 0) - puts(query_buf->data); - else if (!GetVariableBool(pset->vars, "quiet")) - puts("Query buffer is empty."); - } - - /* \pset -- set printing parameters */ - else if (strcmp(cmd, "pset")==0) { - if (!options[0]) { - fputs("Usage: \\pset <parameter> [<value>]\n", stderr); - success = false; + /* \pset -- set printing parameters */ + else if (strcmp(cmd, "pset") == 0) + { + if (!options[0]) + { + fputs("Usage: \\pset <parameter> [<value>]\n", stderr); + success = false; + } + else + success = do_pset(options[0], options[1], &pset->popt, quiet); } - else - success = do_pset(options[0], options[1], &pset->popt, quiet); - } - - /* \q or \quit */ - else if (strcmp(cmd, "q")==0 || strcmp(cmd, "quit")==0) - status = CMD_TERMINATE; - - /* \qecho */ - else if (strcmp(cmd, "qecho") == 0) { - int i; - for (i=0; i<16 && options[i]; i++) - fputs(options[i], pset->queryFout); - fputs("\n", pset->queryFout); - } - - /* reset(clear) the buffer */ - else if (strcmp(cmd, "r")==0 || strcmp(cmd, "reset")==0) - { - resetPQExpBuffer(query_buf); - if (!quiet) puts("Query buffer reset (cleared)."); - } - - - /* \s save history in a file or show it on the screen */ - else if (strcmp(cmd, "s")==0) - { - const char * fname; - if (!options[0]) - fname = "/dev/tty"; - else - fname = options[0]; - - success = saveHistory(fname); - - if (success && !quiet && options[0]) - printf("Wrote history to %s.\n", fname); - } - - - /* \set -- generalized set option command */ - else if (strcmp(cmd, "set")==0) - { - if (!options[0]) { - /* list all variables */ - /* (This is in utter violation of the GetVariable abstraction, but - I have not dreamt up a better way.) */ - struct _variable * ptr; - for (ptr = pset->vars; ptr->next; ptr = ptr->next) - fprintf(stdout, "%s = '%s'\n", ptr->next->name, ptr->next->value); - success = true; + + /* \q or \quit */ + else if (strcmp(cmd, "q") == 0 || strcmp(cmd, "quit") == 0) + status = CMD_TERMINATE; + + /* \qecho */ + else if (strcmp(cmd, "qecho") == 0) + { + int i; + + for (i = 0; i < 16 && options[i]; i++) + fputs(options[i], pset->queryFout); + fputs("\n", pset->queryFout); } - else { - if (!SetVariable(pset->vars, options[0], options[1])) { - fprintf(stderr, "Set variable failed.\n"); - success = false; - } + + /* reset(clear) the buffer */ + else if (strcmp(cmd, "r") == 0 || strcmp(cmd, "reset") == 0) + { + resetPQExpBuffer(query_buf); + if (!quiet) + puts("Query buffer reset (cleared)."); } - } - /* \t -- turn off headers and row count */ - else if (strcmp(cmd, "t")==0) - success = do_pset("tuples_only", NULL, &pset->popt, quiet); + /* \s save history in a file or show it on the screen */ + else if (strcmp(cmd, "s") == 0) + { + const char *fname; + + if (!options[0]) + fname = "/dev/tty"; + else + fname = options[0]; - /* \T -- define html <table ...> attributes */ - else if (strcmp(cmd, "T")==0) - success = do_pset("tableattr", options[0], &pset->popt, quiet); + success = saveHistory(fname); + if (success && !quiet && options[0]) + printf("Wrote history to %s.\n", fname); + } - /* \w -- write query buffer to file */ - else if (strcmp(cmd, "w") == 0 || strcmp(cmd, "write") == 0 ) - { - FILE *fd = NULL; - bool pipe = false; - if (!options[0]) { - fprintf(stderr, "Usage \\%s <filename>\n", cmd); - success = false; + /* \set -- generalized set option command */ + else if (strcmp(cmd, "set") == 0) + { + if (!options[0]) + { + /* list all variables */ + + /* + * (This is in utter violation of the GetVariable abstraction, + * but I have not dreamt up a better way.) + */ + struct _variable *ptr; + + 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])) + { + fprintf(stderr, "Set variable failed.\n"); + success = false; + } + } } - else { - if (options[0][0] == '|') { - pipe = true; + + /* \t -- turn off headers and row count */ + else if (strcmp(cmd, "t") == 0) + 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); + + + /* \w -- write query buffer to file */ + else if (strcmp(cmd, "w") == 0 || strcmp(cmd, "write") == 0) + { + FILE *fd = NULL; + bool pipe = false; + + if (!options[0]) + { + fprintf(stderr, "Usage \\%s <filename>\n", cmd); + success = false; + } + else + { + if (options[0][0] == '|') + { + pipe = true; #ifndef __CYGWIN32__ - fd = popen(&options[0][1], "w"); + fd = popen(&options[0][1], "w"); #else - fd = popen(&options[0][1], "wb"); + fd = popen(&options[0][1], "wb"); #endif - } - else { + } + else + { #ifndef __CYGWIN32__ - fd = fopen(options[0], "w"); + fd = fopen(options[0], "w"); #else - fd = fopen(options[0], "wb"); + fd = fopen(options[0], "wb"); #endif - } + } - if (!fd) { - perror(options[0]); - success = false; - } - } + if (!fd) + { + perror(options[0]); + success = false; + } + } - if (fd) { - int result; + if (fd) + { + int result; - if (query_buf && query_buf->len > 0) - fprintf(fd, "%s\n", query_buf->data); + if (query_buf && query_buf->len > 0) + fprintf(fd, "%s\n", query_buf->data); - if (pipe) - result = pclose(fd); - else - result = fclose(fd); + if (pipe) + result = pclose(fd); + else + result = fclose(fd); - if (result == EOF) { - perror("close"); - success = false; - } + if (result == EOF) + { + perror("close"); + success = false; + } + } } - } - /* \x -- toggle expanded table representation */ - else if (strcmp(cmd, "x")==0) - success = do_pset("expanded", NULL, &pset->popt, quiet); + /* \x -- toggle expanded table representation */ + else if (strcmp(cmd, "x") == 0) + success = do_pset("expanded", NULL, &pset->popt, quiet); - /* list table rights (grant/revoke) */ - else if (strcmp(cmd, "z")==0) - success = permissionsList(options[0], pset); - + /* list table rights (grant/revoke) */ + else if (strcmp(cmd, "z") == 0) + success = permissionsList(options[0], pset); - else if (strcmp(cmd, "!")==0) - success = do_shell(options_string); - else if (strcmp(cmd, "?")==0) - slashUsage(pset); + else if (strcmp(cmd, "!") == 0) + success = do_shell(options_string); + + else if (strcmp(cmd, "?") == 0) + slashUsage(pset); #ifdef NOT_USED - /* These commands don't do anything. I just use them to test the parser. */ - else if (strcmp(cmd, "void")==0 || strcmp(cmd, "#")==0) - { - int i; - fprintf(stderr, "+ optline = |%s|\n", options_string); - for(i=0; options[i]; i++) - fprintf(stderr, "+ opt%d = |%s|\n", i, options[i]); - } + + /* + * These commands don't do anything. I just use them to test the + * parser. + */ + else if (strcmp(cmd, "void") == 0 || strcmp(cmd, "#") == 0) + { + int i; + + fprintf(stderr, "+ optline = |%s|\n", options_string); + for (i = 0; options[i]; i++) + fprintf(stderr, "+ opt%d = |%s|\n", i, options[i]); + } #endif - else { - status = CMD_UNKNOWN; - } + else + status = CMD_UNKNOWN; - if (!success) status = CMD_ERROR; - return status; + if (!success) + status = CMD_ERROR; + return status; } @@ -617,104 +694,119 @@ exec_command(const char * cmd, * The return value is malloc()'ed. */ static char * -unescape(const char * source, PsqlSettings * pset) +unescape(const char *source, PsqlSettings *pset) { - unsigned char *p; - bool esc = false; /* Last character we saw was the - escape character */ - char *destination, *tmp; - size_t length; + unsigned char *p; + bool esc = false; /* Last character we saw was the escape + * character */ + char *destination, + *tmp; + size_t length; #ifdef USE_ASSERT_CHECKING - assert(source); + assert(source); #endif - length = strlen(source)+1; - - tmp = destination = (char *) malloc(length); - if (!tmp) { - perror("malloc"); - exit(EXIT_FAILURE); - } - - for (p = (char *) source; *p; p += PQmblen(p)) { - if (esc) { - char c; - - switch (*p) - { - case 'n': - c = '\n'; - break; - case 'r': - c = '\r'; - break; - case 't': - c = '\t'; - break; - case 'f': - c = '\f'; - break; - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - { - long int l; - char * end; - l = strtol(p, &end, 0); - c = l; - p = end-1; - break; - } - default: - c = *p; - } - *tmp++ = c; - esc = false; - } + length = strlen(source) + 1; - else if (*p == '\\') { - esc = true; + tmp = destination = (char *) malloc(length); + if (!tmp) + { + perror("malloc"); + exit(EXIT_FAILURE); } - else if (*p == '$') + for (p = (char *) source; *p; p += PQmblen(p)) { - if (*(p+1) == '{') { - unsigned int len; - char *copy; - const char *value; - void * new; - len = strcspn(p+2, "}"); - copy = xstrdup(p+2); - copy[len] = '\0'; - value = interpolate_var(copy, pset); - - length += strlen(value) - (len+3); - new = realloc(destination, length); - if (!new) { - perror("realloc"); - exit(EXIT_FAILURE); + if (esc) + { + char c; + + switch (*p) + { + case 'n': + c = '\n'; + break; + case 'r': + c = '\r'; + break; + case 't': + c = '\t'; + break; + case 'f': + c = '\f'; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + long int l; + char *end; + + l = strtol(p, &end, 0); + c = l; + p = end - 1; + break; + } + default: + c = *p; + } + *tmp++ = c; + esc = false; + } + + else if (*p == '\\') + esc = true; + + else if (*p == '$') + { + if (*(p + 1) == '{') + { + unsigned int len; + char *copy; + const char *value; + void *new; + + len = strcspn(p + 2, "}"); + copy = xstrdup(p + 2); + copy[len] = '\0'; + value = interpolate_var(copy, pset); + + length += strlen(value) - (len + 3); + new = realloc(destination, length); + if (!new) + { + perror("realloc"); + exit(EXIT_FAILURE); + } + tmp = new + (tmp - destination); + destination = new; + + strcpy(tmp, value); + tmp += strlen(value); + p += len + 2; + free(copy); + } + else + *tmp++ = '$'; } - tmp = new + (tmp - destination); - destination = new; - - strcpy(tmp, value); - tmp += strlen(value); - p += len + 2; - free(copy); - } - else { - *tmp++ = '$'; - } - } - else { - *tmp++ = *p; - esc = false; + else + { + *tmp++ = *p; + esc = false; + } } - } - *tmp = '\0'; - return destination; + *tmp = '\0'; + return destination; } @@ -731,109 +823,120 @@ unescape(const char * source, PsqlSettings * pset) * but the old one was set back. Otherwise it terminates the program. */ bool -do_connect(const char *new_dbname, const char *new_user, PsqlSettings * pset) +do_connect(const char *new_dbname, const char *new_user, PsqlSettings *pset) { - PGconn *oldconn = pset->db; - const char *dbparam = NULL; - const char *userparam = NULL; - char *pwparam = NULL; - char * prompted_password = NULL; - char * prompted_user = NULL; - bool need_pass; - bool success = false; - - /* 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)) - 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 )) { - 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) - pwparam = prompted_password = simple_prompt("Password: ", 100, false); /* need to save for free() */ - - /* Use old password if no new one given (if you didn't have an old one, fine) */ - if (!pwparam) - pwparam = PQpass(oldconn); + PGconn *oldconn = pset->db; + const char *dbparam = NULL; + const char *userparam = NULL; + char *pwparam = NULL; + char *prompted_password = NULL; + char *prompted_user = NULL; + bool need_pass; + bool success = false; + + /* 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)) + 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)) + 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) + pwparam = prompted_password = simple_prompt("Password: ", 100, false); /* need to save for + * free() */ + + /* + * Use old password if no new one given (if you didn't have an old + * one, fine) + */ + if (!pwparam) + pwparam = PQpass(oldconn); #ifdef MULTIBYTE - /* - * PGCLIENTENCODING may be set by the previous connection. if a - * user does not explicitly set PGCLIENTENCODING, we should - * discard PGCLIENTENCODING so that libpq could get the backend - * encoding as the default PGCLIENTENCODING value. -- 1998/12/12 - * Tatsuo Ishii - */ - - if (!pset->has_client_encoding) - putenv("PGCLIENTENCODING="); + + /* + * PGCLIENTENCODING may be set by the previous connection. if a user + * does not explicitly set PGCLIENTENCODING, we should discard + * PGCLIENTENCODING so that libpq could get the backend encoding as + * the default PGCLIENTENCODING value. -- 1998/12/12 Tatsuo Ishii + */ + + if (!pset->has_client_encoding) + putenv("PGCLIENTENCODING="); #endif - do { - need_pass = false; - 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) { - need_pass = true; - free(prompted_password); - prompted_password = NULL; - pwparam = prompted_password = simple_prompt("Password: ", 100, false); - } - } 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) - { - fprintf(stderr, "Could not establish database connection.\n%s", PQerrorMessage(pset->db)); - PQfinish(pset->db); - if (!oldconn || !pset->cur_cmd_interactive) { /* we don't want unpredictable things to happen - in scripting mode */ - fputs("Terminating.\n", stderr); - if (oldconn) - PQfinish(oldconn); - pset->db = NULL; - } - else { - fputs("Keeping old connection.\n", stderr); - pset->db = oldconn; - } - } - else { - if (!GetVariable(pset->vars, "quiet")) { - if (userparam != new_user) /* no new user */ - printf("You are now connected to database %s.\n", dbparam); - else if (dbparam != new_dbname) /* no new db */ - printf("You are now connected as new user %s.\n", new_user); - else /* both new */ - printf("You are now connected to database %s as user %s.\n", - PQdb(pset->db), PQuser(pset->db)); + do + { + need_pass = false; + 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) + { + need_pass = true; + free(prompted_password); + prompted_password = NULL; + pwparam = prompted_password = simple_prompt("Password: ", 100, false); + } + } 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) + { + fprintf(stderr, "Could not establish database connection.\n%s", PQerrorMessage(pset->db)); + PQfinish(pset->db); + if (!oldconn || !pset->cur_cmd_interactive) + { /* we don't want unpredictable things to + * happen in scripting mode */ + fputs("Terminating.\n", stderr); + if (oldconn) + PQfinish(oldconn); + pset->db = NULL; + } + else + { + fputs("Keeping old connection.\n", stderr); + pset->db = oldconn; + } } + else + { + if (!GetVariable(pset->vars, "quiet")) + { + if (userparam != new_user) /* no new user */ + printf("You are now connected to database %s.\n", dbparam); + else if (dbparam != new_dbname) /* no new db */ + printf("You are now connected as new user %s.\n", new_user); + else +/* both new */ + printf("You are now connected to database %s as user %s.\n", + PQdb(pset->db), PQuser(pset->db)); + } - if (oldconn) - PQfinish(oldconn); + if (oldconn) + PQfinish(oldconn); - success = true; - } + success = true; + } - return success; + return success; } @@ -848,35 +951,36 @@ do_connect(const char *new_dbname, const char *new_user, PsqlSettings * pset) static bool editFile(const char *fname) { - char *editorName; - char *sys; - int result; + char *editorName; + char *sys; + int result; #ifdef USE_ASSERT_CHECKING - assert(fname); + assert(fname); #else - if (!fname) return false; + if (!fname) + return false; #endif - /* Find an editor to use */ - editorName = getenv("PSQL_EDITOR"); - if (!editorName) - editorName = getenv("EDITOR"); - if (!editorName) - editorName = getenv("VISUAL"); - if (!editorName) - editorName = DEFAULT_EDITOR; - - sys = malloc(strlen(editorName) + strlen(fname) + 32 + 1); - if (!sys) - return false; - sprintf(sys, "exec %s %s", editorName, fname); - result = system(sys); - if (result == -1 || result == 127) - perror(sys); - free(sys); - - return result==0; + /* Find an editor to use */ + editorName = getenv("PSQL_EDITOR"); + if (!editorName) + editorName = getenv("EDITOR"); + if (!editorName) + editorName = getenv("VISUAL"); + if (!editorName) + editorName = DEFAULT_EDITOR; + + sys = malloc(strlen(editorName) + strlen(fname) + 32 + 1); + if (!sys) + return false; + sprintf(sys, "exec %s %s", editorName, fname); + result = system(sys); + if (result == -1 || result == 127) + perror(sys); + free(sys); + + return result == 0; } @@ -884,117 +988,135 @@ editFile(const char *fname) static bool do_edit(const char *filename_arg, PQExpBuffer query_buf) { - char fnametmp[64]; - FILE * stream; - const char *fname; - bool error = false; + char fnametmp[64]; + FILE *stream; + const char *fname; + bool error = false; + #ifndef WIN32 - struct stat before, after; + struct stat before, + after; + #endif #ifdef USE_ASSERT_CHECKING - assert(query_buf); + assert(query_buf); #else - if (!query_buf) return false; + if (!query_buf) + return false; #endif - if (filename_arg) - fname = filename_arg; + if (filename_arg) + fname = filename_arg; - else { - /* make a temp file to edit */ + else + { + /* make a temp file to edit */ #ifndef WIN32 - mode_t oldumask; + mode_t oldumask; - sprintf(fnametmp, "/tmp/psql.edit.%ld.%ld", (long) geteuid(), (long) getpid()); + sprintf(fnametmp, "/tmp/psql.edit.%ld.%ld", (long) geteuid(), (long) getpid()); #else - GetTempFileName(".", "psql", 0, fnametmp); + GetTempFileName(".", "psql", 0, fnametmp); #endif - fname = (const char *)fnametmp; + fname = (const char *) fnametmp; #ifndef WIN32 - oldumask = umask(0177); + oldumask = umask(0177); #endif - stream = fopen(fname, "w"); + stream = fopen(fname, "w"); #ifndef WIN32 - umask(oldumask); + umask(oldumask); #endif - if (!stream) { - perror(fname); - error = true; + if (!stream) + { + perror(fname); + error = true; + } + else + { + unsigned int ql = query_buf->len; + + if (ql == 0 || query_buf->data[ql - 1] != '\n') + { + appendPQExpBufferChar(query_buf, '\n'); + ql++; + } + + if (fwrite(query_buf->data, 1, ql, stream) != ql) + { + perror(fname); + fclose(stream); + remove(fname); + error = true; + } + else + fclose(stream); + } } - else { - unsigned int ql = query_buf->len; - if (ql == 0 || query_buf->data[ql - 1] != '\n') { - appendPQExpBufferChar(query_buf, '\n'); - ql++; - } - - if (fwrite(query_buf->data, 1, ql, stream) != ql) { + +#ifndef WIN32 + if (!error && stat(fname, &before) != 0) + { perror(fname); - fclose(stream); - remove(fname); error = true; - } - else - fclose(stream); } - } - -#ifndef WIN32 - if (!error && stat(fname, &before) != 0) { - perror(fname); - error = true; - } #endif - /* call editor */ - if (!error) - error = !editFile(fname); + /* call editor */ + if (!error) + error = !editFile(fname); #ifndef WIN32 - if (!error && stat(fname, &after) !=0) { - perror(fname); - error = true; - } + if (!error && stat(fname, &after) != 0) + { + perror(fname); + error = true; + } - if (!error && before.st_mtime != after.st_mtime) { + if (!error && before.st_mtime != after.st_mtime) + { #else - if (!error) { + if (!error) + { #endif - stream = fopen(fname, "r"); - if (!stream) { - perror(fname); - error = true; - } - else { - /* read file back in */ - char line[1024]; - size_t result; - - resetPQExpBuffer(query_buf); - do { - result = fread(line, 1, 1024, stream); - if (ferror(stream)) { - perror(fname); - error = true; - break; + stream = fopen(fname, "r"); + if (!stream) + { + perror(fname); + error = true; + } + else + { + /* read file back in */ + char line[1024]; + size_t result; + + resetPQExpBuffer(query_buf); + do + { + result = fread(line, 1, 1024, stream); + if (ferror(stream)) + { + perror(fname); + error = true; + break; + } + appendBinaryPQExpBuffer(query_buf, line, result); + } while (!feof(stream)); + appendPQExpBufferChar(query_buf, '\0'); + + fclose(stream); } - appendBinaryPQExpBuffer(query_buf, line, result); - } while (!feof(stream)); - appendPQExpBufferChar(query_buf, '\0'); - fclose(stream); + /* remove temp file */ + if (!filename_arg) + remove(fname); } - /* remove temp file */ - if (!filename_arg) - remove(fname); - } - - return !error; + return !error; } @@ -1008,26 +1130,27 @@ do_edit(const char *filename_arg, PQExpBuffer query_buf) bool process_file(const char *filename, PsqlSettings *pset) { - FILE *fd; - int result; + FILE *fd; + int result; - if (!filename) - return false; + if (!filename) + return false; #ifdef __CYGWIN32__ - fd = fopen(filename, "rb"); + fd = fopen(filename, "rb"); #else - fd = fopen(filename, "r"); + fd = fopen(filename, "r"); #endif - if (!fd) { - perror(filename); - return false; - } + if (!fd) + { + perror(filename); + return false; + } - result = MainLoop(pset, fd); - fclose(fd); - return (result == EXIT_SUCCESS); + result = MainLoop(pset, fd); + fclose(fd); + return (result == EXIT_SUCCESS); } @@ -1039,158 +1162,178 @@ process_file(const char *filename, PsqlSettings *pset) static const char * _align2string(enum printFormat in) { - switch (in) { - case PRINT_NOTHING: - return "nothing"; - break; - case PRINT_UNALIGNED: - return "unaligned"; - break; - case PRINT_ALIGNED: - return "aligned"; - break; - case PRINT_HTML: - return "html"; - break; - case PRINT_LATEX: - return "latex"; - break; - } - return "unknown"; + switch (in) + { + case PRINT_NOTHING: + return "nothing"; + break; + case PRINT_UNALIGNED: + return "unaligned"; + break; + case PRINT_ALIGNED: + return "aligned"; + break; + case PRINT_HTML: + return "html"; + break; + case PRINT_LATEX: + return "latex"; + break; + } + return "unknown"; } bool -do_pset(const char * param, const char * value, printQueryOpt * popt, bool quiet) +do_pset(const char *param, const char *value, printQueryOpt * popt, bool quiet) { - size_t vallen = 0; + size_t vallen = 0; + #ifdef USE_ASSERT_CHECKING - assert(param); + assert(param); #else - if (!param) return false; + if (!param) + return false; #endif - if (value) - vallen = strlen(value); - - /* set format */ - if (strcmp(param, "format")==0) { - if (!value) - ; - else if (strncasecmp("unaligned", value, vallen)==0) - popt->topt.format = PRINT_UNALIGNED; - else if (strncasecmp("aligned", value, vallen)==0) - popt->topt.format = PRINT_ALIGNED; - else if (strncasecmp("html", value, vallen)==0) - popt->topt.format = PRINT_HTML; - else if (strncasecmp("latex", value, vallen)==0) - popt->topt.format = PRINT_LATEX; - else { - fprintf(stderr, "Allowed formats are unaligned, aligned, html, latex.\n"); - return false; + if (value) + vallen = strlen(value); + + /* set format */ + if (strcmp(param, "format") == 0) + { + if (!value) + ; + else if (strncasecmp("unaligned", value, vallen) == 0) + popt->topt.format = PRINT_UNALIGNED; + else if (strncasecmp("aligned", value, vallen) == 0) + popt->topt.format = PRINT_ALIGNED; + else if (strncasecmp("html", value, vallen) == 0) + popt->topt.format = PRINT_HTML; + else if (strncasecmp("latex", value, vallen) == 0) + popt->topt.format = PRINT_LATEX; + else + { + fprintf(stderr, "Allowed formats are unaligned, aligned, html, latex.\n"); + return false; + } + + if (!quiet) + printf("Output format is %s.\n", _align2string(popt->topt.format)); } - if (!quiet) - printf("Output format is %s.\n", _align2string(popt->topt.format)); - } + /* set border style/width */ + else if (strcmp(param, "border") == 0) + { + if (value) + popt->topt.border = atoi(value); - /* set border style/width */ - else if (strcmp(param, "border")==0) { - if (value) - popt->topt.border = atoi(value); - - if (!quiet) - printf("Border style is %d.\n", popt->topt.border); - } - - /* set expanded/vertical mode */ - else if (strcmp(param, "x")==0 || strcmp(param, "expanded")==0 || strcmp(param, "vertical")==0) { - popt->topt.expanded = !popt->topt.expanded; - if (!quiet) - printf("Expanded display is %s.\n", popt->topt.expanded ? "on" : "off"); - } - - /* null display */ - else if (strcmp(param, "null")==0) { - if (value) { - free(popt->nullPrint); - popt->nullPrint = xstrdup(value); - } - if (!quiet) - printf("Null display is \"%s\".\n", popt->nullPrint ? popt->nullPrint : ""); - } - - /* field separator for unaligned text */ - else if (strcmp(param, "fieldsep")==0) { - if (value) { - free(popt->topt.fieldSep); - popt->topt.fieldSep = xstrdup(value); + if (!quiet) + printf("Border style is %d.\n", popt->topt.border); } - if (!quiet) - printf("Field separator is \"%s\".\n", popt->topt.fieldSep); - } - - /* toggle between full and barebones format */ - else if (strcmp(param, "t")==0 || strcmp(param, "tuples_only")==0) { - popt->topt.tuples_only = !popt->topt.tuples_only; - if (!quiet) { - if (popt->topt.tuples_only) - puts("Showing only tuples."); - else - puts("Tuples only is off."); + + /* set expanded/vertical mode */ + else if (strcmp(param, "x") == 0 || strcmp(param, "expanded") == 0 || strcmp(param, "vertical") == 0) + { + popt->topt.expanded = !popt->topt.expanded; + if (!quiet) + printf("Expanded display is %s.\n", popt->topt.expanded ? "on" : "off"); } - } - /* set title override */ - else if (strcmp(param, "title")==0) { - free(popt->title); - if (!value) - popt->title = NULL; - else - popt->title = xstrdup(value); - - if (!quiet) { - if (popt->title) - printf("Title is \"%s\".\n", popt->title); - else - printf("Title is unset.\n"); + /* null display */ + else if (strcmp(param, "null") == 0) + { + if (value) + { + free(popt->nullPrint); + popt->nullPrint = xstrdup(value); + } + if (!quiet) + printf("Null display is \"%s\".\n", popt->nullPrint ? popt->nullPrint : ""); } - } - /* set HTML table tag options */ - else if (strcmp(param, "T")==0 || strcmp(param, "tableattr")==0) { - free(popt->topt.tableAttr); - if (!value) - popt->topt.tableAttr = NULL; - else - popt->topt.tableAttr = xstrdup(value); + /* field separator for unaligned text */ + else if (strcmp(param, "fieldsep") == 0) + { + if (value) + { + free(popt->topt.fieldSep); + popt->topt.fieldSep = xstrdup(value); + } + if (!quiet) + printf("Field separator is \"%s\".\n", popt->topt.fieldSep); + } - if (!quiet) { - if (popt->topt.tableAttr) - printf("Table attribute is \"%s\".\n", popt->topt.tableAttr); - else - printf("Table attributes unset.\n"); + /* toggle between full and barebones format */ + else if (strcmp(param, "t") == 0 || strcmp(param, "tuples_only") == 0) + { + popt->topt.tuples_only = !popt->topt.tuples_only; + if (!quiet) + { + if (popt->topt.tuples_only) + puts("Showing only tuples."); + else + puts("Tuples only is off."); + } + } + + /* set title override */ + else if (strcmp(param, "title") == 0) + { + free(popt->title); + if (!value) + popt->title = NULL; + else + popt->title = xstrdup(value); + + if (!quiet) + { + if (popt->title) + printf("Title is \"%s\".\n", popt->title); + else + printf("Title is unset.\n"); + } } - } - - /* toggle use of pager */ - else if (strcmp(param, "pager")==0) { - popt->topt.pager = !popt->topt.pager; - if (!quiet) { - if (popt->topt.pager) - puts("Using pager is on."); - else - puts("Using pager is off."); + + /* set HTML table tag options */ + else if (strcmp(param, "T") == 0 || strcmp(param, "tableattr") == 0) + { + free(popt->topt.tableAttr); + if (!value) + popt->topt.tableAttr = NULL; + else + popt->topt.tableAttr = xstrdup(value); + + if (!quiet) + { + if (popt->topt.tableAttr) + printf("Table attribute is \"%s\".\n", popt->topt.tableAttr); + else + printf("Table attributes unset.\n"); + } } - } - - else { - fprintf(stderr, "Unknown option: %s\n", param); - return false; - } + /* toggle use of pager */ + else if (strcmp(param, "pager") == 0) + { + popt->topt.pager = !popt->topt.pager; + if (!quiet) + { + if (popt->topt.pager) + puts("Using pager is on."); + else + puts("Using pager is off."); + } + } - return true; + + else + { + fprintf(stderr, "Unknown option: %s\n", param); + return false; + } + + return true; } @@ -1200,29 +1343,31 @@ do_pset(const char * param, const char * value, printQueryOpt * popt, bool quiet static bool do_shell(const char *command) { - int result; + int result; - if (!command) { - char *sys; - char *shellName; + if (!command) + { + char *sys; + char *shellName; + + shellName = getenv("SHELL"); + if (shellName == NULL) + shellName = DEFAULT_SHELL; + + sys = malloc(strlen(shellName) + 16); + if (!sys) + return false; + sprintf(sys, "exec %s", shellName); + result = system(sys); + free(sys); + } + else + result = system(command); - shellName = getenv("SHELL"); - if (shellName == NULL) - shellName = DEFAULT_SHELL; - - sys = malloc(strlen(shellName) + 16); - if (!sys) - return false; - sprintf(sys, "exec %s", shellName); - result = system(sys); - free(sys); - } - else - result = system(command); - - if (result==127 || result==-1) { - perror("system"); - return false; - } - return true; + if (result == 127 || result == -1) + { + perror("system"); + return false; + } + return true; } diff --git a/src/bin/psql/command.h b/src/bin/psql/command.h index eeaf0859ba..a7850263c3 100644 --- a/src/bin/psql/command.h +++ b/src/bin/psql/command.h @@ -11,39 +11,36 @@ -typedef enum _backslashResult { - CMD_UNKNOWN = 0, /* not done parsing yet (internal only) */ - CMD_SEND, /* query complete; send off */ - CMD_SKIP_LINE, /* keep building query */ - CMD_TERMINATE, /* quit program */ - CMD_NEWEDIT, /* query buffer was changed (e.g., via \e) */ - CMD_ERROR /* the execution of the backslash command resulted - in an error */ -} backslashResult; - - - -backslashResult -HandleSlashCmds(PsqlSettings *pset, - const char *line, - PQExpBuffer query_buf, - const char ** end_of_cmd); - -bool -do_connect(const char *new_dbname, - const char *new_user, - PsqlSettings *pset); - -bool -process_file(const char *filename, - PsqlSettings *pset); - - -bool -do_pset(const char * param, - const char * value, - printQueryOpt * popt, - bool quiet); +typedef enum _backslashResult +{ + CMD_UNKNOWN = 0, /* not done parsing yet (internal only) */ + CMD_SEND, /* query complete; send off */ + CMD_SKIP_LINE, /* keep building query */ + CMD_TERMINATE, /* quit program */ + CMD_NEWEDIT, /* query buffer was changed (e.g., via \e) */ + CMD_ERROR /* the execution of the backslash command + * resulted in an error */ +} backslashResult; + + + +backslashResult HandleSlashCmds(PsqlSettings *pset, + const char *line, + PQExpBuffer query_buf, + const char **end_of_cmd); + +bool do_connect(const char *new_dbname, + const char *new_user, + PsqlSettings *pset); + +bool process_file(const char *filename, + PsqlSettings *pset); + + +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 71df7bd098..82c5d12a13 100644 --- a/src/bin/psql/common.c +++ b/src/bin/psql/common.c @@ -14,7 +14,7 @@ #include <signal.h> #include <assert.h> #ifndef WIN32 -#include <unistd.h> /* for write() */ +#include <unistd.h> /* for write() */ #endif #include <libpq-fe.h> @@ -39,19 +39,23 @@ * "Safe" wrapper around strdup() * (Using this also avoids writing #ifdef HAVE_STRDUP in every file :) */ -char * xstrdup(const char * string) +char * +xstrdup(const char *string) { - char * tmp; - if (!string) { - fprintf(stderr, "xstrdup: Cannot duplicate null pointer.\n"); - exit(EXIT_FAILURE); - } - tmp = strdup(string); - if (!tmp) { - perror("strdup"); - exit(EXIT_FAILURE); - } - return tmp; + char *tmp; + + if (!string) + { + fprintf(stderr, "xstrdup: Cannot duplicate null pointer.\n"); + exit(EXIT_FAILURE); + } + tmp = strdup(string); + if (!tmp) + { + perror("strdup"); + exit(EXIT_FAILURE); + } + return tmp; } @@ -67,66 +71,67 @@ char * xstrdup(const char * string) bool setQFout(const char *fname, PsqlSettings *pset) { - bool status = true; + bool status = true; #ifdef USE_ASSERT_CHECKING - assert(pset); + assert(pset); #else - if (!pset) return false; + if (!pset) + return false; #endif - /* Close old file/pipe */ - if (pset->queryFout && pset->queryFout != stdout && pset->queryFout != stderr) - { - if (pset->queryFoutPipe) - pclose(pset->queryFout); - else - fclose(pset->queryFout); - } + /* Close old file/pipe */ + if (pset->queryFout && pset->queryFout != stdout && pset->queryFout != stderr) + { + if (pset->queryFoutPipe) + pclose(pset->queryFout); + else + fclose(pset->queryFout); + } - /* If no filename, set stdout */ - if (!fname || fname[0]=='\0') - { - pset->queryFout = stdout; - pset->queryFoutPipe = false; - } - else if (*fname == '|') - { - const char * pipename = fname+1; + /* If no filename, set stdout */ + if (!fname || fname[0] == '\0') + { + pset->queryFout = stdout; + pset->queryFoutPipe = false; + } + else if (*fname == '|') + { + const char *pipename = fname + 1; #ifndef __CYGWIN32__ - pset->queryFout = popen(pipename, "w"); + pset->queryFout = popen(pipename, "w"); #else - pset->queryFout = popen(pipename, "wb"); + pset->queryFout = popen(pipename, "wb"); #endif - pset->queryFoutPipe = true; - } - else - { + pset->queryFoutPipe = true; + } + else + { #ifndef __CYGWIN32__ - pset->queryFout = fopen(fname, "w"); + pset->queryFout = fopen(fname, "w"); #else - pset->queryFout = fopen(fname, "wb"); + pset->queryFout = fopen(fname, "wb"); #endif - pset->queryFoutPipe = false; - } - - if (!pset->queryFout) - { - perror(fname); - pset->queryFout = stdout; - pset->queryFoutPipe = false; - status = false; - } - - /* Direct signals */ - if (pset->queryFoutPipe) - pqsignal(SIGPIPE, SIG_IGN); - else - pqsignal(SIGPIPE, SIG_DFL); - - return status; + pset->queryFoutPipe = false; + } + + if (!pset->queryFout) + { + perror(fname); + pset->queryFout = stdout; + pset->queryFoutPipe = false; + status = false; + } + + /* Direct signals */ + if (pset->queryFoutPipe) + pqsignal(SIGPIPE, SIG_IGN); + else + pqsignal(SIGPIPE, SIG_DFL); + + return status; } @@ -137,60 +142,67 @@ setQFout(const char *fname, PsqlSettings *pset) * Generalized function especially intended for reading in usernames and * password interactively. Reads from stdin. * - * prompt: The prompt to print - * maxlen: How many characters to accept - * echo: Set to false if you want to hide what is entered (for passwords) + * prompt: The prompt to print + * maxlen: How many characters to accept + * echo: Set to false if you want to hide what is entered (for passwords) * * Returns a malloc()'ed string with the input (w/o trailing newline). */ char * simple_prompt(const char *prompt, int maxlen, bool echo) { - int length; - char * destination; + int length; + char *destination; #ifdef HAVE_TERMIOS_H - struct termios t_orig, t; + struct termios t_orig, + t; + #endif - destination = (char *) malloc(maxlen+2); - if (!destination) - return NULL; - if (prompt) fputs(prompt, stdout); + destination = (char *) malloc(maxlen + 2); + if (!destination) + return NULL; + if (prompt) + fputs(prompt, stdout); #ifdef HAVE_TERMIOS_H - if (!echo) - { - tcgetattr(0, &t); - t_orig = t; - t.c_lflag &= ~ECHO; - tcsetattr(0, TCSADRAIN, &t); - } + if (!echo) + { + tcgetattr(0, &t); + t_orig = t; + t.c_lflag &= ~ECHO; + tcsetattr(0, TCSADRAIN, &t); + } #endif - fgets(destination, maxlen, stdin); + fgets(destination, maxlen, stdin); #ifdef HAVE_TERMIOS_H - if (!echo) { - tcsetattr(0, TCSADRAIN, &t_orig); - puts(""); - } + if (!echo) + { + tcsetattr(0, TCSADRAIN, &t_orig); + puts(""); + } #endif - length = strlen(destination); - if (length > 0 && destination[length - 1] != '\n') { - /* eat rest of the line */ - char buf[512]; - do { - fgets(buf, 512, stdin); - } while (buf[strlen(buf) - 1] != '\n'); - } + length = strlen(destination); + if (length > 0 && destination[length - 1] != '\n') + { + /* eat rest of the line */ + char buf[512]; + + do + { + fgets(buf, 512, stdin); + } while (buf[strlen(buf) - 1] != '\n'); + } - if (length > 0 && destination[length - 1] == '\n') - /* remove trailing newline */ - destination[length - 1] = '\0'; + if (length > 0 && destination[length - 1] == '\n') + /* remove trailing newline */ + destination[length - 1] = '\0'; - return destination; + return destination; } @@ -205,68 +217,79 @@ simple_prompt(const char *prompt, int maxlen, bool echo) * immediate consumption. */ const char * -interpolate_var(const char * name, PsqlSettings * pset) +interpolate_var(const char *name, PsqlSettings *pset) { - const char * var; + const char *var; #ifdef USE_ASSERT_CHECKING - assert(name); - assert(pset); + assert(name); + assert(pset); #else - if (!name || !pset) return NULL; + if (!name || !pset) + return NULL; #endif - if (strspn(name, VALID_VARIABLE_CHARS) == strlen(name)) { - var = GetVariable(pset->vars, name); - if (var) - return var; - else - return ""; - } - - /* 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 (strspn(name, VALID_VARIABLE_CHARS) == strlen(name)) + { + var = GetVariable(pset->vars, name); + if (var) + return var; + else + return ""; + } - if (strcmp(name, "User")==0) { - if (PQuser(pset->db)) - return PQuser(pset->db); - else - return ""; - } + /* otherwise return magic variable */ - if (strcmp(name, "Host")==0) { - if (PQhost(pset->db)) - return PQhost(pset->db); - else - return ""; - } + /* + * (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, "Port")==0) { - if (PQport(pset->db)) - return PQport(pset->db); - else - return ""; - } + 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 ""; + } - /* env vars (if env vars are all caps there should be no prob, otherwise - you're on your own */ + 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 ""; + } + + /* + * env vars (if env vars are all caps there should be no prob, + * otherwise you're on your own + */ - if ((var = getenv(name))) - return var; + if ((var = getenv(name))) + return var; - return ""; + return ""; } - + /* @@ -284,7 +307,7 @@ interpolate_var(const char * name, PsqlSettings * pset) * at least avoid trusting printf by using the more primitive fputs(). */ -PGconn * cancelConn; +PGconn *cancelConn; #ifdef WIN32 #define safe_write_stderr(String) fputs(s, stderr) @@ -296,79 +319,84 @@ PGconn * cancelConn; static void handle_sigint(SIGNAL_ARGS) { - /* accept signal if no connection */ - if (cancelConn == NULL) - exit(1); - /* Try to send cancel request */ - if (PQrequestCancel(cancelConn)) - safe_write_stderr("\nCANCEL request sent\n"); - else { - safe_write_stderr("\nCould not send cancel request: "); - safe_write_stderr(PQerrorMessage(cancelConn)); - } + /* accept signal if no connection */ + if (cancelConn == NULL) + exit(1); + /* Try to send cancel request */ + if (PQrequestCancel(cancelConn)) + safe_write_stderr("\nCANCEL request sent\n"); + else + { + safe_write_stderr("\nCould not send cancel request: "); + safe_write_stderr(PQerrorMessage(cancelConn)); + } } -/* - * PSQLexec +/* + * 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). */ -PGresult * +PGresult * PSQLexec(PsqlSettings *pset, const char *query) { - PGresult *res; - const char * var; - - if (!pset->db) { - fputs("You are not currently connected to a database.\n", stderr); - return NULL; - } - - var = GetVariable(pset->vars, "echo_secret"); - if (var) { - printf("********* QUERY *********\n%s\n*************************\n\n", query); - fflush(stdout); - } - - if (var && strcmp(var, "noexec")==0) - return NULL; - - cancelConn = pset->db; - pqsignal(SIGINT, handle_sigint); /* control-C => cancel */ - - res = PQexec(pset->db, query); - - pqsignal(SIGINT, SIG_DFL); /* no control-C is back to normal */ - - if (PQstatus(pset->db) == CONNECTION_BAD) - { - 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; - return NULL; + PGresult *res; + const char *var; + + if (!pset->db) + { + fputs("You are not currently connected to a database.\n", stderr); + return NULL; + } + + var = GetVariable(pset->vars, "echo_secret"); + if (var) + { + printf("********* QUERY *********\n%s\n*************************\n\n", query); + fflush(stdout); + } + + if (var && strcmp(var, "noexec") == 0) + return NULL; + + cancelConn = pset->db; + pqsignal(SIGINT, handle_sigint); /* control-C => cancel */ + + res = PQexec(pset->db, query); + + pqsignal(SIGINT, SIG_DFL); /* no control-C is back to normal */ + + if (PQstatus(pset->db) == CONNECTION_BAD) + { + 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; + return NULL; + } + else + fputs("Succeeded.\n", stderr); } + + 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("Succeeded.\n", stderr); - } - - 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 { - fprintf(stderr, "%s", PQerrorMessage(pset->db)); - PQclear(res); - return NULL; - } + { + fprintf(stderr, "%s", PQerrorMessage(pset->db)); + PQclear(res); + return NULL; + } } @@ -388,131 +416,136 @@ PSQLexec(PsqlSettings *pset, const char *query) bool SendQuery(PsqlSettings *pset, const char *query) { - bool success = false; - PGresult *results; - PGnotify *notify; - - if (!pset->db) { - fputs("You are not currently connected to a database.\n", stderr); - return false; - } - - if (GetVariableBool(pset->vars, "singlestep")) { - char buf[3]; - fprintf(stdout, "***(Single step mode: Verify query)*********************************************\n" - "QUERY: %s\n" - "***(press return to proceed or enter x and return to cancel)********************\n", - query); - fflush(stdout); - fgets(buf, 3, stdin); - if (buf[0]=='x') - return false; - fflush(stdin); - } - - cancelConn = pset->db; - pqsignal(SIGINT, handle_sigint); - - results = PQexec(pset->db, query); - - pqsignal(SIGINT, SIG_DFL); - - if (results == NULL) - { - fputs(PQerrorMessage(pset->db), pset->queryFout); - success = false; - } - else - { - switch (PQresultStatus(results)) - { - case PGRES_TUPLES_OK: - if (pset->gfname) - { - PsqlSettings settings_copy = *pset; - - settings_copy.queryFout = stdout; - if (!setQFout(pset->gfname, &settings_copy)) { - success = false; - break; - } + bool success = false; + PGresult *results; + PGnotify *notify; - printQuery(results, &settings_copy.popt, settings_copy.queryFout); - - /* close file/pipe */ - setQFout(NULL, &settings_copy); - - free(pset->gfname); - pset->gfname = NULL; - - success = true; - break; - } - else - { - success = true; - printQuery(results, &pset->popt, pset->queryFout); - fflush(pset->queryFout); - } - break; - case PGRES_EMPTY_QUERY: - success = true; - break; - case PGRES_COMMAND_OK: - success = true; - fprintf(pset->queryFout, "%s\n", PQcmdStatus(results)); - break; - - case PGRES_COPY_OUT: - if (pset->cur_cmd_interactive && !GetVariable(pset->vars, "quiet")) - puts("Copy command returns:"); - - success = handleCopyOut(pset->db, pset->queryFout); - break; - - case PGRES_COPY_IN: - if (pset->cur_cmd_interactive && !GetVariable(pset->vars, "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); - break; - - case PGRES_NONFATAL_ERROR: - case PGRES_FATAL_ERROR: - case PGRES_BAD_RESPONSE: - success = false; - fputs(PQerrorMessage(pset->db), pset->queryFout); - break; + if (!pset->db) + { + fputs("You are not currently connected to a database.\n", stderr); + return false; } - if (PQstatus(pset->db) == CONNECTION_BAD) + if (GetVariableBool(pset->vars, "singlestep")) { - 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(results); - pset->db = NULL; - return false; - } - else - fputs("Succeeded.\n", stderr); + char buf[3]; + + fprintf(stdout, "***(Single step mode: Verify query)*********************************************\n" + "QUERY: %s\n" + "***(press return to proceed or enter x and return to cancel)********************\n", + query); + fflush(stdout); + fgets(buf, 3, stdin); + if (buf[0] == 'x') + return false; + fflush(stdin); } - /* check for asynchronous notification returns */ - while ((notify = PQnotifies(pset->db)) != NULL) + cancelConn = pset->db; + pqsignal(SIGINT, handle_sigint); + + results = PQexec(pset->db, query); + + pqsignal(SIGINT, SIG_DFL); + + if (results == NULL) { - fprintf(pset->queryFout, "Asynchronous NOTIFY '%s' from backend with pid '%d' received.\n", - notify->relname, notify->be_pid); - free(notify); + fputs(PQerrorMessage(pset->db), pset->queryFout); + success = false; } + else + { + switch (PQresultStatus(results)) + { + case PGRES_TUPLES_OK: + if (pset->gfname) + { + PsqlSettings settings_copy = *pset; + + settings_copy.queryFout = stdout; + if (!setQFout(pset->gfname, &settings_copy)) + { + success = false; + break; + } + + printQuery(results, &settings_copy.popt, settings_copy.queryFout); + + /* close file/pipe */ + setQFout(NULL, &settings_copy); + + free(pset->gfname); + pset->gfname = NULL; + + success = true; + break; + } + else + { + success = true; + printQuery(results, &pset->popt, pset->queryFout); + fflush(pset->queryFout); + } + break; + case PGRES_EMPTY_QUERY: + success = true; + break; + case PGRES_COMMAND_OK: + success = true; + fprintf(pset->queryFout, "%s\n", PQcmdStatus(results)); + break; + + case PGRES_COPY_OUT: + if (pset->cur_cmd_interactive && !GetVariable(pset->vars, "quiet")) + puts("Copy command returns:"); + + success = handleCopyOut(pset->db, pset->queryFout); + break; + + case PGRES_COPY_IN: + if (pset->cur_cmd_interactive && !GetVariable(pset->vars, "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); + break; + + case PGRES_NONFATAL_ERROR: + case PGRES_FATAL_ERROR: + case PGRES_BAD_RESPONSE: + success = false; + fputs(PQerrorMessage(pset->db), pset->queryFout); + break; + } - if (results) - PQclear(results); - } + if (PQstatus(pset->db) == CONNECTION_BAD) + { + 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(results); + pset->db = NULL; + return false; + } + else + fputs("Succeeded.\n", stderr); + } + + /* check for asynchronous notification returns */ + while ((notify = PQnotifies(pset->db)) != NULL) + { + fprintf(pset->queryFout, "Asynchronous NOTIFY '%s' from backend with pid '%d' received.\n", + notify->relname, notify->be_pid); + free(notify); + } + + if (results) + PQclear(results); + } - return success; + return success; } diff --git a/src/bin/psql/common.h b/src/bin/psql/common.h index 25bda2c0f8..e3924e9d92 100644 --- a/src/bin/psql/common.h +++ b/src/bin/psql/common.h @@ -5,21 +5,21 @@ #include "settings.h" char * -xstrdup(const char * string); + xstrdup(const char *string); bool -setQFout(const char *fname, PsqlSettings *pset); + setQFout(const char *fname, PsqlSettings *pset); char * -simple_prompt(const char *prompt, int maxlen, bool echo); + simple_prompt(const char *prompt, int maxlen, bool echo); const char * -interpolate_var(const char * name, PsqlSettings * pset); + interpolate_var(const char *name, PsqlSettings *pset); -PGresult * -PSQLexec(PsqlSettings *pset, const char *query); +PGresult * + PSQLexec(PsqlSettings *pset, const char *query); bool -SendQuery(PsqlSettings *pset, const char *query); + SendQuery(PsqlSettings *pset, const char *query); -#endif /* COMMON_H */ +#endif /* COMMON_H */ diff --git a/src/bin/psql/copy.c b/src/bin/psql/copy.c index d8d11e3267..1d2a24c39f 100644 --- a/src/bin/psql/copy.c +++ b/src/bin/psql/copy.c @@ -8,9 +8,9 @@ #include <errno.h> #include <assert.h> #ifndef WIN32 -#include <unistd.h> /* for isatty */ +#include <unistd.h> /* for isatty */ #else -#include <io.h> /* I think */ +#include <io.h> /* I think */ #endif #include <libpq-fe.h> @@ -33,137 +33,151 @@ * returns a malloc'ed structure with the options, or NULL on parsing error */ -struct copy_options { - char * table; - char * file; - bool from; - bool binary; - bool oids; - char * delim; +struct copy_options +{ + char *table; + char *file; + bool from; + bool binary; + bool oids; + char *delim; }; static void free_copy_options(struct copy_options * ptr) { - if (!ptr) - return; - free(ptr->table); - free(ptr->file); - free(ptr->delim); - free(ptr); + if (!ptr) + return; + free(ptr->table); + free(ptr->file); + free(ptr->delim); + free(ptr); } static struct copy_options * parse_slash_copy(const char *args) { - struct copy_options * result; - char * line; - char * token; - bool error = false; - char quote; - - line = xstrdup(args); - - if (!(result = calloc(1, sizeof (struct copy_options)))) { - perror("calloc"); - exit(EXIT_FAILURE); - } - - token = strtokx(line, " \t", "\"", '\\', "e, NULL); - if (!token) - error = true; - else { - if (!quote && strcasecmp(token, "binary")==0) { - result->binary = true; - token = strtokx(NULL, " \t", "\"", '\\', "e, NULL); - if (!token) + struct copy_options *result; + char *line; + char *token; + bool error = false; + char quote; + + line = xstrdup(args); + + if (!(result = calloc(1, sizeof(struct copy_options)))) + { + perror("calloc"); + exit(EXIT_FAILURE); + } + + token = strtokx(line, " \t", "\"", '\\', "e, NULL); + if (!token) error = true; + else + { + if (!quote && strcasecmp(token, "binary") == 0) + { + result->binary = true; + token = strtokx(NULL, " \t", "\"", '\\', "e, NULL); + if (!token) + error = true; + } + if (token) + result->table = xstrdup(token); } - if (token) - result->table = xstrdup(token); - } #ifdef USE_ASSERT_CHECKING - assert(error || result->table); + assert(error || result->table); #endif - if (!error) { - token = strtokx(NULL, " \t", NULL, '\\', NULL, NULL); - if (!token) - error = true; - else { - if (strcasecmp(token, "with")==0) { + if (!error) + { token = strtokx(NULL, " \t", NULL, '\\', NULL, NULL); - if (!token || strcasecmp(token, "oids")!=0) - error = true; - else - result->oids = true; - - if (!error) { - token = strtokx(NULL, " \t", NULL, '\\', NULL, NULL); - if (!token) + if (!token) error = true; + else + { + if (strcasecmp(token, "with") == 0) + { + token = strtokx(NULL, " \t", NULL, '\\', NULL, NULL); + if (!token || strcasecmp(token, "oids") != 0) + error = true; + else + result->oids = true; + + if (!error) + { + token = strtokx(NULL, " \t", NULL, '\\', NULL, NULL); + if (!token) + error = true; + } + } + + if (!error && strcasecmp(token, "from") == 0) + result->from = true; + else if (!error && strcasecmp(token, "to") == 0) + result->from = false; + else + error = true; } - } - - if (!error && strcasecmp(token, "from")==0) - result->from = true; - else if (!error && strcasecmp(token, "to")==0) - result->from = false; - else - error = true; } - } - if (!error) { - token = strtokx(NULL, " \t", "'", '\\', NULL, NULL); - if (!token) - error = true; - else - result->file=xstrdup(token); - } + if (!error) + { + token = strtokx(NULL, " \t", "'", '\\', NULL, NULL); + if (!token) + error = true; + else + result->file = xstrdup(token); + } #ifdef USE_ASSERT_CHECKING - assert(error || result->file); + assert(error || result->file); #endif - if (!error) { - token = strtokx(NULL, " \t", NULL, '\\', NULL, NULL); - if (token) { - if (strcasecmp(token, "using")!=0) - error = true; - else { + if (!error) + { token = strtokx(NULL, " \t", NULL, '\\', NULL, NULL); - if (!token || strcasecmp(token, "delimiters")!=0) - error = true; - else { - token = strtokx(NULL, " \t", "'", '\\', NULL, NULL); - if (token) - result->delim = xstrdup(token); - else - error = true; + if (token) + { + if (strcasecmp(token, "using") != 0) + error = true; + else + { + token = strtokx(NULL, " \t", NULL, '\\', NULL, NULL); + if (!token || strcasecmp(token, "delimiters") != 0) + error = true; + else + { + token = strtokx(NULL, " \t", "'", '\\', NULL, NULL); + if (token) + result->delim = xstrdup(token); + else + error = true; + } + } } - } } - } - free(line); + free(line); - if (error) { - fputs("Parse error at ", stderr); - if (!token) - fputs("end of line.", stderr); + if (error) + { + fputs("Parse error at ", stderr); + if (!token) + fputs("end of line.", stderr); + else + fprintf(stderr, "'%s'.", token); + fputs("\n", stderr); + free(result); + return NULL; + } else - fprintf(stderr, "'%s'.", token); - fputs("\n", stderr); - free(result); - return NULL; - } - else - return result; -} + return result; +} @@ -171,103 +185,109 @@ parse_slash_copy(const char *args) * Execute a \copy command (frontend copy). We have to open a file, then * submit a COPY query to the backend and either feed it data from the * file or route its response into the file. - */ + */ bool -do_copy(const char * args, PsqlSettings *pset) +do_copy(const char *args, PsqlSettings *pset) { - char query[128 + NAMEDATALEN]; - FILE *copystream; - struct copy_options *options; - PGresult *result; - bool success; + char query[128 + NAMEDATALEN]; + FILE *copystream; + struct copy_options *options; + PGresult *result; + bool success; - /* parse options */ - options = parse_slash_copy(args); + /* parse options */ + options = parse_slash_copy(args); - if (!options) - return false; + if (!options) + return false; - strcpy(query, "COPY "); - if (options->binary) - fputs("Warning: \\copy binary is not implemented. Resorting to text output.\n", stderr); + strcpy(query, "COPY "); + if (options->binary) + fputs("Warning: \\copy binary is not implemented. Resorting to text output.\n", stderr); /* strcat(query, "BINARY "); */ - strcat(query, "\""); - strncat(query, options->table, NAMEDATALEN); - strcat(query, "\" "); - if (options->oids) - strcat(query, "WITH OIDS "); + strcat(query, "\""); + strncat(query, options->table, NAMEDATALEN); + strcat(query, "\" "); + if (options->oids) + strcat(query, "WITH OIDS "); - if (options->from) - strcat(query, "FROM stdin"); - else - strcat(query, "TO stdout"); + if (options->from) + strcat(query, "FROM stdin"); + else + strcat(query, "TO stdout"); - if (options->delim) { - /* backend copy only uses the first character here, - but that might be the escape backslash - (makes me wonder though why it's called delimiterS) */ - strncat(query, " USING DELIMITERS '", 2); - strcat(query, options->delim); - strcat(query, "'"); - } + if (options->delim) + { + + /* + * backend copy only uses the first character here, but that might + * be the escape backslash (makes me wonder though why it's called + * delimiterS) + */ + strncat(query, " USING DELIMITERS '", 2); + strcat(query, options->delim); + strcat(query, "'"); + } - if (options->from) + if (options->from) #ifndef __CYGWIN32__ - copystream = fopen(options->file, "r"); + copystream = fopen(options->file, "r"); #else - copystream = fopen(options->file, "rb"); + copystream = fopen(options->file, "rb"); #endif - else + else #ifndef __CYGWIN32__ - copystream = fopen(options->file, "w"); + copystream = fopen(options->file, "w"); #else - copystream = fopen(options->file, "wb"); + copystream = fopen(options->file, "wb"); #endif - if (!copystream) { - fprintf(stderr, - "Unable to open file %s which to copy: %s\n", - options->from ? "from" : "to", strerror(errno)); - free_copy_options(options); - return false; - } - - result = PSQLexec(pset, query); - - switch (PQresultStatus(result)) - { - case PGRES_COPY_OUT: - success = handleCopyOut(pset->db, copystream); - break; - case PGRES_COPY_IN: - 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); - break; - default: - success = false; - fprintf(stderr, "Unexpected response (%d)\n", PQresultStatus(result)); - } - - PQclear(result); - - if (!GetVariable(pset->vars, "quiet")) { - if (success) - puts("Successfully copied."); - else - puts("Copy failed."); - } + if (!copystream) + { + fprintf(stderr, + "Unable to open file %s which to copy: %s\n", + options->from ? "from" : "to", strerror(errno)); + free_copy_options(options); + return false; + } + + result = PSQLexec(pset, query); + + switch (PQresultStatus(result)) + { + case PGRES_COPY_OUT: + success = handleCopyOut(pset->db, copystream); + break; + case PGRES_COPY_IN: + 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); + break; + default: + success = false; + fprintf(stderr, "Unexpected response (%d)\n", PQresultStatus(result)); + } + + PQclear(result); - fclose(copystream); - free_copy_options(options); - return success; + if (!GetVariable(pset->vars, "quiet")) + { + if (success) + puts("Successfully copied."); + else + puts("Copy failed."); + } + + fclose(copystream); + free_copy_options(options); + return success; } @@ -287,38 +307,38 @@ do_copy(const char * args, PsqlSettings *pset) bool handleCopyOut(PGconn *conn, FILE *copystream) { - bool copydone = false; /* haven't started yet */ - char copybuf[COPYBUFSIZ]; - int ret; - - while (!copydone) - { - ret = PQgetline(conn, copybuf, COPYBUFSIZ); + bool copydone = false; /* haven't started yet */ + char copybuf[COPYBUFSIZ]; + int ret; - if (copybuf[0] == '\\' && - copybuf[1] == '.' && - copybuf[2] == '\0') + while (!copydone) { - copydone = true; /* we're at the end */ - } - else - { - fputs(copybuf, copystream); - switch (ret) - { - case EOF: - copydone = true; - /* FALLTHROUGH */ - case 0: - fputc('\n', copystream); - break; - case 1: - break; - } + ret = PQgetline(conn, copybuf, COPYBUFSIZ); + + if (copybuf[0] == '\\' && + copybuf[1] == '.' && + copybuf[2] == '\0') + { + copydone = true; /* we're at the end */ + } + else + { + fputs(copybuf, copystream); + switch (ret) + { + case EOF: + copydone = true; + /* FALLTHROUGH */ + case 0: + fputc('\n', copystream); + break; + case 1: + break; + } + } } - } - fflush(copystream); - return !PQendcopy(conn); + fflush(copystream); + return !PQendcopy(conn); } @@ -333,58 +353,58 @@ handleCopyOut(PGconn *conn, FILE *copystream) * (and which gave you PGRES_COPY_IN back); * copystream is the file stream you want the input to come from * prompt is something to display to request user input (only makes sense - * if stdin is an interactive tty) + * if stdin is an interactive tty) */ bool -handleCopyIn(PGconn *conn, FILE *copystream, const char * prompt) +handleCopyIn(PGconn *conn, FILE *copystream, const char *prompt) { - bool copydone = false; - bool firstload; - bool linedone; - char copybuf[COPYBUFSIZ]; - char *s; - int buflen; - int c = 0; - - while (!copydone) - { /* for each input line ... */ - if (prompt && isatty(fileno(stdin))) - { - fputs(prompt, stdout); - fflush(stdout); - } - firstload = true; - linedone = false; - while (!linedone) - { /* for each buffer ... */ - s = copybuf; - for (buflen = COPYBUFSIZ; buflen > 1; buflen--) - { - c = getc(copystream); - if (c == '\n' || c == EOF) + bool copydone = false; + bool firstload; + bool linedone; + char copybuf[COPYBUFSIZ]; + char *s; + int buflen; + int c = 0; + + while (!copydone) + { /* for each input line ... */ + if (prompt && isatty(fileno(stdin))) { - linedone = true; - break; + fputs(prompt, stdout); + fflush(stdout); + } + firstload = true; + linedone = false; + while (!linedone) + { /* for each buffer ... */ + s = copybuf; + for (buflen = COPYBUFSIZ; buflen > 1; buflen--) + { + c = getc(copystream); + if (c == '\n' || c == EOF) + { + linedone = true; + break; + } + *s++ = c; + } + *s = '\0'; + if (c == EOF) + { + PQputline(conn, "\\."); + copydone = true; + break; + } + PQputline(conn, copybuf); + if (firstload) + { + if (!strcmp(copybuf, "\\.")) + copydone = true; + firstload = false; + } } - *s++ = c; - } - *s = '\0'; - if (c == EOF) - { - PQputline(conn, "\\."); - copydone = true; - break; - } - PQputline(conn, copybuf); - if (firstload) - { - if (!strcmp(copybuf, "\\.")) - copydone = true; - firstload = false; - } + PQputline(conn, "\n"); } - PQputline(conn, "\n"); - } - return !PQendcopy(conn); + return !PQendcopy(conn); } diff --git a/src/bin/psql/copy.h b/src/bin/psql/copy.h index 50fe0afcf5..6e01c5457d 100644 --- a/src/bin/psql/copy.h +++ b/src/bin/psql/copy.h @@ -8,15 +8,15 @@ /* handler for \copy */ bool -do_copy(const char *args, PsqlSettings *pset); + do_copy(const char *args, PsqlSettings *pset); /* lower level processors for copy in/out streams */ bool -handleCopyOut(PGconn *conn, FILE *copystream); + handleCopyOut(PGconn *conn, FILE *copystream); bool -handleCopyIn(PGconn *conn, FILE *copystream, const char * prompt); + handleCopyIn(PGconn *conn, FILE *copystream, const char *prompt); #endif diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c index 6304bc14ee..58534e2575 100644 --- a/src/bin/psql/describe.c +++ b/src/bin/psql/describe.c @@ -4,7 +4,7 @@ #include <string.h> -#include <postgres.h> /* for VARHDRSZ, int4 type */ +#include <postgres.h> /* for VARHDRSZ, int4 type */ #include <postgres_ext.h> #include <libpq-fe.h> @@ -20,7 +20,7 @@ * * If you add something here, consider this: * - If (and only if) the variable "description" is set, the description/ - * comment for the object should be displayed. + * comment for the object should be displayed. * - Try to format the query to look nice in -E output. *---------------- */ @@ -34,61 +34,66 @@ * takes an optional regexp to match specific aggregates by name */ bool -describeAggregates(const char * name, PsqlSettings * pset) +describeAggregates(const char *name, PsqlSettings *pset) { - char descbuf[384 + 2*REGEXP_CUTOFF]; /* observe/adjust this if you change the query */ - PGresult * res; - bool description = GetVariableBool(pset->vars, "description"); - printQueryOpt myopt = pset->popt; - - descbuf[0] = '\0'; - - /* There are two kinds of aggregates: ones that work on particular types - ones that work on all */ - strcat(descbuf, - "SELECT a.aggname AS \"Name\", t.typname AS \"Type\""); - if (description) - strcat(descbuf, - ",\n obj_description(a.oid) as \"Description\""); - strcat(descbuf, - "\nFROM pg_aggregate a, pg_type t\n" - "WHERE a.aggbasetype = t.oid\n"); - if (name) { - strcat(descbuf, " AND a.aggname ~* '^"); - strncat(descbuf, name, REGEXP_CUTOFF); - strcat(descbuf, "'\n"); - } - - strcat(descbuf, - "UNION\n" - "SELECT a.aggname AS \"Name\", '(all types)' as \"Type\""); - if (description) - strcat(descbuf, - ",\n obj_description(a.oid) as \"Description\""); - strcat(descbuf, - "\nFROM pg_aggregate a\n" - "WHERE a.aggbasetype = 0\n"); - if (name) - { - strcat(descbuf, " AND a.aggname ~* '^"); - strncat(descbuf, name, REGEXP_CUTOFF); - strcat(descbuf, "'\n"); - } - - strcat(descbuf, "ORDER BY \"Name\", \"Type\""); - - res = PSQLexec(pset, descbuf); - if (!res) - return false; - - myopt.topt.tuples_only = false; - myopt.nullPrint = NULL; - myopt.title = "List of aggregates"; - - printQuery(res, &myopt, pset->queryFout); - - PQclear(res); - return true; + char descbuf[384 + 2 * REGEXP_CUTOFF]; /* observe/adjust this + * if you change the + * query */ + PGresult *res; + bool description = GetVariableBool(pset->vars, "description"); + printQueryOpt myopt = pset->popt; + + descbuf[0] = '\0'; + + /* + * There are two kinds of aggregates: ones that work on particular + * types ones that work on all + */ + strcat(descbuf, + "SELECT a.aggname AS \"Name\", t.typname AS \"Type\""); + if (description) + strcat(descbuf, + ",\n obj_description(a.oid) as \"Description\""); + strcat(descbuf, + "\nFROM pg_aggregate a, pg_type t\n" + "WHERE a.aggbasetype = t.oid\n"); + if (name) + { + strcat(descbuf, " AND a.aggname ~* '^"); + strncat(descbuf, name, REGEXP_CUTOFF); + strcat(descbuf, "'\n"); + } + + strcat(descbuf, + "UNION\n" + "SELECT a.aggname AS \"Name\", '(all types)' as \"Type\""); + if (description) + strcat(descbuf, + ",\n obj_description(a.oid) as \"Description\""); + strcat(descbuf, + "\nFROM pg_aggregate a\n" + "WHERE a.aggbasetype = 0\n"); + if (name) + { + strcat(descbuf, " AND a.aggname ~* '^"); + strncat(descbuf, name, REGEXP_CUTOFF); + strcat(descbuf, "'\n"); + } + + strcat(descbuf, "ORDER BY \"Name\", \"Type\""); + + res = PSQLexec(pset, descbuf); + if (!res) + return false; + + myopt.topt.tuples_only = false; + myopt.nullPrint = NULL; + myopt.title = "List of aggregates"; + + printQuery(res, &myopt, pset->queryFout); + + PQclear(res); + return true; } @@ -96,45 +101,44 @@ describeAggregates(const char * name, PsqlSettings * pset) * takes an optional regexp to narrow down the function name */ bool -describeFunctions(const char * name, PsqlSettings * pset) +describeFunctions(const char *name, PsqlSettings *pset) { - char descbuf[384 + REGEXP_CUTOFF]; - PGresult * res; - printQueryOpt myopt = pset->popt; - - /* - * we skip in/out funcs by excluding functions that take - * some arguments, but have no types defined for those - * arguments - */ - descbuf[0] = '\0'; - - strcat(descbuf, "SELECT t.typname as \"Result\", p.proname as \"Function\",\n" - " oid8types(p.proargtypes) as \"Arguments\""); - if (GetVariableBool(pset->vars, "description")) - strcat(descbuf, "\n, obj_description(p.oid) as \"Description\""); - strcat(descbuf, "\nFROM pg_proc p, pg_type t\n" - "WHERE p.prorettype = t.oid and (pronargs = 0 or oid8types(p.proargtypes) != '')\n"); - if (name) - { - strcat(descbuf, " AND p.proname ~* '^"); - strncat(descbuf, name, REGEXP_CUTOFF); - strcat(descbuf, "'\n"); - } - strcat(descbuf, "ORDER BY \"Function\", \"Result\", \"Arguments\""); - - res = PSQLexec(pset, descbuf); - if (!res) - return false; - - myopt.topt.tuples_only = false; - myopt.nullPrint = NULL; - myopt.title = "List of functions"; - - printQuery(res, &myopt, pset->queryFout); - - PQclear(res); - return true; + char descbuf[384 + REGEXP_CUTOFF]; + PGresult *res; + printQueryOpt myopt = pset->popt; + + /* + * we skip in/out funcs by excluding functions that take some + * arguments, but have no types defined for those arguments + */ + descbuf[0] = '\0'; + + strcat(descbuf, "SELECT t.typname as \"Result\", p.proname as \"Function\",\n" + " oid8types(p.proargtypes) as \"Arguments\""); + if (GetVariableBool(pset->vars, "description")) + strcat(descbuf, "\n, obj_description(p.oid) as \"Description\""); + strcat(descbuf, "\nFROM pg_proc p, pg_type t\n" + "WHERE p.prorettype = t.oid and (pronargs = 0 or oid8types(p.proargtypes) != '')\n"); + if (name) + { + strcat(descbuf, " AND p.proname ~* '^"); + strncat(descbuf, name, REGEXP_CUTOFF); + strcat(descbuf, "'\n"); + } + strcat(descbuf, "ORDER BY \"Function\", \"Result\", \"Arguments\""); + + res = PSQLexec(pset, descbuf); + if (!res) + return false; + + myopt.topt.tuples_only = false; + myopt.nullPrint = NULL; + myopt.title = "List of functions"; + + printQuery(res, &myopt, pset->queryFout); + + PQclear(res); + return true; } @@ -145,38 +149,39 @@ describeFunctions(const char * name, PsqlSettings * pset) * for \dT */ bool -describeTypes(const char * name, PsqlSettings * pset) +describeTypes(const char *name, PsqlSettings *pset) { - char descbuf[256 + REGEXP_CUTOFF]; - PGresult * res; - printQueryOpt myopt = pset->popt; - - descbuf[0] = '\0'; - strcat(descbuf, "SELECT typname AS \"Type\""); - if (GetVariableBool(pset->vars, "description")) - strcat(descbuf, ", obj_description(p.oid) as \"Description\""); - strcat(descbuf, "\nFROM pg_type\n" - "WHERE typrelid = 0 AND typname !~ '^_.*'\n"); - - if (name) { - strcat(descbuf, " AND typname ~* '^"); - strncat(descbuf, name, REGEXP_CUTOFF); - strcat(descbuf, "' "); - } - strcat(descbuf, "ORDER BY typname;"); - - res = PSQLexec(pset, descbuf); - if (!res) - return false; - - myopt.topt.tuples_only = false; - myopt.nullPrint = NULL; - myopt.title = "List of types"; - - printQuery(res, &myopt, pset->queryFout); - - PQclear(res); - return true; + char descbuf[256 + REGEXP_CUTOFF]; + PGresult *res; + printQueryOpt myopt = pset->popt; + + descbuf[0] = '\0'; + strcat(descbuf, "SELECT typname AS \"Type\""); + if (GetVariableBool(pset->vars, "description")) + strcat(descbuf, ", obj_description(p.oid) as \"Description\""); + strcat(descbuf, "\nFROM pg_type\n" + "WHERE typrelid = 0 AND typname !~ '^_.*'\n"); + + if (name) + { + strcat(descbuf, " AND typname ~* '^"); + strncat(descbuf, name, REGEXP_CUTOFF); + strcat(descbuf, "' "); + } + strcat(descbuf, "ORDER BY typname;"); + + res = PSQLexec(pset, descbuf); + if (!res) + return false; + + myopt.topt.tuples_only = false; + myopt.nullPrint = NULL; + myopt.title = "List of types"; + + printQuery(res, &myopt, pset->queryFout); + + PQclear(res); + return true; } @@ -187,87 +192,88 @@ describeTypes(const char * name, PsqlSettings * pset) * exact match string. */ bool -describeOperators(const char * name, PsqlSettings * pset) +describeOperators(const char *name, PsqlSettings *pset) { - char descbuf[1536 + 3 * 32]; /* 32 is max length for operator name */ - PGresult * res; - bool description = GetVariableBool(pset->vars, "description"); - printQueryOpt myopt = pset->popt; - - descbuf[0] = '\0'; - - strcat(descbuf, "SELECT o.oprname AS \"Op\",\n" - " t1.typname AS \"Left arg\",\n" - " t2.typname AS \"Right arg\",\n" - " t0.typname AS \"Result\""); - if (description) - strcat(descbuf, ",\n obj_description(p.oid) as \"Description\""); - strcat(descbuf, "\nFROM pg_proc p, pg_type t0,\n" - " pg_type t1, pg_type t2,\n" - " pg_operator o\n" - "WHERE p.prorettype = t0.oid AND\n" - " RegprocToOid(o.oprcode) = p.oid AND\n" - " p.pronargs = 2 AND\n" - " o.oprleft = t1.oid AND\n" - " o.oprright = t2.oid\n"); - if (name) - { - strcat(descbuf, " AND o.oprname = '"); - strncat(descbuf, name, 32); - strcat(descbuf, "'\n"); - } - - strcat(descbuf, "\nUNION\n\n" - "SELECT o.oprname as \"Op\",\n" - " ''::name AS \"Left arg\",\n" - " t1.typname AS \"Right arg\",\n" - " t0.typname AS \"Result\""); - if (description) - strcat(descbuf, ",\n obj_description(p.oid) as \"Description\""); - strcat(descbuf, "\nFROM pg_operator o, pg_proc p, pg_type t0, pg_type t1\n" - "WHERE RegprocToOid(o.oprcode) = p.oid AND\n" - " o.oprresult = t0.oid AND\n" - " o.oprkind = 'l' AND\n" - " o.oprright = t1.oid\n"); - if (name) - { - strcat(descbuf, "AND o.oprname = '"); - strncat(descbuf, name, 32); - strcat(descbuf, "'\n"); - } - - strcat(descbuf, "\nUNION\n\n" - "SELECT o.oprname as \"Op\",\n" - " t1.typname AS \"Left arg\",\n" - " ''::name AS \"Right arg\",\n" - " t0.typname AS \"Result\""); - if (description) - strcat(descbuf, ",\n obj_description(p.oid) as \"Description\""); - strcat(descbuf, "\nFROM pg_operator o, pg_proc p, pg_type t0, pg_type t1\n" - "WHERE RegprocToOid(o.oprcode) = p.oid AND\n" - " o.oprresult = t0.oid AND\n" - " o.oprkind = 'r' AND\n" - " o.oprleft = t1.oid\n"); - if (name) - { - strcat(descbuf, "AND o.oprname = '"); - strncat(descbuf, name, 32); - strcat(descbuf, "'\n"); - } - strcat(descbuf, "\nORDER BY \"Op\", \"Left arg\", \"Right arg\", \"Result\""); - - res = PSQLexec(pset, descbuf); - if (!res) - return false; - - myopt.topt.tuples_only = false; - myopt.nullPrint = NULL; - myopt.title = "List of operators"; - - printQuery(res, &myopt, pset->queryFout); - - PQclear(res); - return true; + char descbuf[1536 + 3 * 32]; /* 32 is max length for operator + * name */ + PGresult *res; + bool description = GetVariableBool(pset->vars, "description"); + printQueryOpt myopt = pset->popt; + + descbuf[0] = '\0'; + + strcat(descbuf, "SELECT o.oprname AS \"Op\",\n" + " t1.typname AS \"Left arg\",\n" + " t2.typname AS \"Right arg\",\n" + " t0.typname AS \"Result\""); + if (description) + strcat(descbuf, ",\n obj_description(p.oid) as \"Description\""); + strcat(descbuf, "\nFROM pg_proc p, pg_type t0,\n" + " pg_type t1, pg_type t2,\n" + " pg_operator o\n" + "WHERE p.prorettype = t0.oid AND\n" + " RegprocToOid(o.oprcode) = p.oid AND\n" + " p.pronargs = 2 AND\n" + " o.oprleft = t1.oid AND\n" + " o.oprright = t2.oid\n"); + if (name) + { + strcat(descbuf, " AND o.oprname = '"); + strncat(descbuf, name, 32); + strcat(descbuf, "'\n"); + } + + strcat(descbuf, "\nUNION\n\n" + "SELECT o.oprname as \"Op\",\n" + " ''::name AS \"Left arg\",\n" + " t1.typname AS \"Right arg\",\n" + " t0.typname AS \"Result\""); + if (description) + strcat(descbuf, ",\n obj_description(p.oid) as \"Description\""); + strcat(descbuf, "\nFROM pg_operator o, pg_proc p, pg_type t0, pg_type t1\n" + "WHERE RegprocToOid(o.oprcode) = p.oid AND\n" + " o.oprresult = t0.oid AND\n" + " o.oprkind = 'l' AND\n" + " o.oprright = t1.oid\n"); + if (name) + { + strcat(descbuf, "AND o.oprname = '"); + strncat(descbuf, name, 32); + strcat(descbuf, "'\n"); + } + + strcat(descbuf, "\nUNION\n\n" + "SELECT o.oprname as \"Op\",\n" + " t1.typname AS \"Left arg\",\n" + " ''::name AS \"Right arg\",\n" + " t0.typname AS \"Result\""); + if (description) + strcat(descbuf, ",\n obj_description(p.oid) as \"Description\""); + strcat(descbuf, "\nFROM pg_operator o, pg_proc p, pg_type t0, pg_type t1\n" + "WHERE RegprocToOid(o.oprcode) = p.oid AND\n" + " o.oprresult = t0.oid AND\n" + " o.oprkind = 'r' AND\n" + " o.oprleft = t1.oid\n"); + if (name) + { + strcat(descbuf, "AND o.oprname = '"); + strncat(descbuf, name, 32); + strcat(descbuf, "'\n"); + } + strcat(descbuf, "\nORDER BY \"Op\", \"Left arg\", \"Right arg\", \"Result\""); + + res = PSQLexec(pset, descbuf); + if (!res) + return false; + + myopt.topt.tuples_only = false; + myopt.nullPrint = NULL; + myopt.title = "List of operators"; + + printQuery(res, &myopt, pset->queryFout); + + PQclear(res); + return true; } @@ -279,81 +285,82 @@ describeOperators(const char * name, PsqlSettings * pset) bool listAllDbs(PsqlSettings *pset) { - PGresult *res; - char descbuf[256]; - printQueryOpt myopt = pset->popt; + PGresult *res; + char descbuf[256]; + printQueryOpt myopt = pset->popt; - descbuf[0] = '\0'; - strcat(descbuf, "SELECT pg_database.datname as \"Database\",\n" - " pg_user.usename as \"Owner\"" + descbuf[0] = '\0'; + strcat(descbuf, "SELECT pg_database.datname as \"Database\",\n" + " pg_user.usename as \"Owner\"" #ifdef MULTIBYTE - ",\n pg_database.encoding as \"Encoding\"" + ",\n pg_database.encoding as \"Encoding\"" #endif - ); - if (GetVariableBool(pset->vars, "description")) - strcat(descbuf, ",\n obj_description(pg_database.oid) as \"Description\"\n"); - strcat(descbuf, "FROM pg_database, pg_user\n" - "WHERE pg_database.datdba = pg_user.usesysid\n" - "ORDER BY \"Database\""); + ); + if (GetVariableBool(pset->vars, "description")) + strcat(descbuf, ",\n obj_description(pg_database.oid) as \"Description\"\n"); + strcat(descbuf, "FROM pg_database, pg_user\n" + "WHERE pg_database.datdba = pg_user.usesysid\n" + "ORDER BY \"Database\""); - res = PSQLexec(pset, descbuf); - if (!res) - return false; + res = PSQLexec(pset, descbuf); + if (!res) + return false; - myopt.topt.tuples_only = false; - myopt.nullPrint = NULL; - myopt.title = "List of databases"; + myopt.topt.tuples_only = false; + myopt.nullPrint = NULL; + myopt.title = "List of databases"; - printQuery(res, &myopt, pset->queryFout); + printQuery(res, &myopt, pset->queryFout); - PQclear(res); - return true; + PQclear(res); + return true; } /* List Tables Grant/Revoke Permissions * \z (now also \dp -- perhaps more mnemonic) - * + * */ bool -permissionsList(const char * name, PsqlSettings *pset) +permissionsList(const char *name, PsqlSettings *pset) { - char descbuf[256 + REGEXP_CUTOFF]; - PGresult *res; - printQueryOpt myopt = pset->popt; - - descbuf[0] = '\0'; - /* Currently, we ignore indexes since they have no meaningful rights */ - strcat(descbuf, "SELECT relname as \"Relation\",\n" - " relacl as \"Access permissions\"\n" - "FROM pg_class\n" - "WHERE ( relkind = 'r' OR relkind = 'S') AND\n" - " relname !~ '^pg_'\n"); - if (name) { - strcat(descbuf, " AND rename ~ '^"); - strncat(descbuf, name, REGEXP_CUTOFF); - strcat(descbuf, "'\n"); - } - strcat (descbuf, "ORDER BY relname"); - - res = PSQLexec(pset, descbuf); - if (!res) - return false; - - if (PQntuples(res) == 0) { - fputs("Couldn't find any tables.\n", pset->queryFout); - } - else { - myopt.topt.tuples_only = false; - myopt.nullPrint = NULL; - sprintf(descbuf, "Access permissions for database \"%s\"", PQdb(pset->db)); - myopt.title = descbuf; + char descbuf[256 + REGEXP_CUTOFF]; + PGresult *res; + printQueryOpt myopt = pset->popt; + + descbuf[0] = '\0'; + /* Currently, we ignore indexes since they have no meaningful rights */ + strcat(descbuf, "SELECT relname as \"Relation\",\n" + " relacl as \"Access permissions\"\n" + "FROM pg_class\n" + "WHERE ( relkind = 'r' OR relkind = 'S') AND\n" + " relname !~ '^pg_'\n"); + if (name) + { + strcat(descbuf, " AND rename ~ '^"); + strncat(descbuf, name, REGEXP_CUTOFF); + strcat(descbuf, "'\n"); + } + strcat(descbuf, "ORDER BY relname"); - printQuery(res, &myopt, pset->queryFout); - } + res = PSQLexec(pset, descbuf); + if (!res) + return false; + + if (PQntuples(res) == 0) + fputs("Couldn't find any tables.\n", pset->queryFout); + else + { + myopt.topt.tuples_only = false; + myopt.nullPrint = NULL; + sprintf(descbuf, "Access permissions for database \"%s\"", PQdb(pset->db)); + myopt.title = descbuf; - PQclear(res); - return true; + printQuery(res, &myopt, pset->queryFout); + } + + PQclear(res); + return true; } @@ -368,106 +375,113 @@ 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, PsqlSettings *pset) { - char descbuf[2048 + 7*REGEXP_CUTOFF]; - PGresult *res; - printQueryOpt myopt = pset->popt; - - descbuf[0] = '\0'; - - /* Aggregate descriptions */ - strcat(descbuf, "SELECT DISTINCT a.aggname as \"Name\", 'aggregate'::text as \"What\", d.description as \"Description\"\n" - "FROM pg_aggregate a, pg_description d\n" - "WHERE a.oid = d.objoid\n"); - if (object) { - strcat(descbuf," AND a.aggname ~* '^"); - strncat(descbuf, object, REGEXP_CUTOFF); - strcat(descbuf,"'\n"); - } - - /* Function descriptions (except in/outs for datatypes) */ - strcat(descbuf, "\nUNION ALL\n\n"); - strcat(descbuf, "SELECT DISTINCT p.proname as \"Name\", 'function'::text as \"What\", d.description as \"Description\"\n" - "FROM pg_proc p, pg_description d\n" - "WHERE p.oid = d.objoid AND (p.pronargs = 0 or oid8types(p.proargtypes) != '')\n"); - if (object) { - strcat(descbuf," AND p.proname ~* '^"); - strncat(descbuf, object, REGEXP_CUTOFF); - strcat(descbuf,"'\n"); - } - - /* Operator descriptions */ - strcat(descbuf, "\nUNION ALL\n\n"); - strcat(descbuf, "SELECT DISTINCT o.oprname as \"Name\", 'operator'::text as \"What\", d.description as \"Description\"\n" - "FROM pg_operator o, pg_description d\n" - // must get comment via associated function - "WHERE RegprocToOid(o.oprcode) = d.objoid\n"); - if (object) { - strcat(descbuf," AND o.oprname = '"); - strncat(descbuf, object, REGEXP_CUTOFF); - strcat(descbuf,"'\n"); - } - - /* Type description */ - strcat(descbuf, "\nUNION ALL\n\n"); - strcat(descbuf, "SELECT DISTINCT t.typname as \"Name\", 'type'::text as \"What\", d.description as \"Description\"\n" - "FROM pg_type t, pg_description d\n" - "WHERE t.oid = d.objoid\n"); - if (object) { - strcat(descbuf," AND t.typname ~* '^"); - strncat(descbuf, object, REGEXP_CUTOFF); - strcat(descbuf,"'\n"); - } - - /* Relation (tables, views, indices, sequences) descriptions */ - strcat(descbuf, "\nUNION ALL\n\n"); - strcat(descbuf, "SELECT DISTINCT c.relname as \"Name\", 'relation'::text||'('||c.relkind||')' as \"What\", d.description as \"Description\"\n" - "FROM pg_class c, pg_description d\n" - "WHERE c.oid = d.objoid\n"); - if (object) { - strcat(descbuf," AND c.relname ~* '^"); - strncat(descbuf, object, REGEXP_CUTOFF); - strcat(descbuf,"'\n"); - } - - /* Rule description (ignore rules for views) */ - strcat(descbuf, "\nUNION ALL\n\n"); - strcat(descbuf, "SELECT DISTINCT r.rulename as \"Name\", 'rule'::text as \"What\", d.description as \"Description\"\n" - "FROM pg_rewrite r, pg_description d\n" - "WHERE r.oid = d.objoid AND r.rulename !~ '^_RET'\n"); - if (object) { - strcat(descbuf," AND r.rulename ~* '^"); - strncat(descbuf, object, REGEXP_CUTOFF); - strcat(descbuf,"'\n"); - } - - /* Trigger description */ - strcat(descbuf, "\nUNION ALL\n\n"); - strcat(descbuf, "SELECT DISTINCT t.tgname as \"Name\", 'trigger'::text as \"What\", d.description as \"Description\"\n" - "FROM pg_trigger t, pg_description d\n" - "WHERE t.oid = d.objoid\n"); - if (object) { - strcat(descbuf," AND t.tgname ~* '^"); - strncat(descbuf, object, REGEXP_CUTOFF); - strcat(descbuf,"'\n"); - } - - strcat(descbuf, "\nORDER BY \"Name\""); - - - res = PSQLexec(pset, descbuf); - if (!res) - return false; - - myopt.topt.tuples_only = false; - myopt.nullPrint = NULL; - myopt.title = "Object descriptions"; - - printQuery(res, &myopt, pset->queryFout); - - PQclear(res); - return true; + char descbuf[2048 + 7 * REGEXP_CUTOFF]; + PGresult *res; + printQueryOpt myopt = pset->popt; + + descbuf[0] = '\0'; + + /* Aggregate descriptions */ + strcat(descbuf, "SELECT DISTINCT a.aggname as \"Name\", 'aggregate'::text as \"What\", d.description as \"Description\"\n" + "FROM pg_aggregate a, pg_description d\n" + "WHERE a.oid = d.objoid\n"); + if (object) + { + strcat(descbuf, " AND a.aggname ~* '^"); + strncat(descbuf, object, REGEXP_CUTOFF); + strcat(descbuf, "'\n"); + } + + /* Function descriptions (except in/outs for datatypes) */ + strcat(descbuf, "\nUNION ALL\n\n"); + strcat(descbuf, "SELECT DISTINCT p.proname as \"Name\", 'function'::text as \"What\", d.description as \"Description\"\n" + "FROM pg_proc p, pg_description d\n" + "WHERE p.oid = d.objoid AND (p.pronargs = 0 or oid8types(p.proargtypes) != '')\n"); + if (object) + { + strcat(descbuf, " AND p.proname ~* '^"); + strncat(descbuf, object, REGEXP_CUTOFF); + strcat(descbuf, "'\n"); + } + + /* Operator descriptions */ + strcat(descbuf, "\nUNION ALL\n\n"); + strcat(descbuf, "SELECT DISTINCT o.oprname as \"Name\", 'operator'::text as \"What\", d.description as \"Description\"\n" + "FROM pg_operator o, pg_description d\n" + // must get comment via associated function + "WHERE RegprocToOid(o.oprcode) = d.objoid\n"); + if (object) + { + strcat(descbuf, " AND o.oprname = '"); + strncat(descbuf, object, REGEXP_CUTOFF); + strcat(descbuf, "'\n"); + } + + /* Type description */ + strcat(descbuf, "\nUNION ALL\n\n"); + strcat(descbuf, "SELECT DISTINCT t.typname as \"Name\", 'type'::text as \"What\", d.description as \"Description\"\n" + "FROM pg_type t, pg_description d\n" + "WHERE t.oid = d.objoid\n"); + if (object) + { + strcat(descbuf, " AND t.typname ~* '^"); + strncat(descbuf, object, REGEXP_CUTOFF); + strcat(descbuf, "'\n"); + } + + /* Relation (tables, views, indices, sequences) descriptions */ + strcat(descbuf, "\nUNION ALL\n\n"); + strcat(descbuf, "SELECT DISTINCT c.relname as \"Name\", 'relation'::text||'('||c.relkind||')' as \"What\", d.description as \"Description\"\n" + "FROM pg_class c, pg_description d\n" + "WHERE c.oid = d.objoid\n"); + if (object) + { + strcat(descbuf, " AND c.relname ~* '^"); + strncat(descbuf, object, REGEXP_CUTOFF); + strcat(descbuf, "'\n"); + } + + /* Rule description (ignore rules for views) */ + strcat(descbuf, "\nUNION ALL\n\n"); + strcat(descbuf, "SELECT DISTINCT r.rulename as \"Name\", 'rule'::text as \"What\", d.description as \"Description\"\n" + "FROM pg_rewrite r, pg_description d\n" + "WHERE r.oid = d.objoid AND r.rulename !~ '^_RET'\n"); + if (object) + { + strcat(descbuf, " AND r.rulename ~* '^"); + strncat(descbuf, object, REGEXP_CUTOFF); + strcat(descbuf, "'\n"); + } + + /* Trigger description */ + strcat(descbuf, "\nUNION ALL\n\n"); + strcat(descbuf, "SELECT DISTINCT t.tgname as \"Name\", 'trigger'::text as \"What\", d.description as \"Description\"\n" + "FROM pg_trigger t, pg_description d\n" + "WHERE t.oid = d.objoid\n"); + if (object) + { + strcat(descbuf, " AND t.tgname ~* '^"); + strncat(descbuf, object, REGEXP_CUTOFF); + strcat(descbuf, "'\n"); + } + + strcat(descbuf, "\nORDER BY \"Name\""); + + + res = PSQLexec(pset, descbuf); + if (!res) + return false; + + myopt.topt.tuples_only = false; + myopt.nullPrint = NULL; + myopt.title = "Object descriptions"; + + printQuery(res, &myopt, pset->queryFout); + + PQclear(res); + return true; } @@ -480,199 +494,218 @@ objectDescription(const char * object, PsqlSettings *pset) * and pass it to the underlying printTable() function. * */ -static void * xmalloc(size_t size) +static void * +xmalloc(size_t size) { - void * tmp; - tmp = malloc(size); - if (!tmp) { - perror("malloc"); - exit(EXIT_FAILURE); - } - return tmp; + void *tmp; + + tmp = malloc(size); + if (!tmp) + { + perror("malloc"); + exit(EXIT_FAILURE); + } + return tmp; } bool -describeTableDetails(const char * name, PsqlSettings * pset) +describeTableDetails(const char *name, PsqlSettings *pset) { - char descbuf[512 + NAMEDATALEN]; - PGresult *res = NULL, *res2 = NULL, *res3 = NULL; - printTableOpt myopt = pset->popt.topt; - bool description = GetVariableBool(pset->vars, "description"); - int i; - char * view_def = NULL; - char * headers[5]; - char ** cells = NULL; - char * title = NULL; - char ** footers = NULL; - char ** ptr; - unsigned int cols; - - cols = 3 + (description ? 1 : 0); - - headers[0] = "Attribute"; - headers[1] = "Type"; - headers[2] = "Info"; - if (description) { - headers[3] = "Description"; - headers[4] = NULL; - } - else - headers[3] = NULL; - - /* Get general table info */ - strcpy(descbuf, "SELECT a.attname, t.typname, a.attlen, a.atttypmod, a.attnotnull, a.atthasdef, a.attnum"); - if (description) - strcat(descbuf, ", obj_description(a.oid)"); - strcat(descbuf, "\nFROM pg_class c, pg_attribute a, pg_type t\n" - "WHERE c.relname = '"); - strncat(descbuf, name, NAMEDATALEN); - strcat(descbuf, "'\n AND a.attnum > 0 AND a.attrelid = c.oid AND a.atttypid = t.oid\n" - "ORDER BY a.attnum"); - - res = PSQLexec(pset, descbuf); - if (!res) - return false; - - /* Did we get anything? */ - if (PQntuples(res)==0) { - if (!GetVariableBool(pset->vars, "quiet")) - fprintf(stdout, "Did not find any class named \"%s\".\n", name); - PQclear(res); - return false; - } - - /* Check if table is a view */ - strcpy(descbuf, "SELECT definition FROM pg_views WHERE viewname = '"); - strncat(descbuf, name, NAMEDATALEN); - strcat(descbuf, "'"); - res2 = PSQLexec(pset, descbuf); - if (!res2) - return false; - - if (PQntuples(res2) > 0) - view_def = PQgetvalue(res2,0,0); - - - - /* Generate table cells to be printed */ - cells = calloc(PQntuples(res) * cols + 1, sizeof(*cells)); - if (!cells) { - perror("calloc"); - exit(EXIT_FAILURE); - } - - for (i = 0; i < PQntuples(res); i++) { - int4 attypmod = atoi(PQgetvalue(res, i, 3)); - char * attype = PQgetvalue(res, i, 1); - - /* Name */ - cells[i*cols + 0] = PQgetvalue(res, i, 0); /* don't free this afterwards */ - - /* Type */ - cells[i*cols + 1] = xmalloc(NAMEDATALEN + 16); - if (strcmp(attype, "bpchar")==0) - sprintf(cells[i*cols + 1], "char(%d)", attypmod != -1 ? attypmod - VARHDRSZ : 0); - else if (strcmp(attype, "varchar")==0) - sprintf(cells[i*cols + 1], "varchar(%d)", attypmod != -1 ? attypmod - VARHDRSZ : 0); - else if (strcmp(attype, "numeric")==0) - sprintf(cells[i*cols + 1], "numeric(%d,%d)", ((attypmod - VARHDRSZ) >> 16) & 0xffff, - (attypmod - VARHDRSZ) & 0xffff ); - else if (attype[0] == '_') - sprintf(cells[i*cols + 1], "%s[]", attype+1); - else - strcpy(cells[i*cols + 1], attype); - - /* Info */ - cells[i*cols + 2] = xmalloc(128 + 128); /* I'm cutting off the default string at 128 */ - cells[i*cols + 2][0] = '\0'; - if (strcmp(PQgetvalue(res, i, 4), "t") == 0) - strcat(cells[i*cols + 2], "not null"); - if (strcmp(PQgetvalue(res, i, 5), "t") == 0) { - /* handle "default" here */ - strcpy(descbuf, "SELECT substring(d.adsrc for 128) FROM pg_attrdef d, pg_class c\n" - "WHERE c.relname = '"); - strncat(descbuf, name, NAMEDATALEN); - strcat(descbuf, "' AND c.oid = d.adrelid AND d.adnum = "); - strcat(descbuf, PQgetvalue(res, i, 6)); - - res3 = PSQLexec(pset, descbuf); - if (!res) return false; - if (cells[i*cols+2][0]) strcat(cells[i*cols+2], " "); - strcat(cells[i*cols + 2], "default "); - strcat(cells[i*cols + 2], PQgetvalue(res3, 0, 0)); + char descbuf[512 + NAMEDATALEN]; + PGresult *res = NULL, + *res2 = NULL, + *res3 = NULL; + printTableOpt myopt = pset->popt.topt; + bool description = GetVariableBool(pset->vars, "description"); + int i; + char *view_def = NULL; + char *headers[5]; + char **cells = NULL; + char *title = NULL; + char **footers = NULL; + char **ptr; + unsigned int cols; + + cols = 3 + (description ? 1 : 0); + + headers[0] = "Attribute"; + headers[1] = "Type"; + headers[2] = "Info"; + if (description) + { + headers[3] = "Description"; + headers[4] = NULL; } + else + headers[3] = NULL; - /* Description */ + /* Get general table info */ + strcpy(descbuf, "SELECT a.attname, t.typname, a.attlen, a.atttypmod, a.attnotnull, a.atthasdef, a.attnum"); if (description) - cells[i*cols + 3] = PQgetvalue(res, i, 7); - } - - /* Make title */ - title = xmalloc(10 + strlen(name)); - if (view_def) - sprintf(title, "View \"%s\"", name); - else - sprintf(title, "Table \"%s\"", name); - - /* Make footers */ - if (view_def) { - footers = xmalloc(2 * sizeof(*footers)); - footers[0] = xmalloc(20 + strlen(view_def)); - sprintf(footers[0], "View definition: %s", view_def); - footers[1] = NULL; - } - else { - /* display indices */ - strcpy(descbuf, "SELECT c2.relname\n" - "FROM pg_class c, pg_class c2, pg_index i\n" - "WHERE c.relname = '"); + strcat(descbuf, ", obj_description(a.oid)"); + strcat(descbuf, "\nFROM pg_class c, pg_attribute a, pg_type t\n" + "WHERE c.relname = '"); + strncat(descbuf, name, NAMEDATALEN); + strcat(descbuf, "'\n AND a.attnum > 0 AND a.attrelid = c.oid AND a.atttypid = t.oid\n" + "ORDER BY a.attnum"); + + res = PSQLexec(pset, descbuf); + if (!res) + return false; + + /* Did we get anything? */ + if (PQntuples(res) == 0) + { + if (!GetVariableBool(pset->vars, "quiet")) + fprintf(stdout, "Did not find any class named \"%s\".\n", name); + PQclear(res); + return false; + } + + /* Check if table is a view */ + strcpy(descbuf, "SELECT definition FROM pg_views WHERE viewname = '"); strncat(descbuf, name, NAMEDATALEN); - strcat(descbuf, "' AND c.oid = i.indrelid AND i.indexrelid = c2.oid\n" - "ORDER BY c2.relname"); - res3 = PSQLexec(pset, descbuf); - if (!res3) - return false; - - if (PQntuples(res3) > 0) { - footers = xmalloc((PQntuples(res3) + 1) * sizeof(*footers)); - - for (i=0; i<PQntuples(res3); i++) { - footers[i] = xmalloc(10 + NAMEDATALEN); - if (PQntuples(res3)==1) - sprintf(footers[i], "Index: %s", PQgetvalue(res3, i, 0)); - else if (i==0) - sprintf(footers[i], "Indices: %s", PQgetvalue(res3, i, 0)); + strcat(descbuf, "'"); + res2 = PSQLexec(pset, descbuf); + if (!res2) + return false; + + if (PQntuples(res2) > 0) + view_def = PQgetvalue(res2, 0, 0); + + + + /* Generate table cells to be printed */ + cells = calloc(PQntuples(res) * cols + 1, sizeof(*cells)); + if (!cells) + { + perror("calloc"); + exit(EXIT_FAILURE); + } + + for (i = 0; i < PQntuples(res); i++) + { + int4 attypmod = atoi(PQgetvalue(res, i, 3)); + char *attype = PQgetvalue(res, i, 1); + + /* Name */ + cells[i * cols + 0] = PQgetvalue(res, i, 0); /* don't free this + * afterwards */ + + /* Type */ + cells[i * cols + 1] = xmalloc(NAMEDATALEN + 16); + if (strcmp(attype, "bpchar") == 0) + sprintf(cells[i * cols + 1], "char(%d)", attypmod != -1 ? attypmod - VARHDRSZ : 0); + else if (strcmp(attype, "varchar") == 0) + sprintf(cells[i * cols + 1], "varchar(%d)", attypmod != -1 ? attypmod - VARHDRSZ : 0); + else if (strcmp(attype, "numeric") == 0) + sprintf(cells[i * cols + 1], "numeric(%d,%d)", ((attypmod - VARHDRSZ) >> 16) & 0xffff, + (attypmod - VARHDRSZ) & 0xffff); + else if (attype[0] == '_') + sprintf(cells[i * cols + 1], "%s[]", attype + 1); else - sprintf(footers[i], " %s", PQgetvalue(res3, i, 0)); - } + strcpy(cells[i * cols + 1], attype); + + /* Info */ + cells[i * cols + 2] = xmalloc(128 + 128); /* I'm cutting off the + * default string at 128 */ + cells[i * cols + 2][0] = '\0'; + if (strcmp(PQgetvalue(res, i, 4), "t") == 0) + strcat(cells[i * cols + 2], "not null"); + if (strcmp(PQgetvalue(res, i, 5), "t") == 0) + { + /* handle "default" here */ + strcpy(descbuf, "SELECT substring(d.adsrc for 128) FROM pg_attrdef d, pg_class c\n" + "WHERE c.relname = '"); + strncat(descbuf, name, NAMEDATALEN); + strcat(descbuf, "' AND c.oid = d.adrelid AND d.adnum = "); + strcat(descbuf, PQgetvalue(res, i, 6)); + + res3 = PSQLexec(pset, descbuf); + if (!res) + return false; + if (cells[i * cols + 2][0]) + strcat(cells[i * cols + 2], " "); + strcat(cells[i * cols + 2], "default "); + strcat(cells[i * cols + 2], PQgetvalue(res3, 0, 0)); + } + + /* Description */ + if (description) + cells[i * cols + 3] = PQgetvalue(res, i, 7); + } - footers[i] = NULL; + /* Make title */ + title = xmalloc(10 + strlen(name)); + if (view_def) + sprintf(title, "View \"%s\"", name); + else + sprintf(title, "Table \"%s\"", name); + + /* Make footers */ + if (view_def) + { + footers = xmalloc(2 * sizeof(*footers)); + footers[0] = xmalloc(20 + strlen(view_def)); + sprintf(footers[0], "View definition: %s", view_def); + footers[1] = NULL; + } + else + { + /* display indices */ + strcpy(descbuf, "SELECT c2.relname\n" + "FROM pg_class c, pg_class c2, pg_index i\n" + "WHERE c.relname = '"); + strncat(descbuf, name, NAMEDATALEN); + strcat(descbuf, "' AND c.oid = i.indrelid AND i.indexrelid = c2.oid\n" + "ORDER BY c2.relname"); + res3 = PSQLexec(pset, descbuf); + if (!res3) + return false; + + if (PQntuples(res3) > 0) + { + footers = xmalloc((PQntuples(res3) + 1) * sizeof(*footers)); + + for (i = 0; i < PQntuples(res3); i++) + { + footers[i] = xmalloc(10 + NAMEDATALEN); + if (PQntuples(res3) == 1) + sprintf(footers[i], "Index: %s", PQgetvalue(res3, i, 0)); + else if (i == 0) + sprintf(footers[i], "Indices: %s", PQgetvalue(res3, i, 0)); + else + sprintf(footers[i], " %s", PQgetvalue(res3, i, 0)); + } + + footers[i] = NULL; + } } - } - myopt.tuples_only = false; - printTable(title, headers, cells, footers, "llll", &myopt, pset->queryFout); + myopt.tuples_only = false; + printTable(title, headers, cells, footers, "llll", &myopt, pset->queryFout); - /* clean up */ - free(title); + /* clean up */ + free(title); - for (i = 0; i<PQntuples(res); i++) { - free(cells[i*cols + 1]); - free(cells[i*cols + 2]); - } - free(cells); + for (i = 0; i < PQntuples(res); i++) + { + free(cells[i * cols + 1]); + free(cells[i * cols + 2]); + } + free(cells); - for (ptr = footers; footers && *ptr; ptr++) - free(*ptr); - free(footers); + for (ptr = footers; footers && *ptr; ptr++) + free(*ptr); + free(footers); - PQclear(res); - PQclear(res2); - PQclear(res3); + PQclear(res); + PQclear(res2); + PQclear(res3); - return true; + return true; } @@ -691,125 +724,134 @@ describeTableDetails(const char * name, PsqlSettings * pset) * (any order of the above is fine) */ bool -listTables(const char * infotype, const char * name, PsqlSettings * pset) +listTables(const char *infotype, const char *name, PsqlSettings *pset) { - bool showTables = strchr(infotype, 't') != NULL; - bool showIndices= strchr(infotype, 'i') != NULL; - bool showViews = strchr(infotype, 'v') != NULL; - bool showSeq = strchr(infotype, 's') != NULL; - bool showSystem = strchr(infotype, 'S') != NULL; - - bool description = GetVariableBool(pset->vars, "description"); - - char descbuf[1536 + 4 * REGEXP_CUTOFF]; - PGresult *res; - printQueryOpt myopt = pset->popt; - - descbuf[0] = '\0'; - - /* tables */ - if (showTables) { - strcat(descbuf, "SELECT u.usename as \"Owner\", c.relname as \"Name\", 'table'::text as \"Type\""); - if (description) - strcat(descbuf, ", obj_description(c.oid) as \"Description\""); - strcat(descbuf, "\nFROM pg_class c, pg_user u\n" - "WHERE c.relowner = u.usesysid AND c.relkind = 'r'\n" - " AND not exists (select 1 from pg_views where viewname = c.relname)\n"); - strcat(descbuf, showSystem ? " AND c.relname ~ '^pg_'\n" : " AND c.relname !~ '^pg_'\n"); - if (name) { - strcat(descbuf, " AND c.relname ~ '^"); - strncat(descbuf, name, REGEXP_CUTOFF); - strcat(descbuf, "'\n"); + bool showTables = strchr(infotype, 't') != NULL; + bool showIndices = strchr(infotype, 'i') != NULL; + bool showViews = strchr(infotype, 'v') != NULL; + bool showSeq = strchr(infotype, 's') != NULL; + bool showSystem = strchr(infotype, 'S') != NULL; + + bool description = GetVariableBool(pset->vars, "description"); + + char descbuf[1536 + 4 * REGEXP_CUTOFF]; + PGresult *res; + printQueryOpt myopt = pset->popt; + + descbuf[0] = '\0'; + + /* tables */ + if (showTables) + { + strcat(descbuf, "SELECT u.usename as \"Owner\", c.relname as \"Name\", 'table'::text as \"Type\""); + if (description) + strcat(descbuf, ", obj_description(c.oid) as \"Description\""); + strcat(descbuf, "\nFROM pg_class c, pg_user u\n" + "WHERE c.relowner = u.usesysid AND c.relkind = 'r'\n" + " AND not exists (select 1 from pg_views where viewname = c.relname)\n"); + strcat(descbuf, showSystem ? " AND c.relname ~ '^pg_'\n" : " AND c.relname !~ '^pg_'\n"); + if (name) + { + strcat(descbuf, " AND c.relname ~ '^"); + strncat(descbuf, name, REGEXP_CUTOFF); + strcat(descbuf, "'\n"); + } } - } - - /* views */ - if (showViews) { - if (descbuf[0]) - strcat(descbuf, "\nUNION\n\n"); - strcat(descbuf, "SELECT u.usename as \"Owner\", c.relname as \"Name\", 'view'::text as \"Type\""); - if (description) - strcat(descbuf, ", obj_description(c.oid) as \"Description\""); - strcat(descbuf, "\nFROM pg_class c, pg_user u\n" - "WHERE c.relowner = u.usesysid AND c.relkind = 'r'\n" - " AND exists (select 1 from pg_views where viewname = c.relname)\n"); - strcat(descbuf, showSystem ? " AND c.relname ~ '^pg_'\n" : " AND c.relname !~ '^pg_'\n"); - if (name) { - strcat(descbuf, " AND c.relname ~ '^"); - strncat(descbuf, name, REGEXP_CUTOFF); - strcat(descbuf, "'\n"); + /* views */ + if (showViews) + { + if (descbuf[0]) + strcat(descbuf, "\nUNION\n\n"); + + strcat(descbuf, "SELECT u.usename as \"Owner\", c.relname as \"Name\", 'view'::text as \"Type\""); + if (description) + strcat(descbuf, ", obj_description(c.oid) as \"Description\""); + strcat(descbuf, "\nFROM pg_class c, pg_user u\n" + "WHERE c.relowner = u.usesysid AND c.relkind = 'r'\n" + " AND exists (select 1 from pg_views where viewname = c.relname)\n"); + strcat(descbuf, showSystem ? " AND c.relname ~ '^pg_'\n" : " AND c.relname !~ '^pg_'\n"); + if (name) + { + strcat(descbuf, " AND c.relname ~ '^"); + strncat(descbuf, name, REGEXP_CUTOFF); + strcat(descbuf, "'\n"); + } } - } - - /* indices, sequences */ - if (showIndices || showSeq) { - if (descbuf[0]) - strcat(descbuf, "\nUNION\n\n"); - strcat(descbuf, "SELECT u.usename as \"Owner\", c.relname as \"Name\",\n" - " (CASE WHEN relkind = 'S' THEN 'sequence'::text ELSE 'index'::text END) as \"Type\""); - if (description) - strcat(descbuf, ", obj_description(c.oid) as \"Description\""); - strcat(descbuf, "\nFROM pg_class c, pg_user u\n" - "WHERE c.relowner = u.usesysid AND relkind in ("); - if (showIndices && showSeq) - strcat(descbuf, "'i', 'S'"); - else if (showIndices) - strcat(descbuf, "'i'"); - else - strcat(descbuf, "'S'"); - strcat(descbuf, ")\n"); - - /* ignore large-obj indices */ - if (showIndices) - strcat(descbuf, " AND (c.relkind != 'i' OR c.relname !~ '^xinx')\n"); - - strcat(descbuf, showSystem ? " AND c.relname ~ '^pg_'\n" : " AND c.relname !~ '^pg_'\n"); - if (name) { - strcat(descbuf, " AND c.relname ~ '^"); - strncat(descbuf, name, REGEXP_CUTOFF); - strcat(descbuf, "'\n"); + /* indices, sequences */ + if (showIndices || showSeq) + { + if (descbuf[0]) + strcat(descbuf, "\nUNION\n\n"); + + strcat(descbuf, "SELECT u.usename as \"Owner\", c.relname as \"Name\",\n" + " (CASE WHEN relkind = 'S' THEN 'sequence'::text ELSE 'index'::text END) as \"Type\""); + if (description) + strcat(descbuf, ", obj_description(c.oid) as \"Description\""); + strcat(descbuf, "\nFROM pg_class c, pg_user u\n" + "WHERE c.relowner = u.usesysid AND relkind in ("); + if (showIndices && showSeq) + strcat(descbuf, "'i', 'S'"); + else if (showIndices) + strcat(descbuf, "'i'"); + else + strcat(descbuf, "'S'"); + strcat(descbuf, ")\n"); + + /* ignore large-obj indices */ + if (showIndices) + strcat(descbuf, " AND (c.relkind != 'i' OR c.relname !~ '^xinx')\n"); + + strcat(descbuf, showSystem ? " AND c.relname ~ '^pg_'\n" : " AND c.relname !~ '^pg_'\n"); + if (name) + { + strcat(descbuf, " AND c.relname ~ '^"); + strncat(descbuf, name, REGEXP_CUTOFF); + strcat(descbuf, "'\n"); + } } - } - - /* real system catalogue tables */ - if (showSystem && showTables) { - if (descbuf[0]) - strcat(descbuf, "\nUNION\n\n"); - strcat(descbuf, "SELECT u.usename as \"Owner\", c.relname as \"Name\", 'system'::text as \"Type\""); - if (description) - strcat(descbuf, ", obj_description(c.oid) as \"Description\""); - strcat(descbuf, "\nFROM pg_class c, pg_user u\n" - "WHERE c.relowner = u.usesysid AND c.relkind = 's'\n"); - if (name) { - strcat(descbuf, " AND c.relname ~ '^"); - strncat(descbuf, name, REGEXP_CUTOFF); - strcat(descbuf, "'\n"); + /* real system catalogue tables */ + if (showSystem && showTables) + { + if (descbuf[0]) + strcat(descbuf, "\nUNION\n\n"); + + strcat(descbuf, "SELECT u.usename as \"Owner\", c.relname as \"Name\", 'system'::text as \"Type\""); + if (description) + strcat(descbuf, ", obj_description(c.oid) as \"Description\""); + strcat(descbuf, "\nFROM pg_class c, pg_user u\n" + "WHERE c.relowner = u.usesysid AND c.relkind = 's'\n"); + if (name) + { + strcat(descbuf, " AND c.relname ~ '^"); + strncat(descbuf, name, REGEXP_CUTOFF); + strcat(descbuf, "'\n"); + } } - } - strcat(descbuf, "\nORDER BY \"Name\""); + strcat(descbuf, "\nORDER BY \"Name\""); - res = PSQLexec(pset, descbuf); - if (!res) - return false; + res = PSQLexec(pset, descbuf); + if (!res) + return false; - if (PQntuples(res) == 0) - fprintf(pset->queryFout, "No matching classes found.\n"); + if (PQntuples(res) == 0) + fprintf(pset->queryFout, "No matching classes found.\n"); - else { - myopt.topt.tuples_only = false; - myopt.nullPrint = NULL; - myopt.title = "List of classes"; + else + { + myopt.topt.tuples_only = false; + myopt.nullPrint = NULL; + myopt.title = "List of classes"; - printQuery(res, &myopt, pset->queryFout); - } + printQuery(res, &myopt, pset->queryFout); + } - PQclear(res); - return true; + PQclear(res); + return true; } diff --git a/src/bin/psql/describe.h b/src/bin/psql/describe.h index 8f165b4f80..3ab6367c8d 100644 --- a/src/bin/psql/describe.h +++ b/src/bin/psql/describe.h @@ -5,38 +5,38 @@ /* \da */ bool -describeAggregates(const char * name, PsqlSettings * pset); + describeAggregates(const char *name, PsqlSettings *pset); /* \df */ bool -describeFunctions(const char * name, PsqlSettings * pset); + describeFunctions(const char *name, PsqlSettings *pset); /* \dT */ bool -describeTypes(const char * name, PsqlSettings * pset); + describeTypes(const char *name, PsqlSettings *pset); /* \do */ bool -describeOperators(const char * name, PsqlSettings * pset); + describeOperators(const char *name, PsqlSettings *pset); /* \dp (formerly \z) */ bool -permissionsList(const char * name, PsqlSettings *pset); + permissionsList(const char *name, PsqlSettings *pset); /* \dd */ bool -objectDescription(const char * object, PsqlSettings *pset); + objectDescription(const char *object, PsqlSettings *pset); /* \d foo */ bool -describeTableDetails(const char * name, PsqlSettings * pset); + describeTableDetails(const char *name, PsqlSettings *pset); /* \l */ bool -listAllDbs(PsqlSettings *pset); + listAllDbs(PsqlSettings *pset); /* \dt, \di, \dS, etc. */ bool -listTables(const char * infotype, const char * name, PsqlSettings * pset); + listTables(const char *infotype, const char *name, PsqlSettings *pset); -#endif /* DESCRIBE_H */ +#endif /* DESCRIBE_H */ diff --git a/src/bin/psql/help.c b/src/bin/psql/help.c index 0caab0f0d0..0c8943944d 100644 --- a/src/bin/psql/help.c +++ b/src/bin/psql/help.c @@ -7,12 +7,12 @@ #include <signal.h> #ifndef WIN32 -#include <sys/ioctl.h> /* for ioctl() */ +#include <sys/ioctl.h> /* for ioctl() */ #ifdef HAVE_PWD_H -#include <pwd.h> /* for getpwuid() */ +#include <pwd.h> /* for getpwuid() */ #endif -#include <sys/types.h> /* (ditto) */ -#include <unistd.h> /* for getuid() */ +#include <sys/types.h> /* (ditto) */ +#include <unistd.h> /* for getuid() */ #else #define strcasecmp(x,y) stricmp(x,y) #define popen(x,y) _popen(x,y) @@ -34,85 +34,94 @@ */ #define ON(var) (var ? "on" : "off") -void usage(void) +void +usage(void) { - const char *env; - const char *user; + const char *env; + const char *user; + #ifndef WIN32 - struct passwd *pw = NULL; + struct passwd *pw = NULL; + #endif - /* Find default user, in case we need it. */ - user = getenv("USER"); - if (!user) { + /* Find default user, in case we need it. */ + user = getenv("USER"); + if (!user) + { #ifndef WIN32 - pw = getpwuid(getuid()); - if (pw) user = pw->pw_name; - else { - perror("getpwuid()"); - exit(EXIT_FAILURE); - } + pw = getpwuid(getuid()); + if (pw) + user = pw->pw_name; + else + { + perror("getpwuid()"); + exit(EXIT_FAILURE); + } #else - user = "?"; + user = "?"; #endif - } + } /* If string begins " here, then it ought to end there to fit on an 80 column terminal> > > > > > > " */ - fprintf(stderr, "Usage: psql [options] [dbname [username]] \n"); - fprintf(stderr, " -A Unaligned table output mode (-P format=unaligned)\n"); - fprintf(stderr, " -c query Run single query (slash commands, too) and exit\n"); - - /* Display default database */ - env = getenv("PGDATABASE"); - if (!env) env=user; - fprintf(stderr, " -d dbname Specify database name to connect to (default: %s)\n", env); - - fprintf(stderr, " -e Echo all input in non-interactive mode\n"); - fprintf(stderr, " -E Display queries that internal commands generate\n"); - fprintf(stderr, " -f filename Execute queries from file, then exit\n"); - fprintf(stderr, " -F sep Set field separator (default: '" DEFAULT_FIELD_SEP "') (-P fieldsep=)\n"); - - /* Display default host */ - env = getenv("PGHOST"); - fprintf(stderr, " -h host Specify database server host (default: "); - if (env) - fprintf(stderr, env); - else - fprintf(stderr, "domain socket"); - fprintf(stderr, ")\n"); - - fprintf(stderr, " -H HTML table output mode (-P format=html)\n"); - fprintf(stderr, " -l List available databases, then exit\n"); - fprintf(stderr, " -n Do not use readline and history\n"); - fprintf(stderr, " -o filename Send query output to filename (or |pipe)\n"); - - /* Display default port */ - env = getenv("PGPORT"); - fprintf(stderr, " -p port Specify database server port (default: %s)\n", - env ? env : "hardwired"); - - fprintf(stderr, " -P var[=arg] Set printing option 'var' to 'arg'. (see \\pset command)\n"); - fprintf(stderr, " -q Run quietly (no messages, no prompts)\n"); - fprintf(stderr, " -s Single step mode (confirm each query)\n"); - fprintf(stderr, " -S Single line mode (newline sends query)\n"); - fprintf(stderr, " -t Don't print headings and row count (-P tuples_only)\n"); - fprintf(stderr, " -T text Set HTML table tag options (e.g., width, border)\n"); - fprintf(stderr, " -u Prompt for username and password (same as \"-U ? -W\")\n"); - - /* Display default user */ - env = getenv("PGUSER"); - if (!env) env=user; - fprintf(stderr, " -U [username] Specifiy username, \"?\"=prompt (default user: %s)\n", env); - - fprintf(stderr, " -x Turn on expanded table output (-P expanded)\n"); - fprintf(stderr, " -v name=val Set psql variable 'name' to 'value'\n"); - fprintf(stderr, " -V Show version information and exit\n"); - fprintf(stderr, " -W Prompt for password (should happen automatically)\n"); - - fprintf(stderr, "Consult the documentation for the complete details.\n"); + fprintf(stderr, "Usage: psql [options] [dbname [username]] \n"); + fprintf(stderr, " -A Unaligned table output mode (-P format=unaligned)\n"); + fprintf(stderr, " -c query Run single query (slash commands, too) and exit\n"); + + /* Display default database */ + env = getenv("PGDATABASE"); + if (!env) + env = user; + fprintf(stderr, " -d dbname Specify database name to connect to (default: %s)\n", env); + + fprintf(stderr, " -e Echo all input in non-interactive mode\n"); + fprintf(stderr, " -E Display queries that internal commands generate\n"); + fprintf(stderr, " -f filename Execute queries from file, then exit\n"); + fprintf(stderr, " -F sep Set field separator (default: '" DEFAULT_FIELD_SEP "') (-P fieldsep=)\n"); + + /* Display default host */ + env = getenv("PGHOST"); + fprintf(stderr, " -h host Specify database server host (default: "); + if (env) + fprintf(stderr, env); + else + fprintf(stderr, "domain socket"); + fprintf(stderr, ")\n"); + + fprintf(stderr, " -H HTML table output mode (-P format=html)\n"); + fprintf(stderr, " -l List available databases, then exit\n"); + fprintf(stderr, " -n Do not use readline and history\n"); + fprintf(stderr, " -o filename Send query output to filename (or |pipe)\n"); + + /* Display default port */ + env = getenv("PGPORT"); + fprintf(stderr, " -p port Specify database server port (default: %s)\n", + env ? env : "hardwired"); + + fprintf(stderr, " -P var[=arg] Set printing option 'var' to 'arg'. (see \\pset command)\n"); + fprintf(stderr, " -q Run quietly (no messages, no prompts)\n"); + fprintf(stderr, " -s Single step mode (confirm each query)\n"); + fprintf(stderr, " -S Single line mode (newline sends query)\n"); + fprintf(stderr, " -t Don't print headings and row count (-P tuples_only)\n"); + fprintf(stderr, " -T text Set HTML table tag options (e.g., width, border)\n"); + fprintf(stderr, " -u Prompt for username and password (same as \"-U ? -W\")\n"); + + /* Display default user */ + env = getenv("PGUSER"); + if (!env) + env = user; + fprintf(stderr, " -U [username] Specifiy username, \"?\"=prompt (default user: %s)\n", env); + + fprintf(stderr, " -x Turn on expanded table output (-P expanded)\n"); + fprintf(stderr, " -v name=val Set psql variable 'name' to 'value'\n"); + fprintf(stderr, " -V Show version information and exit\n"); + fprintf(stderr, " -W Prompt for password (should happen automatically)\n"); + + fprintf(stderr, "Consult the documentation for the complete details.\n"); #ifndef WIN32 - if (pw) free(pw); + if (pw) + free(pw); #endif } @@ -125,82 +134,85 @@ void usage(void) */ #ifndef TIOCGWINSZ -struct winsize { - int ws_row; - int ws_col; +struct winsize +{ + int ws_row; + int ws_col; }; + #endif void slashUsage(PsqlSettings *pset) { - bool usePipe = false; - const char *pagerenv; - FILE *fout; - struct winsize screen_size; + bool usePipe = false; + const char *pagerenv; + FILE *fout; + struct winsize screen_size; #ifdef TIOCGWINSZ - if (pset->notty == 0 && - (ioctl(fileno(stdout), TIOCGWINSZ, &screen_size) == -1 || - screen_size.ws_col == 0 || - screen_size.ws_row == 0)) - { + if (pset->notty == 0 && + (ioctl(fileno(stdout), TIOCGWINSZ, &screen_size) == -1 || + screen_size.ws_col == 0 || + screen_size.ws_row == 0)) + { #endif - screen_size.ws_row = 24; - screen_size.ws_col = 80; + screen_size.ws_row = 24; + screen_size.ws_col = 80; #ifdef TIOCGWINSZ - } + } #endif - if (pset->notty == 0 && - (pagerenv = getenv("PAGER")) && - (pagerenv[0] != '\0') && - screen_size.ws_row <= 36 && - (fout = popen(pagerenv, "w"))) - { - usePipe = true; - pqsignal(SIGPIPE, SIG_IGN); - } - else - fout = stdout; - - /* if you add/remove a line here, change the row test above */ - fprintf(fout, " \\? -- help\n"); - fprintf(fout, " \\c[onnect] [<dbname>|- [<user>|?]] -- connect to new database (currently '%s')\n", PQdb(pset->db)); - fprintf(fout, " \\copy [binary] <table> [with oids] {from|to} <fname> [with delimiters '<char>']\n"); - fprintf(fout, " \\copyright -- show PostgreSQL copyright\n"); - fprintf(fout, " \\d -- list tables, views, and sequences\n"); - fprintf(fout, " \\distvS -- list only indices/sequences/tables/views/system tables\n"); - fprintf(fout, " \\da -- list aggregates\n"); - fprintf(fout, " \\dd [<object>]- list comment for table, type, function, or operator\n"); - fprintf(fout, " \\df -- list functions\n"); - fprintf(fout, " \\do -- list operators\n"); - fprintf(fout, " \\dT -- list data types\n"); - fprintf(fout, " \\e [<fname>] -- edit the current query buffer or <fname> with external editor\n"); - fprintf(fout, " \\echo <text> -- write text to stdout\n"); - fprintf(fout, " \\g [<fname>] -- send query to backend (and results in <fname> or |pipe)\n"); - fprintf(fout, " \\h [<cmd>] -- help on syntax of sql commands, * for all commands\n"); - fprintf(fout, " \\i <fname> -- read and execute queries from filename\n"); - fprintf(fout, " \\l -- list all databases\n"); - fprintf(fout, " \\lo_export, \\lo_import, \\lo_list, \\lo_unlink -- large object operations\n"); - fprintf(fout, " \\o [<fname>] -- send all query results to <fname>, or |pipe\n"); - fprintf(fout, " \\p -- print the content of the current query buffer\n"); - fprintf(fout, " \\pset -- set table output options\n"); - fprintf(fout, " \\q -- quit\n"); - fprintf(fout, " \\qecho <text>-- write text to query output stream (see \\o)\n"); - fprintf(fout, " \\r -- reset (clear) the query buffer\n"); - fprintf(fout, " \\s [<fname>] -- print history or save it in <fname>\n"); - fprintf(fout, " \\set <var> [<value>] -- set/unset internal variable\n"); - fprintf(fout, " \\t -- don't show table headers or footers (currently %s)\n", ON(pset->popt.topt.tuples_only)); - fprintf(fout, " \\x -- toggle expanded output (currently %s)\n", ON(pset->popt.topt.expanded)); - fprintf(fout, " \\w <fname> -- write current query buffer to a file\n"); - fprintf(fout, " \\z -- list table access permissions\n"); - fprintf(fout, " \\! [<cmd>] -- shell escape or command\n"); - - if (usePipe) { - pclose(fout); - pqsignal(SIGPIPE, SIG_DFL); - } + if (pset->notty == 0 && + (pagerenv = getenv("PAGER")) && + (pagerenv[0] != '\0') && + screen_size.ws_row <= 36 && + (fout = popen(pagerenv, "w"))) + { + usePipe = true; + pqsignal(SIGPIPE, SIG_IGN); + } + else + fout = stdout; + + /* if you add/remove a line here, change the row test above */ + fprintf(fout, " \\? -- help\n"); + fprintf(fout, " \\c[onnect] [<dbname>|- [<user>|?]] -- connect to new database (currently '%s')\n", PQdb(pset->db)); + fprintf(fout, " \\copy [binary] <table> [with oids] {from|to} <fname> [with delimiters '<char>']\n"); + fprintf(fout, " \\copyright -- show PostgreSQL copyright\n"); + fprintf(fout, " \\d -- list tables, views, and sequences\n"); + fprintf(fout, " \\distvS -- list only indices/sequences/tables/views/system tables\n"); + fprintf(fout, " \\da -- list aggregates\n"); + fprintf(fout, " \\dd [<object>]- list comment for table, type, function, or operator\n"); + fprintf(fout, " \\df -- list functions\n"); + fprintf(fout, " \\do -- list operators\n"); + fprintf(fout, " \\dT -- list data types\n"); + fprintf(fout, " \\e [<fname>] -- edit the current query buffer or <fname> with external editor\n"); + fprintf(fout, " \\echo <text> -- write text to stdout\n"); + fprintf(fout, " \\g [<fname>] -- send query to backend (and results in <fname> or |pipe)\n"); + fprintf(fout, " \\h [<cmd>] -- help on syntax of sql commands, * for all commands\n"); + fprintf(fout, " \\i <fname> -- read and execute queries from filename\n"); + fprintf(fout, " \\l -- list all databases\n"); + fprintf(fout, " \\lo_export, \\lo_import, \\lo_list, \\lo_unlink -- large object operations\n"); + fprintf(fout, " \\o [<fname>] -- send all query results to <fname>, or |pipe\n"); + fprintf(fout, " \\p -- print the content of the current query buffer\n"); + fprintf(fout, " \\pset -- set table output options\n"); + fprintf(fout, " \\q -- quit\n"); + fprintf(fout, " \\qecho <text>-- write text to query output stream (see \\o)\n"); + fprintf(fout, " \\r -- reset (clear) the query buffer\n"); + fprintf(fout, " \\s [<fname>] -- print history or save it in <fname>\n"); + fprintf(fout, " \\set <var> [<value>] -- set/unset internal variable\n"); + fprintf(fout, " \\t -- don't show table headers or footers (currently %s)\n", ON(pset->popt.topt.tuples_only)); + fprintf(fout, " \\x -- toggle expanded output (currently %s)\n", ON(pset->popt.topt.expanded)); + fprintf(fout, " \\w <fname> -- write current query buffer to a file\n"); + fprintf(fout, " \\z -- list table access permissions\n"); + fprintf(fout, " \\! [<cmd>] -- shell escape or command\n"); + + if (usePipe) + { + pclose(fout); + pqsignal(SIGPIPE, SIG_DFL); + } } @@ -212,59 +224,59 @@ slashUsage(PsqlSettings *pset) void helpSQL(const char *topic) { - if (!topic || strlen(topic)==0) - { - char left_center_right; /* Which column we're displaying */ - int i; /* Index into QL_HELP[] */ - - puts("Syntax: \\h <cmd> or \\help <cmd>, where <cmd> is one of the following:"); - - left_center_right = 'L';/* Start with left column */ - i = 0; - while (QL_HELP[i].cmd != NULL) + if (!topic || strlen(topic) == 0) { - switch (left_center_right) - { - case 'L': - printf(" %-25s", QL_HELP[i].cmd); - left_center_right = 'C'; - break; - case 'C': - printf("%-25s", QL_HELP[i].cmd); - left_center_right = 'R'; - break; - case 'R': - printf("%-25s\n", QL_HELP[i].cmd); - left_center_right = 'L'; - break; - } - i++; + char left_center_right; /* Which column we're displaying */ + int i; /* Index into QL_HELP[] */ + + puts("Syntax: \\h <cmd> or \\help <cmd>, where <cmd> is one of the following:"); + + left_center_right = 'L';/* Start with left column */ + i = 0; + while (QL_HELP[i].cmd != NULL) + { + switch (left_center_right) + { + case 'L': + printf(" %-25s", QL_HELP[i].cmd); + left_center_right = 'C'; + break; + case 'C': + printf("%-25s", QL_HELP[i].cmd); + left_center_right = 'R'; + break; + case 'R': + printf("%-25s\n", QL_HELP[i].cmd); + left_center_right = 'L'; + break; + } + i++; + } + if (left_center_right != 'L') + puts("\n"); + puts("Or type \\h * for a complete description of all commands."); } - if (left_center_right != 'L') - puts("\n"); - puts("Or type \\h * for a complete description of all commands."); - } - else - { - int i; - bool help_found = false; - - for (i = 0; QL_HELP[i].cmd; i++) + else { - if (strcasecmp(QL_HELP[i].cmd, topic) == 0 || - strcmp(topic, "*") == 0) - { - help_found = true; - printf("Command: %s\nDescription: %s\nSyntax:\n%s\n\n", - QL_HELP[i].cmd, QL_HELP[i].help, QL_HELP[i].syntax); - } + int i; + bool help_found = false; + + for (i = 0; QL_HELP[i].cmd; i++) + { + if (strcasecmp(QL_HELP[i].cmd, topic) == 0 || + strcmp(topic, "*") == 0) + { + help_found = true; + printf("Command: %s\nDescription: %s\nSyntax:\n%s\n\n", + QL_HELP[i].cmd, QL_HELP[i].help, QL_HELP[i].syntax); + } + } + + if (!help_found) + printf("No help available for '%s'.\nTry \\h with no arguments to see available help.\n", topic); } - - if (!help_found) - printf("No help available for '%s'.\nTry \\h with no arguments to see available help.\n", topic); - } } @@ -273,34 +285,34 @@ helpSQL(const char *topic) void print_copyright(void) { - puts( -" -PostgreSQL Data Base Management System + puts( + " + PostgreSQL Data Base Management System -Copyright (c) 1996-9 PostgreSQL Global Development Group + Copyright(c) 1996 - 9 PostgreSQL Global Development Group -This software is based on Postgres95, formerly known as Postgres, which -contains the following notice: + This software is based on Postgres95, formerly known as Postgres, which + contains the following notice: -Copyright (c) 1994-7 Regents of the University of California + Copyright(c) 1994 - 7 Regents of the University of California -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose, without fee, and without a written agreement -is hereby granted, provided that the above copyright notice and this paragraph -and the following two paragraphs appear in all copies. + Permission to use, copy, modify, and distribute this software and its + documentation for any purpose, without fee, and without a written agreement + is hereby granted, provided that the above copyright notice and this paragraph + and the following two paragraphs appear in all copies. -IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR -DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST -PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF -THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. + IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR + DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST + PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF + THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + DAMAGE. -THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, -BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN \"AS IS\" BASIS, -AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, -SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE.THE SOFTWARE PROVIDED HEREUNDER IS ON AN \ "AS IS\" BASIS, + AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, + SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. -(end of terms)" + (end of terms) " ); } diff --git a/src/bin/psql/help.h b/src/bin/psql/help.h index 34bb267764..791e0313ca 100644 --- a/src/bin/psql/help.h +++ b/src/bin/psql/help.h @@ -3,14 +3,13 @@ #include "settings.h" -void usage(void); +void usage(void); -void slashUsage(PsqlSettings *pset); +void slashUsage(PsqlSettings *pset); -void helpSQL(const char *topic); +void helpSQL(const char *topic); -void print_copyright(void); +void print_copyright(void); #endif - diff --git a/src/bin/psql/input.c b/src/bin/psql/input.c index 3bb418be48..d8ceebab93 100644 --- a/src/bin/psql/input.c +++ b/src/bin/psql/input.c @@ -10,9 +10,11 @@ /* (of course there is no runtime command for doing that :) */ #ifdef USE_READLINE static bool useReadline; + #endif #ifdef USE_HISTORY static bool useHistory; + #endif @@ -25,29 +27,31 @@ static bool useHistory; char * gets_interactive(const char *prompt) { - char * s; + char *s; #ifdef USE_READLINE - if (useReadline) { - s = readline(prompt); - fputc('\r', stdout); - fflush(stdout); - } - else { + if (useReadline) + { + s = readline(prompt); + fputc('\r', stdout); + fflush(stdout); + } + else + { #endif - fputs(prompt, stdout); - fflush(stdout); - s = gets_fromFile(stdin); + fputs(prompt, stdout); + fflush(stdout); + s = gets_fromFile(stdin); #ifdef USE_READLINE - } + } #endif #ifdef USE_HISTORY - if (useHistory && s && s[0] != '\0') - add_history(s); + if (useHistory && s && s[0] != '\0') + add_history(s); #endif - return s; + return s; } @@ -60,25 +64,27 @@ gets_interactive(const char *prompt) char * gets_fromFile(FILE *source) { - PQExpBufferData buffer; - char line[1024]; - - initPQExpBuffer(&buffer); - - while (fgets(line, 1024, source) != NULL) { - appendPQExpBufferStr(&buffer, line); - if (buffer.data[buffer.len-1] == '\n') { - buffer.data[buffer.len-1] = '\0'; - return buffer.data; + PQExpBufferData buffer; + char line[1024]; + + initPQExpBuffer(&buffer); + + while (fgets(line, 1024, source) != NULL) + { + appendPQExpBufferStr(&buffer, line); + if (buffer.data[buffer.len - 1] == '\n') + { + buffer.data[buffer.len - 1] = '\0'; + return buffer.data; + } } - } - if (buffer.len > 0) - return buffer.data; /* EOF after reading some bufferload(s) */ + if (buffer.len > 0) + return buffer.data; /* EOF after reading some bufferload(s) */ - /* EOF, so return null */ - termPQExpBuffer(&buffer); - return NULL; + /* EOF, so return null */ + termPQExpBuffer(&buffer); + return NULL; } @@ -93,28 +99,33 @@ void initializeInput(int flags) { #ifdef USE_READLINE - if (flags == 1) { - useReadline = true; - rl_readline_name = "psql"; - } + if (flags == 1) + { + useReadline = true; + rl_readline_name = "psql"; + } #endif #ifdef USE_HISTORY - if (flags == 1) { - const char * home; - - useHistory = true; - using_history(); - home = getenv("HOME"); - if (home) { - char * psql_history = (char *) malloc(strlen(home) + 20); - if (psql_history) { - sprintf(psql_history, "%s/.psql_history", home); - read_history(psql_history); - free(psql_history); - } + if (flags == 1) + { + const char *home; + + useHistory = true; + using_history(); + home = getenv("HOME"); + if (home) + { + char *psql_history = (char *) malloc(strlen(home) + 20); + + if (psql_history) + { + sprintf(psql_history, "%s/.psql_history", home); + read_history(psql_history); + free(psql_history); + } + } } - } #endif } @@ -124,17 +135,19 @@ bool saveHistory(const char *fname) { #ifdef USE_HISTORY - if (useHistory) { - if (write_history(fname) != 0) { - perror(fname); - return false; + if (useHistory) + { + if (write_history(fname) != 0) + { + perror(fname); + return false; + } + return true; } - return true; - } - else - return false; + else + return false; #else - return false; + return false; #endif } @@ -144,19 +157,22 @@ void finishInput(void) { #ifdef USE_HISTORY - if (useHistory) { - char * home; - char * psql_history; - - home = getenv("HOME"); - if (home) { - psql_history = (char *) malloc(strlen(home) + 20); - if (psql_history) { - sprintf(psql_history, "%s/.psql_history", home); - write_history(psql_history); - free(psql_history); - } + if (useHistory) + { + char *home; + char *psql_history; + + home = getenv("HOME"); + if (home) + { + psql_history = (char *) malloc(strlen(home) + 20); + if (psql_history) + { + sprintf(psql_history, "%s/.psql_history", home); + write_history(psql_history); + free(psql_history); + } + } } - } #endif } diff --git a/src/bin/psql/input.h b/src/bin/psql/input.h index 272b0574f1..c91e9ca7b1 100644 --- a/src/bin/psql/input.h +++ b/src/bin/psql/input.h @@ -38,19 +38,19 @@ char * -gets_interactive(const char *prompt); + gets_interactive(const char *prompt); char * -gets_fromFile(FILE *source); + gets_fromFile(FILE *source); void -initializeInput(int flags); + initializeInput(int flags); bool -saveHistory(const char *fname); + saveHistory(const char *fname); void -finishInput(void); + finishInput(void); #endif diff --git a/src/bin/psql/large_obj.c b/src/bin/psql/large_obj.c index dfc39435ab..885a18cd4c 100644 --- a/src/bin/psql/large_obj.c +++ b/src/bin/psql/large_obj.c @@ -14,7 +14,7 @@ #include "print.h" -/* +/* * Since all large object ops must be in a transaction, we must do some magic * here. You can set the variable lo_transaction to one of commit|rollback| * nothing to get your favourite behaviour regarding any transaction in @@ -24,47 +24,50 @@ static char notice[80]; static void -_my_notice_handler(void * arg, const char * message) { - (void)arg; - strncpy(notice, message, 79); - notice[79] = '\0'; +_my_notice_handler(void *arg, const char *message) +{ + (void) arg; + strncpy(notice, message, 79); + notice[79] = '\0'; } static bool -handle_transaction(PsqlSettings * pset) +handle_transaction(PsqlSettings *pset) { - const char * var = GetVariable(pset->vars, "lo_transaction"); - PGresult * res; - bool commit; - PQnoticeProcessor old_notice_hook; + const char *var = GetVariable(pset->vars, "lo_transaction"); + PGresult *res; + bool commit; + PQnoticeProcessor old_notice_hook; - if (var && strcmp(var, "nothing")==0) - return true; + if (var && strcmp(var, "nothing") == 0) + return true; + + commit = (var && strcmp(var, "commit") == 0); + + notice[0] = '\0'; + old_notice_hook = PQsetNoticeProcessor(pset->db, _my_notice_handler, NULL); + + res = PSQLexec(pset, commit ? "COMMIT" : "ROLLBACK"); + if (!res) + return false; - commit = (var && strcmp(var, "commit")==0); - - notice[0] = '\0'; - old_notice_hook = PQsetNoticeProcessor(pset->db, _my_notice_handler, NULL); - - res = PSQLexec(pset, commit ? "COMMIT" : "ROLLBACK"); - if (!res) - return false; - - if (notice[0]) { - if ( (!commit && strcmp(notice, "NOTICE: UserAbortTransactionBlock and not in in-progress state\n")!=0) || - (commit && strcmp(notice, "NOTICE: EndTransactionBlock and not inprogress/abort state\n")!=0) ) - fputs(notice, stderr); - } - else if (!GetVariableBool(pset->vars, "quiet")) { - if (commit) - puts("Warning: Your transaction in progress has been committed."); - else - puts("Warning: Your transaction in progress has been rolled back."); - } - - PQsetNoticeProcessor(pset->db, old_notice_hook, NULL); - return true; + if (notice[0]) + { + if ((!commit && strcmp(notice, "NOTICE: UserAbortTransactionBlock and not in in-progress state\n") != 0) || + (commit && strcmp(notice, "NOTICE: EndTransactionBlock and not inprogress/abort state\n") != 0)) + fputs(notice, stderr); + } + else if (!GetVariableBool(pset->vars, "quiet")) + { + if (commit) + puts("Warning: Your transaction in progress has been committed."); + else + puts("Warning: Your transaction in progress has been rolled back."); + } + + PQsetNoticeProcessor(pset->db, old_notice_hook, NULL); + return true; } @@ -75,54 +78,61 @@ 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(PsqlSettings *pset, const char *loid_arg, const char *filename_arg) { - PGresult * res; - int status; - bool own_transaction = true; - const char * var = GetVariable(pset->vars, "lo_transaction"); - - if (var && strcmp(var, "nothing")==0) - own_transaction = false; + PGresult *res; + int status; + bool own_transaction = true; + const char *var = GetVariable(pset->vars, "lo_transaction"); + + if (var && strcmp(var, "nothing") == 0) + own_transaction = false; + + if (!pset->db) + { + fputs("You are not connected to a database.\n", stderr); + return false; + } - if (!pset->db) { - fputs("You are not connected to a database.\n", stderr); - return false; - } + if (own_transaction) + { + if (!handle_transaction(pset)) + return false; - if (own_transaction) { - if (!handle_transaction(pset)) - return false; + if (!(res = PSQLexec(pset, "BEGIN"))) + return false; - if (!(res = PSQLexec(pset, "BEGIN"))) - return false; + PQclear(res); + } - PQclear(res); - } - - 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); - if (own_transaction) { - res = PQexec(pset->db, "ROLLBACK"); - PQclear(res); + 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); + if (own_transaction) + { + res = PQexec(pset->db, "ROLLBACK"); + PQclear(res); + } + return false; } - return false; - } - - if (own_transaction) { - if (!(res = PSQLexec(pset, "COMMIT"))) { - res = PQexec(pset->db, "ROLLBACK"); - PQclear(res); - return false; + + if (own_transaction) + { + if (!(res = PSQLexec(pset, "COMMIT"))) + { + res = PQexec(pset->db, "ROLLBACK"); + PQclear(res); + return false; + } + + PQclear(res); } - PQclear(res); - } + fprintf(pset->queryFout, "lo_export\n"); - fprintf(pset->queryFout, "lo_export\n"); - - return true; + return true; } @@ -133,76 +143,85 @@ do_lo_export(PsqlSettings * pset, const char * loid_arg, const char * filename_a * Copy large object from file to database */ bool -do_lo_import(PsqlSettings * pset, const char * filename_arg, const char * comment_arg) +do_lo_import(PsqlSettings *pset, 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"); - - if (var && strcmp(var, "nothing")==0) - own_transaction = false; - - if (!pset->db) { - fputs("You are not connected to a database.\n", stderr); - return false; - } + PGresult *res; + Oid loid; + char buf[1024]; + unsigned int i; + bool own_transaction = true; + const char *var = GetVariable(pset->vars, "lo_transaction"); + + if (var && strcmp(var, "nothing") == 0) + own_transaction = false; + + if (!pset->db) + { + fputs("You are not connected to a database.\n", stderr); + return false; + } - if (own_transaction) { - if (!handle_transaction(pset)) - return false; + if (own_transaction) + { + if (!handle_transaction(pset)) + return false; - if (!(res = PSQLexec(pset, "BEGIN"))) - return false; + if (!(res = PSQLexec(pset, "BEGIN"))) + return false; - PQclear(res); - } - - loid = lo_import(pset->db, (char *)filename_arg); - if (loid == InvalidOid) { - fputs(PQerrorMessage(pset->db), stderr); - if (own_transaction) { - res = PQexec(pset->db, "ROLLBACK"); - PQclear(res); - } - return false; - } - - /* insert description if given */ - if (comment_arg) { - sprintf(buf, "INSERT INTO pg_description VALUES (%d, '", loid); - for (i=0; i<strlen(comment_arg); i++) - if (comment_arg[i]=='\'') - strcat(buf, "\\'"); - else - strncat(buf, &comment_arg[i], 1); - strcat(buf, "')"); - - if (!(res = PSQLexec(pset, buf))) { - if (own_transaction) { - res = PQexec(pset->db, "ROLLBACK"); PQclear(res); - } - return false; } - } - if (own_transaction) { - if (!(res = PSQLexec(pset, "COMMIT"))) { - res = PQexec(pset->db, "ROLLBACK"); - PQclear(res); - return false; + loid = lo_import(pset->db, (char *) filename_arg); + if (loid == InvalidOid) + { + fputs(PQerrorMessage(pset->db), stderr); + if (own_transaction) + { + res = PQexec(pset->db, "ROLLBACK"); + PQclear(res); + } + return false; } - PQclear(res); - } + /* insert description if given */ + if (comment_arg) + { + sprintf(buf, "INSERT INTO pg_description VALUES (%d, '", loid); + for (i = 0; i < strlen(comment_arg); i++) + if (comment_arg[i] == '\'') + strcat(buf, "\\'"); + else + strncat(buf, &comment_arg[i], 1); + strcat(buf, "')"); + + if (!(res = PSQLexec(pset, buf))) + { + if (own_transaction) + { + res = PQexec(pset->db, "ROLLBACK"); + PQclear(res); + } + return false; + } + } + if (own_transaction) + { + if (!(res = PSQLexec(pset, "COMMIT"))) + { + res = PQexec(pset->db, "ROLLBACK"); + PQclear(res); + return false; + } - fprintf(pset->queryFout, "lo_import %d\n", loid); + PQclear(res); + } - return true; + + fprintf(pset->queryFout, "lo_import %d\n", loid); + + return true; } @@ -212,67 +231,76 @@ do_lo_import(PsqlSettings * pset, const char * filename_arg, const char * commen * * removes a large object out of the database */ -bool do_lo_unlink(PsqlSettings * pset, const char * loid_arg) +bool +do_lo_unlink(PsqlSettings *pset, 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"); - - if (var && strcmp(var, "nothing")==0) - own_transaction = false; + 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"); + + if (var && strcmp(var, "nothing") == 0) + own_transaction = false; + + if (!pset->db) + { + fputs("You are not connected to a database.\n", stderr); + return false; + } - if (!pset->db) { - fputs("You are not connected to a database.\n", stderr); - return false; - } + if (own_transaction) + { + if (!handle_transaction(pset)) + return false; - if (own_transaction) { - if (!handle_transaction(pset)) - return false; + if (!(res = PSQLexec(pset, "BEGIN"))) + return false; - if (!(res = PSQLexec(pset, "BEGIN"))) - return false; + PQclear(res); + } - PQclear(res); - } - - status = lo_unlink(pset->db, loid); - if (status == -1) { - fputs(PQerrorMessage(pset->db), stderr); - if (own_transaction) { - res = PQexec(pset->db, "ROLLBACK"); - PQclear(res); + status = lo_unlink(pset->db, loid); + if (status == -1) + { + fputs(PQerrorMessage(pset->db), stderr); + if (own_transaction) + { + res = PQexec(pset->db, "ROLLBACK"); + PQclear(res); + } + return false; } - return false; - } - - /* remove the comment as well */ - sprintf(buf, "DELETE FROM pg_description WHERE objoid = %d", loid); - if (!(res = PSQLexec(pset, buf))) { - if (own_transaction) { - res = PQexec(pset->db, "ROLLBACK"); - PQclear(res); + + /* remove the comment as well */ + sprintf(buf, "DELETE FROM pg_description WHERE objoid = %d", loid); + if (!(res = PSQLexec(pset, buf))) + { + if (own_transaction) + { + res = PQexec(pset->db, "ROLLBACK"); + PQclear(res); + } + return false; } - return false; - } - if (own_transaction) { - if (!(res = PSQLexec(pset, "COMMIT"))) { - res = PQexec(pset->db, "ROLLBACK"); - PQclear(res); - return false; + if (own_transaction) + { + if (!(res = PSQLexec(pset, "COMMIT"))) + { + res = PQexec(pset->db, "ROLLBACK"); + PQclear(res); + return false; + } + PQclear(res); } - PQclear(res); - } - fprintf(pset->queryFout, "lo_unlink %d\n", loid); + fprintf(pset->queryFout, "lo_unlink %d\n", loid); - return true; + return true; } @@ -282,30 +310,31 @@ bool do_lo_unlink(PsqlSettings * pset, const char * loid_arg) * * Show all large objects in database, with comments if desired */ -bool do_lo_list(PsqlSettings * pset) +bool +do_lo_list(PsqlSettings *pset) { - PGresult * res; - char descbuf[512]; - printQueryOpt myopt = pset->popt; - - descbuf[0] = '\0'; - strcat(descbuf, "SELECT usename as \"Owner\", substring(relname from 5) as \"ID\""); - if (GetVariableBool(pset->vars, "description")) - strcat(descbuf, ",\n obj_description(pg_class.oid) as \"Description\""); - strcat(descbuf,"\nFROM pg_class, pg_user\n" + PGresult *res; + char descbuf[512]; + printQueryOpt myopt = pset->popt; + + descbuf[0] = '\0'; + strcat(descbuf, "SELECT usename as \"Owner\", substring(relname from 5) as \"ID\""); + if (GetVariableBool(pset->vars, "description")) + strcat(descbuf, ",\n obj_description(pg_class.oid) as \"Description\""); + strcat(descbuf, "\nFROM pg_class, pg_user\n" "WHERE usesysid = relowner AND relkind = 'l'\n" "ORDER BY \"ID\""); - res = PSQLexec(pset, descbuf); - if (!res) - return false; + res = PSQLexec(pset, descbuf); + if (!res) + return false; - myopt.topt.tuples_only = false; - myopt.nullPrint = NULL; - myopt.title = "Large objects"; + myopt.topt.tuples_only = false; + myopt.nullPrint = NULL; + myopt.title = "Large objects"; - printQuery(res, &myopt, pset->queryFout); + printQuery(res, &myopt, pset->queryFout); - PQclear(res); - return true; + PQclear(res); + return true; } diff --git a/src/bin/psql/large_obj.h b/src/bin/psql/large_obj.h index 22228e7b11..4f3f2fc428 100644 --- a/src/bin/psql/large_obj.h +++ b/src/bin/psql/large_obj.h @@ -3,9 +3,9 @@ #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(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); -#endif /* LARGE_OBJ_H */ +#endif /* LARGE_OBJ_H */ diff --git a/src/bin/psql/mainloop.c b/src/bin/psql/mainloop.c index 2f38ffbcff..560488fff4 100644 --- a/src/bin/psql/mainloop.c +++ b/src/bin/psql/mainloop.c @@ -26,343 +26,380 @@ int MainLoop(PsqlSettings *pset, FILE *source) { - PQExpBuffer query_buf; /* buffer for query being accumulated */ - char *line; /* current line of input */ - char *xcomment; /* start of extended comment */ - int len; /* length of the line */ - int successResult = EXIT_SUCCESS; - backslashResult slashCmdStatus; + PQExpBuffer query_buf; /* buffer for query being accumulated */ + char *line; /* current line of input */ + char *xcomment; /* start of extended comment */ + int len; /* length of the line */ + 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 */ - int paren_level; - unsigned int query_start; + bool eof = false; /* end of our command input? */ + bool success; + char in_quote; /* == 0 for no in_quote */ + bool was_bslash; /* backslash */ + int paren_level; + unsigned int query_start; - int i, prevlen, thislen; + int i, + prevlen, + thislen; - /* Save the prior command source */ - FILE *prev_cmd_source; - bool prev_cmd_interactive; + /* Save the prior command source */ + FILE *prev_cmd_source; + bool prev_cmd_interactive; - bool die_on_error; - const char *interpol_char; + bool die_on_error; + const char *interpol_char; - /* Save old settings */ - prev_cmd_source = pset->cur_cmd_source; - prev_cmd_interactive = pset->cur_cmd_interactive; + /* Save old settings */ + 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); + /* Establish new source */ + pset->cur_cmd_source = source; + pset->cur_cmd_interactive = ((source == stdin) && !pset->notty); - query_buf = createPQExpBuffer(); - if (!query_buf) { - perror("createPQExpBuffer"); - exit(EXIT_FAILURE); - } + query_buf = createPQExpBuffer(); + if (!query_buf) + { + perror("createPQExpBuffer"); + exit(EXIT_FAILURE); + } - xcomment = NULL; - in_quote = 0; - paren_level = 0; - slashCmdStatus = CMD_UNKNOWN; /* set default */ + xcomment = NULL; + in_quote = 0; + paren_level = 0; + slashCmdStatus = CMD_UNKNOWN; /* set default */ - /* main loop to get queries and execute them */ - while (!eof) - { - if (slashCmdStatus == CMD_NEWEDIT) + /* main loop to get queries and execute them */ + while (!eof) { - /* - * just returned from editing the line? then just copy to the - * input buffer - */ - line = strdup(query_buf->data); - resetPQExpBuffer(query_buf); - /* reset parsing state since we are rescanning whole query */ - xcomment = NULL; - in_quote = 0; - paren_level = 0; - } - else - { - /* - * otherwise, set interactive prompt if necessary - * and get another line - */ - if (pset->cur_cmd_interactive) - { - int prompt_status; - - if (in_quote && in_quote == '\'') - prompt_status = PROMPT_SINGLEQUOTE; - else if (in_quote && in_quote == '"') - prompt_status= PROMPT_DOUBLEQUOTE; - else if (xcomment != NULL) - prompt_status = PROMPT_COMMENT; - else if (query_buf->len > 0) - prompt_status = PROMPT_CONTINUE; + if (slashCmdStatus == CMD_NEWEDIT) + { + + /* + * just returned from editing the line? then just copy to the + * input buffer + */ + line = strdup(query_buf->data); + resetPQExpBuffer(query_buf); + /* reset parsing state since we are rescanning whole query */ + xcomment = NULL; + in_quote = 0; + paren_level = 0; + } else - prompt_status = PROMPT_READY; - - line = gets_interactive(get_prompt(pset, prompt_status)); - } - else - line = gets_fromFile(source); - } + { + + /* + * otherwise, set interactive prompt if necessary and get + * another line + */ + if (pset->cur_cmd_interactive) + { + int prompt_status; + + if (in_quote && in_quote == '\'') + prompt_status = PROMPT_SINGLEQUOTE; + else if (in_quote && in_quote == '"') + prompt_status = PROMPT_DOUBLEQUOTE; + else if (xcomment != NULL) + prompt_status = PROMPT_COMMENT; + else if (query_buf->len > 0) + prompt_status = PROMPT_CONTINUE; + else + prompt_status = PROMPT_READY; + + line = gets_interactive(get_prompt(pset, prompt_status)); + } + else + line = gets_fromFile(source); + } - /* Setting these will not have effect until next line */ - die_on_error = GetVariableBool(pset->vars, "die_on_error"); - interpol_char = GetVariable(pset->vars, "sql_interpol");; + /* Setting these will not have effect until next line */ + die_on_error = GetVariableBool(pset->vars, "die_on_error"); + interpol_char = GetVariable(pset->vars, "sql_interpol");; - /* - * query_buf holds query already accumulated. line is the malloc'd - * new line of input (note it must be freed before looping around!) - * query_start is the next command start location within the line. - */ + /* + * query_buf holds query already accumulated. line is the + * malloc'd new line of input (note it must be freed before + * looping around!) query_start is the next command start location + * within the line. + */ - /* No more input. Time to quit, or \i done */ - if (line == NULL || (!pset->cur_cmd_interactive && *line == '\0')) - { - if (GetVariableBool(pset->vars, "echo") && !GetVariableBool(pset->vars, "quiet")) - puts("EOF"); - eof = true; - continue; - } + /* No more input. Time to quit, or \i done */ + if (line == NULL || (!pset->cur_cmd_interactive && *line == '\0')) + { + if (GetVariableBool(pset->vars, "echo") && !GetVariableBool(pset->vars, "quiet")) + puts("EOF"); + eof = true; + continue; + } - /* not currently inside an extended comment? */ - if (xcomment) - xcomment = line; + /* not currently inside an extended comment? */ + if (xcomment) + xcomment = line; - /* strip trailing backslashes, they don't have a clear meaning */ - while (1) { - char * cp = strrchr(line, '\\'); - if (cp && (*(cp + 1) == '\0')) - *cp = '\0'; - else - break; - } + /* strip trailing backslashes, they don't have a clear meaning */ + while (1) + { + char *cp = strrchr(line, '\\'); - - /* echo back if input is from file and flag is set */ - if (!pset->cur_cmd_interactive && GetVariableBool(pset->vars, "echo")) - fprintf(stderr, "%s\n", line); - - - /* interpolate variables into SQL */ - len = strlen(line); - thislen = PQmblen(line); - - for (i = 0; line[i]; i += (thislen = PQmblen(&line[i])) ) { - if (interpol_char && interpol_char[0] != '\0' && interpol_char[0] == line[i]) { - size_t in_length, out_length; - const char * value; - char * new; - bool closer; /* did we have a closing delimiter or just an end of line? */ - - in_length = strcspn(&line[i+thislen], interpol_char); - closer = line[i + thislen + in_length] == line[i]; - line[i + thislen + in_length] = '\0'; - value = interpolate_var(&line[i + thislen], pset); - out_length = strlen(value); - - new = malloc(len + out_length - (in_length + (closer ? 2 : 1)) + 1); - if (!new) { - perror("malloc"); - exit(EXIT_FAILURE); + if (cp && (*(cp + 1) == '\0')) + *cp = '\0'; + else + break; } - new[0] = '\0'; - strncat(new, line, i); - strcat(new, value); - if (closer) - strcat(new, line + i + 2 + in_length); - free(line); - line = new; - i += out_length; - } - } + /* echo back if input is from file and flag is set */ + if (!pset->cur_cmd_interactive && GetVariableBool(pset->vars, "echo")) + fprintf(stderr, "%s\n", line); + + + /* interpolate variables into SQL */ + len = strlen(line); + thislen = PQmblen(line); + + for (i = 0; line[i]; i += (thislen = PQmblen(&line[i]))) + { + if (interpol_char && interpol_char[0] != '\0' && interpol_char[0] == line[i]) + { + size_t in_length, + out_length; + const char *value; + char *new; + bool closer; /* did we have a closing delimiter + * or just an end of line? */ + + in_length = strcspn(&line[i + thislen], interpol_char); + closer = line[i + thislen + in_length] == line[i]; + line[i + thislen + in_length] = '\0'; + value = interpolate_var(&line[i + thislen], pset); + out_length = strlen(value); + + new = malloc(len + out_length - (in_length + (closer ? 2 : 1)) + 1); + if (!new) + { + perror("malloc"); + exit(EXIT_FAILURE); + } + + new[0] = '\0'; + strncat(new, line, i); + strcat(new, value); + if (closer) + strcat(new, line + i + 2 + in_length); + + free(line); + line = new; + i += out_length; + } + } - /* nothing left on line? then ignore */ - if (line[0] == '\0') { - free(line); - continue; - } + /* nothing left on line? then ignore */ + if (line[0] == '\0') + { + free(line); + continue; + } - slashCmdStatus = CMD_UNKNOWN; + slashCmdStatus = CMD_UNKNOWN; - len = strlen(line); - query_start = 0; + len = strlen(line); + query_start = 0; - /* - * Parse line, looking for command separators. - * - * The current character is at line[i], the prior character at - * line[i - prevlen], the next character at line[i + thislen]. - */ - prevlen = 0; - thislen = (len > 0) ? PQmblen(line) : 0; + /* + * Parse line, looking for command separators. + * + * The current character is at line[i], the prior character at line[i + * - prevlen], the next character at line[i + thislen]. + */ + prevlen = 0; + thislen = (len > 0) ? PQmblen(line) : 0; #define ADVANCE_1 (prevlen = thislen, i += thislen, thislen = PQmblen(line+i)) - success = true; - for (i = 0; i < len; ADVANCE_1) { - if (!success && die_on_error) - break; - - - /* was the previous character a backslash? */ - if (i > 0 && line[i - prevlen] == '\\') - was_bslash = true; - else - was_bslash = false; - - - /* in quote? */ - if (in_quote) { - /* end of quote */ - if (line[i] == in_quote && !was_bslash) - in_quote = '\0'; - } - - /* start of quote */ - else if (line[i] == '\'' || line[i] == '"') - in_quote = line[i]; - - /* in extended comment? */ - else if (xcomment != NULL) { - if (line[i] == '*' && line[i + thislen] == '/') { - xcomment = NULL; - ADVANCE_1; - } - } - - /* start of extended comment? */ - else if (line[i] == '/' && line[i + thislen] == '*') { - xcomment = &line[i]; - ADVANCE_1; - } - - /* single-line comment? truncate line */ - else if ((line[i] == '-' && line[i + thislen] == '-') || - (line[i] == '/' && line[i + thislen] == '/')) - { - line[i] = '\0'; /* remove comment */ - break; - } - - /* count nested parentheses */ - else if (line[i] == '(') - paren_level++; - - else if (line[i] == ')' && paren_level > 0) - paren_level--; - - /* semicolon? then send query */ - else if (line[i] == ';' && !was_bslash && paren_level==0) { - line[i] = '\0'; - /* is there anything else on the line? */ - if (line[query_start + strspn(line + query_start, " \t")]!='\0') { - /* insert a cosmetic newline, if this is not the first line in the buffer */ - if (query_buf->len > 0) - appendPQExpBufferChar(query_buf, '\n'); - /* append the line to the query buffer */ - appendPQExpBufferStr(query_buf, line + query_start); + success = true; + for (i = 0; i < len; ADVANCE_1) + { + if (!success && die_on_error) + break; + + + /* was the previous character a backslash? */ + if (i > 0 && line[i - prevlen] == '\\') + was_bslash = true; + else + was_bslash = false; + + + /* in quote? */ + if (in_quote) + { + /* end of quote */ + if (line[i] == in_quote && !was_bslash) + in_quote = '\0'; + } + + /* start of quote */ + else if (line[i] == '\'' || line[i] == '"') + in_quote = line[i]; + + /* in extended comment? */ + else if (xcomment != NULL) + { + if (line[i] == '*' && line[i + thislen] == '/') + { + xcomment = NULL; + ADVANCE_1; + } + } + + /* start of extended comment? */ + else if (line[i] == '/' && line[i + thislen] == '*') + { + xcomment = &line[i]; + ADVANCE_1; + } + + /* single-line comment? truncate line */ + else if ((line[i] == '-' && line[i + thislen] == '-') || + (line[i] == '/' && line[i + thislen] == '/')) + { + line[i] = '\0'; /* remove comment */ + break; + } + + /* count nested parentheses */ + else if (line[i] == '(') + paren_level++; + + else if (line[i] == ')' && paren_level > 0) + paren_level--; + + /* semicolon? then send query */ + else if (line[i] == ';' && !was_bslash && paren_level == 0) + { + line[i] = '\0'; + /* is there anything else on the line? */ + if (line[query_start + strspn(line + query_start, " \t")] != '\0') + { + + /* + * insert a cosmetic newline, if this is not the first + * line in the buffer + */ + if (query_buf->len > 0) + appendPQExpBufferChar(query_buf, '\n'); + /* append the line to the query buffer */ + appendPQExpBufferStr(query_buf, line + query_start); + } + + /* execute query */ + success = SendQuery(pset, query_buf->data); + + resetPQExpBuffer(query_buf); + query_start = i + thislen; + } + + /* backslash command */ + else if (was_bslash) + { + const char *end_of_cmd = NULL; + + line[i - prevlen] = '\0'; /* overwrites backslash */ + + /* is there anything else on the line? */ + if (line[query_start + strspn(line + query_start, " \t")] != '\0') + { + + /* + * insert a cosmetic newline, if this is not the first + * line in the buffer + */ + if (query_buf->len > 0) + appendPQExpBufferChar(query_buf, '\n'); + /* append the line to the query buffer */ + appendPQExpBufferStr(query_buf, line + query_start); + } + + /* handle backslash command */ + + slashCmdStatus = HandleSlashCmds(pset, &line[i], query_buf, &end_of_cmd); + + success = slashCmdStatus != CMD_ERROR; + + if (slashCmdStatus == CMD_SEND) + { + success = SendQuery(pset, query_buf->data); + resetPQExpBuffer(query_buf); + query_start = i + thislen; + } + + /* is there anything left after the backslash command? */ + if (end_of_cmd) + { + i += end_of_cmd - &line[i]; + query_start = i; + } + else + break; + } } - /* execute query */ - success = SendQuery(pset, query_buf->data); - - resetPQExpBuffer(query_buf); - query_start = i + thislen; - } - - /* backslash command */ - else if (was_bslash) { - const char * end_of_cmd = NULL; - - line[i - prevlen] = '\0'; /* overwrites backslash */ - /* is there anything else on the line? */ - if (line[query_start + strspn(line + query_start, " \t")]!='\0') { - /* insert a cosmetic newline, if this is not the first line in the buffer */ - if (query_buf->len > 0) - appendPQExpBufferChar(query_buf, '\n'); - /* append the line to the query buffer */ - appendPQExpBufferStr(query_buf, line + query_start); + if (!success && die_on_error && !pset->cur_cmd_interactive) + { + successResult = EXIT_USER; + break; } - /* handle backslash command */ - slashCmdStatus = HandleSlashCmds(pset, &line[i], query_buf, &end_of_cmd); - - success = slashCmdStatus != CMD_ERROR; - - if (slashCmdStatus == CMD_SEND) { - success = SendQuery(pset, query_buf->data); - resetPQExpBuffer(query_buf); - query_start = i + thislen; + if (slashCmdStatus == CMD_TERMINATE) + { + successResult = EXIT_SUCCESS; + break; } - /* is there anything left after the backslash command? */ - if (end_of_cmd) { - i += end_of_cmd - &line[i]; - query_start = i; - } - else - break; - } - } - - - if (!success && die_on_error && !pset->cur_cmd_interactive) { - successResult = EXIT_USER; - break; - } + /* Put the rest of the line in the query buffer. */ + if (line[query_start + strspn(line + query_start, " \t")] != '\0') + { + if (query_buf->len > 0) + appendPQExpBufferChar(query_buf, '\n'); + appendPQExpBufferStr(query_buf, line + query_start); + } - if (slashCmdStatus == CMD_TERMINATE) { - successResult = EXIT_SUCCESS; - break; - } - + free(line); - /* Put the rest of the line in the query buffer. */ - if (line[query_start + strspn(line + query_start, " \t")]!='\0') { - if (query_buf->len > 0) - appendPQExpBufferChar(query_buf, '\n'); - appendPQExpBufferStr(query_buf, line + query_start); - } - free(line); + /* In single line mode, send off the query if any */ + if (query_buf->data[0] != '\0' && GetVariableBool(pset->vars, "singleline")) + { + success = SendQuery(pset, query_buf->data); + resetPQExpBuffer(query_buf); + } - /* In single line mode, send off the query if any */ - if (query_buf->data[0] != '\0' && GetVariableBool(pset->vars, "singleline")) { - success = SendQuery(pset, query_buf->data); - resetPQExpBuffer(query_buf); - } - - - /* Have we lost the db connection? */ - if (pset->db == NULL && !pset->cur_cmd_interactive) { - successResult = EXIT_BADCONN; - break; - } - } /* while */ + /* Have we lost the db connection? */ + if (pset->db == NULL && !pset->cur_cmd_interactive) + { + successResult = EXIT_BADCONN; + break; + } + } /* while */ - destroyPQExpBuffer(query_buf); + destroyPQExpBuffer(query_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; + return successResult; } /* MainLoop() */ - diff --git a/src/bin/psql/mainloop.h b/src/bin/psql/mainloop.h index 0e2e5dd06e..b2b05d7d11 100644 --- a/src/bin/psql/mainloop.h +++ b/src/bin/psql/mainloop.h @@ -5,6 +5,6 @@ #include "settings.h" int -MainLoop(PsqlSettings *pset, FILE *source); + MainLoop(PsqlSettings *pset, FILE *source); -#endif MAINLOOP_H +#endif /* MAINLOOP_H */ diff --git a/src/bin/psql/print.c b/src/bin/psql/print.c index c710f02f28..5c6525b6f3 100644 --- a/src/bin/psql/print.c +++ b/src/bin/psql/print.c @@ -7,8 +7,8 @@ #include <math.h> #include <signal.h> #ifndef WIN32 -#include <unistd.h> /* for isatty() */ -#include <sys/ioctl.h> /* for ioctl() */ +#include <unistd.h> /* for isatty() */ +#include <sys/ioctl.h> /* for ioctl() */ #else #define popen(x,y) _popen(x,y) #define pclose(x) _pclose(x) @@ -16,386 +16,422 @@ #include <pqsignal.h> #include <libpq-fe.h> -#include <postgres_ext.h> /* for Oid type */ +#include <postgres_ext.h> /* for Oid type */ #define DEFAULT_PAGER "/bin/more" /*************************/ -/* Unaligned text */ +/* Unaligned text */ /*************************/ static void -print_unaligned_text(const char * title, char ** headers, char ** cells, char ** footers, - const char * opt_fieldsep, bool opt_barebones, - FILE * fout) +print_unaligned_text(const char *title, char **headers, char **cells, char **footers, + const char *opt_fieldsep, bool opt_barebones, + FILE *fout) { - unsigned int col_count = 0; - unsigned int i; - char ** ptr; - - if (!opt_fieldsep) - opt_fieldsep = ""; - - /* print title */ - if (!opt_barebones && title) - fprintf(fout, "%s\n", title); - - /* print headers and count columns */ - for (ptr = headers; *ptr; ptr++) { - col_count++; - if (!opt_barebones) { - if (col_count>1) - fputs(opt_fieldsep, fout); - fputs(*ptr, fout); - } - } - if (!opt_barebones) - fputs("\n", fout); - - /* print cells */ - i = 0; - for (ptr = cells; *ptr; ptr++) { - fputs(*ptr, fout); - if ((i+1) % col_count) - fputs(opt_fieldsep, fout); - else - fputs("\n", fout); - i++; - } + unsigned int col_count = 0; + unsigned int i; + char **ptr; + + if (!opt_fieldsep) + opt_fieldsep = ""; + + /* print title */ + if (!opt_barebones && title) + fprintf(fout, "%s\n", title); + + /* print headers and count columns */ + for (ptr = headers; *ptr; ptr++) + { + col_count++; + if (!opt_barebones) + { + if (col_count > 1) + fputs(opt_fieldsep, fout); + fputs(*ptr, fout); + } + } + if (!opt_barebones) + fputs("\n", fout); + + /* print cells */ + i = 0; + for (ptr = cells; *ptr; ptr++) + { + fputs(*ptr, fout); + if ((i + 1) % col_count) + fputs(opt_fieldsep, fout); + else + fputs("\n", fout); + i++; + } - /* print footers */ + /* print footers */ - if (!opt_barebones && footers) - for (ptr = footers; *ptr; ptr++) - fprintf(fout, "%s\n", *ptr); + if (!opt_barebones && footers) + for (ptr = footers; *ptr; ptr++) + fprintf(fout, "%s\n", *ptr); } static void -print_unaligned_vertical(const char * title, char ** headers, char ** cells, char ** footers, - const char * opt_fieldsep, bool opt_barebones, - FILE * fout) +print_unaligned_vertical(const char *title, char **headers, char **cells, char **footers, + const char *opt_fieldsep, bool opt_barebones, + FILE *fout) { - unsigned int col_count = 0; - unsigned int i; - unsigned int record = 1; - char ** ptr; - - if (!opt_fieldsep) - opt_fieldsep = ""; - - /* print title */ - if (!opt_barebones && title) - fprintf(fout, "%s\n", title); - - /* count columns */ - for (ptr = headers; *ptr; ptr++) { - col_count++; - } - - /* print records */ - for (i=0, ptr = cells; *ptr; i++, ptr++) { - if (i % col_count == 0) { - if (!opt_barebones) - fprintf(fout, "-- RECORD %d\n", record++); - else - fputc('\n', fout); + unsigned int col_count = 0; + unsigned int i; + unsigned int record = 1; + char **ptr; + + if (!opt_fieldsep) + opt_fieldsep = ""; + + /* print title */ + if (!opt_barebones && title) + fprintf(fout, "%s\n", title); + + /* count columns */ + for (ptr = headers; *ptr; ptr++) + col_count++; + + /* print records */ + for (i = 0, ptr = cells; *ptr; i++, ptr++) + { + if (i % col_count == 0) + { + if (!opt_barebones) + fprintf(fout, "-- RECORD %d\n", record++); + else + fputc('\n', fout); + } + fprintf(fout, "%s%s%s\n", headers[i % col_count], opt_fieldsep, *ptr); } - fprintf(fout, "%s%s%s\n", headers[i%col_count], opt_fieldsep, *ptr); - } - /* print footers */ + /* print footers */ - if (!opt_barebones && footers) { - fputs("--- END ---\n", fout); - for (ptr = footers; *ptr; ptr++) - fprintf(fout, "%s\n", *ptr); - } + if (!opt_barebones && footers) + { + fputs("--- END ---\n", fout); + for (ptr = footers; *ptr; ptr++) + fprintf(fout, "%s\n", *ptr); + } } /********************/ -/* Aligned text */ +/* Aligned text */ /********************/ /* draw "line" */ static void -_print_horizontal_line(const unsigned int col_count, const unsigned int * widths, unsigned short border, FILE * fout) +_print_horizontal_line(const unsigned int col_count, const unsigned int *widths, unsigned short border, FILE *fout) { - unsigned int i, j; - if (border == 1) - fputc('-', fout); - else if (border == 2) - fputs("+-", fout); - - for (i=0; i<col_count; i++) { - for (j=0; j<widths[i]; j++) - fputc('-', fout); - - if (i<col_count-1) { - if (border == 0) - fputc(' ', fout); - else - fputs("-+-", fout); - } - } - - if (border == 2) - fputs("-+", fout); - else if (border == 1) - fputc('-', fout); - - fputc('\n', fout); + unsigned int i, + j; + + if (border == 1) + fputc('-', fout); + else if (border == 2) + fputs("+-", fout); + + for (i = 0; i < col_count; i++) + { + for (j = 0; j < widths[i]; j++) + fputc('-', fout); + + if (i < col_count - 1) + { + if (border == 0) + fputc(' ', fout); + else + fputs("-+-", fout); + } + } + + if (border == 2) + fputs("-+", fout); + else if (border == 1) + fputc('-', fout); + + fputc('\n', fout); } static void -print_aligned_text(const char * title, char ** headers, char ** cells, char ** footers, - const char * opt_align, bool opt_barebones, unsigned short int opt_border, - FILE * fout) +print_aligned_text(const char *title, char **headers, char **cells, char **footers, +const char *opt_align, bool opt_barebones, unsigned short int opt_border, + FILE *fout) { - unsigned int col_count = 0; - unsigned int i, tmp; - unsigned int * widths, total_w; - char ** ptr; - - /* count columns */ - for (ptr = headers; *ptr; ptr++) - col_count++; - - widths = calloc(col_count, sizeof (*widths)); - if (!widths) { - perror("calloc"); - exit(EXIT_FAILURE); - } - - /* calc column widths */ - for (i=0; i<col_count; i++) - if ((tmp = strlen(headers[i])) > widths[i]) - widths[i] = tmp; /* don't wanna call strlen twice */ - - for (i=0, ptr = cells; *ptr; ptr++, i++) - if ((tmp = strlen(*ptr)) > widths[i % col_count]) - widths[i % col_count] = tmp; - - if (opt_border==0) - total_w = col_count - 1; - else if (opt_border==1) - total_w = col_count*3 - 2; - else - total_w = col_count*3 + 1; - - for (i=0; i<col_count; i++) - total_w += widths[i]; - - /* print title */ - if (title && !opt_barebones) { - if (strlen(title)>=total_w) - fprintf(fout, "%s\n", title); + unsigned int col_count = 0; + unsigned int i, + tmp; + unsigned int *widths, + total_w; + char **ptr; + + /* count columns */ + for (ptr = headers; *ptr; ptr++) + col_count++; + + widths = calloc(col_count, sizeof(*widths)); + if (!widths) + { + perror("calloc"); + exit(EXIT_FAILURE); + } + + /* calc column widths */ + for (i = 0; i < col_count; i++) + if ((tmp = strlen(headers[i])) > widths[i]) + widths[i] = tmp; /* don't wanna call strlen twice */ + + for (i = 0, ptr = cells; *ptr; ptr++, i++) + if ((tmp = strlen(*ptr)) > widths[i % col_count]) + widths[i % col_count] = tmp; + + if (opt_border == 0) + total_w = col_count - 1; + else if (opt_border == 1) + total_w = col_count * 3 - 2; else - fprintf(fout, "%-*s%s\n", (total_w-strlen(title))/2, "", title); - } - - /* print headers */ - if (!opt_barebones) { - if (opt_border==2) - _print_horizontal_line(col_count, widths, opt_border, fout); - - if (opt_border==2) - fputs("| ", fout); - else if (opt_border==1) - fputc(' ', fout); - - for (i=0; i<col_count; i++) { - /* centered */ - fprintf(fout, "%-*s%s%-*s", (int)floor((widths[i]-strlen(headers[i]))/2.0), "", headers[i], (int)ceil((widths[i]-strlen(headers[i]))/2.0) , ""); - - if (i<col_count-1) { - if (opt_border==0) - fputc(' ', fout); + total_w = col_count * 3 + 1; + + for (i = 0; i < col_count; i++) + total_w += widths[i]; + + /* print title */ + if (title && !opt_barebones) + { + if (strlen(title) >= total_w) + fprintf(fout, "%s\n", title); else - fputs(" | ", fout); - } + fprintf(fout, "%-*s%s\n", (total_w - strlen(title)) / 2, "", title); } - if (opt_border==2) - fputs(" |", fout); - else if (opt_border==1) - fputc(' ', fout);; - fputc('\n', fout); + /* print headers */ + if (!opt_barebones) + { + if (opt_border == 2) + _print_horizontal_line(col_count, widths, opt_border, fout); - _print_horizontal_line(col_count, widths, opt_border, fout); - } + if (opt_border == 2) + fputs("| ", fout); + else if (opt_border == 1) + fputc(' ', fout); + + for (i = 0; i < col_count; i++) + { + /* centered */ + fprintf(fout, "%-*s%s%-*s", (int) floor((widths[i] - strlen(headers[i])) / 2.0), "", headers[i], (int) ceil((widths[i] - strlen(headers[i])) / 2.0), ""); + + if (i < col_count - 1) + { + if (opt_border == 0) + fputc(' ', fout); + else + fputs(" | ", fout); + } + } - /* print cells */ - for (i=0, ptr = cells; *ptr; i++, ptr++) { - /* beginning of line */ - if (i % col_count == 0) { - if (opt_border==2) - fputs("| ", fout); - else if (opt_border==1) - fputc(' ', fout); - } + if (opt_border == 2) + fputs(" |", fout); + else if (opt_border == 1) + fputc(' ', fout);; + fputc('\n', fout); - /* content */ - if (opt_align[(i) % col_count ] == 'r') - fprintf(fout, "%*s", widths[i%col_count], cells[i]); - else { - if ((i+1) % col_count == 0 && opt_border != 2) - fputs(cells[i], fout); - else - fprintf(fout, "%-*s", widths[i%col_count], cells[i]); + _print_horizontal_line(col_count, widths, opt_border, fout); } - /* divider */ - if ((i+1) % col_count) { - if (opt_border==0) - fputc(' ', fout); - else - fputs(" | ", fout); - } - /* end of line */ - else { - if (opt_border==2) - fputs(" |", fout); - fputc('\n', fout); + /* print cells */ + for (i = 0, ptr = cells; *ptr; i++, ptr++) + { + /* beginning of line */ + if (i % col_count == 0) + { + if (opt_border == 2) + fputs("| ", fout); + else if (opt_border == 1) + fputc(' ', fout); + } + + /* content */ + if (opt_align[(i) % col_count] == 'r') + fprintf(fout, "%*s", widths[i % col_count], cells[i]); + else + { + if ((i + 1) % col_count == 0 && opt_border != 2) + fputs(cells[i], fout); + else + fprintf(fout, "%-*s", widths[i % col_count], cells[i]); + } + + /* divider */ + if ((i + 1) % col_count) + { + if (opt_border == 0) + fputc(' ', fout); + else + fputs(" | ", fout); + } + /* end of line */ + else + { + if (opt_border == 2) + fputs(" |", fout); + fputc('\n', fout); + } } - } - if (opt_border==2) - _print_horizontal_line(col_count, widths, opt_border, fout); + if (opt_border == 2) + _print_horizontal_line(col_count, widths, opt_border, fout); - /* print footers */ - if (footers && !opt_barebones) - for (ptr = footers; *ptr; ptr++) - fprintf(fout, "%s\n", *ptr); + /* print footers */ + if (footers && !opt_barebones) + for (ptr = footers; *ptr; ptr++) + fprintf(fout, "%s\n", *ptr); - fputc('\n', fout); + fputc('\n', fout); - /* clean up */ - free(widths); + /* clean up */ + free(widths); } static void -print_aligned_vertical(const char * title, char ** headers, char ** cells, char ** footers, - bool opt_barebones, unsigned short int opt_border, - FILE * fout) +print_aligned_vertical(const char *title, char **headers, char **cells, char **footers, + bool opt_barebones, unsigned short int opt_border, + FILE *fout) { - unsigned int col_count = 0; - unsigned int record = 1; - char ** ptr; - unsigned int i, tmp, hwidth=0, dwidth=0; - char * divider; - - /* count columns and find longest header */ - for (ptr = headers; *ptr; ptr++) { - col_count++; - if ((tmp = strlen(*ptr)) > hwidth) - hwidth = tmp; /* don't wanna call strlen twice */ - } - - /* find longest data cell */ - for (ptr = cells; *ptr; ptr++) - if ((tmp = strlen(*ptr)) > dwidth) - dwidth = tmp; - - /* print title */ - if (!opt_barebones && title) - fprintf(fout, "%s\n", title); - - /* make horizontal border */ - divider = malloc(hwidth + dwidth + 10); - if (!divider) { - perror("malloc"); - exit(EXIT_FAILURE); - } - divider[0] = '\0'; - if (opt_border == 2) - strcat(divider, "+-"); - for (i=0; i<hwidth; i++) strcat(divider, opt_border > 0 ? "-" : " "); - if (opt_border > 0) - strcat(divider, "-+-"); - else - strcat(divider, " "); - for (i=0; i<dwidth; i++) strcat(divider, opt_border > 0 ? "-" : " "); - if (opt_border == 2) - strcat(divider, "-+"); - - - /* print records */ - for (i=0, ptr = cells; *ptr; i++, ptr++) { - if (i % col_count == 0) { - if (!opt_barebones) { - char * div_copy = strdup(divider); - char * record_str = malloc(32); - size_t record_str_len; - - if (!div_copy || !record_str) { - perror("malloc"); - exit(EXIT_FAILURE); - } + unsigned int col_count = 0; + unsigned int record = 1; + char **ptr; + unsigned int i, + tmp, + hwidth = 0, + dwidth = 0; + char *divider; + + /* count columns and find longest header */ + for (ptr = headers; *ptr; ptr++) + { + col_count++; + if ((tmp = strlen(*ptr)) > hwidth) + hwidth = tmp; /* don't wanna call strlen twice */ + } - if (opt_border==0) - sprintf(record_str, "* Record %d", record++); - else - sprintf(record_str, "[ RECORD %d ]", record++); - record_str_len = strlen(record_str); - if (record_str_len + opt_border > strlen(div_copy)) { - void * new; - new = realloc(div_copy, record_str_len + opt_border); - if (!new) { - perror("realloc"); - exit(EXIT_FAILURE); - } - div_copy = new; - } - strncpy(div_copy + opt_border, record_str, record_str_len); - fprintf(fout, "%s\n", div_copy); - free(record_str); - free(div_copy); - } - else if (i != 0 && opt_border < 2) - fprintf(fout, "%s\n", divider); + /* find longest data cell */ + for (ptr = cells; *ptr; ptr++) + if ((tmp = strlen(*ptr)) > dwidth) + dwidth = tmp; + + /* print title */ + if (!opt_barebones && title) + fprintf(fout, "%s\n", title); + + /* make horizontal border */ + divider = malloc(hwidth + dwidth + 10); + if (!divider) + { + perror("malloc"); + exit(EXIT_FAILURE); } + divider[0] = '\0'; if (opt_border == 2) - fputs("| ", fout); - fprintf(fout, "%-*s", hwidth, headers[i%col_count]); + strcat(divider, "+-"); + for (i = 0; i < hwidth; i++) + strcat(divider, opt_border > 0 ? "-" : " "); if (opt_border > 0) - fputs(" | ", fout); + strcat(divider, "-+-"); else - fputs(" ", fout); + strcat(divider, " "); + for (i = 0; i < dwidth; i++) + strcat(divider, opt_border > 0 ? "-" : " "); + if (opt_border == 2) + strcat(divider, "-+"); + + + /* print records */ + for (i = 0, ptr = cells; *ptr; i++, ptr++) + { + if (i % col_count == 0) + { + if (!opt_barebones) + { + char *div_copy = strdup(divider); + char *record_str = malloc(32); + size_t record_str_len; + + if (!div_copy || !record_str) + { + perror("malloc"); + exit(EXIT_FAILURE); + } + + if (opt_border == 0) + sprintf(record_str, "* Record %d", record++); + else + sprintf(record_str, "[ RECORD %d ]", record++); + record_str_len = strlen(record_str); + if (record_str_len + opt_border > strlen(div_copy)) + { + void *new; + + new = realloc(div_copy, record_str_len + opt_border); + if (!new) + { + perror("realloc"); + exit(EXIT_FAILURE); + } + div_copy = new; + } + strncpy(div_copy + opt_border, record_str, record_str_len); + fprintf(fout, "%s\n", div_copy); + free(record_str); + free(div_copy); + } + else if (i != 0 && opt_border < 2) + fprintf(fout, "%s\n", divider); + } + if (opt_border == 2) + fputs("| ", fout); + fprintf(fout, "%-*s", hwidth, headers[i % col_count]); + if (opt_border > 0) + fputs(" | ", fout); + else + fputs(" ", fout); - if (opt_border < 2) - fprintf(fout, "%s\n", *ptr); - else - fprintf(fout, "%-*s |\n", dwidth, *ptr); - } + if (opt_border < 2) + fprintf(fout, "%s\n", *ptr); + else + fprintf(fout, "%-*s |\n", dwidth, *ptr); + } - if (opt_border == 2) - fprintf(fout, "%s\n", divider); + if (opt_border == 2) + fprintf(fout, "%s\n", divider); - /* print footers */ + /* print footers */ - if (!opt_barebones && footers && *footers) { - if (opt_border < 2) - fputc('\n', fout); - for (ptr = footers; *ptr; ptr++) - fprintf(fout, "%s\n", *ptr); - } + if (!opt_barebones && footers && *footers) + { + if (opt_border < 2) + fputc('\n', fout); + for (ptr = footers; *ptr; ptr++) + fprintf(fout, "%s\n", *ptr); + } - fputc('\n', fout); - free(divider); + fputc('\n', fout); + free(divider); } @@ -408,351 +444,382 @@ print_aligned_vertical(const char * title, char ** headers, char ** cells, char static void -html_escaped_print(const char * in, FILE * fout) +html_escaped_print(const char *in, FILE *fout) { - const char * p; - for (p=in; *p; p++) - switch (*p) { - case '&': - fputs("&", fout); - break; - case '<': - fputs("<", fout); - break; - case '>': - fputs(">", fout); - break; - case '\n': - fputs("<br>", fout); - break; - default: - fputc(*p, fout); - } + const char *p; + + for (p = in; *p; p++) + switch (*p) + { + case '&': + fputs("&", fout); + break; + case '<': + fputs("<", fout); + break; + case '>': + fputs(">", fout); + break; + case '\n': + fputs("<br>", fout); + break; + default: + fputc(*p, fout); + } } static void -print_html_text(const char * title, char ** headers, char ** cells, char ** footers, - const char * opt_align, bool opt_barebones, unsigned short int opt_border, - char * opt_table_attr, - FILE * fout) +print_html_text(const char *title, char **headers, char **cells, char **footers, +const char *opt_align, bool opt_barebones, unsigned short int opt_border, + char *opt_table_attr, + FILE *fout) { - unsigned int col_count = 0; - unsigned int i; - char ** ptr; - - fprintf(fout, "<table border=%d", opt_border); - if (opt_table_attr) - fprintf(fout, " %s", opt_table_attr); - fputs(">\n", fout); - - /* print title */ - if (!opt_barebones && title) { - fputs(" <caption>", fout); - html_escaped_print(title, fout); - fputs("</caption>\n", fout); - } - - /* print headers and count columns */ - if (!opt_barebones) - fputs(" <tr>\n", fout); - for (i=0, ptr = headers; *ptr; i++, ptr++) { - col_count++; - if (!opt_barebones) { - fputs(" <th align=center>", fout); - html_escaped_print(*ptr, fout); - fputs("</th>\n", fout); - } - } - if (!opt_barebones) - fputs(" </tr>\n", fout); - - /* print cells */ - for (i=0, ptr = cells; *ptr; i++, ptr++) { - if ( i % col_count == 0 ) - fputs(" <tr valign=top>\n", fout); - - fprintf(fout, " <td align=%s>", opt_align[(i)%col_count] == 'r' ? "right" : "left"); - if ( (*ptr)[strspn(*ptr, " \t")] == '\0' ) /* is string only whitespace? */ - fputs(" ", fout); - else - html_escaped_print(*ptr, fout); - fputs("</td>\n", fout); + unsigned int col_count = 0; + unsigned int i; + char **ptr; + + fprintf(fout, "<table border=%d", opt_border); + if (opt_table_attr) + fprintf(fout, " %s", opt_table_attr); + fputs(">\n", fout); + + /* print title */ + if (!opt_barebones && title) + { + fputs(" <caption>", fout); + html_escaped_print(title, fout); + fputs("</caption>\n", fout); + } - if ( (i+1) % col_count == 0 ) - fputs(" </tr>\n", fout); - } + /* print headers and count columns */ + if (!opt_barebones) + fputs(" <tr>\n", fout); + for (i = 0, ptr = headers; *ptr; i++, ptr++) + { + col_count++; + if (!opt_barebones) + { + fputs(" <th align=center>", fout); + html_escaped_print(*ptr, fout); + fputs("</th>\n", fout); + } + } + if (!opt_barebones) + fputs(" </tr>\n", fout); + + /* print cells */ + for (i = 0, ptr = cells; *ptr; i++, ptr++) + { + if (i % col_count == 0) + fputs(" <tr valign=top>\n", fout); + + fprintf(fout, " <td align=%s>", opt_align[(i) % col_count] == 'r' ? "right" : "left"); + if ((*ptr)[strspn(*ptr, " \t")] == '\0') /* is string only + * whitespace? */ + fputs(" ", fout); + else + html_escaped_print(*ptr, fout); + fputs("</td>\n", fout); - fputs("</table>\n", fout); + if ((i + 1) % col_count == 0) + fputs(" </tr>\n", fout); + } - /* print footers */ + fputs("</table>\n", fout); - if (footers && !opt_barebones) - for (ptr = footers; *ptr; ptr++) { - html_escaped_print(*ptr, fout); - fputs("<br>\n", fout); - } + /* print footers */ + + if (footers && !opt_barebones) + for (ptr = footers; *ptr; ptr++) + { + html_escaped_print(*ptr, fout); + fputs("<br>\n", fout); + } - fputc('\n', fout); + fputc('\n', fout); } static void -print_html_vertical(const char * title, char ** headers, char ** cells, char ** footers, - const char * opt_align, bool opt_barebones, unsigned short int opt_border, - char * opt_table_attr, - FILE * fout) +print_html_vertical(const char *title, char **headers, char **cells, char **footers, +const char *opt_align, bool opt_barebones, unsigned short int opt_border, + char *opt_table_attr, + FILE *fout) { - unsigned int col_count = 0; - unsigned int i; - unsigned int record = 1; - char ** ptr; - - fprintf(fout, "<table border=%d", opt_border); - if (opt_table_attr) - fprintf(fout, " %s", opt_table_attr); - fputs(">\n", fout); - - /* print title */ - if (!opt_barebones && title) { - fputs(" <caption>", fout); - html_escaped_print(title, fout); - fputs("</caption>\n", fout); - } - - /* count columns */ - for (ptr = headers; *ptr; ptr++) - col_count++; - - /* print records */ - for (i=0, ptr = cells; *ptr; i++, ptr++) { - if (i % col_count == 0) { - if (!opt_barebones) - fprintf(fout, "\n <tr><td colspan=2 align=center>Record %d</td></tr>\n", record++); - else - fputs("\n <tr><td colspan=2> </td></tr>\n", fout); - } - fputs(" <tr valign=top>\n" - " <th>", fout); - html_escaped_print(headers[i%col_count], fout); - fputs("</th>\n", fout); - - fprintf(fout, " <td align=%s>", opt_align[i%col_count] == 'r' ? "right" : "left"); - if ( (*ptr)[strspn(*ptr, " \t")] == '\0' ) /* is string only whitespace? */ - fputs(" ", fout); - else - html_escaped_print(*ptr, fout); - fputs("</td>\n </tr>\n", fout); - } + unsigned int col_count = 0; + unsigned int i; + unsigned int record = 1; + char **ptr; + + fprintf(fout, "<table border=%d", opt_border); + if (opt_table_attr) + fprintf(fout, " %s", opt_table_attr); + fputs(">\n", fout); + + /* print title */ + if (!opt_barebones && title) + { + fputs(" <caption>", fout); + html_escaped_print(title, fout); + fputs("</caption>\n", fout); + } - fputs("</table>\n", fout); + /* count columns */ + for (ptr = headers; *ptr; ptr++) + col_count++; - /* print footers */ - if (footers && !opt_barebones) - for (ptr = footers; *ptr; ptr++) { - html_escaped_print(*ptr, fout); - fputs("<br>\n", fout); + /* print records */ + for (i = 0, ptr = cells; *ptr; i++, ptr++) + { + if (i % col_count == 0) + { + if (!opt_barebones) + fprintf(fout, "\n <tr><td colspan=2 align=center>Record %d</td></tr>\n", record++); + else + fputs("\n <tr><td colspan=2> </td></tr>\n", fout); + } + fputs(" <tr valign=top>\n" + " <th>", fout); + html_escaped_print(headers[i % col_count], fout); + fputs("</th>\n", fout); + + fprintf(fout, " <td align=%s>", opt_align[i % col_count] == 'r' ? "right" : "left"); + if ((*ptr)[strspn(*ptr, " \t")] == '\0') /* is string only + * whitespace? */ + fputs(" ", fout); + else + html_escaped_print(*ptr, fout); + fputs("</td>\n </tr>\n", fout); } - fputc('\n', fout); + fputs("</table>\n", fout); + + /* print footers */ + if (footers && !opt_barebones) + for (ptr = footers; *ptr; ptr++) + { + html_escaped_print(*ptr, fout); + fputs("<br>\n", fout); + } + + fputc('\n', fout); } /*************************/ -/* LaTeX */ +/* LaTeX */ /*************************/ static void -latex_escaped_print(const char * in, FILE * fout) +latex_escaped_print(const char *in, FILE *fout) { - const char * p; - for (p=in; *p; p++) - switch (*p) { - case '&': - fputs("\\&", fout); - break; - case '%': - fputs("\\%", fout); - break; - case '$': - fputs("\\$", fout); - break; - case '{': - fputs("\\{", fout); - break; - case '}': - fputs("\\}", fout); - break; - case '\\': - fputs("\\backslash", fout); - break; - case '\n': - fputs("\\\\", fout); - break; - default: - fputc(*p, fout); - } + const char *p; + + for (p = in; *p; p++) + switch (*p) + { + case '&': + fputs("\\&", fout); + break; + case '%': + fputs("\\%", fout); + break; + case '$': + fputs("\\$", fout); + break; + case '{': + fputs("\\{", fout); + break; + case '}': + fputs("\\}", fout); + break; + case '\\': + fputs("\\backslash", fout); + break; + case '\n': + fputs("\\\\", fout); + break; + default: + fputc(*p, fout); + } } static void -print_latex_text(const char * title, char ** headers, char ** cells, char ** footers, - const char * opt_align, bool opt_barebones, unsigned short int opt_border, - FILE * fout) +print_latex_text(const char *title, char **headers, char **cells, char **footers, +const char *opt_align, bool opt_barebones, unsigned short int opt_border, + FILE *fout) { - unsigned int col_count = 0; - unsigned int i; - const char * cp; - char ** ptr; - - - /* print title */ - if (!opt_barebones && title) { - fputs("\begin{center}\n", fout); - latex_escaped_print(title, fout); - fputs("\n\end{center}\n\n", fout); - } - - /* begin environment and set alignments and borders */ - fputs("\\begin{tabular}{", fout); - if (opt_border==0) - fputs(opt_align, fout); - else if (opt_border==1) { - for (cp = opt_align; *cp; cp++) { - if (cp != opt_align) fputc('|', fout); - fputc(*cp, fout); - } - } - else if (opt_border==2) { - for (cp = opt_align; *cp; cp++) { - fputc('|', fout); - fputc(*cp, fout); - } - fputc('|', fout); - } - fputs("}\n", fout); - - if (!opt_barebones && opt_border==2) - fputs("\\hline\n", fout); - - /* print headers and count columns */ - for (i=0, ptr = headers; *ptr; i++, ptr++) { - col_count++; - if (!opt_barebones) { - if (i!=0) - fputs(" & ", fout); - latex_escaped_print(*ptr, fout); + unsigned int col_count = 0; + unsigned int i; + const char *cp; + char **ptr; + + + /* print title */ + if (!opt_barebones && title) + { + fputs("\begin{center}\n", fout); + latex_escaped_print(title, fout); + fputs("\n\end{center}\n\n", fout); } - } - if (!opt_barebones) { - fputs(" \\\\\n", fout); - fputs("\\hline\n", fout); - } + /* begin environment and set alignments and borders */ + fputs("\\begin{tabular}{", fout); + if (opt_border == 0) + fputs(opt_align, fout); + else if (opt_border == 1) + { + for (cp = opt_align; *cp; cp++) + { + if (cp != opt_align) + fputc('|', fout); + fputc(*cp, fout); + } + } + else if (opt_border == 2) + { + for (cp = opt_align; *cp; cp++) + { + fputc('|', fout); + fputc(*cp, fout); + } + fputc('|', fout); + } + fputs("}\n", fout); - /* print cells */ - for (i=0, ptr = cells; *ptr; i++, ptr++) { - latex_escaped_print(*ptr, fout); + if (!opt_barebones && opt_border == 2) + fputs("\\hline\n", fout); - if ( (i+1) % col_count == 0 ) - fputs(" \\\\\n", fout); - else - fputs(" & ", fout); - } + /* print headers and count columns */ + for (i = 0, ptr = headers; *ptr; i++, ptr++) + { + col_count++; + if (!opt_barebones) + { + if (i != 0) + fputs(" & ", fout); + latex_escaped_print(*ptr, fout); + } + } + + if (!opt_barebones) + { + fputs(" \\\\\n", fout); + fputs("\\hline\n", fout); + } + + /* print cells */ + for (i = 0, ptr = cells; *ptr; i++, ptr++) + { + latex_escaped_print(*ptr, fout); - if (opt_border==2) - fputs("\\hline\n", fout); + if ((i + 1) % col_count == 0) + fputs(" \\\\\n", fout); + else + fputs(" & ", fout); + } - fputs("\\end{tabular}\n\n", fout); + if (opt_border == 2) + fputs("\\hline\n", fout); + fputs("\\end{tabular}\n\n", fout); - /* print footers */ - if (footers && !opt_barebones) - for (ptr = footers; *ptr; ptr++) { - latex_escaped_print(*ptr, fout); - fputs(" \\\\\n", fout); - } + /* print footers */ - fputc('\n', fout); + if (footers && !opt_barebones) + for (ptr = footers; *ptr; ptr++) + { + latex_escaped_print(*ptr, fout); + fputs(" \\\\\n", fout); + } + + fputc('\n', fout); } static void -print_latex_vertical(const char * title, char ** headers, char ** cells, char ** footers, - const char * opt_align, bool opt_barebones, unsigned short int opt_border, - FILE * fout) +print_latex_vertical(const char *title, char **headers, char **cells, char **footers, +const char *opt_align, bool opt_barebones, unsigned short int opt_border, + FILE *fout) { - unsigned int col_count = 0; - unsigned int i; - char ** ptr; - unsigned int record = 1; - - (void)opt_align; /* currently unused parameter */ - - /* print title */ - if (!opt_barebones && title) { - fputs("\begin{center}\n", fout); - latex_escaped_print(title, fout); - fputs("\n\end{center}\n\n", fout); - } - - /* begin environment and set alignments and borders */ - fputs("\\begin{tabular}{", fout); - if (opt_border==0) - fputs("cl", fout); - else if (opt_border==1) - fputs("c|l", fout); - else if (opt_border==2) - fputs("|c|l|", fout); - fputs("}\n", fout); - - - /* count columns */ - for (ptr = headers; *ptr; ptr++) - col_count++; - - - /* print records */ - for (i=0, ptr = cells; *ptr; i++, ptr++) { - /* new record */ - if (i % col_count == 0) { - if (!opt_barebones) { - if (opt_border == 2) - fputs("\\hline\n", fout); - fprintf(fout, "\\multicolumn{2}{c}{Record %d} \\\\\n", record++); - } - if (opt_border >= 1) - fputs("\\hline\n", fout); + unsigned int col_count = 0; + unsigned int i; + char **ptr; + unsigned int record = 1; + + (void) opt_align; /* currently unused parameter */ + + /* print title */ + if (!opt_barebones && title) + { + fputs("\begin{center}\n", fout); + latex_escaped_print(title, fout); + fputs("\n\end{center}\n\n", fout); } - latex_escaped_print(headers[i%col_count], fout); - fputs(" & ", fout); - latex_escaped_print(*ptr, fout); - fputs(" \\\\\n", fout); - } + /* begin environment and set alignments and borders */ + fputs("\\begin{tabular}{", fout); + if (opt_border == 0) + fputs("cl", fout); + else if (opt_border == 1) + fputs("c|l", fout); + else if (opt_border == 2) + fputs("|c|l|", fout); + fputs("}\n", fout); - if (opt_border==2) - fputs("\\hline\n", fout); - fputs("\\end{tabular}\n\n", fout); + /* count columns */ + for (ptr = headers; *ptr; ptr++) + col_count++; - /* print footers */ + /* print records */ + for (i = 0, ptr = cells; *ptr; i++, ptr++) + { + /* new record */ + if (i % col_count == 0) + { + if (!opt_barebones) + { + if (opt_border == 2) + fputs("\\hline\n", fout); + fprintf(fout, "\\multicolumn{2}{c}{Record %d} \\\\\n", record++); + } + if (opt_border >= 1) + fputs("\\hline\n", fout); + } - if (footers && !opt_barebones) - for (ptr = footers; *ptr; ptr++) { - latex_escaped_print(*ptr, fout); - fputs(" \\\\\n", fout); + latex_escaped_print(headers[i % col_count], fout); + fputs(" & ", fout); + latex_escaped_print(*ptr, fout); + fputs(" \\\\\n", fout); } - fputc('\n', fout); + if (opt_border == 2) + fputs("\\hline\n", fout); + + fputs("\\end{tabular}\n\n", fout); + + + /* print footers */ + + if (footers && !opt_barebones) + for (ptr = footers; *ptr; ptr++) + { + latex_escaped_print(*ptr, fout); + fputs(" \\\\\n", fout); + } + + fputc('\n', fout); } @@ -761,214 +828,231 @@ print_latex_vertical(const char * title, char ** headers, char ** cells, char ** /********************************/ -/* Public functions */ +/* Public functions */ /********************************/ void -printTable(const char * title, char ** headers, char ** cells, char ** footers, - const char * align, - const printTableOpt * opt, FILE * fout) +printTable(const char *title, char **headers, char **cells, char **footers, + const char *align, + const printTableOpt * opt, FILE *fout) { - char * default_footer[] = { NULL }; - unsigned short int border = opt->border; - FILE * pager = NULL, - * output; + char *default_footer[] = {NULL}; + unsigned short int border = opt->border; + FILE *pager = NULL, + *output; - if (opt->format == PRINT_NOTHING) - return; + if (opt->format == PRINT_NOTHING) + return; - if (!footers) - footers = default_footer; + if (!footers) + footers = default_footer; - if (opt->format != PRINT_HTML && border > 2) - border = 2; + if (opt->format != PRINT_HTML && border > 2) + border = 2; - /* check whether we need / can / are supposed to use pager */ - if (fout == stdout && opt->pager + /* check whether we need / can / are supposed to use pager */ + if (fout == stdout && opt->pager #ifndef WIN32 - && - isatty(fileno(stdin)) && - isatty(fileno(stdout)) + && + isatty(fileno(stdin)) && + isatty(fileno(stdout)) #endif - ) - { - const char * pagerprog; -#ifdef TIOCGWINSZ - unsigned int col_count=0, row_count=0, lines; - char ** ptr; - int result; - struct winsize screen_size; - - /* rough estimate of columns and rows */ - if (headers) - for (ptr=headers; *ptr; ptr++) - col_count++; - if (cells) - for (ptr=cells; *ptr; ptr++) - row_count++; - row_count /= col_count; + ) + { + const char *pagerprog; - if (opt->expanded) - lines = (col_count+1) * row_count; - else - lines = row_count+1; - if (!opt->tuples_only) - lines += 5; +#ifdef TIOCGWINSZ + unsigned int col_count = 0, + row_count = 0, + lines; + char **ptr; + int result; + struct winsize screen_size; + + /* rough estimate of columns and rows */ + if (headers) + for (ptr = headers; *ptr; ptr++) + col_count++; + if (cells) + for (ptr = cells; *ptr; ptr++) + row_count++; + row_count /= col_count; + + if (opt->expanded) + lines = (col_count + 1) * row_count; + else + lines = row_count + 1; + if (!opt->tuples_only) + lines += 5; - result = ioctl(fileno(stdout), TIOCGWINSZ, &screen_size); - if (result==-1 || lines > screen_size.ws_row) { + result = ioctl(fileno(stdout), TIOCGWINSZ, &screen_size); + if (result == -1 || lines > screen_size.ws_row) + { #endif - pagerprog = getenv("PAGER"); - if (!pagerprog) pagerprog = DEFAULT_PAGER; - pager = popen(pagerprog, "w"); + pagerprog = getenv("PAGER"); + if (!pagerprog) + pagerprog = DEFAULT_PAGER; + pager = popen(pagerprog, "w"); #ifdef TIOCGWINSZ - } + } #endif - } - - if (pager) { - output = pager; - pqsignal(SIGPIPE, SIG_IGN); - } - else - output = fout; - - - /* print the stuff */ + } - switch (opt->format) { - case PRINT_UNALIGNED: - if (opt->expanded) - print_unaligned_vertical(title, headers, cells, footers, opt->fieldSep, opt->tuples_only, output); - else - print_unaligned_text(title, headers, cells, footers, opt->fieldSep, opt->tuples_only, output); - break; - case PRINT_ALIGNED: - if (opt->expanded) - print_aligned_vertical(title, headers, cells, footers, opt->tuples_only, border, output); - else - print_aligned_text(title, headers, cells, footers, align, opt->tuples_only, border, output); - break; - case PRINT_HTML: - if (opt->expanded) - print_html_vertical(title, headers, cells, footers, align, opt->tuples_only, border, opt->tableAttr, output); - else - print_html_text(title, headers, cells, footers, align, opt->tuples_only, border, opt->tableAttr, output); - break; - case PRINT_LATEX: - if (opt->expanded) - print_latex_vertical(title, headers, cells, footers, align, opt->tuples_only, border, output); + if (pager) + { + output = pager; + pqsignal(SIGPIPE, SIG_IGN); + } else - print_latex_text(title, headers, cells, footers, align, opt->tuples_only, border, output); - break; - default: - fprintf(stderr, "+ Oops, you shouldn't see this!\n"); - } - - if (pager) { - pclose(pager); - pqsignal(SIGPIPE, SIG_DFL); - } + output = fout; + + + /* print the stuff */ + + switch (opt->format) + { + case PRINT_UNALIGNED: + if (opt->expanded) + print_unaligned_vertical(title, headers, cells, footers, opt->fieldSep, opt->tuples_only, output); + else + print_unaligned_text(title, headers, cells, footers, opt->fieldSep, opt->tuples_only, output); + break; + case PRINT_ALIGNED: + if (opt->expanded) + print_aligned_vertical(title, headers, cells, footers, opt->tuples_only, border, output); + else + print_aligned_text(title, headers, cells, footers, align, opt->tuples_only, border, output); + break; + case PRINT_HTML: + if (opt->expanded) + print_html_vertical(title, headers, cells, footers, align, opt->tuples_only, border, opt->tableAttr, output); + else + print_html_text(title, headers, cells, footers, align, opt->tuples_only, border, opt->tableAttr, output); + break; + case PRINT_LATEX: + if (opt->expanded) + print_latex_vertical(title, headers, cells, footers, align, opt->tuples_only, border, output); + else + print_latex_text(title, headers, cells, footers, align, opt->tuples_only, border, output); + break; + default: + fprintf(stderr, "+ Oops, you shouldn't see this!\n"); + } + + if (pager) + { + pclose(pager); + pqsignal(SIGPIPE, SIG_DFL); + } } void -printQuery(PGresult * result, const printQueryOpt * opt, FILE * fout) +printQuery(PGresult *result, const printQueryOpt * opt, FILE *fout) { - int nfields; - char ** headers; - char ** cells; - char ** footers; - char * align; - int i; + int nfields; + char **headers; + char **cells; + char **footers; + char *align; + int i; + + /* extract headers */ + + nfields = PQnfields(result); + + headers = calloc(nfields + 1, sizeof(*headers)); + if (!headers) + { + perror("calloc"); + exit(EXIT_FAILURE); + } - /* extract headers */ + for (i = 0; i < nfields; i++) + headers[i] = PQfname(result, i); - nfields = PQnfields(result); + /* set cells */ - headers = calloc(nfields+1, sizeof(*headers)); - if (!headers) { - perror("calloc"); - exit(EXIT_FAILURE); - } + cells = calloc(nfields * PQntuples(result) + 1, sizeof(*cells)); + if (!cells) + { + perror("calloc"); + exit(EXIT_FAILURE); + } - for (i=0; i<nfields; i++) - headers[i] = PQfname(result, i); + for (i = 0; i < nfields * PQntuples(result); i++) + { + if (PQgetisnull(result, i / nfields, i % nfields)) + cells[i] = opt->nullPrint ? opt->nullPrint : ""; + else + cells[i] = PQgetvalue(result, i / nfields, i % nfields); + } - /* set cells */ + /* set footers */ - cells = calloc(nfields * PQntuples(result) + 1, sizeof(*cells)); - if (!cells) { - perror("calloc"); - exit(EXIT_FAILURE); - } + if (opt->footers) + footers = opt->footers; + else if (!opt->topt.expanded) + { + footers = calloc(2, sizeof(*footers)); + if (!footers) + { + perror("calloc"); + exit(EXIT_FAILURE); + } - for (i=0; i< nfields * PQntuples(result); i++) { - if (PQgetisnull(result, i / nfields, i % nfields)) - cells[i] = opt->nullPrint ? opt->nullPrint : ""; + footers[0] = malloc(100); + if (PQntuples(result) == 1) + strcpy(footers[0], "(1 row)"); + else + sprintf(footers[0], "(%d rows)", PQntuples(result)); + } else - cells[i] = PQgetvalue(result, i / nfields, i % nfields); - } + footers = NULL; - /* set footers */ + /* set alignment */ - if (opt->footers) - footers = opt->footers; - else if (!opt->topt.expanded) { - footers = calloc(2, sizeof(*footers)); - if (!footers) { - perror("calloc"); - exit(EXIT_FAILURE); + align = calloc(nfields + 1, sizeof(*align)); + if (!align) + { + perror("calloc"); + exit(EXIT_FAILURE); } - footers[0] = malloc(100); - if (PQntuples(result)==1) - strcpy(footers[0], "(1 row)"); - else - sprintf(footers[0], "(%d rows)", PQntuples(result)); - } - else - footers = NULL; - - /* set alignment */ - - align = calloc(nfields+1, sizeof(*align)); - if (!align) { - perror("calloc"); - exit(EXIT_FAILURE); - } - - for (i=0; i<nfields; i++) { - Oid ftype = PQftype(result, i); - if ( ftype == 20 || /* int8 */ - ftype == 21 || /* int2 */ - ftype == 23 || /* int4 */ - (ftype >=26 && ftype <=30) || /* ?id */ - ftype == 700 || /* float4 */ - ftype == 701 || /* float8 */ - ftype == 790 || /* money */ - ftype == 1700 /* numeric */ - ) - align[i] = 'r'; - else - align[i] = 'l'; - } + for (i = 0; i < nfields; i++) + { + Oid ftype = PQftype(result, i); + + if (ftype == 20 || /* int8 */ + ftype == 21 || /* int2 */ + ftype == 23 || /* int4 */ + (ftype >= 26 && ftype <= 30) || /* ?id */ + ftype == 700 || /* float4 */ + ftype == 701 || /* float8 */ + ftype == 790 || /* money */ + ftype == 1700 /* numeric */ + ) + align[i] = 'r'; + else + align[i] = 'l'; + } - /* call table printer */ + /* call table printer */ - printTable(opt->title, headers, cells, footers ? footers : opt->footers, align, - &opt->topt, fout); + printTable(opt->title, headers, cells, footers ? footers : opt->footers, align, + &opt->topt, fout); - free(headers); - free(cells); - if (footers) { - free(footers[0]); - free(footers); - } + free(headers); + free(cells); + if (footers) + { + free(footers[0]); + free(footers); + } } diff --git a/src/bin/psql/print.h b/src/bin/psql/print.h index d24e41e853..64d0271f50 100644 --- a/src/bin/psql/print.h +++ b/src/bin/psql/print.h @@ -7,52 +7,58 @@ #include <stdio.h> #include <libpq-fe.h> -enum printFormat { - PRINT_NOTHING = 0, /* to make sure someone initializes this */ - PRINT_UNALIGNED, - PRINT_ALIGNED, - PRINT_HTML, - PRINT_LATEX - /* add your favourite output format here ... */ +enum printFormat +{ + PRINT_NOTHING = 0, /* to make sure someone initializes this */ + PRINT_UNALIGNED, + PRINT_ALIGNED, + PRINT_HTML, + PRINT_LATEX + /* add your favourite output format here ... */ }; -typedef struct _printTableOpt { - enum printFormat format; /* one of the above */ - bool expanded; /* expanded/vertical output (if supported by output format) */ - bool pager; /* use pager for output (if to stdout and stdout is a tty) */ - bool tuples_only; /* don't output headers, row counts, etc. */ - unsigned short int border; /* Print a border around the table. 0=none, 1=dividing lines, 2=full */ - char *fieldSep; /* field separator for unaligned text mode */ - char *tableAttr; /* attributes for HTML <table ...> */ -} printTableOpt; +typedef struct _printTableOpt +{ + enum printFormat format; /* one of the above */ + bool expanded; /* expanded/vertical output (if supported + * by output format) */ + bool pager; /* use pager for output (if to stdout and + * stdout is a tty) */ + bool tuples_only; /* don't output headers, row counts, etc. */ + unsigned short int border; /* Print a border around the table. + * 0=none, 1=dividing lines, 2=full */ + char *fieldSep; /* field separator for unaligned text mode */ + char *tableAttr; /* attributes for HTML <table ...> */ +} printTableOpt; /* * Use this to print just any table in the supported formats. * - title is just any string (NULL is fine) * - headers is the column headings (NULL ptr terminated). It must be given and - * complete since the column count is generated from this. + * complete since the column count is generated from this. * - cells are the data cells to be printed. Now you know why the correct - * column count is important + * column count is important * - footers are lines to be printed below the table * - align is an 'l' or an 'r' for every column, if the output format needs it. - * (You must specify this long enough. Otherwise anything could happen.) + * (You must specify this long enough. Otherwise anything could happen.) */ -void -printTable(const char * title, char ** headers, char ** cells, char ** footers, - const char * align, - const printTableOpt * opt, FILE * fout); +void printTable(const char *title, char **headers, char **cells, char **footers, + const char *align, + const printTableOpt * opt, FILE *fout); -typedef struct _printQueryOpt { - printTableOpt topt; /* the options above */ - char * nullPrint; /* how to print null entities */ - bool quote; /* quote all values as much as possible */ - char * title; /* override title */ - char ** footers; /* override footer (default is "(xx rows)") */ -} printQueryOpt; +typedef struct _printQueryOpt +{ + printTableOpt topt; /* the options above */ + char *nullPrint; /* how to print null entities */ + bool quote; /* quote all values as much as possible */ + char *title; /* override title */ + char **footers; /* override footer (default is "(xx + * rows)") */ +} printQueryOpt; /* * Use this to print query results @@ -60,7 +66,7 @@ typedef struct _printQueryOpt { * It calls the printTable above with all the things set straight. */ void -printQuery(PGresult * result, const printQueryOpt * opt, FILE * fout); + printQuery(PGresult *result, const printQueryOpt * opt, FILE *fout); -#endif /* PRINT_H */ +#endif /* PRINT_H */ diff --git a/src/bin/psql/prompt.c b/src/bin/psql/prompt.c index a0fa797595..2912bd16eb 100644 --- a/src/bin/psql/prompt.c +++ b/src/bin/psql/prompt.c @@ -34,20 +34,20 @@ * %~ - like %/ but "~" when database name equals user name * %# - "#" if the username is postgres, ">" otherwise * %R - in prompt1 normally =, or ^ if single line mode, - * or a ! if session is not connected to a database; - * in prompt2 -, *, ', or "; - * in prompt3 nothing + * or a ! if session is not connected to a database; + * in prompt2 -, *, ', or "; + * in prompt3 nothing * %? - the error code of the last query (not yet implemented) * %% - a percent sign * - * %[0-9] - the character with the given decimal code - * %0[0-7] - the character with the given octal code + * %[0-9] - the character with the given decimal code + * %0[0-7] - the character with the given octal code * %0x[0-9A-Fa-f] - the character with the given hexadecimal code * - * %`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) + * %`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) * (those will not be rescanned for more escape sequences!) * * @@ -60,197 +60,214 @@ const char * get_prompt(PsqlSettings *pset, promptStatus_t status) { #define MAX_PROMPT_SIZE 256 - static char destination[MAX_PROMPT_SIZE+1]; - char buf[MAX_PROMPT_SIZE+1]; - bool esc = false; - const char *p; - const char * prompt_string; + static char destination[MAX_PROMPT_SIZE + 1]; + char buf[MAX_PROMPT_SIZE + 1]; + bool esc = false; + const char *p; + const char *prompt_string; - if (GetVariable(pset->vars, "quiet")) - return ""; + if (GetVariable(pset->vars, "quiet")) + return ""; - if (status == PROMPT_READY) - prompt_string = GetVariable(pset->vars, "prompt1"); - else if (status == PROMPT_CONTINUE || status == PROMPT_SINGLEQUOTE || status == PROMPT_DOUBLEQUOTE || status == PROMPT_COMMENT) - prompt_string = GetVariable(pset->vars, "prompt2"); - else if (status == PROMPT_COPY) - prompt_string = GetVariable(pset->vars, "prompt3"); - else - prompt_string = "? "; + if (status == PROMPT_READY) + 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"); + else if (status == PROMPT_COPY) + prompt_string = GetVariable(pset->vars, "prompt3"); + else + prompt_string = "? "; - destination[0] = '\0'; + destination[0] = '\0'; - for (p = prompt_string; - p && *p && strlen(destination)<MAX_PROMPT_SIZE; - p++) - { - MemSet(buf, 0, MAX_PROMPT_SIZE+1); - if (esc) + for (p = prompt_string; + p && *p && strlen(destination) < MAX_PROMPT_SIZE; + p++) { - switch (*p) - { - case '%': - strcpy(buf, "%"); - break; + MemSet(buf, 0, MAX_PROMPT_SIZE + 1); + if (esc) + { + switch (*p) + { + case '%': + strcpy(buf, "%"); + break; - /* Current database */ - case '/': - if (pset->db) - strncpy(buf, PQdb(pset->db), MAX_PROMPT_SIZE); - break; - case '~': { - const char * var; - if (pset->db) { - 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); - } - break; - } - /* DB server hostname (long/short) */ - case 'M': - case 'm': - if (pset->db) { - if (PQhost(pset->db)) { - strncpy(buf, PQhost(pset->db), MAX_PROMPT_SIZE); - if (*p == 'm') - buf[strcspn(buf,".")] = '\0'; - } - else - buf[0] = '.'; - } - break; - /* DB server port number */ - case '>': - if (pset->db) { - if (PQhost(pset->db)) - strncpy(buf, PQport(pset->db), MAX_PROMPT_SIZE); - else - buf[0] = '.'; - } - break; - /* DB server user name */ - case 'n': - if (pset->db) - strncpy(buf, PQuser(pset->db), MAX_PROMPT_SIZE); - break; + /* Current database */ + case '/': + if (pset->db) + strncpy(buf, PQdb(pset->db), MAX_PROMPT_SIZE); + break; + case '~': + { + const char *var; - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - { - long int l; - char * end; - l = strtol(p, &end, 0); - sprintf(buf, "%c", (unsigned char)l); - p = end-1; - break; - } + if (pset->db) + { + 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); + } + break; + } + /* DB server hostname (long/short) */ + case 'M': + case 'm': + if (pset->db) + { + if (PQhost(pset->db)) + { + strncpy(buf, PQhost(pset->db), MAX_PROMPT_SIZE); + if (*p == 'm') + buf[strcspn(buf, ".")] = '\0'; + } + else + buf[0] = '.'; + } + break; + /* DB server port number */ + case '>': + if (pset->db) + { + if (PQhost(pset->db)) + strncpy(buf, PQport(pset->db), MAX_PROMPT_SIZE); + else + buf[0] = '.'; + } + break; + /* DB server user name */ + case 'n': + if (pset->db) + strncpy(buf, PQuser(pset->db), MAX_PROMPT_SIZE); + break; - case 'R': - switch(status) { - case PROMPT_READY: - if (!pset->db) - buf[0] = '!'; - else if (!GetVariableBool(pset->vars, "singleline")) - buf[0] = '='; - else - buf[0] = '^'; - break; - case PROMPT_CONTINUE: - buf[0] = '-'; - break; - case PROMPT_SINGLEQUOTE: - buf[0] = '\''; - break; - case PROMPT_DOUBLEQUOTE: - buf[0] = '"'; - break; - case PROMPT_COMMENT: - buf[0] = '*'; - break; - default: - buf[0] = '\0'; - break; - } + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + long int l; + char *end; - case '?': - /* not here yet */ - break; + l = strtol(p, &end, 0); + sprintf(buf, "%c", (unsigned char) l); + p = end - 1; + break; + } - case '#': - { - if (pset->db && strcmp(PQuser(pset->db), "postgres")==0) - buf[0] = '#'; - else - buf[0] = '>'; - - break; - } + case 'R': + switch (status) + { + case PROMPT_READY: + if (!pset->db) + buf[0] = '!'; + else if (!GetVariableBool(pset->vars, "singleline")) + buf[0] = '='; + else + buf[0] = '^'; + break; + case PROMPT_CONTINUE: + buf[0] = '-'; + break; + case PROMPT_SINGLEQUOTE: + buf[0] = '\''; + break; + case PROMPT_DOUBLEQUOTE: + buf[0] = '"'; + break; + case PROMPT_COMMENT: + buf[0] = '*'; + break; + default: + buf[0] = '\0'; + break; + } - /* execute command */ - case '`': - { - FILE * fd = NULL; - char * file = strdup(p+1); - int cmdend; - cmdend = strcspn(file, "`"); - file[cmdend] = '\0'; - if (file) - fd = popen(file, "r"); - if (fd) { - fgets(buf, MAX_PROMPT_SIZE-1, fd); - pclose(fd); - } - if (buf[strlen(buf)-1] == '\n') - buf[strlen(buf)-1] = '\0'; - free(file); - p += cmdend+1; - break; - } + case '?': + /* not here yet */ + break; - /* interpolate variable */ - case '$': - { - char *name; - const char *val; - int nameend; - name = strdup(p+1); - nameend = strcspn(name, "$"); - name[nameend] = '\0'; - val = interpolate_var(name, pset); - if (val) - strncpy(buf, val, MAX_PROMPT_SIZE); - free(name); - p += nameend+1; - break; - } - + case '#': + { + if (pset->db && strcmp(PQuser(pset->db), "postgres") == 0) + buf[0] = '#'; + else + buf[0] = '>'; - default: - buf[0] = *p; - buf[1] = '\0'; + break; + } - } - esc = false; - } - else if (*p == '%') - esc = true; - else - { - buf[0] = *p; - buf[1] = '\0'; - esc = false; - } + /* execute command */ + case '`': + { + FILE *fd = NULL; + char *file = strdup(p + 1); + int cmdend; - if (!esc) { - strncat(destination, buf, MAX_PROMPT_SIZE-strlen(destination)); + cmdend = strcspn(file, "`"); + file[cmdend] = '\0'; + if (file) + fd = popen(file, "r"); + if (fd) + { + fgets(buf, MAX_PROMPT_SIZE - 1, fd); + pclose(fd); + } + if (buf[strlen(buf) - 1] == '\n') + buf[strlen(buf) - 1] = '\0'; + free(file); + p += cmdend + 1; + break; + } + + /* interpolate variable */ + case '$': + { + char *name; + const char *val; + int nameend; + + name = strdup(p + 1); + nameend = strcspn(name, "$"); + name[nameend] = '\0'; + val = interpolate_var(name, pset); + if (val) + strncpy(buf, val, MAX_PROMPT_SIZE); + free(name); + p += nameend + 1; + break; + } + + + default: + buf[0] = *p; + buf[1] = '\0'; + + } + esc = false; + } + else if (*p == '%') + esc = true; + else + { + buf[0] = *p; + buf[1] = '\0'; + esc = false; + } + + if (!esc) + strncat(destination, buf, MAX_PROMPT_SIZE - strlen(destination)); } - } - destination[MAX_PROMPT_SIZE] = '\0'; - return destination; + destination[MAX_PROMPT_SIZE] = '\0'; + return destination; } - diff --git a/src/bin/psql/prompt.h b/src/bin/psql/prompt.h index f38a2d6f31..e4c1242deb 100644 --- a/src/bin/psql/prompt.h +++ b/src/bin/psql/prompt.h @@ -3,17 +3,18 @@ #include "settings.h" -typedef enum _promptStatus { - PROMPT_READY, - PROMPT_CONTINUE, - PROMPT_COMMENT, - PROMPT_SINGLEQUOTE, - PROMPT_DOUBLEQUOTE, - PROMPT_COPY -} promptStatus_t; +typedef enum _promptStatus +{ + PROMPT_READY, + PROMPT_CONTINUE, + PROMPT_COMMENT, + PROMPT_SINGLEQUOTE, + PROMPT_DOUBLEQUOTE, + PROMPT_COPY +} promptStatus_t; const char * -get_prompt(PsqlSettings *pset, promptStatus_t status); + get_prompt(PsqlSettings *pset, promptStatus_t status); -#endif /* PROMPT_H */ +#endif /* PROMPT_H */ diff --git a/src/bin/psql/psql.c b/src/bin/psql/psql.c deleted file mode 100644 index ca2fc6f27c..0000000000 --- a/src/bin/psql/psql.c +++ /dev/null @@ -1,3297 +0,0 @@ -/*------------------------------------------------------------------------- - * - * psql.c - * an interactive front-end to postgreSQL - * - * Copyright (c) 1996, Regents of the University of California - * - * - * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/bin/psql/Attic/psql.c,v 1.195 1999/10/26 04:40:58 momjian Exp $ - * - *------------------------------------------------------------------------- - */ -#include <signal.h> -#include <errno.h> -#include <sys/types.h> -#ifdef WIN32 -#define WIN32_LEAN_AND_MEAN -#include <windows.h> -#include <io.h> -#else -#include <sys/ioctl.h> -#include <unistd.h> -#endif -#include <sys/stat.h> -#include <fcntl.h> -#include <ctype.h> - -#include "postgres.h" -#include "libpq-fe.h" -#include "pqexpbuffer.h" -#include "pqsignal.h" -#include "stringutils.h" -#include "psqlHelp.h" - -#ifndef HAVE_STRDUP -#include "strdup.h" -#endif - -#ifdef HAVE_TERMIOS_H -#include <termios.h> -#endif - -#ifdef HAVE_GETOPT_H -#include <getopt.h> -#endif - -#ifdef HAVE_LIBREADLINE -#ifdef HAVE_READLINE_H -#include <readline.h> -#define USE_READLINE 1 -#if defined(HAVE_HISTORY_H) -#include <history.h> -#define USE_HISTORY 1 -#endif -#else -#if defined(HAVE_READLINE_READLINE_H) -#include <readline/readline.h> -#define USE_READLINE 1 -#if defined(HAVE_READLINE_HISTORY_H) -#include <readline/history.h> -#define USE_HISTORY 1 -#endif -#endif -#endif -#if defined(HAVE_HISTORY) && !defined(USE_HISTORY) -#define USE_HISTORY 1 -#endif -#endif - - -#ifdef WIN32 -#define popen(x,y) _popen(x,y) -#define pclose(x) _pclose(x) -#define open(x,y,z) _open(x,y,z) -#define strcasecmp(x,y) stricmp(x,y) -#define pqsignal(x,y) -#define R_OK 0 - -/* getopt is not in the standard includes on Win32 */ -extern char *optarg; -extern int optind, - opterr, - optopt; -int getopt(int, char *const[], const char *); -char *__progname = "psql"; - -#endif - -#ifdef MULTIBYTE -/* flag to indicate if PGCLIENTENCODING has been set by a user */ -static char *has_client_encoding = 0; - -#endif - -/* This prompt string is assumed to have at least 3 characters by code in MainLoop(). - * A character two characters from the end is replaced each time by a mode character. - */ -#define PROMPT "=> " - -#define PROMPT_READY '=' -#define PROMPT_CONTINUE '-' -#define PROMPT_COMMENT '*' -#define PROMPT_SINGLEQUOTE '\'' -#define PROMPT_DOUBLEQUOTE '"' - -/* Backslash command handling: - * 0 - send currently constructed query to backend (i.e. we got a \g) - * 1 - skip processing of this line, continue building up query - * 2 - terminate processing (i.e. we got a \q) - * 3 - new query supplied by edit - */ -#define CMD_UNKNOWN -1 -#define CMD_SEND 0 -#define CMD_SKIP_LINE 1 -#define CMD_TERMINATE 2 -#define CMD_NEWEDIT 3 - -#define COPYBUFSIZ 8192 - -#define DEFAULT_FIELD_SEP "|" -#define DEFAULT_EDITOR "vi" -#define DEFAULT_SHELL "/bin/sh" - -typedef struct _psqlSettings -{ - PGconn *db; /* connection to backend */ - FILE *queryFout; /* where to send the query results */ - PQprintOpt opt; /* options to be passed to PQprint */ - char *prompt; /* prompt to display */ - char *gfname; /* one-shot file output argument for \g */ - bool notty; /* input or output is not a tty */ - bool pipe; /* queryFout is from a popen() */ - bool echoQuery; /* echo the query before sending it */ - bool echoAllQueries; /* echo all queries before sending it */ - bool quiet; /* run quietly, no messages, no promt */ - bool singleStep; /* prompt before for each query */ - bool singleLineMode; /* query terminated by newline */ - bool useReadline; /* use libreadline routines */ - bool getPassword; /* prompt the user for a username and - * password */ -} PsqlSettings; - -/* - * cur_cmd_source and cur_cmd_interactive are the top of a stack of - * source files (one stack level per recursive invocation of MainLoop). - * It's kinda grotty to make these global variables, but the alternative - * of passing them around through many function parameter lists seems - * worse. - */ -static FILE *cur_cmd_source = NULL; /* current source of command input */ -static bool cur_cmd_interactive = false; /* is it an interactive - * source? */ - - -#ifdef TIOCGWINSZ -struct winsize screen_size; - -#else -struct winsize -{ - int ws_row; - int ws_col; -} screen_size; - -#endif - -/* declarations for functions in this file */ -static void usage(char *progname); -static void slashUsage(); -static bool handleCopyOut(PGconn *conn, FILE *copystream); -static bool handleCopyIn(PGconn *conn, const bool mustprompt, - FILE *copystream); -static int tableList(PsqlSettings *pset, bool deep_tablelist, - char info_type, bool system_tables); -static int tableDesc(PsqlSettings *pset, char *table, FILE *fout); -static int objectDescription(PsqlSettings *pset, char *object); -static int rightsList(PsqlSettings *pset); -static void emitNtimes(FILE *fout, const char *str, int N); -static void prompt_for_password(char *username, char *password); - -static char *gets_noreadline(char *prompt, FILE *source); -static char *gets_readline(char *prompt, FILE *source); -static char *gets_fromFile(char *prompt, FILE *source); -static int listAllDbs(PsqlSettings *pset); -static bool SendQuery(PsqlSettings *pset, const char *query, - FILE *copy_in_stream, FILE *copy_out_stream); -static int HandleSlashCmds(PsqlSettings *pset, char *line, - PQExpBuffer query_buf); -static int MainLoop(PsqlSettings *pset, FILE *source); -static FILE *setFout(PsqlSettings *pset, char *fname); - -static char *selectVersion(PsqlSettings *pset); - -/* - * usage print out usage for command line arguments - */ - -static void -usage(char *progname) -{ - fprintf(stderr, "Usage: %s [options] [dbname]\n", progname); - fprintf(stderr, "\t -a authsvc set authentication service\n"); - fprintf(stderr, "\t -A turn off alignment when printing out attributes\n"); - fprintf(stderr, "\t -c query run single query (slash commands too)\n"); - fprintf(stderr, "\t -d dbName specify database name\n"); - fprintf(stderr, "\t -e echo the query sent to the backend\n"); - fprintf(stderr, "\t -E echo all queries sent to the backend\n"); - fprintf(stderr, "\t -f filename use file as a source of queries\n"); - fprintf(stderr, "\t -F sep set the field separator (default is '|')\n"); - fprintf(stderr, "\t -h host set database server host\n"); - fprintf(stderr, "\t -H turn on html3.0 table output\n"); - fprintf(stderr, "\t -l list available databases\n"); - fprintf(stderr, "\t -n don't use readline library\n"); - fprintf(stderr, "\t -o filename send output to filename or (|pipe)\n"); - fprintf(stderr, "\t -p port set port number\n"); - fprintf(stderr, "\t -q run quietly (no messages, no prompts)\n"); - fprintf(stderr, "\t -s single step mode (prompts for each query)\n"); - fprintf(stderr, "\t -S single line mode (i.e. query terminated by newline)\n"); - fprintf(stderr, "\t -t turn off printing of headings and row count\n"); - fprintf(stderr, "\t -T html set html3.0 table command options (cf. -H)\n"); - fprintf(stderr, "\t -u ask for a username and password for authentication\n"); - fprintf(stderr, "\t -x turn on expanded output (field names on left)\n"); - exit(1); -} - -/* - * slashUsage print out usage for the backslash commands - */ - -static char * -on(bool f) -{ - return f ? "on" : "off"; -} - -static void -slashUsage(PsqlSettings *pset) -{ - int usePipe = 0; - char *pagerenv; - FILE *fout; - -#ifdef TIOCGWINSZ - if (pset->notty == 0 && - (ioctl(fileno(stdout), TIOCGWINSZ, &screen_size) == -1 || - screen_size.ws_col == 0 || - screen_size.ws_row == 0)) - { -#endif - screen_size.ws_row = 24; - screen_size.ws_col = 80; -#ifdef TIOCGWINSZ - } -#endif - - if (pset->notty == 0 && - (pagerenv = getenv("PAGER")) && - (pagerenv[0] != '\0') && - screen_size.ws_row <= 35 && - (fout = popen(pagerenv, "w"))) - { - usePipe = 1; - pqsignal(SIGPIPE, SIG_IGN); - } - else - fout = stdout; - - /* if you add/remove a line here, change the row test above */ - fprintf(fout, " \\? -- help\n"); - fprintf(fout, " \\a -- toggle field-alignment (currently %s)\n", on(pset->opt.align)); - fprintf(fout, " \\C [<captn>] -- set html3 caption (currently '%s')\n", pset->opt.caption ? pset->opt.caption : ""); - fprintf(fout, " \\connect <dbname|-> <user> -- connect to new database (currently '%s')\n", PQdb(pset->db)); - fprintf(fout, " \\copy table {from | to} <fname>\n"); - fprintf(fout, " \\d [<table>] -- list tables and indices, columns in <table>, or * for all\n"); - fprintf(fout, " \\da -- list aggregates\n"); - fprintf(fout, " \\dd [<object>]- list comment an object.\n"); - fprintf(fout, " \\df -- list functions\n"); - fprintf(fout, " \\di -- list only indices\n"); - fprintf(fout, " \\do -- list operators\n"); - fprintf(fout, " \\ds -- list only sequences\n"); - fprintf(fout, " \\dS -- list system tables and indexes\n"); - fprintf(fout, " \\dt -- list only tables\n"); - fprintf(fout, " \\dT -- list types\n"); - fprintf(fout, " \\e [<fname>] -- edit the current query buffer or <fname>\n"); - fprintf(fout, " \\E [<fname>] -- edit the current query buffer or <fname>, and execute\n"); - fprintf(fout, " \\f [<sep>] -- change field separater (currently '%s')\n", pset->opt.fieldSep); - fprintf(fout, " \\g [<fname>] [|<cmd>] -- send query to backend [and results in <fname> or pipe]\n"); - fprintf(fout, " \\h [<cmd>] -- help on syntax of sql commands, * for all commands\n"); - fprintf(fout, " \\H -- toggle html3 output (currently %s)\n", on(pset->opt.html3)); - fprintf(fout, " \\i <fname> -- read and execute queries from filename\n"); - fprintf(fout, " \\l -- list all databases\n"); - fprintf(fout, " \\m -- toggle monitor-like table display (currently %s)\n", on(pset->opt.standard)); - fprintf(fout, " \\o [<fname>] [|<cmd>] -- send all query results to stdout, <fname>, or pipe\n"); - fprintf(fout, " \\p -- print the current query buffer\n"); - fprintf(fout, " \\q -- quit\n"); - fprintf(fout, " \\r -- reset(clear) the query buffer\n"); - fprintf(fout, " \\s [<fname>] -- print history or save it in <fname>\n"); - fprintf(fout, " \\t -- toggle table headings and row count (currently %s)\n", on(pset->opt.header)); - fprintf(fout, " \\T [<html>] -- set html3.0 <table ...> options (currently '%s')\n", pset->opt.tableOpt ? pset->opt.tableOpt : ""); - fprintf(fout, " \\x -- toggle expanded output (currently %s)\n", on(pset->opt.expanded)); - fprintf(fout, " \\w <fname> -- write current buffer to a file\n"); - fprintf(fout, " \\z -- list current grant/revoke permissions\n"); - fprintf(fout, " \\! [<cmd>] -- shell escape or command\n"); - - if (usePipe) - { - pclose(fout); - pqsignal(SIGPIPE, SIG_DFL); - } -} - -static PGresult * -PSQLexec(PsqlSettings *pset, char *query) -{ - PGresult *res; - - if (pset->echoAllQueries) - { - fprintf(stderr, "QUERY: %s\n", query); - fprintf(stderr, "\n"); - fflush(stderr); - } - - res = PQexec(pset->db, query); - if (!res) - fputs(PQerrorMessage(pset->db), stderr); - else - { - if (PQresultStatus(res) == PGRES_COMMAND_OK || - PQresultStatus(res) == PGRES_TUPLES_OK) - return res; - if (!pset->quiet) - fputs(PQerrorMessage(pset->db), stderr); - PQclear(res); - } - return NULL; -} - -/* - * Code to support command cancellation. - * If interactive, we enable a SIGINT signal catcher that sends - * a cancel request to the backend. - * Note that sending the cancel directly from the signal handler - * is safe only because PQrequestCancel is carefully written to - * make it so. We have to be very careful what else we do in the - * signal handler. - * Writing on stderr is potentially dangerous, if the signal interrupted - * some stdio operation on stderr. On Unix we can avoid trouble by using - * write() instead; on Windows that's probably not workable, but we can - * at least avoid trusting printf by using the more primitive fputs. - */ - -static PGconn *cancelConn = NULL; /* connection to try cancel on */ - -static void -safe_write_stderr(const char *s) -{ -#ifdef WIN32 - fputs(s, stderr); -#else - write(fileno(stderr), s, strlen(s)); -#endif -} - -static void -handle_sigint(SIGNAL_ARGS) -{ - if (cancelConn == NULL) - exit(1); /* accept signal if no connection */ - /* Try to send cancel request */ - if (PQrequestCancel(cancelConn)) - safe_write_stderr("\nCANCEL request sent\n"); - else - { - safe_write_stderr("\nCannot send cancel request:\n"); - safe_write_stderr(PQerrorMessage(cancelConn)); - } -} - - -/* - * listAllDbs - * - * list all the databases in the system returns 0 if all went well - * - * - */ - -static int -listAllDbs(PsqlSettings *pset) -{ - PGresult *results; - char *query = "select * from pg_database;"; - - if (!(results = PSQLexec(pset, query))) - return 1; - else - { - PQprint(pset->queryFout, - results, - &pset->opt); - PQclear(results); - return 0; - } -} - -/* - * List The Database Tables returns 0 if all went well - * - */ -static int -tableList(PsqlSettings *pset, bool deep_tablelist, char info_type, - bool system_tables) -{ - char listbuf[512]; - int nColumns; - int i; - char *rk; - char *rr; - PGresult *res; - int usePipe = 0; - bool haveIndexes = false; - char *pagerenv; - FILE *fout; - -#ifdef TIOCGWINSZ - if (pset->notty == 0 && - (ioctl(fileno(stdout), TIOCGWINSZ, &screen_size) == -1 || - screen_size.ws_col == 0 || - screen_size.ws_row == 0)) - { -#endif - screen_size.ws_row = 24; - screen_size.ws_col = 80; -#ifdef TIOCGWINSZ - } -#endif - - listbuf[0] = '\0'; - strcat(listbuf, "SELECT usename, relname, relkind, relhasrules "); - strcat(listbuf, "FROM pg_class, pg_user "); - strcat(listbuf, "WHERE usesysid = relowner "); - switch (info_type) - { - case 't': - strcat(listbuf, "and ( relkind = 'r') "); - break; - case 'i': - strcat(listbuf, "and ( relkind = 'i') "); - haveIndexes = true; - break; - case 'S': - strcat(listbuf, "and ( relkind = 'S') "); - break; - case 'b': - default: - strcat(listbuf, "and ( relkind = 'r' OR relkind = 'i' OR relkind = 'S') "); - haveIndexes = true; - break; - } - if (!system_tables) - strcat(listbuf, "and relname !~ '^pg_' "); - else - strcat(listbuf, "and relname ~ '^pg_' "); - /* - * Large-object relations are automatically ignored because they have - * relkind 'l'. However, we want to ignore their indexes as well. - * The clean way to do that would be to do a join to find out which - * table each index is for. The ugly but fast way is to know that - * large object indexes have names starting with 'xinx'. - */ - if (haveIndexes) - strcat(listbuf, "and (relkind != 'i' OR relname !~ '^xinx') "); - - strcat(listbuf, " ORDER BY relname "); - if (!(res = PSQLexec(pset, listbuf))) - return -1; - /* first, print out the attribute names */ - nColumns = PQntuples(res); - if (nColumns > 0) - { - if (pset->notty == 0 && - (pagerenv = getenv("PAGER")) && - pagerenv[0] != '\0' && - (deep_tablelist || - screen_size.ws_row <= nColumns + 7) && - (fout = popen(pagerenv, "w"))) - { - usePipe = 1; - pqsignal(SIGPIPE, SIG_IGN); - } - else - fout = stdout; - - if (deep_tablelist) - { - /* describe everything here */ - char **table; - - table = (char **) malloc(nColumns * sizeof(char *)); - if (table == NULL) - perror("malloc"); - - /* load table table */ - - /* - * Put double quotes around the table name to allow for - * mixed-case and whitespaces in the table name. - BGA - * 1998-11-14 - */ - for (i = 0; i < nColumns; i++) - { - table[i] = (char *) malloc(PQgetlength(res, i, 1) * sizeof(char) + 3); - if (table[i] == NULL) - perror("malloc"); - strcpy(table[i], "\""); - strcat(table[i], PQgetvalue(res, i, 1)); - strcat(table[i], "\""); - } - - PQclear(res); - for (i = 0; i < nColumns; i++) - tableDesc(pset, table[i], fout); - free(table); - } - else - { - /* Display the information */ - - fprintf(fout, "Database = %s\n", PQdb(pset->db)); - fprintf(fout, " +------------------+----------------------------------+----------+\n"); - fprintf(fout, " | Owner | Relation | Type |\n"); - fprintf(fout, " +------------------+----------------------------------+----------+\n"); - - /* next, print out the instances */ - for (i = 0; i < PQntuples(res); i++) - { - fprintf(fout, " | %-16.16s", PQgetvalue(res, i, 0)); - fprintf(fout, " | %-32.32s | ", PQgetvalue(res, i, 1)); - rk = PQgetvalue(res, i, 2); - rr = PQgetvalue(res, i, 3); - if (strcmp(rk, "r") == 0) - fprintf(fout, "%-8.8s |", (rr[0] == 't') ? "view?" : "table"); - else if (strcmp(rk, "i") == 0) - fprintf(fout, "%-8.8s |", "index"); - else - fprintf(fout, "%-8.8s |", "sequence"); - fprintf(fout, "\n"); - } - fprintf(fout, " +------------------+----------------------------------+----------+\n"); - fprintf(fout, "\n"); - PQclear(res); - } - if (usePipe) - { - pclose(fout); - pqsignal(SIGPIPE, SIG_DFL); - } - return 0; - - } - else - { - PQclear(res); - switch (info_type) - { - case 't': - fprintf(stderr, "Couldn't find any tables!\n"); - break; - case 'i': - fprintf(stderr, "Couldn't find any indices!\n"); - break; - case 'S': - fprintf(stderr, "Couldn't find any sequences!\n"); - break; - case 'b': - default: - fprintf(stderr, "Couldn't find any tables, sequences or indices!\n"); - break; - } - return -1; - } -} - -/* - * List Tables Grant/Revoke Permissions returns 0 if all went well - * - */ -static int -rightsList(PsqlSettings *pset) -{ - char listbuf[512]; - int nColumns; - int i; - int maxCol1Len; - int maxCol2Len; - int usePipe = 0; - char *pagerenv; - FILE *fout; - PGresult *res; - -#ifdef TIOCGWINSZ - if (pset->notty == 0 && - (ioctl(fileno(stdout), TIOCGWINSZ, &screen_size) == -1 || - screen_size.ws_col == 0 || - screen_size.ws_row == 0)) - { -#endif - screen_size.ws_row = 24; - screen_size.ws_col = 80; -#ifdef TIOCGWINSZ - } -#endif - - listbuf[0] = '\0'; - strcat(listbuf, "SELECT relname, relacl "); - strcat(listbuf, "FROM pg_class "); - /* Currently, we ignore indexes since they have no meaningful rights */ - strcat(listbuf, "WHERE ( relkind = 'r' OR relkind = 'S') "); - strcat(listbuf, " and relname !~ '^pg_'"); - strcat(listbuf, " ORDER BY relname "); - if (!(res = PSQLexec(pset, listbuf))) - return -1; - /* first, print out the attribute names */ - nColumns = PQntuples(res); - if (nColumns > 0) - { - if (pset->notty == 0 && - (pagerenv = getenv("PAGER")) && - pagerenv[0] != '\0' && - screen_size.ws_row <= nColumns + 7 && - (fout = popen(pagerenv, "w"))) - { - usePipe = 1; - pqsignal(SIGPIPE, SIG_IGN); - } - else - fout = stdout; - - /* choose column widths */ - maxCol1Len = strlen("Relation"); - maxCol2Len = strlen("Grant/Revoke Permissions"); - for (i = 0; i < PQntuples(res); i++) - { - int l = strlen(PQgetvalue(res, i, 0)); - - if (l > maxCol1Len) - maxCol1Len = l; - l = strlen(PQgetvalue(res, i, 1)); - if (l > maxCol2Len) - maxCol2Len = l; - } - - /* Display the information */ - - fprintf(fout, "Database = %s\n", PQdb(pset->db)); - fprintf(fout, " +"); - emitNtimes(fout, "-", maxCol1Len + 2); - fprintf(fout, "+"); - emitNtimes(fout, "-", maxCol2Len + 2); - fprintf(fout, "+\n"); - fprintf(fout, " | %-*s | %-*s |\n", - maxCol1Len, "Relation", - maxCol2Len, "Grant/Revoke Permissions"); - fprintf(fout, " +"); - emitNtimes(fout, "-", maxCol1Len + 2); - fprintf(fout, "+"); - emitNtimes(fout, "-", maxCol2Len + 2); - fprintf(fout, "+\n"); - - /* next, print out the instances */ - for (i = 0; i < PQntuples(res); i++) - { - fprintf(fout, " | %-*s | %-*s |\n", - maxCol1Len, PQgetvalue(res, i, 0), - maxCol2Len, PQgetvalue(res, i, 1)); - } - - fprintf(fout, " +"); - emitNtimes(fout, "-", maxCol1Len + 2); - fprintf(fout, "+"); - emitNtimes(fout, "-", maxCol2Len + 2); - fprintf(fout, "+\n"); - - PQclear(res); - if (usePipe) - { - pclose(fout); - pqsignal(SIGPIPE, SIG_DFL); - } - return 0; - } - else - { - PQclear(res); - fprintf(stderr, "Couldn't find any tables!\n"); - return -1; - } -} - -static void -emitNtimes(FILE *fout, const char *str, int N) -{ - int i; - - for (i = 0; i < N; i++) - fputs(str, fout); -} - -/* - * Describe a table - * - * Describe the columns in a database table. returns 0 if all went well - * - * - */ -static int -tableDesc(PsqlSettings *pset, char *table, FILE *fout) -{ - char descbuf[512]; - int nColumns, - nIndices; - char *rtype; - char *rnotnull; - char *rhasdef; - int i; - int attlen, - atttypmod; - PGresult *res, - *res2; - int usePipe = 0; - char *pagerenv; - -#ifdef TIOCGWINSZ - if (pset->notty == 0 && - (ioctl(fileno(stdout), TIOCGWINSZ, &screen_size) == -1 || - screen_size.ws_col == 0 || - screen_size.ws_row == 0)) - { -#endif - screen_size.ws_row = 24; - screen_size.ws_col = 80; -#ifdef TIOCGWINSZ - } -#endif - - /* Build the query */ - - /* - * if the table name is surrounded by double-quotes, then don't - * convert case - */ - if (*table == '"') - { - table++; - if (*(table + strlen(table) - 1) == '"') - *(table + strlen(table) - 1) = '\0'; - } - else - { -#ifdef MULTIBYTE - for (i = 0; table[i]; i += PQmblen(table + i)) -#else - for (i = 0; table[i]; i++) -#endif - if (isascii((unsigned char) table[i]) && - isupper(table[i])) - table[i] = tolower(table[i]); - } - - descbuf[0] = '\0'; - strcat(descbuf, "SELECT a.attnum, a.attname, t.typname, a.attlen, "); - strcat(descbuf, "a.atttypmod, a.attnotnull, a.atthasdef "); - strcat(descbuf, "FROM pg_class c, pg_attribute a, pg_type t "); - strcat(descbuf, "WHERE c.relname = '"); - strcat(descbuf, table); - strcat(descbuf, "'"); - strcat(descbuf, " and a.attnum > 0 "); - strcat(descbuf, " and a.attrelid = c.oid "); - strcat(descbuf, " and a.atttypid = t.oid "); - strcat(descbuf, " ORDER BY attnum "); - if (!(res = PSQLexec(pset, descbuf))) - return -1; - /* first, print out the attribute names */ - nColumns = PQntuples(res); - if (nColumns > 0) - { - if (fout == NULL) - { - if (pset->notty == 0 && - (pagerenv = getenv("PAGER")) && - pagerenv[0] != '\0' && - screen_size.ws_row <= nColumns + 7 && - (fout = popen(pagerenv, "w"))) - { - usePipe = 1; - pqsignal(SIGPIPE, SIG_IGN); - } - else - fout = stdout; - } - - /* - * Extract the veiw name and veiw definition from pg_views. -Ryan - * 2/14/99 - */ - - descbuf[0] = '\0'; - strcat(descbuf, "SELECT viewname, definition "); - strcat(descbuf, "FROM pg_views "); - strcat(descbuf, "WHERE viewname like '"); - strcat(descbuf, table); - strcat(descbuf, "' "); - if (!(res2 = PSQLexec(pset, descbuf))) - return -1; - - /* - * Display the information - */ - if (PQntuples(res2)) - { - - /* - * display the query. o * -Ryan 2/14/99 - */ - fprintf(fout, "View = %s\n", table); - fprintf(fout, "Query = %s\n", PQgetvalue(res2, 0, 1)); - } - else - fprintf(fout, "Table = %s\n", table); - PQclear(res2); - - fprintf(fout, "+----------------------------------+----------------------------------+-------+\n"); - fprintf(fout, "| Field | Type | Length|\n"); - fprintf(fout, "+----------------------------------+----------------------------------+-------+\n"); - - /* next, print out the instances */ - for (i = 0; i < PQntuples(res); i++) - { - char type_str[33]; - - fprintf(fout, "| %-32.32s | ", PQgetvalue(res, i, 1)); - rtype = PQgetvalue(res, i, 2); - attlen = atoi(PQgetvalue(res, i, 3)); - atttypmod = atoi(PQgetvalue(res, i, 4)); - rnotnull = PQgetvalue(res, i, 5); - rhasdef = PQgetvalue(res, i, 6); - - strcpy(type_str, rtype); - if (strcmp(rtype, "bpchar") == 0) - strcpy(type_str, "char()"); - else if (strcmp(rtype, "varchar") == 0) - strcpy(type_str, "varchar()"); - else if (rtype[0] == '_') - { - strcpy(type_str, rtype + 1); - strncat(type_str, "[]", 32 - strlen(type_str)); - type_str[32] = '\0'; - } - - if (rnotnull[0] == 't') - { - strncat(type_str, " not null", 32 - strlen(type_str)); - type_str[32] = '\0'; - } - if (rhasdef[0] == 't') - { - descbuf[0] = '\0'; - strcat(descbuf, "SELECT d.adsrc "); - strcat(descbuf, "FROM pg_attrdef d, pg_class c "); - strcat(descbuf, "WHERE c.relname = '"); - strcat(descbuf, table); - strcat(descbuf, "'"); - strcat(descbuf, " and c.oid = d.adrelid "); - strcat(descbuf, " and d.adnum = "); - strcat(descbuf, PQgetvalue(res, i, 0)); - if (!(res2 = PSQLexec(pset, descbuf))) - return -1; - strcat(type_str, " default "); - strncat(type_str, PQgetvalue(res2, 0, 0), 32 - strlen(type_str)); - type_str[32] = '\0'; - } - fprintf(fout, "%-32.32s |", type_str); - - if (strcmp(rtype, "text") == 0) - fprintf(fout, "%6s |", "var"); - else if (strcmp(rtype, "bpchar") == 0 || - strcmp(rtype, "varchar") == 0) - fprintf(fout, "%6i |", atttypmod != -1 ? atttypmod - VARHDRSZ : 0); - else if (strcmp(rtype, "numeric") == 0) - fprintf(fout, "%3i.%-2i |", - ((atttypmod - VARHDRSZ) >> 16) & 0xffff, - (atttypmod - VARHDRSZ) & 0xffff); - else - { - if (attlen > 0) - fprintf(fout, "%6i |", attlen); - else - fprintf(fout, "%6s |", "var"); - } - fprintf(fout, "\n"); - } - fprintf(fout, "+----------------------------------+----------------------------------+-------+\n"); - PQclear(res); - - /* display defined indexes for this table */ - descbuf[0] = '\0'; - strcat(descbuf, "SELECT c2.relname "); - strcat(descbuf, "FROM pg_class c, pg_class c2, pg_index i "); - strcat(descbuf, "WHERE c.relname = '"); - strcat(descbuf, table); - strcat(descbuf, "'"); - strcat(descbuf, " and c.oid = i.indrelid "); - strcat(descbuf, " and i.indexrelid = c2.oid "); - strcat(descbuf, " ORDER BY c2.relname "); - if ((res = PSQLexec(pset, descbuf))) - { - nIndices = PQntuples(res); - if (nIndices > 0) - { - - /* - * Display the information - */ - - if (nIndices == 1) - fprintf(fout, "Index: "); - else - fprintf(fout, "Indices: "); - - /* next, print out the instances */ - for (i = 0; i < PQntuples(res); i++) - if (i == 0) - fprintf(fout, "%s\n", PQgetvalue(res, i, 0)); - else - fprintf(fout, " %s\n", PQgetvalue(res, i, 0)); - fprintf(fout, "\n"); - } - PQclear(res); - } - if (usePipe) - { - pclose(fout); - pqsignal(SIGPIPE, SIG_DFL); - } - return 0; - } - else - { - PQclear(res); - fprintf(stderr, "Couldn't find table %s!\n", table); - return -1; - } -} - -/* - * Get object comments - * - * Describe the columns in a database table. returns 0 if all went well - * - * - */ -static int -objectDescription(PsqlSettings *pset, char *object) -{ - char descbuf[512]; - PGresult *res; - int i; - bool success; - - /* Build the query */ - - while (isspace(*object)) - object++; - - /* - * if the object name is surrounded by double-quotes, then don't - * convert case - */ - if (*object == '"') - { - object++; - if (*(object + strlen(object) - 1) == '"') - *(object + strlen(object) - 1) = '\0'; - } - else - { -#ifdef MULTIBYTE - for (i = 0; object[i]; i += PQmblen(object + i)) -#else - for (i = 0; object[i]; i++) -#endif - if (isupper(object[i])) - object[i] = tolower(object[i]); - } - - descbuf[0] = '\0'; - if (strchr(object, '.') != NULL) - { - char table[NAMEDATALEN], - column[NAMEDATALEN]; - - StrNCpy(table, object, - ((strchr(object, '.') - object + 1) < NAMEDATALEN) ? - (strchr(object, '.') - object + 1) : NAMEDATALEN); - StrNCpy(column, strchr(object, '.') + 1, NAMEDATALEN); - strcat(descbuf, "SELECT DISTINCT description "); - strcat(descbuf, "FROM pg_class, pg_attribute, pg_description "); - strcat(descbuf, "WHERE pg_class.relname = '"); - strcat(descbuf, table); - strcat(descbuf, "' and "); - strcat(descbuf, "pg_class.oid = pg_attribute.attrelid and "); - strcat(descbuf, "pg_attribute.attname = '"); - strcat(descbuf, column); - strcat(descbuf, "' and "); - strcat(descbuf, " pg_attribute.oid = pg_description.objoid "); - if (!(res = PSQLexec(pset, descbuf))) - return -1; - } - else - { - strcat(descbuf, "SELECT DISTINCT description "); - strcat(descbuf, "FROM pg_class, pg_description "); - strcat(descbuf, "WHERE pg_class.relname ~ '^"); - strcat(descbuf, object); - strcat(descbuf, "'"); - strcat(descbuf, " and pg_class.oid = pg_description.objoid "); - if (!(res = PSQLexec(pset, descbuf))) - return -1; - else if (PQntuples(res) <= 0) - { - PQclear(res); - descbuf[0] = '\0'; - strcat(descbuf, "SELECT DISTINCT description "); - strcat(descbuf, "FROM pg_type, pg_description "); - strcat(descbuf, "WHERE pg_type.typname ~ '^"); - strcat(descbuf, object); - strcat(descbuf, "' and "); - strcat(descbuf, " pg_type.oid = pg_description.objoid "); - if (!(res = PSQLexec(pset, descbuf))) - return -1; - else if (PQntuples(res) <= 0) - { - PQclear(res); - descbuf[0] = '\0'; - strcat(descbuf, "SELECT DISTINCT description "); - strcat(descbuf, "FROM pg_proc, pg_description "); - strcat(descbuf, "WHERE pg_proc.proname ~ '^"); - strcat(descbuf, object); - strcat(descbuf, "'"); - strcat(descbuf, " and pg_proc.oid = pg_description.objoid "); - if (!(res = PSQLexec(pset, descbuf))) - return -1; - else if (PQntuples(res) <= 0) - { - PQclear(res); - descbuf[0] = '\0'; - strcat(descbuf, "SELECT DISTINCT description "); - strcat(descbuf, "FROM pg_operator, pg_description "); - strcat(descbuf, "WHERE pg_operator.oprname ~ '^"); - strcat(descbuf, object); - strcat(descbuf, "'"); - /* operator descriptions are attached to the proc */ - strcat(descbuf, " and RegprocToOid(pg_operator.oprcode) = pg_description.objoid "); - if (!(res = PSQLexec(pset, descbuf))) - return -1; - else if (PQntuples(res) <= 0) - { - PQclear(res); - descbuf[0] = '\0'; - strcat(descbuf, "SELECT DISTINCT description "); - strcat(descbuf, "FROM pg_aggregate, pg_description "); - strcat(descbuf, "WHERE pg_aggregate.aggname ~ '^"); - strcat(descbuf, object); - strcat(descbuf, "'"); - strcat(descbuf, " and pg_aggregate.oid = pg_description.objoid "); - if (!(res = PSQLexec(pset, descbuf))) - return -1; - else if (PQntuples(res) <= 0) - { - PQclear(res); - descbuf[0] = '\0'; - strcat(descbuf, "SELECT 'no description' as description "); - if (!(res = PSQLexec(pset, descbuf))) - return -1; - } - } - } - } - } - } - - PQclear(res); - - success = SendQuery(pset, descbuf, NULL, NULL); - - return 0; -} - -/* - * Basic routines to read a line of input - * - * All three routines will return a malloc'd string of indefinite size. - */ -typedef char *(*READ_ROUTINE) (char *prompt, FILE *source); - -/* - * gets_noreadline - * gets a line of interactive input (without using readline) - * - * the source is ignored - */ -static char * -gets_noreadline(char *prompt, FILE *source) -{ - fputs(prompt, stdout); - fflush(stdout); - return gets_fromFile(prompt, stdin); -} - -/* - * gets_readline - * gets a line of interactive input using readline library - * - * the source is ignored - */ -static char * -gets_readline(char *prompt, FILE *source) -{ - char *s; - -#ifdef USE_READLINE - s = readline(prompt); -#else - s = gets_noreadline(prompt, source); -#endif - fputc('\r', stdout); - fflush(stdout); - return s; -} - -/* - * gets_fromFile - * gets a line of noninteractive input from a file - * - * the prompt is ignored - */ -static char * -gets_fromFile(char *prompt, FILE *source) -{ - PQExpBufferData buffer; - char line[COPYBUFSIZ]; - - initPQExpBuffer(&buffer); - - while (fgets(line, COPYBUFSIZ, source) != NULL) - { - appendPQExpBufferStr(&buffer, line); - if (buffer.data[buffer.len-1] == '\n') - return buffer.data; - } - - if (buffer.len > 0) - return buffer.data; /* EOF after reading some bufferload(s) */ - - /* EOF, so return null */ - termPQExpBuffer(&buffer); - return NULL; -} - -/* - * SendQuery: send the query string to the backend. - * - * Return true if the query executed successfully, false otherwise. - * - * If not NULL, copy_in_stream and copy_out_stream are files to redirect - * copy in/out data to. - */ -static bool -SendQuery(PsqlSettings *pset, const char *query, - FILE *copy_in_stream, FILE *copy_out_stream) -{ - bool success = false; - PGresult *results; - PGnotify *notify; - - if (pset->singleStep) - fprintf(stdout, "\n**************************************" - "*****************************************\n"); - - if (pset->echoQuery || pset->singleStep) - { - fprintf(stderr, "QUERY: %s\n", query); - fflush(stderr); - } - if (pset->singleStep) - { - fprintf(stdout, "\n**************************************" - "*****************************************\n"); - fflush(stdout); - printf("\npress return to continue ..\n"); - gets_fromFile("", stdin); - } - results = PQexec(pset->db, query); - if (results == NULL) - { - fprintf(stderr, "%s", PQerrorMessage(pset->db)); - success = false; - } - else - { - switch (PQresultStatus(results)) - { - case PGRES_TUPLES_OK: - if (pset->gfname) - { - PsqlSettings settings_copy = *pset; - FILE *fp; - - settings_copy.queryFout = stdout; - fp = setFout(&settings_copy, pset->gfname); - if (!fp || fp == stdout) - { - success = false; - break; - } - PQprint(fp, - results, - &pset->opt); - if (settings_copy.pipe) - pclose(fp); - else - fclose(fp); - free(pset->gfname); - pset->gfname = NULL; - success = true; - break; - } - else - { - success = true; - PQprint(pset->queryFout, - results, - &(pset->opt)); - fflush(pset->queryFout); - } - break; - case PGRES_EMPTY_QUERY: - success = true; - break; - case PGRES_COMMAND_OK: - success = true; - if (!pset->quiet) - printf("%s\n", PQcmdStatus(results)); - break; - case PGRES_COPY_OUT: - if (copy_out_stream) - success = handleCopyOut(pset->db, copy_out_stream); - else - { - if (pset->queryFout == stdout && !pset->quiet) - printf("Copy command returns...\n"); - - success = handleCopyOut(pset->db, pset->queryFout); - } - break; - case PGRES_COPY_IN: - if (copy_in_stream) - success = handleCopyIn(pset->db, false, copy_in_stream); - else - success = handleCopyIn(pset->db, - cur_cmd_interactive && !pset->quiet, - cur_cmd_source); - break; - case PGRES_NONFATAL_ERROR: - case PGRES_FATAL_ERROR: - case PGRES_BAD_RESPONSE: - success = false; - fprintf(stderr, "%s", PQerrorMessage(pset->db)); - break; - } - - if (PQstatus(pset->db) == CONNECTION_BAD) - { - fprintf(stderr, - "We have lost the connection to the backend, so " - "further processing is impossible. " - "Terminating.\n"); - exit(2); /* we are out'ta here */ - } - /* check for asynchronous returns */ - while ((notify = PQnotifies(pset->db)) != NULL) - { - fprintf(stderr, - "ASYNC NOTIFY of '%s' from backend pid '%d' received\n", - notify->relname, notify->be_pid); - free(notify); - } - if (results) - PQclear(results); - } - return success; -} - - - -static void -editFile(char *fname) -{ - char *editorName; - char *sys; - - editorName = getenv("EDITOR"); - if (!editorName) - editorName = DEFAULT_EDITOR; - sys = malloc(strlen(editorName) + strlen(fname) + 32 + 1); - if (!sys) - { - perror("malloc"); - exit(1); - } - sprintf(sys, "exec '%s' '%s'", editorName, fname); - system(sys); - free(sys); -} - -static bool -toggle(PsqlSettings *pset, bool *sw, char *msg) -{ - *sw = !*sw; - if (!pset->quiet) - printf("turned %s %s\n", on(*sw), msg); - return *sw; -} - - - -static void -unescape(char *dest, const char *source) -{ - /*----------------------------------------------------------------------------- - Return as the string <dest> the value of string <source> with escape - sequences turned into the bytes they represent. - -----------------------------------------------------------------------------*/ - char *p; - bool esc; /* Last character we saw was the escape - * character (/) */ - - esc = false; /* Haven't seen escape character yet */ - for (p = (char *) source; *p; p++) - { - char c; /* Our output character */ - - if (esc) - { - switch (*p) - { - case 'n': - c = '\n'; - break; - case 'r': - c = '\r'; - break; - case 't': - c = '\t'; - break; - case 'f': - c = '\f'; - break; - case '\\': - c = '\\'; - break; - default: - c = *p; - } - esc = false; - } - else if (*p == '\\') - { - esc = true; - c = ' '; /* meaningless, but compiler doesn't know - * that */ - } - else - { - c = *p; - esc = false; - } - if (!esc) - *dest++ = c; - } - *dest = '\0'; /* Terminating null character */ -} - - - -static void -parse_slash_copy(const char *args, char *table, const int table_len, - char *file, const int file_len, - bool *from_p, bool *error_p) -{ - - char work_args[200]; - - /* - * A copy of the \copy command arguments, except that we modify it as - * we parse to suit our parsing needs. - */ - char *table_tok, - *fromto_tok; - - strncpy(work_args, args, sizeof(work_args)); - work_args[sizeof(work_args) - 1] = '\0'; - - *error_p = false; /* initial assumption */ - - table_tok = strtok(work_args, " "); - if (table_tok == NULL) - { - fprintf(stderr, "\\copy needs arguments.\n"); - *error_p = true; - } - else - { - strncpy(table, table_tok, table_len); - file[table_len - 1] = '\0'; - - fromto_tok = strtok(NULL, " "); - if (fromto_tok == NULL) - { - fprintf(stderr, "'FROM' or 'TO' must follow table name.\n"); - *error_p = true; - } - else - { - if (strcasecmp(fromto_tok, "from") == 0) - *from_p = true; - else if (strcasecmp(fromto_tok, "to") == 0) - *from_p = false; - else - { - fprintf(stderr, - "Unrecognized token found where " - "'FROM' or 'TO' expected: '%s'.\n", - fromto_tok); - *error_p = true; - } - if (!*error_p) - { - char *file_tok; - - file_tok = strtok(NULL, " "); - if (file_tok == NULL) - { - fprintf(stderr, "A file pathname must follow '%s'.\n", - fromto_tok); - *error_p = true; - } - else - { - strncpy(file, file_tok, file_len); - file[file_len - 1] = '\0'; - if (strtok(NULL, " ") != NULL) - { - fprintf(stderr, - "You have extra tokens after the filename.\n"); - *error_p = true; - } - } - } - } - } -} - - - -static void -do_copy(const char *args, PsqlSettings *pset) -{ - /*--------------------------------------------------------------------------- - Execute a \copy command (frontend copy). We have to open a file, then - submit a COPY query to the backend and either feed it data from the - file or route its response into the file. - - We do a text copy with default (tab) column delimiters. Some day, we - should do all the things a backend copy can do. - - ----------------------------------------------------------------------------*/ - char query[200]; - - /* The COPY command we send to the back end */ - bool from; - - /* The direction of the copy is from a file to a table. */ - char file[MAXPGPATH]; - - /* The pathname of the file from/to which we copy */ - char table[NAMEDATALEN]; - - /* The name of the table from/to which we copy */ - bool syntax_error; - - /* The \c command has invalid syntax */ - FILE *copystream; - - parse_slash_copy(args, table, sizeof(table), file, sizeof(file), - &from, &syntax_error); - - if (!syntax_error) - { - strcpy(query, "COPY "); - strcat(query, table); - - if (from) - strcat(query, " FROM stdin"); - else - strcat(query, " TO stdout"); - - if (from) -#ifndef __CYGWIN32__ - copystream = fopen(file, "r"); -#else - copystream = fopen(file, "rb"); -#endif - else -#ifndef __CYGWIN32__ - copystream = fopen(file, "w"); -#else - copystream = fopen(file, "wb"); -#endif - if (copystream == NULL) - fprintf(stderr, - "Unable to open file %s which to copy, errno = %s (%d).", - from ? "from" : "to", strerror(errno), errno); - else - { - bool success;/* The query succeeded at the backend */ - - success = SendQuery(pset, query, - from ? copystream : (FILE *) NULL, - !from ? copystream : (FILE *) NULL); - fclose(copystream); - if (!pset->quiet) - { - if (success) - printf("Successfully copied.\n"); - else - printf("Copy failed.\n"); - } - } - } -} - - -static void -do_connect(const char *new_dbname, - const char *new_user, - PsqlSettings *pset) -{ - if (!new_dbname) - fprintf(stderr, "\\connect must be followed by a database name\n"); - else if (new_user != NULL && pset->getPassword) - fprintf(stderr, "You can't specify a username when using passwords.\n"); - else - { - PGconn *olddb = pset->db; - const char *dbparam; - const char *userparam; - const char *pwparam; - - if (strcmp(new_dbname, "-") != 0) - dbparam = new_dbname; - else - dbparam = PQdb(olddb); - - if (new_user != NULL && strcmp(new_user, "-") != 0) - userparam = new_user; - else - userparam = PQuser(olddb); - - /* FIXME: if changing user, ought to prompt for a new password? */ - pwparam = PQpass(olddb); - -#ifdef MULTIBYTE - - /* - * PGCLIENTENCODING may be set by the previous connection. if a - * user does not explicitly set PGCLIENTENCODING, we should - * discard PGCLIENTENCODING so that libpq could get the backend - * encoding as the default PGCLIENTENCODING value. -- 1998/12/12 - * Tatsuo Ishii - */ - - if (!has_client_encoding) - { - static const char ev[] = "PGCLIENTENCODING="; - - putenv(ev); - } -#endif - - pset->db = PQsetdbLogin(PQhost(olddb), PQport(olddb), - NULL, NULL, dbparam, userparam, pwparam); - - if (!pset->quiet) - { - if (!new_user) - printf("connecting to new database: %s\n", dbparam); - else if (dbparam != new_dbname) - printf("connecting as new user: %s\n", new_user); - else - printf("connecting to new database: %s as user: %s\n", - dbparam, new_user); - } - - if (PQstatus(pset->db) == CONNECTION_BAD) - { - fprintf(stderr, "%s\n", PQerrorMessage(pset->db)); - fprintf(stderr, "Could not connect to new database. exiting\n"); - exit(2); - } - else - { - cancelConn = pset->db; /* redirect sigint's loving - * attentions */ - PQfinish(olddb); - free(pset->prompt); - pset->prompt = malloc(strlen(PQdb(pset->db)) + 10); - sprintf(pset->prompt, "%s%s", PQdb(pset->db), PROMPT); - } - } -} - - -static void -do_edit(const char *filename_arg, PQExpBuffer query_buf, int *status_p) -{ - int fd; - char fnametmp[64]; - char *fname; - int cc; - int ql = query_buf->len; - bool error; - char line[COPYBUFSIZ+1]; - - if (filename_arg) - { - fname = (char *) filename_arg; - error = false; - } - else - { -#ifndef WIN32 - sprintf(fnametmp, "/tmp/psql.%ld.%ld", - (long) geteuid(), (long) getpid()); -#else - GetTempFileName(".", "psql", 0, fnametmp); -#endif - fname = fnametmp; - unlink(fname); - if ((fd = open(fname, O_EXCL | O_CREAT | O_WRONLY, 0600)) < 0) - { - perror(fname); - error = true; - } - else - { - if (ql == 0 || query_buf->data[ql - 1] != '\n') - { - appendPQExpBufferChar(query_buf, '\n'); - ql++; - } - if (write(fd, query_buf->data, ql) != ql) - { - perror(fname); - close(fd); - unlink(fname); - error = true; - } - else - { - close(fd); - error = false; - } - } - } - - if (error) - *status_p = CMD_SKIP_LINE; - else - { - editFile(fname); - if ((fd = open(fname, O_RDONLY, 0)) < 0) - { - perror(fname); - *status_p = CMD_SKIP_LINE; - } - else - { - resetPQExpBuffer(query_buf); - while ((cc = (int) read(fd, line, COPYBUFSIZ)) > 0) - { - line[cc] = '\0'; - appendPQExpBufferStr(query_buf, line); - } - close(fd); - rightTrim(query_buf->data); - query_buf->len = strlen(query_buf->data); - *status_p = CMD_NEWEDIT; - } - if (!filename_arg) - unlink(fname); - } -} - - -static void -do_help(PsqlSettings *pset, const char *topic) -{ - - if (!topic) - { - char left_center_right; /* Which column we're displaying */ - int i; /* Index into QL_HELP[] */ - - printf("type \\h <cmd> where <cmd> is one of the following:\n"); - - left_center_right = 'L';/* Start with left column */ - i = 0; - while (QL_HELP[i].cmd != NULL) - { - switch (left_center_right) - { - case 'L': - printf(" %-25s", QL_HELP[i].cmd); - left_center_right = 'C'; - break; - case 'C': - printf("%-25s", QL_HELP[i].cmd); - left_center_right = 'R'; - break; - case 'R': - printf("%-25s\n", QL_HELP[i].cmd); - left_center_right = 'L'; - break; - } - i++; - } - if (left_center_right != 'L') - puts("\n"); - printf("type \\h * for a complete description of all commands\n"); - } - else - { - int i; /* Index into QL_HELP[] */ - bool help_found; /* We found the help he asked for */ - - int usePipe = 0; - char *pagerenv; - FILE *fout; - - if (strcmp(topic, "*") == 0 && - (pset->notty == 0) && - (pagerenv = getenv("PAGER")) && - (pagerenv[0] != '\0') && - (fout = popen(pagerenv, "w"))) - { - usePipe = 1; - pqsignal(SIGPIPE, SIG_IGN); - } - else - fout = stdout; - - help_found = false; /* Haven't found it yet */ - for (i = 0; QL_HELP[i].cmd; i++) - { - if (strcasecmp(QL_HELP[i].cmd, topic) == 0 || - strcmp(topic, "*") == 0) - { - help_found = true; - fprintf(fout, "Command: %s\n", QL_HELP[i].cmd); - fprintf(fout, "Description: %s\n", QL_HELP[i].help); - fprintf(fout, "Syntax:\n"); - fprintf(fout, "%s\n", QL_HELP[i].syntax); - fprintf(fout, "\n"); - } - } - - if (usePipe) - { - pclose(fout); - pqsignal(SIGPIPE, SIG_DFL); - } - - if (!help_found) - fprintf(stderr, "command not found, " - "try \\h with no arguments to see available help\n"); - } -} - - - -static void -do_shell(const char *command) -{ - - if (!command) - { - char *sys; - char *shellName; - - shellName = getenv("SHELL"); - if (shellName == NULL) - shellName = DEFAULT_SHELL; - sys = malloc(strlen(shellName) + 16); - if (!sys) - { - perror("malloc"); - exit(1); - } - sprintf(sys, "exec %s", shellName); - system(sys); - free(sys); - } - else - system(command); -} - - - -/*---------- - * HandleSlashCmds: - * - * Handles all the different commands that start with \ - * - * 'line' is the current input line (ie, the backslash command) - * 'query_buf' contains the query-so-far, which may be modified by - * execution of the backslash command (for example, \r clears it) - * - * query_buf can be NULL if there is no query-so-far. - * - * Returns a status code: - * 0 - send currently constructed query to backend (i.e. we got a \g) - * 1 - skip processing of this line, continue building up query - * 2 - terminate processing (i.e. we got a \q) - * 3 - new query supplied by edit - *---------- - */ -static int -HandleSlashCmds(PsqlSettings *pset, - char *line, - PQExpBuffer query_buf) -{ - int status = CMD_SKIP_LINE; - bool success; - char *cmd; - /* - * String: value of the slash command, less the slash and with escape - * sequences decoded. - */ - char *optarg; - /* - * Pointer inside the <cmd> string to the argument of the slash - * command, assuming it is a one-character slash command. If it's not - * a one-character command, this is meaningless. - */ - char *optarg2; - /* - * Pointer inside the <cmd> string to the argument of the slash - * command assuming it's not a one-character command. If it's a - * one-character command, this is meaningless. - */ - int blank_loc; - /* Offset within <cmd> of first blank */ - - cmd = malloc(strlen(line)); /* unescaping better not make string grow. */ - - unescape(cmd, line + 1); /* sets cmd string */ - - if (strlen(cmd) >= 1 && cmd[strlen(cmd) - 1] == ';') /* strip trailing ; */ - cmd[strlen(cmd) - 1] = '\0'; - - /* - * Originally, there were just single character commands. Now, we - * define some longer, friendly commands, but we have to keep the old - * single character commands too. \c used to be what \connect is now. - * Complicating matters is the fact that with the single-character - * commands, you can start the argument right after the single - * character, so "\copy" would mean "connect to database named 'opy'". - */ - - if (strlen(cmd) > 1) - optarg = cmd + 1 + strspn(cmd + 1, " \t"); - else - optarg = NULL; - - blank_loc = strcspn(cmd, " \t"); - if (blank_loc == 0 || !cmd[blank_loc]) - optarg2 = NULL; - else - optarg2 = cmd + blank_loc + strspn(cmd + blank_loc, " \t"); - - switch (cmd[0]) - { - case 'a': /* toggles to align fields on output */ - toggle(pset, &pset->opt.align, "field alignment"); - break; - - case 'C': /* define new caption */ - if (pset->opt.caption) - { - free(pset->opt.caption); - pset->opt.caption = NULL; - } - if (optarg && !(pset->opt.caption = strdup(optarg))) - { - perror("malloc"); - exit(CMD_TERMINATE); - } - break; - - case 'c': - { - if (strncmp(cmd, "copy ", strlen("copy ")) == 0 || - strncmp(cmd, "copy ", strlen("copy ")) == 0) - do_copy(optarg2, pset); - else if (strcmp(cmd, "copy") == 0) - { - fprintf(stderr, "See \\? for help\n"); - break; - } - else if (strncmp(cmd, "connect ", strlen("connect ")) == 0 || - strcmp(cmd, "connect") == 0 /* issue error message */ ) - { - char *optarg3 = NULL; - int blank_loc2; - - if (optarg2) - { - blank_loc2 = strcspn(optarg2, " \t"); - if (blank_loc2 == 0 || *(optarg2 + blank_loc2) == '\0') - optarg3 = NULL; - else - { - optarg3 = optarg2 + blank_loc2 + - strspn(optarg2 + blank_loc2, " \t"); - *(optarg2 + blank_loc2) = '\0'; - } - } - do_connect(optarg2, optarg3, pset); - } - else - { - char *optarg3 = NULL; - int blank_loc2; - - if (optarg) - { - blank_loc2 = strcspn(optarg, " \t"); - if (blank_loc2 == 0 || *(optarg + blank_loc2) == '\0') - optarg3 = NULL; - else - { - optarg3 = optarg + blank_loc2 + - strspn(optarg + blank_loc2, " \t"); - *(optarg + blank_loc2) = '\0'; - } - } - do_connect(optarg, optarg3, pset); - } - } - break; - - case 'd': /* \d describe database information */ - - /* - * if the optarg2 name is surrounded by double-quotes, then - * don't convert case - */ - if (optarg2) - { - if (*optarg2 == '"') - { - optarg2++; - if (*(optarg2 + strlen(optarg2) - 1) == '"') - *(optarg2 + strlen(optarg2) - 1) = '\0'; - } - else - { - int i; - -#ifdef MULTIBYTE - for (i = 0; optarg2[i]; i += PQmblen(optarg2 + i)) -#else - for (i = 0; optarg2[i]; i++) -#endif - if (isupper(optarg2[i])) - optarg2[i] = tolower(optarg2[i]); - } - } - -#ifdef TIOCGWINSZ - if (pset->notty == 0 && - (ioctl(fileno(stdout), TIOCGWINSZ, &screen_size) == -1 || - screen_size.ws_col == 0 || - screen_size.ws_row == 0)) - { -#endif - screen_size.ws_row = 24; - screen_size.ws_col = 80; -#ifdef TIOCGWINSZ - } -#endif - if (strncmp(cmd, "da", 2) == 0) - { - char descbuf[4096]; - - /* aggregates */ - descbuf[0] = '\0'; - strcat(descbuf, "SELECT a.aggname AS aggname, "); - strcat(descbuf, " t.typname AS type, "); - strcat(descbuf, " obj_description(a.oid) as description "); - strcat(descbuf, "FROM pg_aggregate a, pg_type t "); - strcat(descbuf, "WHERE a.aggbasetype = t.oid "); - if (optarg2) - { - strcat(descbuf, "AND a.aggname ~ '^"); - strcat(descbuf, optarg2); - strcat(descbuf, "' "); - } - strcat(descbuf, "UNION "); - strcat(descbuf, "SELECT a.aggname AS aggname, "); - strcat(descbuf, " 'all types' as type, "); - strcat(descbuf, " obj_description(a.oid) as description "); - strcat(descbuf, "FROM pg_aggregate a "); - strcat(descbuf, "WHERE a.aggbasetype = 0 "); - if (optarg2) - { - strcat(descbuf, "AND a.aggname ~ '^"); - strcat(descbuf, optarg2); - strcat(descbuf, "' "); - } - strcat(descbuf, "ORDER BY aggname, type;"); - success = SendQuery(pset, descbuf, NULL, NULL); - } - else if (strncmp(cmd, "dd", 2) == 0) - /* descriptions */ - objectDescription(pset, optarg + 1); - else if (strncmp(cmd, "df", 2) == 0) - { - char descbuf[4096]; - - /* functions/procedures */ - - /* - * we skip in/out funcs by excluding functions that take - * some arguments, but have no types defined for those - * arguments - */ - descbuf[0] = '\0'; - strcat(descbuf, "SELECT t.typname as result, "); - strcat(descbuf, " p.proname as function, "); - if (screen_size.ws_col <= 80) - strcat(descbuf, " substr(oid8types(p.proargtypes),1,14) as arguments, "); - else - strcat(descbuf, " oid8types(p.proargtypes) as arguments, "); - if (screen_size.ws_col <= 80) - strcat(descbuf, " substr(obj_description(p.oid),1,34) as description "); - else - strcat(descbuf, " obj_description(p.oid) as description "); - strcat(descbuf, "FROM pg_proc p, pg_type t "); - strcat(descbuf, "WHERE p.prorettype = t.oid and "); - strcat(descbuf, "(pronargs = 0 or oid8types(p.proargtypes) != '') "); - if (optarg2) - { - strcat(descbuf, "AND p.proname ~ '^"); - strcat(descbuf, optarg2); - strcat(descbuf, "' "); - } - strcat(descbuf, "ORDER BY result, function, arguments;"); - success = SendQuery(pset, descbuf, NULL, NULL); - } - else if (strncmp(cmd, "di", 2) == 0) - /* only indices */ - tableList(pset, false, 'i', false); - else if (strncmp(cmd, "do", 2) == 0) - { - char descbuf[4096]; - - /* operators */ - descbuf[0] = '\0'; - strcat(descbuf, "SELECT o.oprname AS op, "); - strcat(descbuf, " t1.typname AS left_arg, "); - strcat(descbuf, " t2.typname AS right_arg, "); - strcat(descbuf, " t0.typname AS result, "); - if (screen_size.ws_col <= 80) - strcat(descbuf, " substr(obj_description(p.oid),1,41) as description "); - else - strcat(descbuf, " obj_description(p.oid) as description "); - strcat(descbuf, "FROM pg_proc p, pg_type t0, "); - strcat(descbuf, " pg_type t1, pg_type t2, "); - strcat(descbuf, " pg_operator o "); - strcat(descbuf, "WHERE p.prorettype = t0.oid AND "); - strcat(descbuf, " RegprocToOid(o.oprcode) = p.oid AND "); - strcat(descbuf, " p.pronargs = 2 AND "); - strcat(descbuf, " o.oprleft = t1.oid AND "); - strcat(descbuf, " o.oprright = t2.oid "); - if (optarg2) - { - strcat(descbuf, "AND o.oprname ~ '^"); - strcat(descbuf, optarg2); - strcat(descbuf, "' "); - } - strcat(descbuf, "UNION "); - strcat(descbuf, "SELECT o.oprname as op, "); - strcat(descbuf, " ''::name AS left_arg, "); - strcat(descbuf, " t1.typname AS right_arg, "); - strcat(descbuf, " t0.typname AS result, "); - if (screen_size.ws_col <= 80) - strcat(descbuf, " substr(obj_description(p.oid),1,41) as description "); - else - strcat(descbuf, " obj_description(p.oid) as description "); - strcat(descbuf, "FROM pg_operator o, pg_proc p, pg_type t0, pg_type t1 "); - strcat(descbuf, "WHERE RegprocToOid(o.oprcode) = p.oid AND "); - strcat(descbuf, " o.oprresult = t0.oid AND "); - strcat(descbuf, " o.oprkind = 'l' AND "); - strcat(descbuf, " o.oprright = t1.oid "); - if (optarg2) - { - strcat(descbuf, "AND o.oprname ~ '^"); - strcat(descbuf, optarg2); - strcat(descbuf, "' "); - } - strcat(descbuf, "UNION "); - strcat(descbuf, "SELECT o.oprname as op, "); - strcat(descbuf, " t1.typname AS left_arg, "); - strcat(descbuf, " ''::name AS right_arg, "); - strcat(descbuf, " t0.typname AS result, "); - if (screen_size.ws_col <= 80) - strcat(descbuf, " substr(obj_description(p.oid),1,41) as description "); - else - strcat(descbuf, " obj_description(p.oid) as description "); - strcat(descbuf, "FROM pg_operator o, pg_proc p, pg_type t0, pg_type t1 "); - strcat(descbuf, "WHERE RegprocToOid(o.oprcode) = p.oid AND "); - strcat(descbuf, " o.oprresult = t0.oid AND "); - strcat(descbuf, " o.oprkind = 'r' AND "); - strcat(descbuf, " o.oprleft = t1.oid "); - if (optarg2) - { - strcat(descbuf, "AND o.oprname ~ '^"); - strcat(descbuf, optarg2); - strcat(descbuf, "' "); - } - strcat(descbuf, "ORDER BY op, left_arg, right_arg, result;"); - success = SendQuery(pset, descbuf, NULL, NULL); - } - else if (strncmp(cmd, "ds", 2) == 0) - /* only sequences */ - tableList(pset, false, 'S', false); - else if (strncmp(cmd, "dS", 2) == 0) - /* system tables */ - tableList(pset, false, 'b', true); - else if (strncmp(cmd, "dt", 2) == 0) - /* only tables */ - tableList(pset, false, 't', false); - else if (strncmp(cmd, "dT", 2) == 0) - { - char descbuf[4096]; - - /* types */ - descbuf[0] = '\0'; - strcat(descbuf, "SELECT typname AS type, "); - strcat(descbuf, " obj_description(oid) as description "); - strcat(descbuf, "FROM pg_type "); - strcat(descbuf, "WHERE typrelid = 0 AND "); - strcat(descbuf, " typname !~ '^_.*' "); - strcat(descbuf, "ORDER BY type;"); - if (optarg2) - { - strcat(descbuf, "AND typname ~ '^"); - strcat(descbuf, optarg2); - strcat(descbuf, "' "); - } - success = SendQuery(pset, descbuf, NULL, NULL); - } - else if (!optarg) - /* show tables, sequences and indices */ - tableList(pset, false, 'b', false); - else if (strcmp(optarg, "*") == 0) - { /* show everything */ - if (tableList(pset, false, 'b', false) == 0) - tableList(pset, true, 'b', false); - } - else if (strncmp(cmd, "d ", 2) == 0) - /* describe the specified table */ - tableDesc(pset, optarg, NULL); - else - slashUsage(pset); - break; - - case 'e': /* edit */ - if (query_buf) - do_edit(optarg, query_buf, &status); - break; - - case 'E': - { - FILE *fd; - static char *lastfile; - struct stat st, - st2; - - if (optarg) - { - if (lastfile) - free(lastfile); - lastfile = malloc(strlen(optarg + 1)); - if (!lastfile) - { - perror("malloc"); - exit(CMD_TERMINATE); - } - strcpy(lastfile, optarg); - } - else if (!lastfile) - { - fprintf(stderr, "\\r must be followed by a file name initially\n"); - break; - } - stat(lastfile, &st); - editFile(lastfile); -#ifndef __CYGWIN32__ - if ((stat(lastfile, &st2) == -1) || ((fd = fopen(lastfile, "r")) == NULL)) -#else - if ((stat(lastfile, &st2) == -1) || ((fd = fopen(lastfile, "rb")) == NULL)) -#endif - { - perror(lastfile); - break; - } - if (st2.st_mtime == st.st_mtime) - { - if (!pset->quiet) - fprintf(stderr, "warning: %s not modified. query not executed\n", lastfile); - fclose(fd); - break; - } - MainLoop(pset, fd); - fclose(fd); - break; - } - - case 'f': - { - char *fs = DEFAULT_FIELD_SEP; - - if (optarg) - fs = optarg; - /* handle \f \{space} */ - if (optarg && !*optarg && strlen(cmd) > 1) - { - int i; - - /* line and cmd match until the first blank space */ - for (i = 2; isspace(line[i]); i++) - ; - fs = cmd + i - 1; - } - if (pset->opt.fieldSep) - free(pset->opt.fieldSep); - if (!(pset->opt.fieldSep = strdup(fs))) - { - perror("malloc"); - exit(CMD_TERMINATE); - } - if (!pset->quiet) - printf("field separator changed to '%s'\n", pset->opt.fieldSep); - break; - } - case 'g': /* \g means send query */ - if (!optarg) - pset->gfname = NULL; - else if (!(pset->gfname = strdup(optarg))) - { - perror("malloc"); - exit(CMD_TERMINATE); - } - status = CMD_SEND; - break; - - case 'h': /* help */ - { - do_help(pset, optarg); - break; - } - - case 'i': /* \i is include file */ - { - FILE *fd; - - if (!optarg) - { - fprintf(stderr, "\\i must be followed by a file name\n"); - break; - } -#ifndef __CYGWIN32__ - if ((fd = fopen(optarg, "r")) == NULL) -#else - if ((fd = fopen(optarg, "rb")) == NULL) -#endif - { - fprintf(stderr, "file named %s could not be opened\n", optarg); - break; - } - MainLoop(pset, fd); - fclose(fd); - break; - } - - case 'H': - if (toggle(pset, &pset->opt.html3, "HTML3.0 tabular output")) - pset->opt.standard = 0; - break; - - case 'l': /* \l is list database */ - listAllDbs(pset); - break; - - case 'm': /* monitor like type-setting */ - if (toggle(pset, &pset->opt.standard, "standard SQL separaters and padding")) - { - pset->opt.html3 = pset->opt.expanded = 0; - pset->opt.align = pset->opt.header = 1; - if (pset->opt.fieldSep) - free(pset->opt.fieldSep); - pset->opt.fieldSep = strdup("|"); - if (!pset->quiet) - printf("field separator changed to '%s'\n", pset->opt.fieldSep); - } - else - { - if (pset->opt.fieldSep) - free(pset->opt.fieldSep); - pset->opt.fieldSep = strdup(DEFAULT_FIELD_SEP); - if (!pset->quiet) - printf("field separator changed to '%s'\n", pset->opt.fieldSep); - } - break; - - case 'o': - setFout(pset, optarg); - break; - - case 'p': - if (query_buf && query_buf->len > 0) - { - fputs(query_buf->data, stdout); - fputc('\n', stdout); - } - break; - - case 'q': /* \q is quit */ - status = CMD_TERMINATE; - break; - - case 'r': /* reset(clear) the buffer */ - if (query_buf) - { - resetPQExpBuffer(query_buf); - if (!pset->quiet) - printf("buffer reset(cleared)\n"); - } - break; - - case 's': /* \s is save history to a file */ - if (!optarg) - optarg = "/dev/tty"; -#ifdef USE_HISTORY - if (write_history(optarg) != 0) - fprintf(stderr, "cannot write history to %s\n", optarg); -#endif - break; - - case 't': /* toggle headers */ - toggle(pset, &pset->opt.header, "output headings and row count"); - break; - - case 'T': /* define html <table ...> option */ - if (pset->opt.tableOpt) - free(pset->opt.tableOpt); - if (!optarg) - pset->opt.tableOpt = NULL; - else if (!(pset->opt.tableOpt = strdup(optarg))) - { - perror("malloc"); - exit(CMD_TERMINATE); - } - break; - - case 'w': - { - FILE *fd; - - if (!optarg) - { - fprintf(stderr, "\\w must be followed by a file name\n"); - break; - } -#ifndef __CYGWIN32__ - if ((fd = fopen(optarg, "w")) == NULL) -#else - if ((fd = fopen(optarg, "w")) == NULL) -#endif - { - fprintf(stderr, "file named %s could not be opened\n", optarg); - break; - } - if (query_buf) - fputs(query_buf->data, fd); - fputc('\n', fd); - fclose(fd); - break; - } - - case 'x': - toggle(pset, &pset->opt.expanded, "expanded table representation"); - break; - - case 'z': /* list table rights (grant/revoke) */ - rightsList(pset); - break; - - case '!': - do_shell(optarg); - break; - default: - - case '?': /* \? is help */ - slashUsage(pset); - break; - } - free(cmd); - return status; -} - -/* MainLoop() - * Main processing loop for reading lines of input - * and sending them to the backend. - * - * This loop is re-entrant. May be called by \i command - * which reads input from a file. - * db_ptr must be initialized and set. - */ - -static int -MainLoop(PsqlSettings *pset, FILE *source) -{ - PQExpBuffer query_buf; /* buffer for query being accumulated */ - char *line; /* current line of input */ - char *xcomment; /* start of extended comment */ - int len; /* length of the line */ - int successResult = 1; - int slashCmdStatus = CMD_SEND; - - /*-------------------------------------------------------------- - * slashCmdStatus can be: - * CMD_UNKNOWN - send currently constructed query to backend - * (i.e. we got a \g) - * CMD_SEND - send currently constructed query to backend - * (i.e. we got a \g) - * CMD_SKIP_LINE - skip processing of this line, continue building - * up query - * CMD_TERMINATE - terminate processing of this query entirely - * CMD_NEWEDIT - new query supplied by edit - *--------------------------------------------------------------- - */ - - bool querySent = false; - READ_ROUTINE GetNextLine; - bool eof = false; /* end of our command input? */ - bool success; - char in_quote; /* == 0 for no in_quote */ - bool was_bslash; /* backslash */ - int paren_level; - char *query_start; - - /* Stack the prior command source */ - FILE *prev_cmd_source = cur_cmd_source; - bool prev_cmd_interactive = cur_cmd_interactive; - - /* Establish new source */ - cur_cmd_source = source; - cur_cmd_interactive = ((source == stdin) && !pset->notty); - - if (cur_cmd_interactive) - { - if (pset->prompt) - free(pset->prompt); - pset->prompt = malloc(strlen(PQdb(pset->db)) + strlen(PROMPT) + 1); - if (pset->quiet) - pset->prompt[0] = '\0'; - else - sprintf(pset->prompt, "%s%s", PQdb(pset->db), PROMPT); - if (pset->useReadline) - { -#ifdef USE_HISTORY - using_history(); -#endif - GetNextLine = gets_readline; - } - else - GetNextLine = gets_noreadline; - } - else - GetNextLine = gets_fromFile; - - query_buf = createPQExpBuffer(); - xcomment = NULL; - in_quote = false; - paren_level = 0; - slashCmdStatus = CMD_UNKNOWN; /* set default */ - - /* main loop to get queries and execute them */ - while (!eof) - { - if (slashCmdStatus == CMD_NEWEDIT) - { - /* - * just returned from editing the line? then just copy to the - * input buffer - */ - line = strdup(query_buf->data); - resetPQExpBuffer(query_buf); - /* reset parsing state since we are rescanning whole query */ - xcomment = NULL; - in_quote = false; - paren_level = 0; - } - else - { - /* - * otherwise, set interactive prompt if necessary - * and get another line - */ - if (cur_cmd_interactive && !pset->quiet) - { - if (in_quote && in_quote == PROMPT_SINGLEQUOTE) - pset->prompt[strlen(pset->prompt) - 3] = PROMPT_SINGLEQUOTE; - else if (in_quote && in_quote == PROMPT_DOUBLEQUOTE) - pset->prompt[strlen(pset->prompt) - 3] = PROMPT_DOUBLEQUOTE; - else if (xcomment != NULL) - pset->prompt[strlen(pset->prompt) - 3] = PROMPT_COMMENT; - else if (query_buf->len > 0 && !querySent) - pset->prompt[strlen(pset->prompt) - 3] = PROMPT_CONTINUE; - else - pset->prompt[strlen(pset->prompt) - 3] = PROMPT_READY; - } - line = GetNextLine(pset->prompt, source); -#ifdef USE_HISTORY - if (cur_cmd_interactive && pset->useReadline && line != NULL) - add_history(line); /* save non-empty lines in history */ -#endif - } - - /* - * query_buf holds query already accumulated. line is the malloc'd - * new line of input (note it must be freed before looping around!) - * query_start is the next command start location within the line. - */ - if (line == NULL || (!cur_cmd_interactive && *line == '\0')) - { /* No more input. Time to quit, or \i - * done */ - if (!pset->quiet) - printf("EOF\n");/* Goes on prompt line */ - eof = true; - continue; - } - - /* not currently inside an extended comment? */ - if (xcomment == NULL) - { - query_start = line; - } - else - { - /* otherwise, continue the extended comment... */ - query_start = line; - xcomment = line; - } - - /* remove whitespaces on the right, incl. \n's */ - line = rightTrim(line); - - /* echo back if input is from file */ - if (!cur_cmd_interactive && !pset->singleStep && !pset->quiet) - fprintf(stderr, "%s\n", line); - - slashCmdStatus = CMD_UNKNOWN; - /* nothing on line after trimming? then ignore */ - if (line[0] == '\0') - { - free(line); - continue; - } - - len = strlen(line); - - if (pset->singleLineMode) - { - success = SendQuery(pset, line, NULL, NULL); - successResult &= success; - querySent = true; - } - else - { - int i; - - /* - * Parse line, looking for command separators. - * - * The current character is at line[i], the prior character at - * line[i - prevlen], the next character at line[i + thislen]. - */ -#ifdef MULTIBYTE - int prevlen = 0; - int thislen = (len > 0) ? PQmblen(line) : 0; - -#define ADVANCE_I (prevlen = thislen, i += thislen, thislen = PQmblen(line+i)) -#else -#define prevlen 1 -#define thislen 1 -#define ADVANCE_I (i++) -#endif - - was_bslash = false; - for (i = 0; i < len; ADVANCE_I) - { - if (line[i] == '\\' && !in_quote) - { - /* backslash command. Copy whatever is before \ to - * query_buf. - */ - char hold_char = line[i]; - - line[i] = '\0'; - if (query_start[0] != '\0') - { - if (query_buf->len > 0) - appendPQExpBufferChar(query_buf, '\n'); - appendPQExpBufferStr(query_buf, query_start); - } - line[i] = hold_char; - query_start = line + i; - break; /* go handle backslash command */ - } - - if (querySent && - isascii((unsigned char) (line[i])) && - !isspace(line[i])) - { - resetPQExpBuffer(query_buf); - querySent = false; - } - - if (was_bslash) - was_bslash = false; - else if (i > 0 && line[i - prevlen] == '\\') - was_bslash = true; - - /* inside a quote? */ - if (in_quote && (line[i] != in_quote || was_bslash)) - /* do nothing */ ; - /* inside an extended comment? */ - else if (xcomment != NULL) - { - if (line[i] == '*' && line[i + thislen] == '/') - { - xcomment = NULL; - ADVANCE_I; - } - } - /* start of extended comment? */ - else if (line[i] == '/' && line[i + thislen] == '*') - { - xcomment = line + i; - ADVANCE_I; - } - /* single-line comment? truncate line */ - else if ((line[i] == '-' && line[i + thislen] == '-') || - (line[i] == '/' && line[i + thislen] == '/')) - { - /* print comment at top of query */ - if (pset->singleStep) - fprintf(stdout, "%s\n", line + i); - line[i] = '\0'; /* remove comment */ - break; - } - else if (in_quote && line[i] == in_quote) - in_quote = false; - else if (!in_quote && (line[i] == '\'' || line[i] == '"')) - in_quote = line[i]; - /* semi-colon? then send query now */ - else if (!paren_level && line[i] == ';') - { - char hold_char = line[i + thislen]; - - line[i + thislen] = '\0'; - if (query_start[0] != '\0') - { - if (query_buf->len > 0) - appendPQExpBufferChar(query_buf, '\n'); - appendPQExpBufferStr(query_buf, query_start); - } - success = SendQuery(pset, query_buf->data, NULL, NULL); - successResult &= success; - line[i + thislen] = hold_char; - query_start = line + i + thislen; - /* sometimes, people do ';\g', don't execute twice */ - if (*query_start == '\\' && - *(query_start + 1) == 'g') - query_start += 2; - querySent = true; - } - else if (line[i] == '(') - { - paren_level++; - - } - else if (paren_level && line[i] == ')') - paren_level--; - } - } - - /* nothing on line after trimming? then ignore */ - if (line[0] == '\0') - { - free(line); - continue; - } - - if (!in_quote && query_start[0] == '\\') - { - /* loop to handle \p\g and other backslash combinations */ - while (query_start[0] != '\0') - { - char hold_char; - -#ifndef WIN32 - /* I believe \w \dos\system\x would cause a problem */ - /* do we have '\p\g' or '\p \g' ? */ - if (strlen(query_start) > 2 && - query_start[2 + strspn(query_start + 2, " \t")] == '\\') - { - hold_char = query_start[2 + strspn(query_start + 2, " \t")]; - query_start[2 + strspn(query_start + 2, " \t")] = '\0'; - } - else -/* spread over #endif */ -#endif - hold_char = '\0'; - - slashCmdStatus = HandleSlashCmds(pset, - query_start, - query_buf); - - if (slashCmdStatus == CMD_SKIP_LINE && !hold_char) - { - if (query_buf->len == 0) - paren_level = 0; - break; - } - if (slashCmdStatus == CMD_TERMINATE) - break; - - query_start += strlen(query_start); - if (hold_char) - query_start[0] = hold_char; - } - free(line); - if (slashCmdStatus == CMD_TERMINATE) - break; /* They did \q, leave the loop */ - } - else - { - if (query_start[0] != '\0') - { - querySent = false; - if (query_buf->len > 0) - appendPQExpBufferChar(query_buf, '\n'); - appendPQExpBufferStr(query_buf, query_start); - } - free(line); - } - - /* had a backslash-g? force the query to be sent */ - if (slashCmdStatus == CMD_SEND) - { - success = SendQuery(pset, query_buf->data, NULL, NULL); - successResult &= success; - xcomment = NULL; - in_quote = false; - paren_level = 0; - querySent = true; - } - } /* while */ - - destroyPQExpBuffer(query_buf); - - cur_cmd_source = prev_cmd_source; - cur_cmd_interactive = prev_cmd_interactive; - - return successResult; -} /* MainLoop() */ - -int -main(int argc, char **argv) -{ - extern char *optarg; - extern int optind; - - char *dbname = NULL; - char *host = NULL; - char *port = NULL; - char *qfilename = NULL; - - PsqlSettings settings; - - char *singleQuery = NULL; - - bool listDatabases = 0; - int successResult = 1; - bool singleSlashCmd = 0; - int c; - - char *home = NULL; /* Used to store $HOME */ - char *version = NULL; /* PostgreSQL version */ - - /* - * initialize cur_cmd_source in case we do not use MainLoop ... some - * systems fail if we try to use a static initializer for this :-( - */ - cur_cmd_source = stdin; - cur_cmd_interactive = false; - - MemSet(&settings, 0, sizeof settings); - settings.opt.align = 1; - settings.opt.header = 1; - settings.queryFout = stdout; - settings.opt.fieldSep = strdup(DEFAULT_FIELD_SEP); - settings.opt.pager = 1; - if (!isatty(0) || !isatty(1)) - { - /* Noninteractive defaults */ - settings.notty = 1; - } - else - { - /* Interactive defaults */ - pqsignal(SIGINT, handle_sigint); /* control-C => cancel */ -#ifdef USE_READLINE - settings.useReadline = 1; - { - /* Set the application name, used for parsing .inputrc */ - char *progname = strrchr(argv[0], SEP_CHAR); - rl_readline_name = (progname ? progname+1 : argv[0]); - } -#endif - } -#ifdef PSQL_ALWAYS_GET_PASSWORDS - settings.getPassword = 1; -#else - settings.getPassword = 0; -#endif - -#ifdef MULTIBYTE - has_client_encoding = getenv("PGCLIENTENCODING"); -#endif - - while ((c = getopt(argc, argv, "Aa:c:d:eEf:F:lh:Hnso:p:qStT:ux")) != EOF) - { - switch (c) - { - case 'A': - settings.opt.align = 0; - break; - case 'a': -#ifdef NOT_USED /* this no longer does anything */ - fe_setauthsvc(optarg, errbuf); -#endif - break; - case 'c': - singleQuery = strdup(optarg); - if (singleQuery[0] == '\\') - singleSlashCmd = 1; - break; - case 'd': - dbname = optarg; - break; - case 'e': - settings.echoQuery = 1; - break; - case 'E': - settings.echoAllQueries = 1; - settings.echoQuery = 1; - break; - case 'f': - qfilename = optarg; - break; - case 'F': - settings.opt.fieldSep = strdup(optarg); - break; - case 'l': - listDatabases = 1; - break; - case 'h': - host = optarg; - break; - case 'H': - settings.opt.html3 = 1; - break; - case 'n': - settings.useReadline = 0; - break; - case 'o': - setFout(&settings, optarg); - break; - case 'p': - port = optarg; - break; - case 'q': - settings.quiet = 1; - break; - case 's': - settings.singleStep = 1; - break; - case 'S': - settings.singleLineMode = 1; - break; - case 't': - settings.opt.header = 0; - break; - case 'T': - settings.opt.tableOpt = strdup(optarg); - break; - case 'u': - settings.getPassword = 1; - break; - case 'x': - settings.opt.expanded = 1; - break; - default: - usage(argv[0]); - break; - } - } - /* if we still have an argument, use it as the database name */ - if (argc - optind == 1) - dbname = argv[optind]; - - if (listDatabases) - dbname = "template1"; - - if (settings.getPassword) - { - char username[100]; - char password[100]; - - prompt_for_password(username, password); - - settings.db = PQsetdbLogin(host, port, NULL, NULL, dbname, - username, password); - } - else - settings.db = PQsetdb(host, port, NULL, NULL, dbname); - - dbname = PQdb(settings.db); - - if (PQstatus(settings.db) == CONNECTION_BAD) - { - fprintf(stderr, "Connection to database '%s' failed.\n", dbname); - fprintf(stderr, "%s\n", PQerrorMessage(settings.db)); - PQfinish(settings.db); - exit(1); - } - - cancelConn = settings.db; /* enable SIGINT to send cancel */ - - if (listDatabases) - exit(listAllDbs(&settings)); - if (!settings.quiet && !settings.notty && !singleQuery && !qfilename) - { - printf("Welcome to the POSTGRESQL interactive sql monitor:\n"); - printf(" Please read the file COPYRIGHT for copyright terms " - "of POSTGRESQL\n"); - - if ((version = selectVersion(&settings)) != NULL) - printf("[%s]\n", version); - - printf("\n"); - printf(" type \\? for help on slash commands\n"); - printf(" type \\q to quit\n"); - printf(" type \\g or terminate with semicolon to execute query\n"); - printf(" You are currently connected to the database: %s\n\n", dbname); - } - - /* - * 20.06.97 ACRM See if we've got a /etc/psqlrc or .psqlrc file - */ - if (!access("/etc/psqlrc", R_OK)) - HandleSlashCmds(&settings, "\\i /etc/psqlrc", NULL); - if ((home = getenv("HOME")) != NULL) - { - char *psqlrc = NULL, - *line = NULL; - - if ((psqlrc = (char *) malloc(strlen(home) + 10)) != NULL) - { - sprintf(psqlrc, "%s/.psqlrc", home); - if (!access(psqlrc, R_OK)) - { - if ((line = (char *) malloc(strlen(psqlrc) + 5)) != NULL) - { - sprintf(line, "\\i %s", psqlrc); - HandleSlashCmds(&settings, line, NULL); - free(line); - } - } - free(psqlrc); - } - } - /* End of check for psqlrc files */ - - if (qfilename || singleSlashCmd) - { - - /* - * read in a file full of queries instead of reading in queries - * interactively - */ - char *line; - - if (singleSlashCmd) - { - /* Not really a query, but "Do what I mean, not what I say." */ - line = singleQuery; - } - else - { - line = malloc(strlen(qfilename) + 5); - sprintf(line, "\\i %s", qfilename); - } - HandleSlashCmds(&settings, line, NULL); - free(line); - } - else - { - if (singleQuery) - successResult = SendQuery(&settings, singleQuery, NULL, NULL); - else - successResult = MainLoop(&settings, stdin); - } - - PQfinish(settings.db); - free(settings.opt.fieldSep); - if (settings.prompt) - free(settings.prompt); - - return !successResult; -} - -static bool -handleCopyOut(PGconn *conn, FILE *copystream) -{ - bool copydone; - char copybuf[COPYBUFSIZ]; - int ret; - - copydone = false; /* Can't be done; haven't started. */ - - while (!copydone) - { - ret = PQgetline(conn, copybuf, COPYBUFSIZ); - - if (copybuf[0] == '\\' && - copybuf[1] == '.' && - copybuf[2] == '\0') - { - copydone = true; /* don't print this... */ - } - else - { - fputs(copybuf, copystream); - switch (ret) - { - case EOF: - copydone = true; - /* FALLTHROUGH */ - case 0: - fputc('\n', copystream); - break; - case 1: - break; - } - } - } - fflush(copystream); - return !PQendcopy(conn); -} - - - -static bool -handleCopyIn(PGconn *conn, const bool mustprompt, FILE *copystream) -{ - bool copydone = false; - bool firstload; - bool linedone; - char copybuf[COPYBUFSIZ]; - char *s; - int buflen; - int c = 0; - - if (mustprompt) - { - fputs("Enter info followed by a newline\n", stdout); - fputs("End with a backslash and a " - "period on a line by itself.\n", stdout); - } - while (!copydone) - { /* for each input line ... */ - if (mustprompt) - { - fputs(">> ", stdout); - fflush(stdout); - } - firstload = true; - linedone = false; - while (!linedone) - { /* for each buffer ... */ - s = copybuf; - for (buflen = COPYBUFSIZ; buflen > 1; buflen--) - { - c = getc(copystream); - if (c == '\n' || c == EOF) - { - linedone = true; - break; - } - *s++ = c; - } - *s = '\0'; - if (c == EOF) - { - PQputline(conn, "\\."); - copydone = true; - break; - } - PQputline(conn, copybuf); - if (firstload) - { - if (!strcmp(copybuf, "\\.")) - copydone = true; - firstload = false; - } - } - PQputline(conn, "\n"); - } - return !PQendcopy(conn); -} - - - -/* - * try to open fname and return a FILE *, if it fails, use stdout, instead - */ - -static FILE * -setFout(PsqlSettings *pset, char *fname) -{ - if (pset->queryFout && pset->queryFout != stdout) - { - if (pset->pipe) - pclose(pset->queryFout); - else - fclose(pset->queryFout); - } - if (!fname) - { - pset->queryFout = stdout; - pqsignal(SIGPIPE, SIG_DFL); - } - else - { - if (*fname == '|') - { - pqsignal(SIGPIPE, SIG_IGN); -#ifndef __CYGWIN32__ - pset->queryFout = popen(fname + 1, "w"); -#else - pset->queryFout = popen(fname + 1, "wb"); -#endif - pset->pipe = 1; - } - else - { - pset->queryFout = fopen(fname, "w"); - pqsignal(SIGPIPE, SIG_DFL); - pset->pipe = 0; - } - if (!pset->queryFout) - { - perror(fname); - pset->queryFout = stdout; - } - } - return pset->queryFout; -} - -static void -prompt_for_password(char *username, char *password) -{ - char buf[512]; - int length; - -#ifdef HAVE_TERMIOS_H - struct termios t_orig, - t; - -#endif - - printf("Username: "); - fgets(username, 100, stdin); - length = strlen(username); - /* skip rest of the line */ - if (length > 0 && username[length - 1] != '\n') - { - do - { - fgets(buf, 512, stdin); - } while (buf[strlen(buf) - 1] != '\n'); - } - if (length > 0 && username[length - 1] == '\n') - username[length - 1] = '\0'; - - printf("Password: "); -#ifdef HAVE_TERMIOS_H - tcgetattr(0, &t); - t_orig = t; - t.c_lflag &= ~ECHO; - tcsetattr(0, TCSADRAIN, &t); -#endif - fgets(password, 100, stdin); -#ifdef HAVE_TERMIOS_H - tcsetattr(0, TCSADRAIN, &t_orig); -#endif - - length = strlen(password); - /* skip rest of the line */ - if (length > 0 && password[length - 1] != '\n') - { - do - { - fgets(buf, 512, stdin); - } while (buf[strlen(buf) - 1] != '\n'); - } - if (length > 0 && password[length - 1] == '\n') - password[length - 1] = '\0'; - - printf("\n\n"); -} - -static char * -selectVersion(PsqlSettings *pset) -{ -#define PGVERSIONBUFSZ 128 - static char version[PGVERSIONBUFSZ + 1]; - PGresult *res; - char *query = "select version();"; - - if (!(res = PQexec(pset->db, query))) - return (NULL); - - if (PQresultStatus(res) == PGRES_COMMAND_OK || - PQresultStatus(res) == PGRES_TUPLES_OK) - { - strncpy(version, PQgetvalue(res, 0, 0), PGVERSIONBUFSZ); - version[PGVERSIONBUFSZ] = '\0'; - PQclear(res); - return (version); - } - else - { - PQclear(res); - return (NULL); - } -} diff --git a/src/bin/psql/psqlHelp.h b/src/bin/psql/psqlHelp.h index 0d4bc1c687..81bee606f5 100644 --- a/src/bin/psql/psqlHelp.h +++ b/src/bin/psql/psqlHelp.h @@ -5,7 +5,7 @@ * * Copyright (c) 1994, Regents of the University of California * - * $Id: psqlHelp.h,v 1.80 1999/10/29 23:52:22 momjian Exp $ + * $Id: psqlHelp.h,v 1.81 1999/11/04 23:14:29 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -384,5 +384,6 @@ TIMEZONE|XACTISOLEVEL|CLIENT_ENCODING|SERVER_ENCODING"}, \tVACUUM [VERBOSE] [ANALYZE] [table]\n\ \tor\n\ \tVACUUM [VERBOSE] ANALYZE [table [(column_name1, ...column_nameN)]];"}, - {NULL, NULL, NULL} /* important to keep a NULL terminator here!*/ + {NULL, NULL, NULL} /* important to keep a NULL terminator + * here! */ }; diff --git a/src/bin/psql/settings.h b/src/bin/psql/settings.h index 6ceefd8b44..5687e1801f 100644 --- a/src/bin/psql/settings.h +++ b/src/bin/psql/settings.h @@ -20,24 +20,27 @@ typedef struct _psqlSettings { - PGconn *db; /* connection to backend */ - FILE *queryFout; /* where to send the query results */ - bool queryFoutPipe; /* queryFout is from a popen() */ - - printQueryOpt popt; - VariableSpace vars; /* "shell variable" repository */ - - char *gfname; /* one-shot file output argument for \g */ - - bool notty; /* stdin or stdout is not a tty (as determined on startup) */ - bool useReadline; /* use libreadline routines */ - bool useHistory; - bool getPassword; /* prompt the user for a username and - password */ - FILE * cur_cmd_source; /* describe the status of the current main loop */ - bool cur_cmd_interactive; - - bool has_client_encoding; /* was PGCLIENTENCODING set on startup? */ + PGconn *db; /* connection to backend */ + FILE *queryFout; /* where to send the query results */ + bool queryFoutPipe; /* queryFout is from a popen() */ + + printQueryOpt popt; + VariableSpace vars; /* "shell variable" repository */ + + char *gfname; /* one-shot file output argument for \g */ + + bool notty; /* stdin or stdout is not a tty (as + * determined on startup) */ + bool useReadline; /* use libreadline routines */ + bool useHistory; + bool getPassword; /* prompt the user for a username and + * password */ + FILE *cur_cmd_source; /* describe the status of the current main + * loop */ + bool cur_cmd_interactive; + + bool has_client_encoding; /* was PGCLIENTENCODING set on + * startup? */ } PsqlSettings; diff --git a/src/bin/psql/sql_help.h b/src/bin/psql/sql_help.h index 60d5a40147..f37a63fcc7 100644 --- a/src/bin/psql/sql_help.h +++ b/src/bin/psql/sql_help.h @@ -7,251 +7,251 @@ struct _helpStruct { - char *cmd; /* the command name */ - char *help; /* the help associated with it */ - char *syntax; /* the syntax associated with it */ + char *cmd; /* the command name */ + char *help; /* the help associated with it */ + char *syntax; /* the syntax associated with it */ }; static struct _helpStruct QL_HELP[] = { - { "TRUNCATE", - "Empty a table", - "TRUNCATE [ TABLE ] name" }, + {"TRUNCATE", + "Empty a table", + "TRUNCATE [ TABLE ] name"}, - { "ABORT", - "Aborts the current transaction", - "ABORT [ WORK | TRANSACTION ]" }, + {"ABORT", + "Aborts the current transaction", + "ABORT [ WORK | TRANSACTION ]"}, - { "ALTER TABLE", - "Modifies table properties", - "ALTER TABLE table\n [ * ] ADD [ COLUMN ] ER\">coBLE> type\nALTER TABLE table\n [ * ] RENAME [ COLUMN ] ER\">coBLE> TO newcolumn\nALTER TABLE table\n RENAME TO newtable" }, + {"ALTER TABLE", + "Modifies table properties", + "ALTER TABLE table\n [ * ] ADD [ COLUMN ] ER\">coBLE> type\nALTER TABLE table\n [ * ] RENAME [ COLUMN ] ER\">coBLE> TO newcolumn\nALTER TABLE table\n RENAME TO newtable"}, - { "ALTER USER", - "Modifies user account information", - "ALTER USER username [ WITH PASSWORD password ]\n [ CREATEDB | NOCREATEDB ] [ CREATEUSER | NOCREATEUSER ]\n [ IN GROUP groupname [, ...] ]\n [ VALID UNTIL 'abstime' ]" }, + {"ALTER USER", + "Modifies user account information", + "ALTER USER username [ WITH PASSWORD password ]\n [ CREATEDB | NOCREATEDB ] [ CREATEUSER | NOCREATEUSER ]\n [ IN GROUP groupname [, ...] ]\n [ VALID UNTIL 'abstime' ]"}, - { "BEGIN", - "Begins a transaction in chained mode", - "BEGIN [ WORK | TRANSACTION ]" }, + {"BEGIN", + "Begins a transaction in chained mode", + "BEGIN [ WORK | TRANSACTION ]"}, - { "CLOSE", - "Close a cursor", - "CLOSE cursor" }, + {"CLOSE", + "Close a cursor", + "CLOSE cursor"}, - { "CLUSTER", - "Gives storage clustering advice to the server", - "CLUSTER indexname ON table" }, + {"CLUSTER", + "Gives storage clustering advice to the server", + "CLUSTER indexname ON table"}, - { "COMMIT", - "Commits the current transaction", - "COMMIT [ WORK | TRANSACTION ]" }, + {"COMMIT", + "Commits the current transaction", + "COMMIT [ WORK | TRANSACTION ]"}, - { "COPY", - "Copies data between files and tables", - "COPY [ BINARY ] table [ WITH OIDS ]\n FROM { 'filename' | stdin }\n [ [USING] DELIMITERS 'delimiter' ]\nCOPY [ BINARY ] table [ WITH OIDS ]\n TO { 'filename' | stdout }\n [ [USING] DELIMITERS 'delimiter' ]" }, + {"COPY", + "Copies data between files and tables", + "COPY [ BINARY ] table [ WITH OIDS ]\n FROM { 'filename' | stdin }\n [ [USING] DELIMITERS 'delimiter' ]\nCOPY [ BINARY ] table [ WITH OIDS ]\n TO { 'filename' | stdout }\n [ [USING] DELIMITERS 'delimiter' ]"}, - { "CREATE AGGREGATE", - "Defines a new aggregate function", - "CREATE AGGREGATE name [ AS ] ( BASETYPE = data_type\n [ , SFUNC1 = sfunc1, STYPE1 = sfunc1_return_type ]\n [ , SFUNC2 = sfunc2, STYPE2 = sfunc2_return_type ]\n [ , FINALFUNC = ffunc ]\n [ , INITCOND1 = initial_condition1 ]\n [ , INITCOND2 = initial_condition2 ] )" }, + {"CREATE AGGREGATE", + "Defines a new aggregate function", + "CREATE AGGREGATE name [ AS ] ( BASETYPE = data_type\n [ , SFUNC1 = sfunc1, STYPE1 = sfunc1_return_type ]\n [ , SFUNC2 = sfunc2, STYPE2 = sfunc2_return_type ]\n [ , FINALFUNC = ffunc ]\n [ , INITCOND1 = initial_condition1 ]\n [ , INITCOND2 = initial_condition2 ] )"}, - { "CREATE DATABASE", - "Creates a new database", - "CREATE DATABASE name [ WITH LOCATION = 'dbpath' ]" }, + {"CREATE DATABASE", + "Creates a new database", + "CREATE DATABASE name [ WITH LOCATION = 'dbpath' ]"}, - { "CREATE FUNCTION", - "Defines a new function", - "CREATE FUNCTION name ( [ ftype [, ...] ] )\n RETURNS rtype\n [ WITH ( attribute [, ...] ) ]\n AS definition \n LANGUAGE 'langname'\n\n\nCREATE FUNCTION name ( [ ftype [, ...] ] )\n RETURNS rtype\n [ WITH ( attribute [, ...] ) ]\n AS obj_file , link_symbol \n LANGUAGE 'C'" }, + {"CREATE FUNCTION", + "Defines a new function", + "CREATE FUNCTION name ( [ ftype [, ...] ] )\n RETURNS rtype\n [ WITH ( attribute [, ...] ) ]\n AS definition \n LANGUAGE 'langname'\n\n\nCREATE FUNCTION name ( [ ftype [, ...] ] )\n RETURNS rtype\n [ WITH ( attribute [, ...] ) ]\n AS obj_file , link_symbol \n LANGUAGE 'C'"}, - { "CREATE INDEX", - "Constructs a secondary index", - "CREATE [ UNIQUE ] INDEX index_name ON table\n [ USING acc_name ] ( column [ ops_name] [, ...] )\nCREATE [ UNIQUE ] INDEX index_name ON table\n [ USING acc_name ] ( func_name( r\">colle> [, ... ]) ops_name )" }, + {"CREATE INDEX", + "Constructs a secondary index", + "CREATE [ UNIQUE ] INDEX index_name ON table\n [ USING acc_name ] ( column [ ops_name] [, ...] )\nCREATE [ UNIQUE ] INDEX index_name ON table\n [ USING acc_name ] ( func_name( r\">colle> [, ... ]) ops_name )"}, - { "CREATE LANGUAGE", - "Defines a new language for functions", - "CREATE [ TRUSTED ] PROCEDURAL LANGUAGE 'langname'\n HANDLER call_handler\n LANCOMPILER 'comment'" }, + {"CREATE LANGUAGE", + "Defines a new language for functions", + "CREATE [ TRUSTED ] PROCEDURAL LANGUAGE 'langname'\n HANDLER call_handler\n LANCOMPILER 'comment'"}, - { "CREATE OPERATOR", - "Defines a new user operator", - "CREATE OPERATOR name ( PROCEDURE = func_name\n [, LEFTARG = type1 ] [, RIGHTARG = type2 ]\n [, COMMUTATOR = com_op ] [, NEGATOR = neg_op ]\n [, RESTRICT = res_proc ] [, JOIN = join_proc ]\n [, HASHES ] [, SORT1 = left_sort_op ] [, SORT2 = right_sort_op ] )" }, + {"CREATE OPERATOR", + "Defines a new user operator", + "CREATE OPERATOR name ( PROCEDURE = func_name\n [, LEFTARG = type1 ] [, RIGHTARG = type2 ]\n [, COMMUTATOR = com_op ] [, NEGATOR = neg_op ]\n [, RESTRICT = res_proc ] [, JOIN = join_proc ]\n [, HASHES ] [, SORT1 = left_sort_op ] [, SORT2 = right_sort_op ] )"}, - { "CREATE RULE", - "Defines a new rule", - "CREATE RULE name AS ON event\n TO object [ WHERE condition ]\n DO [ INSTEAD ] [ action | NOTHING ]" }, + {"CREATE RULE", + "Defines a new rule", + "CREATE RULE name AS ON event\n TO object [ WHERE condition ]\n DO [ INSTEAD ] [ action | NOTHING ]"}, - { "CREATE SEQUENCE", - "Creates a new sequence number generator", - "CREATE SEQUENCE seqname [ INCREMENT increment ]\n [ MINVALUE minvalue ] [ MAXVALUE maxvalue ]\n [ START start ] [ CACHE cache ] [ CYCLE ]" }, + {"CREATE SEQUENCE", + "Creates a new sequence number generator", + "CREATE SEQUENCE seqname [ INCREMENT increment ]\n [ MINVALUE minvalue ] [ MAXVALUE maxvalue ]\n [ START start ] [ CACHE cache ] [ CYCLE ]"}, - { "CREATE TABLE", - "Creates a new table", - "CREATE [ TEMPORARY | TEMP ] TABLE table (\n column type\n [ NULL | NOT NULL ] [ UNIQUE ] [ DEFAULT value ]\n [column_constraint_clause | PRIMARY KEY } [ ... ] ]\n [, ... ]\n [, PRIMARY KEY ( column [, ...] ) ]\n [, CHECK ( condition ) ]\n [, table_constraint_clause ]\n ) [ INHERITS ( inherited_table [, ...] ) ]" }, + {"CREATE TABLE", + "Creates a new table", + "CREATE [ TEMPORARY | TEMP ] TABLE table (\n column type\n [ NULL | NOT NULL ] [ UNIQUE ] [ DEFAULT value ]\n [column_constraint_clause | PRIMARY KEY } [ ... ] ]\n [, ... ]\n [, PRIMARY KEY ( column [, ...] ) ]\n [, CHECK ( condition ) ]\n [, table_constraint_clause ]\n ) [ INHERITS ( inherited_table [, ...] ) ]"}, - { "CREATE TABLE AS", - "Creates a new table", - "CREATE TABLE table [ (column [, ...] ) ]\n AS select_clause" }, + {"CREATE TABLE AS", + "Creates a new table", + "CREATE TABLE table [ (column [, ...] ) ]\n AS select_clause"}, - { "CREATE TRIGGER", - "Creates a new trigger", - "CREATE TRIGGER name { BEFORE | AFTER } { event [OR ...] }\n ON table FOR EACH { ROW | STATEMENT }\n EXECUTE PROCEDURE ER\">funcBLE> ( arguments )" }, + {"CREATE TRIGGER", + "Creates a new trigger", + "CREATE TRIGGER name { BEFORE | AFTER } { event [OR ...] }\n ON table FOR EACH { ROW | STATEMENT }\n EXECUTE PROCEDURE ER\">funcBLE> ( arguments )"}, - { "CREATE TYPE", - "Defines a new base data type", - "CREATE TYPE typename ( INPUT = input_function, OUTPUT = output_function\n , INTERNALLENGTH = { internallength | VARIABLE } [ , EXTERNALLENGTH = { externallength | VARIABLE } ]\n [ , DEFAULT = \"default\" ]\n [ , ELEMENT = element ] [ , DELIMITER = delimiter ]\n [ , SEND = send_function ] [ , RECEIVE = receive_function ]\n [ , PASSEDBYVALUE ] )" }, + {"CREATE TYPE", + "Defines a new base data type", + "CREATE TYPE typename ( INPUT = input_function, OUTPUT = output_function\n , INTERNALLENGTH = { internallength | VARIABLE } [ , EXTERNALLENGTH = { externallength | VARIABLE } ]\n [ , DEFAULT = \"default\" ]\n [ , ELEMENT = element ] [ , DELIMITER = delimiter ]\n [ , SEND = send_function ] [ , RECEIVE = receive_function ]\n [ , PASSEDBYVALUE ] )"}, - { "CREATE USER", - "Creates account information for a new user", - "CREATE USER username\n [ WITH PASSWORD password ]\n [ CREATEDB | NOCREATEDB ] [ CREATEUSER | NOCREATEUSER ]\n [ IN GROUP groupname [, ...] ]\n [ VALID UNTIL 'abstime' ]" }, + {"CREATE USER", + "Creates account information for a new user", + "CREATE USER username\n [ WITH PASSWORD password ]\n [ CREATEDB | NOCREATEDB ] [ CREATEUSER | NOCREATEUSER ]\n [ IN GROUP groupname [, ...] ]\n [ VALID UNTIL 'abstime' ]"}, - { "CREATE VIEW", - "Constructs a virtual table", - "CREATE VIEW view AS SELECT query" }, + {"CREATE VIEW", + "Constructs a virtual table", + "CREATE VIEW view AS SELECT query"}, - { "DECLARE", - "Defines a cursor for table access", - "DECLARE cursor [ BINARY ] [ INSENSITIVE ] [ SCROLL ]\n CURSOR FOR query\n [ FOR { READ ONLY | UPDATE [ OF column [, ...] ] ]" }, + {"DECLARE", + "Defines a cursor for table access", + "DECLARE cursor [ BINARY ] [ INSENSITIVE ] [ SCROLL ]\n CURSOR FOR query\n [ FOR { READ ONLY | UPDATE [ OF column [, ...] ] ]"}, - { "DELETE", - "Removes rows from a table", - "DELETE FROM table [ WHERE condition ]" }, + {"DELETE", + "Removes rows from a table", + "DELETE FROM table [ WHERE condition ]"}, - { "DROP AGGREGATE", - "Removes the definition of an aggregate function", - "DROP AGGREGATE name type" }, + {"DROP AGGREGATE", + "Removes the definition of an aggregate function", + "DROP AGGREGATE name type"}, - { "FETCH", - "Gets rows using a cursor", - "FETCH [ selector ] [ count ] { IN | FROM } cursor\nFETCH [ RELATIVE ] [ { [ # | ALL | NEXT | PRIOR ] } ] FROM ] cursor" }, + {"FETCH", + "Gets rows using a cursor", + "FETCH [ selector ] [ count ] { IN | FROM } cursor\nFETCH [ RELATIVE ] [ { [ # | ALL | NEXT | PRIOR ] } ] FROM ] cursor"}, - { "DROP DATABASE", - "Destroys an existing database", - "DROP DATABASE name" }, + {"DROP DATABASE", + "Destroys an existing database", + "DROP DATABASE name"}, - { "DROP FUNCTION", - "Removes a user-defined C function", - "DROP FUNCTION name ( [ type [, ...] ] )" }, + {"DROP FUNCTION", + "Removes a user-defined C function", + "DROP FUNCTION name ( [ type [, ...] ] )"}, - { "DROP INDEX", - "Removes an index from a database", - "DROP INDEX index_name" }, + {"DROP INDEX", + "Removes an index from a database", + "DROP INDEX index_name"}, - { "DROP LANGUAGE", - "Removes a user-defined procedural language", - "DROP PROCEDURAL LANGUAGE 'name'" }, + {"DROP LANGUAGE", + "Removes a user-defined procedural language", + "DROP PROCEDURAL LANGUAGE 'name'"}, - { "DROP OPERATOR", - "Removes an operator from the database", - "DROP OPERATOR id ( type | NONE [,...] )" }, + {"DROP OPERATOR", + "Removes an operator from the database", + "DROP OPERATOR id ( type | NONE [,...] )"}, - { "DROP RULE", - "Removes an existing rule from the database", - "DROP RULE name" }, + {"DROP RULE", + "Removes an existing rule from the database", + "DROP RULE name"}, - { "DROP SEQUENCE", - "Removes an existing sequence", - "DROP SEQUENCE name [, ...]" }, + {"DROP SEQUENCE", + "Removes an existing sequence", + "DROP SEQUENCE name [, ...]"}, - { "DROP TABLE", - "Removes existing tables from a database", - "DROP TABLE name [, ...]" }, + {"DROP TABLE", + "Removes existing tables from a database", + "DROP TABLE name [, ...]"}, - { "DROP TRIGGER", - "Removes the definition of a trigger", - "DROP TRIGGER name ON table" }, + {"DROP TRIGGER", + "Removes the definition of a trigger", + "DROP TRIGGER name ON table"}, - { "DROP TYPE", - "Removes a user-defined type from the system catalogs", - "DROP TYPE typename" }, + {"DROP TYPE", + "Removes a user-defined type from the system catalogs", + "DROP TYPE typename"}, - { "DROP USER", - "Removes an user account information", - "DROP USER name" }, + {"DROP USER", + "Removes an user account information", + "DROP USER name"}, - { "DROP VIEW", - "Removes an existing view from a database", - "DROP VIEW name" }, + {"DROP VIEW", + "Removes an existing view from a database", + "DROP VIEW name"}, - { "EXPLAIN", - "Shows statement execution details", - "EXPLAIN [ VERBOSE ] query" }, + {"EXPLAIN", + "Shows statement execution details", + "EXPLAIN [ VERBOSE ] query"}, - { "GRANT", - "Grants access privilege to a user, a group or all users", - "GRANT privilege [, ...] ON object [, ...]\n TO { PUBLIC | GROUP group | username }" }, + {"GRANT", + "Grants access privilege to a user, a group or all users", + "GRANT privilege [, ...] ON object [, ...]\n TO { PUBLIC | GROUP group | username }"}, - { "INSERT", - "Inserts new rows into a table", - "INSERT INTO table [ ( column [, ...] ) ]\n { VALUES ( expression [, ...] ) | SELECT query }" }, + {"INSERT", + "Inserts new rows into a table", + "INSERT INTO table [ ( column [, ...] ) ]\n { VALUES ( expression [, ...] ) | SELECT query }"}, - { "LISTEN", - "Listen for a response on a notify condition", - "LISTEN name" }, + {"LISTEN", + "Listen for a response on a notify condition", + "LISTEN name"}, - { "LOAD", - "Dynamically loads an object file", - "LOAD 'filename'" }, + {"LOAD", + "Dynamically loads an object file", + "LOAD 'filename'"}, - { "LOCK", - "Explicitly lock a table inside a transaction", - "LOCK [ TABLE ] name\nLOCK [ TABLE ] name IN [ ROW | ACCESS ] { SHARE | EXCLUSIVE } MODE\nLOCK [ TABLE ] name IN SHARE ROW EXCLUSIVE MODE" }, + {"LOCK", + "Explicitly lock a table inside a transaction", + "LOCK [ TABLE ] name\nLOCK [ TABLE ] name IN [ ROW | ACCESS ] { SHARE | EXCLUSIVE } MODE\nLOCK [ TABLE ] name IN SHARE ROW EXCLUSIVE MODE"}, - { "MOVE", - "Moves cursor position", - "MOVE [ selector ] [ count ] \n { IN | FROM } cursor\n FETCH [ RELATIVE ] [ { [ # | ALL | NEXT | PRIOR ] } ] FROM ] cursor" }, + {"MOVE", + "Moves cursor position", + "MOVE [ selector ] [ count ] \n { IN | FROM } cursor\n FETCH [ RELATIVE ] [ { [ # | ALL | NEXT | PRIOR ] } ] FROM ] cursor"}, - { "NOTIFY", - "Signals all frontends and backends listening on a notify condition", - "NOTIFY name" }, + {"NOTIFY", + "Signals all frontends and backends listening on a notify condition", + "NOTIFY name"}, - { "RESET", - "Restores run-time parameters for session to default values", - "RESET variable" }, + {"RESET", + "Restores run-time parameters for session to default values", + "RESET variable"}, - { "REVOKE", - "Revokes access privilege from a user, a group or all users.", - "REVOKE privilege [, ...]\n ON object [, ...]\n FROM { PUBLIC | GROUP ER\">gBLE> | username }" }, + {"REVOKE", + "Revokes access privilege from a user, a group or all users.", + "REVOKE privilege [, ...]\n ON object [, ...]\n FROM { PUBLIC | GROUP ER\">gBLE> | username }"}, - { "ROLLBACK", - "Aborts the current transaction", - "ROLLBACK [ WORK | TRANSACTION ]" }, + {"ROLLBACK", + "Aborts the current transaction", + "ROLLBACK [ WORK | TRANSACTION ]"}, - { "SELECT", - "Retrieve rows from a table or view.", - "SELECT [ ALL | DISTINCT [ ON column ] ]\n expression [ AS name ] [, ...]\n [ INTO [ TEMPORARY | TEMP ] [ TABLE ] new_table ]\n [ FROM table [ alias ] [, ...] ]\n [ WHERE condition ]\n [ GROUP BY column [, ...] ]\n [ HAVING condition [, ...] ]\n [ { UNION [ ALL ] | INTERSECT | EXCEPT } select ]\n [ ORDER BY column [ ASC | DESC ] [, ...] ]\n [ FOR UPDATE [ OF class_name... ] ]\n [ LIMIT { count | ALL } [ { OFFSET | , } count ] ]" }, + {"SELECT", + "Retrieve rows from a table or view.", + "SELECT [ ALL | DISTINCT [ ON column ] ]\n expression [ AS name ] [, ...]\n [ INTO [ TEMPORARY | TEMP ] [ TABLE ] new_table ]\n [ FROM table [ alias ] [, ...] ]\n [ WHERE condition ]\n [ GROUP BY column [, ...] ]\n [ HAVING condition [, ...] ]\n [ { UNION [ ALL ] | INTERSECT | EXCEPT } select ]\n [ ORDER BY column [ ASC | DESC ] [, ...] ]\n [ FOR UPDATE [ OF class_name... ] ]\n [ LIMIT { count | ALL } [ { OFFSET | , } count ] ]"}, - { "SELECT INTO", - "Create a new table from an existing table or view", - "SELECT [ ALL | DISTINCT ] expression [ AS name ] [, ...]\n INTO [TEMP] [ TABLE ] new_table ]\n [ FROM table [alias] [, ...] ]\n [ WHERE condition ]\n [ GROUP BY column [, ...] ]\n [ HAVING condition [, ...] ]\n [ { UNION [ALL] | INTERSECT | EXCEPT } select]\n [ ORDER BY column [ ASC | DESC ] [, ...] ]\n [ FOR UPDATE [OF class_name...]]\n [ LIMIT count [OFFSET|, count]]" }, + {"SELECT INTO", + "Create a new table from an existing table or view", + "SELECT [ ALL | DISTINCT ] expression [ AS name ] [, ...]\n INTO [TEMP] [ TABLE ] new_table ]\n [ FROM table [alias] [, ...] ]\n [ WHERE condition ]\n [ GROUP BY column [, ...] ]\n [ HAVING condition [, ...] ]\n [ { UNION [ALL] | INTERSECT | EXCEPT } select]\n [ ORDER BY column [ ASC | DESC ] [, ...] ]\n [ FOR UPDATE [OF class_name...]]\n [ LIMIT count [OFFSET|, count]]"}, - { "SET", - "Set run-time parameters for session", - "SET variable { TO | = } { 'value' | DEFAULT }\nSET TIME ZONE { 'timezone' | LOCAL | DEFAULT }\nSET TRANSACTION ISOLATION LEVEL { READ COMMITTED | SERIALIZABLE }" }, + {"SET", + "Set run-time parameters for session", + "SET variable { TO | = } { 'value' | DEFAULT }\nSET TIME ZONE { 'timezone' | LOCAL | DEFAULT }\nSET TRANSACTION ISOLATION LEVEL { READ COMMITTED | SERIALIZABLE }"}, - { "SHOW", - "Shows run-time parameters for session", - "SHOW keyword" }, + {"SHOW", + "Shows run-time parameters for session", + "SHOW keyword"}, - { "UNLISTEN", - "Stop listening for notification", - "UNLISTEN { notifyname | * }" }, + {"UNLISTEN", + "Stop listening for notification", + "UNLISTEN { notifyname | * }"}, - { "UPDATE", - "Replaces values of columns in a table", - "UPDATE table SET R\">colle> = expression [, ...]\n [ FROM fromlist ]\n [ WHERE condition ]" }, + {"UPDATE", + "Replaces values of columns in a table", + "UPDATE table SET R\">colle> = expression [, ...]\n [ FROM fromlist ]\n [ WHERE condition ]"}, - { "VACUUM", - "Clean and analyze a Postgres database", - "VACUUM [ VERBOSE ] [ ANALYZE ] [ table ]\nVACUUM [ VERBOSE ] ANALYZE [ ER\">tBLE> [ (column [, ...] ) ] ]" }, + {"VACUUM", + "Clean and analyze a Postgres database", + "VACUUM [ VERBOSE ] [ ANALYZE ] [ table ]\nVACUUM [ VERBOSE ] ANALYZE [ ER\">tBLE> [ (column [, ...] ) ] ]"}, - { "END", - "Commits the current transaction", - "END [ WORK | TRANSACTION ]" }, + {"END", + "Commits the current transaction", + "END [ WORK | TRANSACTION ]"}, - { "COMMENT", - "Add comment to an object", - "COMMENT ON\n[\n [ DATABASE | INDEX | RULE | SEQUENCE | TABLE | TYPE | VIEW ]\n object_name |\n COLUMN table_name.column_name|\n AGGREGATE agg_name agg_type|\n FUNCTION func_name (arg1, arg2, ...)|\n OPERATOR op (leftoperand_type rightoperand_type) |\n TRIGGER trigger_name ON table_name\n] IS 'text'" }, + {"COMMENT", + "Add comment to an object", + "COMMENT ON\n[\n [ DATABASE | INDEX | RULE | SEQUENCE | TABLE | TYPE | VIEW ]\n object_name |\n COLUMN table_name.column_name|\n AGGREGATE agg_name agg_type|\n FUNCTION func_name (arg1, arg2, ...)|\n OPERATOR op (leftoperand_type rightoperand_type) |\n TRIGGER trigger_name ON table_name\n] IS 'text'"}, - { NULL, NULL, NULL } /* End of list marker */ + {NULL, NULL, NULL} /* End of list marker */ }; -#endif /* SQL_HELP_H */ +#endif /* SQL_HELP_H */ diff --git a/src/bin/psql/startup.c b/src/bin/psql/startup.c index 480e1bc01b..350b7f4937 100644 --- a/src/bin/psql/startup.c +++ b/src/bin/psql/startup.c @@ -37,35 +37,38 @@ static void -process_psqlrc(PsqlSettings * pset); + process_psqlrc(PsqlSettings *pset); static void -showVersion(PsqlSettings *pset, bool verbose); + showVersion(PsqlSettings *pset, bool verbose); /* Structures to pass information between the option parsing routine * and the main function */ -enum _actions { ACT_NOTHING = 0, - ACT_SINGLE_SLASH, - ACT_LIST_DB, - ACT_SHOW_VER, - ACT_SINGLE_QUERY, - ACT_FILE +enum _actions +{ + ACT_NOTHING = 0, + ACT_SINGLE_SLASH, + ACT_LIST_DB, + ACT_SHOW_VER, + ACT_SINGLE_QUERY, + ACT_FILE }; -struct adhoc_opts { - char * dbname; - char * host; - char * port; - char * username; - enum _actions action; - char * action_string; - bool no_readline; +struct adhoc_opts +{ + char *dbname; + char *host; + char *port; + char *username; + enum _actions action; + char *action_string; + bool no_readline; }; static void -parse_options(int argc, char *argv[], PsqlSettings * pset, struct adhoc_opts * options); + parse_options(int argc, char *argv[], PsqlSettings *pset, struct adhoc_opts * options); @@ -77,133 +80,140 @@ parse_options(int argc, char *argv[], PsqlSettings * pset, struct adhoc_opts * o int main(int argc, char **argv) { - PsqlSettings settings; - struct adhoc_opts options; - int successResult; + PsqlSettings settings; + struct adhoc_opts options; + int successResult; - char * username = NULL; - char * password = NULL; - bool need_pass; + char *username = NULL; + char *password = NULL; + bool need_pass; - MemSet(&settings, 0, sizeof settings); + MemSet(&settings, 0, sizeof settings); - settings.cur_cmd_source = stdin; - settings.cur_cmd_interactive = false; + settings.cur_cmd_source = stdin; + settings.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.vars = CreateVariableSpace(); + settings.popt.topt.format = PRINT_ALIGNED; + settings.queryFout = stdout; + settings.popt.topt.fieldSep = strdup(DEFAULT_FIELD_SEP); + settings.popt.topt.border = 1; - SetVariable(settings.vars, "prompt1", DEFAULT_PROMPT1); - SetVariable(settings.vars, "prompt2", DEFAULT_PROMPT2); - SetVariable(settings.vars, "prompt3", DEFAULT_PROMPT3); + SetVariable(settings.vars, "prompt1", DEFAULT_PROMPT1); + SetVariable(settings.vars, "prompt2", DEFAULT_PROMPT2); + SetVariable(settings.vars, "prompt3", DEFAULT_PROMPT3); - settings.notty = (!isatty(fileno(stdin)) || !isatty(fileno(stdout))); + settings.notty = (!isatty(fileno(stdin)) || !isatty(fileno(stdout))); - /* This is obsolete and will be removed very soon. */ + /* This is obsolete and will be removed very soon. */ #ifdef PSQL_ALWAYS_GET_PASSWORDS - settings.getPassword = true; + settings.getPassword = true; #else - settings.getPassword = false; + settings.getPassword = false; #endif #ifdef MULTIBYTE - settings.has_client_encoding = (getenv("PGCLIENTENCODING") != NULL); + settings.has_client_encoding = (getenv("PGCLIENTENCODING") != NULL); #endif - parse_options(argc, argv, &settings, &options); + parse_options(argc, argv, &settings, &options); - if (options.action==ACT_LIST_DB || options.action==ACT_SHOW_VER) - options.dbname = "template1"; + if (options.action == ACT_LIST_DB || options.action == ACT_SHOW_VER) + options.dbname = "template1"; - if (options.username) { - if (strcmp(options.username, "?")==0) - username = simple_prompt("Username: ", 100, true); - else - username = strdup(options.username); - } - - if (settings.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); - - if (PQstatus(settings.db)==CONNECTION_BAD && - strcmp(PQerrorMessage(settings.db), "fe_sendauth: no password supplied\n")==0) { - need_pass = true; - free(password); - password = NULL; - password = simple_prompt("Password: ", 100, false); + if (options.username) + { + if (strcmp(options.username, "?") == 0) + username = simple_prompt("Username: ", 100, true); + else + username = strdup(options.username); } - } while (need_pass); - free(username); - free(password); + if (settings.getPassword) + password = simple_prompt("Password: ", 100, false); - if (PQstatus(settings.db) == CONNECTION_BAD) { - fprintf(stderr, "Connection to database '%s' failed.\n%s\n", PQdb(settings.db), PQerrorMessage(settings.db)); - PQfinish(settings.db); - exit(EXIT_BADCONN); - } + /* 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); + + if (PQstatus(settings.db) == CONNECTION_BAD && + strcmp(PQerrorMessage(settings.db), "fe_sendauth: no password supplied\n") == 0) + { + need_pass = true; + free(password); + password = NULL; + password = simple_prompt("Password: ", 100, false); + } + } while (need_pass); - if (options.action == ACT_LIST_DB) { - int success = listAllDbs(&settings); - PQfinish(settings.db); - exit (!success); - } + free(username); + free(password); + + if (PQstatus(settings.db) == CONNECTION_BAD) + { + fprintf(stderr, "Connection to database '%s' failed.\n%s\n", PQdb(settings.db), PQerrorMessage(settings.db)); + PQfinish(settings.db); + exit(EXIT_BADCONN); + } + + if (options.action == ACT_LIST_DB) + { + int success = listAllDbs(&settings); + + PQfinish(settings.db); + exit(!success); + } + + if (options.action == ACT_SHOW_VER) + { + showVersion(&settings, true); + PQfinish(settings.db); + exit(EXIT_SUCCESS); + } + + + if (!GetVariable(settings.vars, "quiet") && !settings.notty && !options.action) + { + puts("Welcome to psql, the PostgreSQL interactive terminal.\n" + "(Please type \\copyright to see the distribution terms of PostgreSQL.)"); - if (options.action == ACT_SHOW_VER) { - showVersion(&settings, true); + //showVersion(&settings, false); + + puts("\n" + "Type \\h for help with SQL commands,\n" + " \\? for help on internal slash commands,\n" + " \\q to quit,\n" + " \\g or terminate with semicolon to execute query."); + } + + process_psqlrc(&settings); + + initializeInput(options.no_readline ? 0 : 1); + + /* Now find something to do */ + + /* process file given by -f */ + if (options.action == ACT_FILE) + successResult = process_file(options.action_string, &settings) ? 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; + /* 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; + /* or otherwise enter interactive main loop */ + else + successResult = MainLoop(&settings, stdin); + + /* clean up */ + finishInput(); PQfinish(settings.db); - exit (EXIT_SUCCESS); - } - - - if (!GetVariable(settings.vars, "quiet") && !settings.notty && !options.action) - { - puts("Welcome to psql, the PostgreSQL interactive terminal.\n" - "(Please type \\copyright to see the distribution terms of PostgreSQL.)"); - -// showVersion(&settings, false); - - puts("\n" - "Type \\h for help with SQL commands,\n" - " \\? for help on internal slash commands,\n" - " \\q to quit,\n" - " \\g or terminate with semicolon to execute query."); - } - - process_psqlrc(&settings); - - initializeInput(options.no_readline ? 0 : 1); - - /* Now find something to do */ - - /* process file given by -f */ - if (options.action == ACT_FILE) - successResult = process_file(options.action_string, &settings) ? 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; - /* 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; - /* or otherwise enter interactive main loop */ - else - successResult = MainLoop(&settings, stdin); - - /* clean up */ - finishInput(); - PQfinish(settings.db); - setQFout(NULL, &settings); - DestroyVariableSpace(settings.vars); - - return successResult; + setQFout(NULL, &settings); + DestroyVariableSpace(settings.vars); + + return successResult; } @@ -214,215 +224,231 @@ main(int argc, char **argv) #ifdef WIN32 /* getopt is not in the standard includes on Win32 */ -int getopt(int, char *const[], const char *); +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[], PsqlSettings *pset, struct adhoc_opts * options) { #ifdef HAVE_GETOPT_LONG - static struct option long_options[] = { - { "no-align", no_argument, NULL, 'A' }, - { "command", required_argument, NULL, 'c' }, - { "database", required_argument, NULL, 'd' }, - { "dbname", required_argument, NULL, 'd' }, - { "echo", no_argument, NULL, 'e' }, - { "echo-queries", no_argument, NULL, 'e' }, - { "echo-all", no_argument, NULL, 'E' }, - { "echo-all-queries", no_argument, NULL, 'E' }, - { "file", required_argument, NULL, 'f' }, - { "field-sep", required_argument, NULL, 'F' }, - { "host", required_argument, NULL, 'h' }, - { "html", no_argument, NULL, 'H' }, - { "list", no_argument, NULL, 'l' }, - { "no-readline", no_argument, NULL, 'n' }, - { "out", required_argument, NULL, 'o' }, - { "to-file", required_argument, NULL, 'o' }, - { "port", required_argument, NULL, 'p' }, - { "pset", required_argument, NULL, 'P' }, - { "quiet", no_argument, NULL, 'q' }, - { "single-step", no_argument, NULL, 's' }, - { "single-line", no_argument, NULL, 'S' }, - { "tuples-only", no_argument, NULL, 't' }, - { "table-attr", required_argument, NULL, 'T' }, - { "username", required_argument, NULL, 'U' }, - { "expanded", no_argument, NULL, 'x' }, - { "set", required_argument, NULL, 'v' }, - { "variable", required_argument, NULL, 'v' }, - { "version", no_argument, NULL, 'V' }, - { "password", no_argument, NULL, 'W' }, - { "help", no_argument, NULL, '?' }, - }; - - int optindex; + static struct option long_options[] = { + {"no-align", no_argument, NULL, 'A'}, + {"command", required_argument, NULL, 'c'}, + {"database", required_argument, NULL, 'd'}, + {"dbname", required_argument, NULL, 'd'}, + {"echo", no_argument, NULL, 'e'}, + {"echo-queries", no_argument, NULL, 'e'}, + {"echo-all", no_argument, NULL, 'E'}, + {"echo-all-queries", no_argument, NULL, 'E'}, + {"file", required_argument, NULL, 'f'}, + {"field-sep", required_argument, NULL, 'F'}, + {"host", required_argument, NULL, 'h'}, + {"html", no_argument, NULL, 'H'}, + {"list", no_argument, NULL, 'l'}, + {"no-readline", no_argument, NULL, 'n'}, + {"out", required_argument, NULL, 'o'}, + {"to-file", required_argument, NULL, 'o'}, + {"port", required_argument, NULL, 'p'}, + {"pset", required_argument, NULL, 'P'}, + {"quiet", no_argument, NULL, 'q'}, + {"single-step", no_argument, NULL, 's'}, + {"single-line", no_argument, NULL, 'S'}, + {"tuples-only", no_argument, NULL, 't'}, + {"table-attr", required_argument, NULL, 'T'}, + {"username", required_argument, NULL, 'U'}, + {"expanded", no_argument, NULL, 'x'}, + {"set", required_argument, NULL, 'v'}, + {"variable", required_argument, NULL, 'v'}, + {"version", no_argument, NULL, 'V'}, + {"password", no_argument, NULL, 'W'}, + {"help", no_argument, NULL, '?'}, + }; + + int optindex; + #endif - extern char *optarg; - extern int optind; - int c; + extern char *optarg; + extern int optind; + int c; - MemSet(options, 0, sizeof *options); + MemSet(options, 0, sizeof *options); #ifdef HAVE_GETOPT_LONG - while ((c = getopt_long(argc, argv, "Ac:d:eEf:F:lh:Hno:p:P:qsStT:uU:v:VWx?", long_options, &optindex)) != -1) + while ((c = getopt_long(argc, argv, "Ac:d:eEf:F:lh:Hno:p:P:qsStT:uU:v:VWx?", long_options, &optindex)) != -1) #else - /* Be sure to leave the '-' in here, so we can catch accidental long options. */ - while ((c = getopt(argc, argv, "Ac:d:eEf:F:lh:Hno:p:P:qsStT:uU:v:VWx?-")) != -1) + + /* + * Be sure to leave the '-' in here, so we can catch accidental long + * options. + */ + while ((c = getopt(argc, argv, "Ac:d:eEf:F:lh:Hno:p:P:qsStT:uU:v:VWx?-")) != -1) #endif - { - switch (c) - { - case 'A': - pset->popt.topt.format = PRINT_UNALIGNED; - break; - case 'c': - options->action_string = optarg; - if (optarg[0] == '\\') - options->action = ACT_SINGLE_SLASH; - else - options->action = ACT_SINGLE_QUERY; - break; - case 'd': - options->dbname = optarg; - break; - case 'e': - SetVariable(pset->vars, "echo", ""); - break; - case 'E': - SetVariable(pset->vars, "echo_secret", ""); - break; - case 'f': - options->action = ACT_FILE; - options->action_string = optarg; - break; - case 'F': - pset->popt.topt.fieldSep = strdup(optarg); - break; - case 'h': - options->host = optarg; - break; - case 'H': - pset->popt.topt.format = PRINT_HTML; - break; - case 'l': - options->action = ACT_LIST_DB; - break; - case 'n': - options->no_readline = true; - break; - case 'o': - setQFout(optarg, pset); - break; - case 'p': - options->port = optarg; - break; - case 'P': - { - char *value; - char *equal_loc; - bool result; - - value = xstrdup(optarg); - equal_loc = strchr(value, '='); - if (!equal_loc) - result = do_pset(value, NULL, &pset->popt, true); - else { - *equal_loc = '\0'; - result = do_pset(value, equal_loc+1, &pset->popt, true); - } - - if (!result) { - fprintf(stderr, "Couldn't set printing paramter %s.\n", value); - exit(EXIT_FAILURE); - } - - free(value); - break; - } - case 'q': - SetVariable(pset->vars, "quiet", ""); - break; - case 's': - SetVariable(pset->vars, "singlestep", ""); - break; - case 'S': - SetVariable(pset->vars, "singleline", ""); - break; - case 't': - pset->popt.topt.tuples_only = true; - break; - case 'T': - pset->popt.topt.tableAttr = xstrdup(optarg); - break; - case 'u': - pset->getPassword = true; - options->username = "?"; - break; - case 'U': - options->username = optarg; - break; - case 'x': - pset->popt.topt.expanded = true; - break; - case 'v': { - char *value; - char *equal_loc; - - value = xstrdup(optarg); - equal_loc = strchr(value, '='); - if (!equal_loc) { - if (!DeleteVariable(pset->vars, value)) { - fprintf(stderr, "Couldn't delete variable %s.\n", value); - exit(EXIT_FAILURE); - } - } - else { - *equal_loc = '\0'; - if (!SetVariable(pset->vars, value, equal_loc+1)) { - fprintf(stderr, "Couldn't set variable %s to %s.\n", value, equal_loc); - exit(EXIT_FAILURE); - } - } - - free(value); - break; - } - case 'V': - options->action = ACT_SHOW_VER; - break; - case 'W': - pset->getPassword = true; - break; - case '?': - usage(); - exit(EXIT_SUCCESS); - break; + switch (c) + { + case 'A': + pset->popt.topt.format = PRINT_UNALIGNED; + break; + case 'c': + options->action_string = optarg; + if (optarg[0] == '\\') + options->action = ACT_SINGLE_SLASH; + else + options->action = ACT_SINGLE_QUERY; + break; + case 'd': + options->dbname = optarg; + break; + case 'e': + SetVariable(pset->vars, "echo", ""); + break; + case 'E': + SetVariable(pset->vars, "echo_secret", ""); + break; + case 'f': + options->action = ACT_FILE; + options->action_string = optarg; + break; + case 'F': + pset->popt.topt.fieldSep = strdup(optarg); + break; + case 'h': + options->host = optarg; + break; + case 'H': + pset->popt.topt.format = PRINT_HTML; + break; + case 'l': + options->action = ACT_LIST_DB; + break; + case 'n': + options->no_readline = true; + break; + case 'o': + setQFout(optarg, pset); + break; + case 'p': + options->port = optarg; + break; + case 'P': + { + char *value; + char *equal_loc; + bool result; + + value = xstrdup(optarg); + equal_loc = strchr(value, '='); + if (!equal_loc) + result = do_pset(value, NULL, &pset->popt, true); + else + { + *equal_loc = '\0'; + result = do_pset(value, equal_loc + 1, &pset->popt, true); + } + + if (!result) + { + fprintf(stderr, "Couldn't set printing paramter %s.\n", value); + exit(EXIT_FAILURE); + } + + free(value); + break; + } + case 'q': + SetVariable(pset->vars, "quiet", ""); + break; + case 's': + SetVariable(pset->vars, "singlestep", ""); + break; + case 'S': + SetVariable(pset->vars, "singleline", ""); + break; + case 't': + pset->popt.topt.tuples_only = true; + break; + case 'T': + pset->popt.topt.tableAttr = xstrdup(optarg); + break; + case 'u': + pset->getPassword = true; + options->username = "?"; + break; + case 'U': + options->username = optarg; + break; + case 'x': + pset->popt.topt.expanded = true; + break; + case 'v': + { + char *value; + char *equal_loc; + + value = xstrdup(optarg); + equal_loc = strchr(value, '='); + if (!equal_loc) + { + if (!DeleteVariable(pset->vars, value)) + { + fprintf(stderr, "Couldn't delete variable %s.\n", value); + exit(EXIT_FAILURE); + } + } + else + { + *equal_loc = '\0'; + if (!SetVariable(pset->vars, value, equal_loc + 1)) + { + fprintf(stderr, "Couldn't set variable %s to %s.\n", value, equal_loc); + exit(EXIT_FAILURE); + } + } + + free(value); + break; + } + case 'V': + options->action = ACT_SHOW_VER; + break; + case 'W': + pset->getPassword = true; + break; + case '?': + usage(); + exit(EXIT_SUCCESS); + break; #ifndef HAVE_GETOPT_LONG - case '-': - fprintf(stderr, "This version of psql was compiled without support for long options.\n" - "Use -? for help on invocation options.\n"); - exit(EXIT_FAILURE); - break; + case '-': + fprintf(stderr, "This version of psql was compiled without support for long options.\n" + "Use -? for help on invocation options.\n"); + exit(EXIT_FAILURE); + break; #endif - default: - usage(); - exit(EXIT_FAILURE); - break; + default: + usage(); + exit(EXIT_FAILURE); + break; + } } - } - - /* if we still have arguments, use it as the database name and username */ - while (argc - optind >= 1) { - if (!options->dbname) - options->dbname = argv[optind]; - else if (!options->username) - options->username = argv[optind]; - else - fprintf(stderr, "Warning: extra option %s ignored.\n", argv[optind]); - optind++; - } + /* + * if we still have arguments, use it as the database name and + * username + */ + while (argc - optind >= 1) + { + if (!options->dbname) + options->dbname = argv[optind]; + else if (!options->username) + options->username = argv[optind]; + else + fprintf(stderr, "Warning: extra option %s ignored.\n", argv[optind]); + + optind++; + } } @@ -431,41 +457,44 @@ parse_options(int argc, char *argv[], PsqlSettings * pset, struct adhoc_opts * o * Load /etc/psqlrc or .psqlrc file, if found. */ static void -process_psqlrc(PsqlSettings * pset) +process_psqlrc(PsqlSettings *pset) { - char *psqlrc; - char * home; + char *psqlrc; + char *home; #ifdef WIN32 #define R_OK 0 #endif - /* 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); - else if (access("/etc/psqlrc", R_OK) == 0) - process_file("/etc/psqlrc", 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); + else if (access("/etc/psqlrc", R_OK) == 0) + process_file("/etc/psqlrc", pset); - /* Look for one in the home dir */ - home = getenv("HOME"); + /* Look for one in the home dir */ + home = getenv("HOME"); - if (home) { - psqlrc = (char *) malloc(strlen(home) + 20); - if (!psqlrc) { - perror("malloc"); - exit(EXIT_FAILURE); - } + if (home) + { + psqlrc = (char *) malloc(strlen(home) + 20); + if (!psqlrc) + { + perror("malloc"); + exit(EXIT_FAILURE); + } - sprintf(psqlrc, "%s/.psqlrc-"PG_RELEASE"."PG_VERSION"."PG_SUBVERSION, home); - if (access(psqlrc, R_OK) == 0) - process_file(psqlrc, pset); - else { - sprintf(psqlrc, "%s/.psqlrc", home); - if (access(psqlrc, R_OK) == 0) - process_file(psqlrc, pset); + sprintf(psqlrc, "%s/.psqlrc-" PG_RELEASE "." PG_VERSION "." PG_SUBVERSION, home); + if (access(psqlrc, R_OK) == 0) + process_file(psqlrc, pset); + else + { + sprintf(psqlrc, "%s/.psqlrc", home); + if (access(psqlrc, R_OK) == 0) + process_file(psqlrc, pset); + } + free(psqlrc); } - free(psqlrc); - } } @@ -482,62 +511,68 @@ process_psqlrc(PsqlSettings * pset) static void showVersion(PsqlSettings *pset, bool verbose) { - PGresult *res; - char *versionstr = NULL; - long int release = 0, version = 0, subversion = 0; - - /* get backend version */ - res = PSQLexec(pset, "SELECT version()"); - if (PQresultStatus(res) == PGRES_TUPLES_OK) - versionstr = PQgetvalue(res, 0, 0); - - if (!verbose) { - if (versionstr) puts(versionstr); - PQclear(res); - return; - } + PGresult *res; + char *versionstr = NULL; + long int release = 0, + version = 0, + subversion = 0; + + /* get backend version */ + res = PSQLexec(pset, "SELECT version()"); + if (PQresultStatus(res) == PGRES_TUPLES_OK) + versionstr = PQgetvalue(res, 0, 0); + + if (!verbose) + { + if (versionstr) + puts(versionstr); + PQclear(res); + return; + } + + if (strncmp(versionstr, "PostgreSQL ", 11) == 0) + { + char *tmp; - if (strncmp(versionstr, "PostgreSQL ", 11) == 0) { - char *tmp; - release = strtol(&versionstr[11], &tmp, 10); - version = strtol(tmp+1, &tmp, 10); - subversion = strtol(tmp+1, &tmp, 10); - } + release = strtol(&versionstr[11], &tmp, 10); + version = strtol(tmp + 1, &tmp, 10); + subversion = strtol(tmp + 1, &tmp, 10); + } - printf("Server: %s\npsql", versionstr ? versionstr : "(could not connected)"); + printf("Server: %s\npsql", versionstr ? versionstr : "(could not connected)"); - if (strcmp(versionstr, PG_VERSION_STR) != 0) - printf(&PG_VERSION_STR[strcspn(PG_VERSION_STR, " ")]); - printf(" ("__DATE__" "__TIME__")"); + if (strcmp(versionstr, PG_VERSION_STR) != 0) + printf(&PG_VERSION_STR[strcspn(PG_VERSION_STR, " ")]); + printf(" (" __DATE__ " " __TIME__ ")"); #ifdef MULTIBYTE - printf(", multibyte"); + printf(", multibyte"); #endif #ifdef HAVE_GETOPT_LONG - printf(", long options"); + printf(", long options"); #endif #ifdef USE_READLINE - printf(", readline"); + printf(", readline"); #endif #ifdef USE_HISTORY - printf(", history"); + printf(", history"); #endif #ifdef USE_LOCALE - printf(", locale"); + printf(", locale"); #endif #ifdef PSQL_ALWAYS_GET_PASSWORDS - printf(", always password"); + printf(", always password"); #endif #ifdef USE_ASSERT_CHECKING - printf(", assert checks"); + printf(", assert checks"); #endif - puts(""); + puts(""); - if (release < 6 || (release == 6 && version < 5)) - puts ("\nWarning: The server you are connected to is potentially too old for this client\n" - "version. You should ideally be using clients and servers from the same\n" - "distribution."); + if (release < 6 || (release == 6 && version < 5)) + puts("\nWarning: The server you are connected to is potentially too old for this client\n" + "version. You should ideally be using clients and servers from the same\n" + "distribution."); - PQclear(res); + PQclear(res); } diff --git a/src/bin/psql/stringutils.c b/src/bin/psql/stringutils.c index c495fd4966..b4f5be926b 100644 --- a/src/bin/psql/stringutils.c +++ b/src/bin/psql/stringutils.c @@ -2,11 +2,13 @@ #include <c.h> #include "stringutils.h" -//#include <ctype.h> +// +#include <ctype.h> #include <stdlib.h> #include <string.h> #include <assert.h> -//#include <stdio.h> +// +#include <stdio.h> #include <postgres.h> #ifndef HAVE_STRDUP @@ -17,118 +19,130 @@ static void -unescape_quotes(char *source, char quote, char escape); + unescape_quotes(char *source, char quote, char escape); /* * Replacement for strtok() (a.k.a. poor man's flex) * * The calling convention is similar to that of strtok. - * s - string to parse, if NULL continue parsing the last string - * delim - set of characters that delimit tokens (usually whitespace) - * quote - set of characters that quote stuff, they're not part of the token - * escape - character than can quote quotes + * s - string to parse, if NULL continue parsing the last string + * delim - set of characters that delimit tokens (usually whitespace) + * quote - set of characters that quote stuff, they're not part of the token + * escape - character than can quote quotes * was_quoted - if not NULL, stores the quoting character if any was encountered - * token_pos - if not NULL, receives a count to the start of the token in the - * parsed string + * token_pos - if not NULL, receives a count to the start of the token in the + * parsed string * * Note that the string s is _not_ overwritten in this implementation. */ -char * strtokx(const char *s, - const char *delim, - const char *quote, - char escape, - char * was_quoted, - unsigned int * token_pos) +char * +strtokx(const char *s, + const char *delim, + const char *quote, + char escape, + char *was_quoted, + unsigned int *token_pos) { - static char * storage = NULL; /* store the local copy of the users string here */ - static char * string = NULL; /* pointer into storage where to continue on next call */ - /* variously abused variables: */ - unsigned int offset; - char * start; - char *cp = NULL; - - if (s) { - free(storage); - storage = strdup(s); - string = storage; - } - - if (!storage) - return NULL; - - /* skip leading "whitespace" */ - offset = strspn(string, delim); - - /* end of string reached */ - if (string[offset] == '\0') { - /* technically we don't need to free here, but we're nice */ - free(storage); - storage = NULL; - string = NULL; - return NULL; - } - - /* test if quoting character */ - if (quote) - cp = strchr(quote, string[offset]); - - if (cp) { - /* okay, we have a quoting character, now scan for the closer */ - char *p; - start = &string[offset+1]; + static char *storage = NULL;/* store the local copy of the users + * string here */ + static char *string = NULL; /* pointer into storage where to continue + * on next call */ + + /* variously abused variables: */ + unsigned int offset; + char *start; + char *cp = NULL; + + if (s) + { + free(storage); + storage = strdup(s); + string = storage; + } - if (token_pos) - *token_pos = start - storage; + if (!storage) + return NULL; + + /* skip leading "whitespace" */ + offset = strspn(string, delim); + + /* end of string reached */ + if (string[offset] == '\0') + { + /* technically we don't need to free here, but we're nice */ + free(storage); + storage = NULL; + string = NULL; + return NULL; + } - for(p = start; - *p && (*p != *cp || *(p-1) == escape) ; + /* test if quoting character */ + if (quote) + cp = strchr(quote, string[offset]); + + if (cp) + { + /* okay, we have a quoting character, now scan for the closer */ + char *p; + + start = &string[offset + 1]; + + if (token_pos) + *token_pos = start - storage; + + for (p = start; + *p && (*p != *cp || *(p - 1) == escape); #ifdef MULTIBYTE - p += PQmblen(p) + p += PQmblen(p) #else - p++ + p++ #endif - ); - - /* not yet end of string? */ - if (*p != '\0') { - *p = '\0'; - string = p + 1; - if (was_quoted) - *was_quoted = *cp; - unescape_quotes (start, *cp, escape); - return start; + ); + + /* not yet end of string? */ + if (*p != '\0') + { + *p = '\0'; + string = p + 1; + if (was_quoted) + *was_quoted = *cp; + unescape_quotes(start, *cp, escape); + return start; + } + else + { + if (was_quoted) + *was_quoted = *cp; + string = p; + + unescape_quotes(start, *cp, escape); + return start; + } } - else { - if (was_quoted) - *was_quoted = *cp; - string = p; - unescape_quotes (start, *cp, escape); - return start; - } - } + /* otherwise no quoting character. scan till next delimiter */ + start = &string[offset]; - /* otherwise no quoting character. scan till next delimiter */ - start = &string[offset]; - - if (token_pos) - *token_pos = start - storage; + if (token_pos) + *token_pos = start - storage; - offset = strcspn(start, delim); - if (was_quoted) - *was_quoted = 0; + offset = strcspn(start, delim); + if (was_quoted) + *was_quoted = 0; - if (start[offset] != '\0') { - start[offset] = '\0'; - string = &start[offset]+1; + if (start[offset] != '\0') + { + start[offset] = '\0'; + string = &start[offset] + 1; - return start; - } - else { - string = &start[offset]; - return start; - } + return start; + } + else + { + string = &start[offset]; + return start; + } } @@ -142,38 +156,41 @@ char * strtokx(const char *s, static void unescape_quotes(char *source, char quote, char escape) { - char *p; - char *destination, *tmp; + char *p; + char *destination, + *tmp; #ifdef USE_ASSERT_CHECKING - assert(source); + assert(source); #endif - destination = (char *) calloc(1, strlen(source)+1); - if (!destination) { - perror("calloc"); - exit(EXIT_FAILURE); - } + destination = (char *) calloc(1, strlen(source) + 1); + if (!destination) + { + perror("calloc"); + exit(EXIT_FAILURE); + } - tmp = destination; + tmp = destination; - for (p = source; *p; p++) - { - char c; + for (p = source; *p; p++) + { + char c; - if (*p == escape && *(p+1) && quote == *(p+1)) { - c = *(p+1); - p++; - } - else - c = *p; + if (*p == escape && *(p + 1) && quote == *(p + 1)) + { + c = *(p + 1); + p++; + } + else + c = *p; - *tmp = c; - tmp ++; - } + *tmp = c; + tmp++; + } - /* Terminating null character */ - *tmp = '\0'; + /* Terminating null character */ + *tmp = '\0'; - strcpy(source, destination); + strcpy(source, destination); } diff --git a/src/bin/psql/stringutils.h b/src/bin/psql/stringutils.h index f505a7b2c1..5d72006c8e 100644 --- a/src/bin/psql/stringutils.h +++ b/src/bin/psql/stringutils.h @@ -3,12 +3,11 @@ /* The cooler version of strtok() which knows about quotes and doesn't * overwrite your input */ -extern char * -strtokx(const char *s, - const char *delim, - const char *quote, - char escape, - char * was_quoted, - unsigned int * token_pos); +extern char *strtokx(const char *s, + const char *delim, + const char *quote, + char escape, + char *was_quoted, + unsigned int *token_pos); #endif /* STRINGUTILS_H */ diff --git a/src/bin/psql/variables.c b/src/bin/psql/variables.c index ea824cff69..132ecc9322 100644 --- a/src/bin/psql/variables.c +++ b/src/bin/psql/variables.c @@ -6,127 +6,145 @@ #include <assert.h> -VariableSpace CreateVariableSpace(void) +VariableSpace +CreateVariableSpace(void) { - struct _variable *ptr; - - ptr = calloc(1, sizeof *ptr); - if (!ptr) return NULL; + struct _variable *ptr; + + ptr = calloc(1, sizeof *ptr); + if (!ptr) + return NULL; + + ptr->name = strdup("@"); + ptr->value = strdup(""); + if (!ptr->name || !ptr->value) + { + free(ptr->name); + free(ptr->value); + free(ptr); + return NULL; + } - ptr->name = strdup("@"); - ptr->value = strdup(""); - if (!ptr->name || !ptr->value) { - free(ptr->name); - free(ptr->value); - free(ptr); - return NULL; - } - - return ptr; + return ptr; } -const char * GetVariable(VariableSpace space, const char * name) +const char * +GetVariable(VariableSpace space, const char *name) { - struct _variable *current; + struct _variable *current; - if (!space) - return NULL; + if (!space) + return NULL; - if (strspn(name, VALID_VARIABLE_CHARS) != strlen(name)) return NULL; + if (strspn(name, VALID_VARIABLE_CHARS) != strlen(name)) + return NULL; - for (current = space; current; current = current->next) { + for (current = space; current; current = current->next) + { #ifdef USE_ASSERT_CHECKING - assert(current->name); - assert(current->value); + assert(current->name); + assert(current->value); #endif - if (strcmp(current->name, name)==0) - return current->value; - } + if (strcmp(current->name, name) == 0) + return current->value; + } - return NULL; + return NULL; } -bool GetVariableBool(VariableSpace space, const char * name) +bool +GetVariableBool(VariableSpace space, const char *name) { - return GetVariable(space, name)!=NULL ? true : false; + return GetVariable(space, name) != NULL ? true : false; } -bool SetVariable(VariableSpace space, const char * name, const char * value) +bool +SetVariable(VariableSpace space, const char *name, const char *value) { - struct _variable *current, *previous; + struct _variable *current, + *previous; - if (!space) - return false; + if (!space) + return false; - if (!value) - return DeleteVariable(space, name); + if (!value) + return DeleteVariable(space, name); - if (strspn(name, VALID_VARIABLE_CHARS) != strlen(name)) return false; + if (strspn(name, VALID_VARIABLE_CHARS) != strlen(name)) + return false; - for (current = space; current; previous = current, current = current->next) { + for (current = space; current; previous = current, current = current->next) + { #ifdef USE_ASSERT_CHECKING - assert(current->name); - assert(current->value); + assert(current->name); + assert(current->value); #endif - if (strcmp(current->name, name)==0) { - free (current->value); - current->value = strdup(value); - return current->value ? true : false; + if (strcmp(current->name, name) == 0) + { + free(current->value); + current->value = strdup(value); + return current->value ? true : false; + } } - } - - previous->next = calloc(1, sizeof *(previous->next)); - if (!previous->next) - return false; - previous->next->name = strdup(name); - if (!previous->next->name) - return false; - previous->next->value = strdup(value); - return previous->next->value ? true : false; + + previous->next = calloc(1, sizeof *(previous->next)); + if (!previous->next) + return false; + previous->next->name = strdup(name); + if (!previous->next->name) + return false; + previous->next->value = strdup(value); + return previous->next->value ? true : false; } -bool DeleteVariable(VariableSpace space, const char * name) +bool +DeleteVariable(VariableSpace space, const char *name) { - struct _variable *current, *previous; + struct _variable *current, + *previous; - if (!space) - return false; + if (!space) + return false; - if (strspn(name, VALID_VARIABLE_CHARS) != strlen(name)) return false; + if (strspn(name, VALID_VARIABLE_CHARS) != strlen(name)) + return false; - for (current = space, previous = NULL; current; previous = current, current = current->next) { + for (current = space, previous = NULL; current; previous = current, current = current->next) + { #ifdef USE_ASSERT_CHECKING - assert(current->name); - assert(current->value); + assert(current->name); + assert(current->value); #endif - if (strcmp(current->name, name)==0) { - free (current->name); - free (current->value); - if (previous) - previous->next = current->next; - free(current); - return true; + if (strcmp(current->name, name) == 0) + { + free(current->name); + free(current->value); + if (previous) + previous->next = current->next; + free(current); + return true; + } } - } - return true; + return true; } -void DestroyVariableSpace(VariableSpace space) +void +DestroyVariableSpace(VariableSpace space) { - if (!space) - return; + if (!space) + return; - DestroyVariableSpace(space->next); - free(space); + DestroyVariableSpace(space->next); + free(space); } diff --git a/src/bin/psql/variables.h b/src/bin/psql/variables.h index 9e2dd2e3a7..c8c3a0adae 100644 --- a/src/bin/psql/variables.h +++ b/src/bin/psql/variables.h @@ -13,21 +13,22 @@ #define VALID_VARIABLE_CHARS "abcdefghijklmnopqrstuvwxyz0123456789_" -struct _variable { - char * name; - char * value; - struct _variable * next; +struct _variable +{ + char *name; + char *value; + struct _variable *next; }; -typedef struct _variable * VariableSpace; +typedef struct _variable *VariableSpace; VariableSpace CreateVariableSpace(void); -const char * GetVariable(VariableSpace space, const char * name); -bool GetVariableBool(VariableSpace space, const char * name); -bool SetVariable(VariableSpace space, const char * name, const char * value); -bool DeleteVariable(VariableSpace space, const char * name); -void DestroyVariableSpace(VariableSpace space); +const char *GetVariable(VariableSpace space, const char *name); +bool GetVariableBool(VariableSpace space, const char *name); +bool SetVariable(VariableSpace space, const char *name, const char *value); +bool DeleteVariable(VariableSpace space, const char *name); +void DestroyVariableSpace(VariableSpace space); -#endif /* VARIABLES_H */ +#endif /* VARIABLES_H */ |