1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-23 14:01:44 +03:00

psql cleanup

This commit is contained in:
Bruce Momjian
1999-11-04 23:14:30 +00:00
parent 2323b63631
commit 0e6652e673
29 changed files with 5255 additions and 8040 deletions

View File

@ -35,8 +35,7 @@
/* functions for use in this file only */ /* functions for use in this file only */
static backslashResult static backslashResult exec_command(const char *cmd,
exec_command(const char * cmd,
char *const * options, char *const * options,
const char *options_string, const char *options_string,
PQExpBuffer query_buf, PQExpBuffer query_buf,
@ -84,32 +83,40 @@ HandleSlashCmds(PsqlSettings *pset,
const char *cmd; const char *cmd;
size_t blank_loc; size_t blank_loc;
int i; int i;
const char * continue_parse = NULL; /* tell the mainloop where the backslash command ended */ const char *continue_parse = NULL; /* tell the mainloop where the
* backslash command ended */
my_line = xstrdup(line); my_line = xstrdup(line);
/* Find the first whitespace (or backslash) /*
line[blank_loc] will now be the whitespace character * Find the first whitespace (or backslash) line[blank_loc] will now
or the \0 at the end */ * be the whitespace character or the \0 at the end
*/
blank_loc = strcspn(my_line, " \t"); blank_loc = strcspn(my_line, " \t");
/* do we have an option string? */ /* do we have an option string? */
if (my_line[blank_loc] != '\0') { if (my_line[blank_loc] != '\0')
{
options_string = &my_line[blank_loc + 1]; options_string = &my_line[blank_loc + 1];
my_line[blank_loc] = '\0'; my_line[blank_loc] = '\0';
} }
if (options_string) { if (options_string)
{
char quote; char quote;
unsigned int pos; unsigned int pos;
options_string = &options_string[strspn(options_string, " \t")]; /* skip leading whitespace */
options_string = &options_string[strspn(options_string, " \t")]; /* skip leading
* whitespace */
i = 0; i = 0;
token = strtokx(options_string, " \t", "\"'`", '\\', &quote, &pos); token = strtokx(options_string, " \t", "\"'`", '\\', &quote, &pos);
for (i = 0; token && i<16; i++) { for (i = 0; token && i < 16; i++)
switch(quote) { {
switch (quote)
{
case '"': case '"':
options[i] = unescape(token, pset); options[i] = unescape(token, pset);
break; break;
@ -126,17 +133,21 @@ HandleSlashCmds(PsqlSettings *pset,
size_t result; size_t result;
fd = popen(file, "r"); fd = popen(file, "r");
if (!fd) { if (!fd)
{
perror(file); perror(file);
error = true; error = true;
} }
if (!error) { if (!error)
{
initPQExpBuffer(&output); initPQExpBuffer(&output);
do { do
{
result = fread(buf, 1, 512, fd); result = fread(buf, 1, 512, fd);
if (ferror(fd)) { if (ferror(fd))
{
perror(file); perror(file);
error = true; error = true;
break; break;
@ -145,13 +156,15 @@ HandleSlashCmds(PsqlSettings *pset,
} while (!feof(fd)); } while (!feof(fd));
appendPQExpBufferChar(&output, '\0'); appendPQExpBufferChar(&output, '\0');
if (pclose(fd) == -1) { if (pclose(fd) == -1)
{
perror(file); perror(file);
error = true; error = true;
} }
} }
if (!error) { if (!error)
{
if (output.data[strlen(output.data) - 1] == '\n') if (output.data[strlen(output.data) - 1] == '\n')
output.data[strlen(output.data) - 1] = '\0'; output.data[strlen(output.data) - 1] = '\0';
} }
@ -159,7 +172,8 @@ HandleSlashCmds(PsqlSettings *pset,
free(file); free(file);
if (!error) if (!error)
options[i] = output.data; options[i] = output.data;
else { else
{
options[i] = xstrdup(""); options[i] = xstrdup("");
termPQExpBuffer(&output); termPQExpBuffer(&output);
} }
@ -187,11 +201,15 @@ HandleSlashCmds(PsqlSettings *pset,
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 (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. */ * 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]; const char *new_options[17];
char new_cmd[2]; char new_cmd[2];
int i; int i;
@ -206,7 +224,8 @@ HandleSlashCmds(PsqlSettings *pset,
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) { if (status == CMD_UNKNOWN)
{
fprintf(stderr, "Unrecognized command: \\%s. Try \\? for help.\n", cmd); fprintf(stderr, "Unrecognized command: \\%s. Try \\? for help.\n", cmd);
status = CMD_ERROR; status = CMD_ERROR;
} }
@ -215,7 +234,8 @@ HandleSlashCmds(PsqlSettings *pset,
continue_parse += 2; continue_parse += 2;
if (end_of_cmd) { if (end_of_cmd)
{
if (continue_parse) if (continue_parse)
*end_of_cmd = line + (continue_parse - my_line); *end_of_cmd = line + (continue_parse - my_line);
else else
@ -241,15 +261,19 @@ exec_command(const char * cmd,
PQExpBuffer query_buf, PQExpBuffer query_buf,
PsqlSettings *pset) PsqlSettings *pset)
{ {
bool success = true; /* indicate here if the command ran ok or failed */ bool success = true; /* indicate here if the command ran ok or
* failed */
bool quiet = GetVariableBool(pset->vars, "quiet"); 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. */ * \a -- toggle field alignment This is deprecated and makes no sense,
if (strcmp(cmd, "a") == 0) { * but we keep it around.
*/
if (strcmp(cmd, "a") == 0)
{
if (pset->popt.topt.format != PRINT_ALIGNED) if (pset->popt.topt.format != PRINT_ALIGNED)
success = do_pset("format", "aligned", &pset->popt, quiet); success = do_pset("format", "aligned", &pset->popt, quiet);
else else
@ -257,30 +281,36 @@ exec_command(const char * cmd,
} }
/* \C -- override table title /*
(formerly change HTML caption) This is deprecated. */ * \C -- override table title (formerly change HTML caption) This is
* deprecated.
*/
else if (strcmp(cmd, "C") == 0) else if (strcmp(cmd, "C") == 0)
success = do_pset("title", options[0], &pset->popt, quiet); success = do_pset("title", options[0], &pset->popt, quiet);
/* \c or \connect -- connect to new database or as different user /*
* \c or \connect -- connect to new database or as different user
* *
* \c foo bar : connect to db "foo" as user "bar" * \c foo bar : connect to db "foo" as user "bar" \c foo [-] :
* \c foo [-] : connect to db "foo" as current user * connect to db "foo" as current user \c - bar : connect to
* \c - bar : connect to current db as user "bar" * current db as user "bar" \c : connect to default db as
* \c : connect to default db as default user * default user
*/ */
else if (strcmp(cmd, "c") == 0 || strcmp(cmd, "connect") == 0) else if (strcmp(cmd, "c") == 0 || strcmp(cmd, "connect") == 0)
{ {
if (options[1]) if (options[1])
/* gave username */ /* gave username */
success = do_connect(options[0], options[1], pset); success = do_connect(options[0], options[1], pset);
else { else
{
if (options[0]) if (options[0])
/* gave database name */ /* gave database name */
success = do_connect(options[0], "", pset); /* empty string is same username as before, success = do_connect(options[0], "", pset); /* empty string is same
NULL would mean libpq default */ * username as before,
* NULL would mean libpq
* default */
else else
/* connect to default db as default user */ /* connect to default db as default user */
success = do_connect(NULL, NULL, pset); success = do_connect(NULL, NULL, pset);
@ -297,13 +327,16 @@ exec_command(const char * cmd,
print_copyright(); print_copyright();
/* \d* commands */ /* \d* commands */
else if (cmd[0] == 'd') { else if (cmd[0] == 'd')
switch(cmd[1]) { {
switch (cmd[1])
{
case '\0': case '\0':
if (options[0]) if (options[0])
success = describeTableDetails(options[0], pset); success = describeTableDetails(options[0], pset);
else else
success = listTables("tvs", NULL, pset); /* standard listing of interesting things */ success = listTables("tvs", NULL, pset); /* standard listing of
* interesting things */
break; break;
case 'a': case 'a':
success = describeAggregates(options[0], pset); success = describeAggregates(options[0], pset);
@ -326,7 +359,11 @@ exec_command(const char * cmd,
case 'T': case 'T':
success = describeTypes(options[0], pset); success = describeTypes(options[0], pset);
break; break;
case 't': case 'v': case 'i': case 's': case 'S': case 't':
case 'v':
case 'i':
case 's':
case 'S':
if (cmd[1] == 'S' && cmd[2] == '\0') if (cmd[1] == 'S' && cmd[2] == '\0')
success = listTables("Stvs", NULL, pset); success = listTables("Stvs", NULL, pset);
else else
@ -338,28 +375,35 @@ exec_command(const char * cmd,
} }
/* \e or \edit -- edit the current query buffer (or a file and make it the /*
query buffer */ * \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) else if (strcmp(cmd, "e") == 0 || strcmp(cmd, "edit") == 0)
status = do_edit(options[0], query_buf) ? CMD_NEWEDIT : CMD_ERROR; status = do_edit(options[0], query_buf) ? CMD_NEWEDIT : CMD_ERROR;
/* \echo */ /* \echo */
else if (strcmp(cmd, "echo") == 0) { else if (strcmp(cmd, "echo") == 0)
{
int i; int i;
for (i = 0; i < 16 && options[i]; i++) for (i = 0; i < 16 && options[i]; i++)
fputs(options[i], stdout); fputs(options[i], stdout);
fputs("\n", stdout); fputs("\n", stdout);
} }
/* \f -- change field separator /*
(This is deprecated in favour of \pset.) */ * \f -- change field separator (This is deprecated in favour of
* \pset.)
*/
else if (strcmp(cmd, "f") == 0) else if (strcmp(cmd, "f") == 0)
success = do_pset("fieldsep", options[0], &pset->popt, quiet); success = do_pset("fieldsep", options[0], &pset->popt, quiet);
/* \g means send query */ /* \g means send query */
else if (strcmp(cmd, "g") == 0) { else if (strcmp(cmd, "g") == 0)
{
if (!options[0]) if (!options[0])
pset->gfname = NULL; pset->gfname = NULL;
else else
@ -380,7 +424,8 @@ exec_command(const char * cmd,
/* \i is include file */ /* \i is include file */
else if (strcmp(cmd, "i") == 0 || strcmp(cmd, "include") == 0) else if (strcmp(cmd, "i") == 0 || strcmp(cmd, "include") == 0)
{ {
if (!options[0]) { if (!options[0])
{
fputs("Usage: \\i <filename>\n", stderr); fputs("Usage: \\i <filename>\n", stderr);
success = false; success = false;
} }
@ -394,9 +439,12 @@ exec_command(const char * cmd,
/* large object things */ /* large object things */
else if (strncmp(cmd, "lo_", 3)==0) { else if (strncmp(cmd, "lo_", 3) == 0)
if (strcmp(cmd+3, "export") == 0) { {
if (!options[1]) { if (strcmp(cmd + 3, "export") == 0)
{
if (!options[1])
{
fputs("Usage: \\lo_export <loid> <filename>\n", stderr); fputs("Usage: \\lo_export <loid> <filename>\n", stderr);
success = false; success = false;
} }
@ -404,8 +452,10 @@ exec_command(const char * cmd,
success = do_lo_export(pset, options[0], options[1]); success = do_lo_export(pset, options[0], options[1]);
} }
else if (strcmp(cmd+3, "import") == 0) { else if (strcmp(cmd + 3, "import") == 0)
if (!options[0]) { {
if (!options[0])
{
fputs("Usage: \\lo_import <filename> [<description>]\n", stderr); fputs("Usage: \\lo_import <filename> [<description>]\n", stderr);
success = false; success = false;
} }
@ -416,8 +466,10 @@ exec_command(const char * cmd,
else if (strcmp(cmd + 3, "list") == 0) else if (strcmp(cmd + 3, "list") == 0)
success = do_lo_list(pset); success = do_lo_list(pset);
else if (strcmp(cmd+3, "unlink") == 0) { else if (strcmp(cmd + 3, "unlink") == 0)
if (!options[0]) { {
if (!options[0])
{
fputs("Usage: \\lo_unlink <loid>\n", stderr); fputs("Usage: \\lo_unlink <loid>\n", stderr);
success = false; success = false;
} }
@ -444,8 +496,10 @@ exec_command(const char * cmd,
} }
/* \pset -- set printing parameters */ /* \pset -- set printing parameters */
else if (strcmp(cmd, "pset")==0) { else if (strcmp(cmd, "pset") == 0)
if (!options[0]) { {
if (!options[0])
{
fputs("Usage: \\pset <parameter> [<value>]\n", stderr); fputs("Usage: \\pset <parameter> [<value>]\n", stderr);
success = false; success = false;
} }
@ -458,8 +512,10 @@ exec_command(const char * cmd,
status = CMD_TERMINATE; status = CMD_TERMINATE;
/* \qecho */ /* \qecho */
else if (strcmp(cmd, "qecho") == 0) { else if (strcmp(cmd, "qecho") == 0)
{
int i; int i;
for (i = 0; i < 16 && options[i]; i++) for (i = 0; i < 16 && options[i]; i++)
fputs(options[i], pset->queryFout); fputs(options[i], pset->queryFout);
fputs("\n", pset->queryFout); fputs("\n", pset->queryFout);
@ -469,7 +525,8 @@ exec_command(const char * cmd,
else if (strcmp(cmd, "r") == 0 || strcmp(cmd, "reset") == 0) else if (strcmp(cmd, "r") == 0 || strcmp(cmd, "reset") == 0)
{ {
resetPQExpBuffer(query_buf); resetPQExpBuffer(query_buf);
if (!quiet) puts("Query buffer reset (cleared)."); if (!quiet)
puts("Query buffer reset (cleared).");
} }
@ -477,6 +534,7 @@ exec_command(const char * cmd,
else if (strcmp(cmd, "s") == 0) else if (strcmp(cmd, "s") == 0)
{ {
const char *fname; const char *fname;
if (!options[0]) if (!options[0])
fname = "/dev/tty"; fname = "/dev/tty";
else else
@ -492,17 +550,24 @@ exec_command(const char * cmd,
/* \set -- generalized set option command */ /* \set -- generalized set option command */
else if (strcmp(cmd, "set") == 0) else if (strcmp(cmd, "set") == 0)
{ {
if (!options[0]) { if (!options[0])
{
/* list all variables */ /* list all variables */
/* (This is in utter violation of the GetVariable abstraction, but
I have not dreamt up a better way.) */ /*
* (This is in utter violation of the GetVariable abstraction,
* but I have not dreamt up a better way.)
*/
struct _variable *ptr; struct _variable *ptr;
for (ptr = pset->vars; ptr->next; ptr = ptr->next) for (ptr = pset->vars; ptr->next; ptr = ptr->next)
fprintf(stdout, "%s = '%s'\n", ptr->next->name, ptr->next->value); fprintf(stdout, "%s = '%s'\n", ptr->next->name, ptr->next->value);
success = true; success = true;
} }
else { else
if (!SetVariable(pset->vars, options[0], options[1])) { {
if (!SetVariable(pset->vars, options[0], options[1]))
{
fprintf(stderr, "Set variable failed.\n"); fprintf(stderr, "Set variable failed.\n");
success = false; success = false;
} }
@ -525,12 +590,15 @@ exec_command(const char * cmd,
FILE *fd = NULL; FILE *fd = NULL;
bool pipe = false; bool pipe = false;
if (!options[0]) { if (!options[0])
{
fprintf(stderr, "Usage \\%s <filename>\n", cmd); fprintf(stderr, "Usage \\%s <filename>\n", cmd);
success = false; success = false;
} }
else { else
if (options[0][0] == '|') { {
if (options[0][0] == '|')
{
pipe = true; pipe = true;
#ifndef __CYGWIN32__ #ifndef __CYGWIN32__
fd = popen(&options[0][1], "w"); fd = popen(&options[0][1], "w");
@ -538,7 +606,8 @@ exec_command(const char * cmd,
fd = popen(&options[0][1], "wb"); fd = popen(&options[0][1], "wb");
#endif #endif
} }
else { else
{
#ifndef __CYGWIN32__ #ifndef __CYGWIN32__
fd = fopen(options[0], "w"); fd = fopen(options[0], "w");
#else #else
@ -546,13 +615,15 @@ exec_command(const char * cmd,
#endif #endif
} }
if (!fd) { if (!fd)
{
perror(options[0]); perror(options[0]);
success = false; success = false;
} }
} }
if (fd) { if (fd)
{
int result; int result;
if (query_buf && query_buf->len > 0) if (query_buf && query_buf->len > 0)
@ -563,7 +634,8 @@ exec_command(const char * cmd,
else else
result = fclose(fd); result = fclose(fd);
if (result == EOF) { if (result == EOF)
{
perror("close"); perror("close");
success = false; success = false;
} }
@ -588,21 +660,26 @@ exec_command(const char * cmd,
#ifdef NOT_USED #ifdef NOT_USED
/* These commands don't do anything. I just use them to test the parser. */
/*
* These commands don't do anything. I just use them to test the
* parser.
*/
else if (strcmp(cmd, "void") == 0 || strcmp(cmd, "#") == 0) else if (strcmp(cmd, "void") == 0 || strcmp(cmd, "#") == 0)
{ {
int i; int i;
fprintf(stderr, "+ optline = |%s|\n", options_string); fprintf(stderr, "+ optline = |%s|\n", options_string);
for (i = 0; options[i]; i++) for (i = 0; options[i]; i++)
fprintf(stderr, "+ opt%d = |%s|\n", i, options[i]); fprintf(stderr, "+ opt%d = |%s|\n", i, options[i]);
} }
#endif #endif
else { else
status = CMD_UNKNOWN; status = CMD_UNKNOWN;
}
if (!success) status = CMD_ERROR; if (!success)
status = CMD_ERROR;
return status; return status;
} }
@ -620,9 +697,10 @@ static char *
unescape(const char *source, PsqlSettings *pset) unescape(const char *source, PsqlSettings *pset)
{ {
unsigned char *p; unsigned char *p;
bool esc = false; /* Last character we saw was the bool esc = false; /* Last character we saw was the escape
escape character */ * character */
char *destination, *tmp; char *destination,
*tmp;
size_t length; size_t length;
#ifdef USE_ASSERT_CHECKING #ifdef USE_ASSERT_CHECKING
@ -632,13 +710,16 @@ unescape(const char * source, PsqlSettings * pset)
length = strlen(source) + 1; length = strlen(source) + 1;
tmp = destination = (char *) malloc(length); tmp = destination = (char *) malloc(length);
if (!tmp) { if (!tmp)
{
perror("malloc"); perror("malloc");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
for (p = (char *) source; *p; p += PQmblen(p)) { for (p = (char *) source; *p; p += PQmblen(p))
if (esc) { {
if (esc)
{
char c; char c;
switch (*p) switch (*p)
@ -655,11 +736,20 @@ unescape(const char * source, PsqlSettings * pset)
case 'f': case 'f':
c = '\f'; c = '\f';
break; break;
case '0': case '1': case '2': case '3': case '4': case '0':
case '5': case '6': case '7': case '8': case '9': case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
{ {
long int l; long int l;
char *end; char *end;
l = strtol(p, &end, 0); l = strtol(p, &end, 0);
c = l; c = l;
p = end - 1; p = end - 1;
@ -672,17 +762,18 @@ unescape(const char * source, PsqlSettings * pset)
esc = false; esc = false;
} }
else if (*p == '\\') { else if (*p == '\\')
esc = true; esc = true;
}
else if (*p == '$') else if (*p == '$')
{ {
if (*(p+1) == '{') { if (*(p + 1) == '{')
{
unsigned int len; unsigned int len;
char *copy; char *copy;
const char *value; const char *value;
void *new; void *new;
len = strcspn(p + 2, "}"); len = strcspn(p + 2, "}");
copy = xstrdup(p + 2); copy = xstrdup(p + 2);
copy[len] = '\0'; copy[len] = '\0';
@ -690,7 +781,8 @@ unescape(const char * source, PsqlSettings * pset)
length += strlen(value) - (len + 3); length += strlen(value) - (len + 3);
new = realloc(destination, length); new = realloc(destination, length);
if (!new) { if (!new)
{
perror("realloc"); perror("realloc");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -702,12 +794,12 @@ unescape(const char * source, PsqlSettings * pset)
p += len + 2; p += len + 2;
free(copy); free(copy);
} }
else { else
*tmp++ = '$'; *tmp++ = '$';
} }
}
else { else
{
*tmp++ = *p; *tmp++ = *p;
esc = false; esc = false;
} }
@ -749,9 +841,8 @@ do_connect(const char *new_dbname, const char *new_user, PsqlSettings * pset)
dbparam = new_dbname; dbparam = new_dbname;
/* If user is "" or "-" then use the old one */ /* If user is "" or "-" then use the old one */
if ( new_user && PQuser(oldconn) && ( strcmp(new_user, "")==0 || strcmp(new_user, "-")==0 || strcmp(new_user, PQuser(oldconn))==0 )) { if (new_user && PQuser(oldconn) && (strcmp(new_user, "") == 0 || strcmp(new_user, "-") == 0 || strcmp(new_user, PQuser(oldconn)) == 0))
userparam = PQuser(oldconn); userparam = PQuser(oldconn);
}
/* If username is "?" then prompt */ /* If username is "?" then prompt */
else if (new_user && strcmp(new_user, "?") == 0) else if (new_user && strcmp(new_user, "?") == 0)
userparam = prompted_user = simple_prompt("Username: ", 100, true); /* save for free() */ userparam = prompted_user = simple_prompt("Username: ", 100, true); /* save for free() */
@ -760,33 +851,39 @@ do_connect(const char *new_dbname, const char *new_user, PsqlSettings * pset)
/* need to prompt for password? */ /* need to prompt for password? */
if (pset->getPassword) if (pset->getPassword)
pwparam = prompted_password = simple_prompt("Password: ", 100, false); /* need to save for free() */ 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) */ /*
* Use old password if no new one given (if you didn't have an old
* one, fine)
*/
if (!pwparam) if (!pwparam)
pwparam = PQpass(oldconn); pwparam = PQpass(oldconn);
#ifdef MULTIBYTE #ifdef MULTIBYTE
/* /*
* PGCLIENTENCODING may be set by the previous connection. if a * PGCLIENTENCODING may be set by the previous connection. if a user
* user does not explicitly set PGCLIENTENCODING, we should * does not explicitly set PGCLIENTENCODING, we should discard
* discard PGCLIENTENCODING so that libpq could get the backend * PGCLIENTENCODING so that libpq could get the backend encoding as
* encoding as the default PGCLIENTENCODING value. -- 1998/12/12 * the default PGCLIENTENCODING value. -- 1998/12/12 Tatsuo Ishii
* Tatsuo Ishii
*/ */
if (!pset->has_client_encoding) if (!pset->has_client_encoding)
putenv("PGCLIENTENCODING="); putenv("PGCLIENTENCODING=");
#endif #endif
do { do
{
need_pass = false; need_pass = false;
pset->db = PQsetdbLogin(PQhost(oldconn), PQport(oldconn), pset->db = PQsetdbLogin(PQhost(oldconn), PQport(oldconn),
NULL, NULL, dbparam, userparam, pwparam); NULL, NULL, dbparam, userparam, pwparam);
if (PQstatus(pset->db) == CONNECTION_BAD && if (PQstatus(pset->db) == CONNECTION_BAD &&
strcmp(PQerrorMessage(pset->db), "fe_sendauth: no password supplied\n")==0) { strcmp(PQerrorMessage(pset->db), "fe_sendauth: no password supplied\n") == 0)
{
need_pass = true; need_pass = true;
free(prompted_password); free(prompted_password);
prompted_password = NULL; prompted_password = NULL;
@ -797,32 +894,38 @@ do_connect(const char *new_dbname, const char *new_user, PsqlSettings * pset)
free(prompted_password); free(prompted_password);
free(prompted_user); 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 * If connection failed, try at least keep the old one. That's
program. */ * probably more convenient than just kicking you out of the program.
*/
if (!pset->db || PQstatus(pset->db) == CONNECTION_BAD) if (!pset->db || PQstatus(pset->db) == CONNECTION_BAD)
{ {
fprintf(stderr, "Could not establish database connection.\n%s", PQerrorMessage(pset->db)); fprintf(stderr, "Could not establish database connection.\n%s", PQerrorMessage(pset->db));
PQfinish(pset->db); PQfinish(pset->db);
if (!oldconn || !pset->cur_cmd_interactive) { /* we don't want unpredictable things to happen if (!oldconn || !pset->cur_cmd_interactive)
in scripting mode */ { /* we don't want unpredictable things to
* happen in scripting mode */
fputs("Terminating.\n", stderr); fputs("Terminating.\n", stderr);
if (oldconn) if (oldconn)
PQfinish(oldconn); PQfinish(oldconn);
pset->db = NULL; pset->db = NULL;
} }
else { else
{
fputs("Keeping old connection.\n", stderr); fputs("Keeping old connection.\n", stderr);
pset->db = oldconn; pset->db = oldconn;
} }
} }
else { else
if (!GetVariable(pset->vars, "quiet")) { {
if (!GetVariable(pset->vars, "quiet"))
{
if (userparam != new_user) /* no new user */ if (userparam != new_user) /* no new user */
printf("You are now connected to database %s.\n", dbparam); printf("You are now connected to database %s.\n", dbparam);
else if (dbparam != new_dbname) /* no new db */ else if (dbparam != new_dbname) /* no new db */
printf("You are now connected as new user %s.\n", new_user); printf("You are now connected as new user %s.\n", new_user);
else /* both new */ else
/* both new */
printf("You are now connected to database %s as user %s.\n", printf("You are now connected to database %s as user %s.\n",
PQdb(pset->db), PQuser(pset->db)); PQdb(pset->db), PQuser(pset->db));
} }
@ -855,7 +958,8 @@ editFile(const char *fname)
#ifdef USE_ASSERT_CHECKING #ifdef USE_ASSERT_CHECKING
assert(fname); assert(fname);
#else #else
if (!fname) return false; if (!fname)
return false;
#endif #endif
/* Find an editor to use */ /* Find an editor to use */
@ -888,21 +992,26 @@ do_edit(const char *filename_arg, PQExpBuffer query_buf)
FILE *stream; FILE *stream;
const char *fname; const char *fname;
bool error = false; bool error = false;
#ifndef WIN32 #ifndef WIN32
struct stat before, after; struct stat before,
after;
#endif #endif
#ifdef USE_ASSERT_CHECKING #ifdef USE_ASSERT_CHECKING
assert(query_buf); assert(query_buf);
#else #else
if (!query_buf) return false; if (!query_buf)
return false;
#endif #endif
if (filename_arg) if (filename_arg)
fname = filename_arg; fname = filename_arg;
else { else
{
/* make a temp file to edit */ /* make a temp file to edit */
#ifndef WIN32 #ifndef WIN32
mode_t oldumask; mode_t oldumask;
@ -921,18 +1030,23 @@ do_edit(const char *filename_arg, PQExpBuffer query_buf)
umask(oldumask); umask(oldumask);
#endif #endif
if (!stream) { if (!stream)
{
perror(fname); perror(fname);
error = true; error = true;
} }
else { else
{
unsigned int ql = query_buf->len; unsigned int ql = query_buf->len;
if (ql == 0 || query_buf->data[ql - 1] != '\n') {
if (ql == 0 || query_buf->data[ql - 1] != '\n')
{
appendPQExpBufferChar(query_buf, '\n'); appendPQExpBufferChar(query_buf, '\n');
ql++; ql++;
} }
if (fwrite(query_buf->data, 1, ql, stream) != ql) { if (fwrite(query_buf->data, 1, ql, stream) != ql)
{
perror(fname); perror(fname);
fclose(stream); fclose(stream);
remove(fname); remove(fname);
@ -944,7 +1058,8 @@ do_edit(const char *filename_arg, PQExpBuffer query_buf)
} }
#ifndef WIN32 #ifndef WIN32
if (!error && stat(fname, &before) != 0) { if (!error && stat(fname, &before) != 0)
{
perror(fname); perror(fname);
error = true; error = true;
} }
@ -955,29 +1070,36 @@ do_edit(const char *filename_arg, PQExpBuffer query_buf)
error = !editFile(fname); error = !editFile(fname);
#ifndef WIN32 #ifndef WIN32
if (!error && stat(fname, &after) !=0) { if (!error && stat(fname, &after) != 0)
{
perror(fname); perror(fname);
error = true; error = true;
} }
if (!error && before.st_mtime != after.st_mtime) { if (!error && before.st_mtime != after.st_mtime)
{
#else #else
if (!error) { if (!error)
{
#endif #endif
stream = fopen(fname, "r"); stream = fopen(fname, "r");
if (!stream) { if (!stream)
{
perror(fname); perror(fname);
error = true; error = true;
} }
else { else
{
/* read file back in */ /* read file back in */
char line[1024]; char line[1024];
size_t result; size_t result;
resetPQExpBuffer(query_buf); resetPQExpBuffer(query_buf);
do { do
{
result = fread(line, 1, 1024, stream); result = fread(line, 1, 1024, stream);
if (ferror(stream)) { if (ferror(stream))
{
perror(fname); perror(fname);
error = true; error = true;
break; break;
@ -1020,7 +1142,8 @@ process_file(const char *filename, PsqlSettings *pset)
fd = fopen(filename, "r"); fd = fopen(filename, "r");
#endif #endif
if (!fd) { if (!fd)
{
perror(filename); perror(filename);
return false; return false;
} }
@ -1039,7 +1162,8 @@ process_file(const char *filename, PsqlSettings *pset)
static const char * static const char *
_align2string(enum printFormat in) _align2string(enum printFormat in)
{ {
switch (in) { switch (in)
{
case PRINT_NOTHING: case PRINT_NOTHING:
return "nothing"; return "nothing";
break; break;
@ -1064,17 +1188,20 @@ 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 #ifdef USE_ASSERT_CHECKING
assert(param); assert(param);
#else #else
if (!param) return false; if (!param)
return false;
#endif #endif
if (value) if (value)
vallen = strlen(value); vallen = strlen(value);
/* set format */ /* set format */
if (strcmp(param, "format")==0) { if (strcmp(param, "format") == 0)
{
if (!value) if (!value)
; ;
else if (strncasecmp("unaligned", value, vallen) == 0) else if (strncasecmp("unaligned", value, vallen) == 0)
@ -1085,7 +1212,8 @@ do_pset(const char * param, const char * value, printQueryOpt * popt, bool quiet
popt->topt.format = PRINT_HTML; popt->topt.format = PRINT_HTML;
else if (strncasecmp("latex", value, vallen) == 0) else if (strncasecmp("latex", value, vallen) == 0)
popt->topt.format = PRINT_LATEX; popt->topt.format = PRINT_LATEX;
else { else
{
fprintf(stderr, "Allowed formats are unaligned, aligned, html, latex.\n"); fprintf(stderr, "Allowed formats are unaligned, aligned, html, latex.\n");
return false; return false;
} }
@ -1095,7 +1223,8 @@ do_pset(const char * param, const char * value, printQueryOpt * popt, bool quiet
} }
/* set border style/width */ /* set border style/width */
else if (strcmp(param, "border")==0) { else if (strcmp(param, "border") == 0)
{
if (value) if (value)
popt->topt.border = atoi(value); popt->topt.border = atoi(value);
@ -1104,15 +1233,18 @@ do_pset(const char * param, const char * value, printQueryOpt * popt, bool quiet
} }
/* set expanded/vertical mode */ /* set expanded/vertical mode */
else if (strcmp(param, "x")==0 || strcmp(param, "expanded")==0 || strcmp(param, "vertical")==0) { else if (strcmp(param, "x") == 0 || strcmp(param, "expanded") == 0 || strcmp(param, "vertical") == 0)
{
popt->topt.expanded = !popt->topt.expanded; popt->topt.expanded = !popt->topt.expanded;
if (!quiet) if (!quiet)
printf("Expanded display is %s.\n", popt->topt.expanded ? "on" : "off"); printf("Expanded display is %s.\n", popt->topt.expanded ? "on" : "off");
} }
/* null display */ /* null display */
else if (strcmp(param, "null")==0) { else if (strcmp(param, "null") == 0)
if (value) { {
if (value)
{
free(popt->nullPrint); free(popt->nullPrint);
popt->nullPrint = xstrdup(value); popt->nullPrint = xstrdup(value);
} }
@ -1121,8 +1253,10 @@ do_pset(const char * param, const char * value, printQueryOpt * popt, bool quiet
} }
/* field separator for unaligned text */ /* field separator for unaligned text */
else if (strcmp(param, "fieldsep")==0) { else if (strcmp(param, "fieldsep") == 0)
if (value) { {
if (value)
{
free(popt->topt.fieldSep); free(popt->topt.fieldSep);
popt->topt.fieldSep = xstrdup(value); popt->topt.fieldSep = xstrdup(value);
} }
@ -1131,9 +1265,11 @@ do_pset(const char * param, const char * value, printQueryOpt * popt, bool quiet
} }
/* toggle between full and barebones format */ /* toggle between full and barebones format */
else if (strcmp(param, "t")==0 || strcmp(param, "tuples_only")==0) { else if (strcmp(param, "t") == 0 || strcmp(param, "tuples_only") == 0)
{
popt->topt.tuples_only = !popt->topt.tuples_only; popt->topt.tuples_only = !popt->topt.tuples_only;
if (!quiet) { if (!quiet)
{
if (popt->topt.tuples_only) if (popt->topt.tuples_only)
puts("Showing only tuples."); puts("Showing only tuples.");
else else
@ -1142,14 +1278,16 @@ do_pset(const char * param, const char * value, printQueryOpt * popt, bool quiet
} }
/* set title override */ /* set title override */
else if (strcmp(param, "title")==0) { else if (strcmp(param, "title") == 0)
{
free(popt->title); free(popt->title);
if (!value) if (!value)
popt->title = NULL; popt->title = NULL;
else else
popt->title = xstrdup(value); popt->title = xstrdup(value);
if (!quiet) { if (!quiet)
{
if (popt->title) if (popt->title)
printf("Title is \"%s\".\n", popt->title); printf("Title is \"%s\".\n", popt->title);
else else
@ -1158,14 +1296,16 @@ do_pset(const char * param, const char * value, printQueryOpt * popt, bool quiet
} }
/* set HTML table tag options */ /* set HTML table tag options */
else if (strcmp(param, "T")==0 || strcmp(param, "tableattr")==0) { else if (strcmp(param, "T") == 0 || strcmp(param, "tableattr") == 0)
{
free(popt->topt.tableAttr); free(popt->topt.tableAttr);
if (!value) if (!value)
popt->topt.tableAttr = NULL; popt->topt.tableAttr = NULL;
else else
popt->topt.tableAttr = xstrdup(value); popt->topt.tableAttr = xstrdup(value);
if (!quiet) { if (!quiet)
{
if (popt->topt.tableAttr) if (popt->topt.tableAttr)
printf("Table attribute is \"%s\".\n", popt->topt.tableAttr); printf("Table attribute is \"%s\".\n", popt->topt.tableAttr);
else else
@ -1174,9 +1314,11 @@ do_pset(const char * param, const char * value, printQueryOpt * popt, bool quiet
} }
/* toggle use of pager */ /* toggle use of pager */
else if (strcmp(param, "pager")==0) { else if (strcmp(param, "pager") == 0)
{
popt->topt.pager = !popt->topt.pager; popt->topt.pager = !popt->topt.pager;
if (!quiet) { if (!quiet)
{
if (popt->topt.pager) if (popt->topt.pager)
puts("Using pager is on."); puts("Using pager is on.");
else else
@ -1185,7 +1327,8 @@ do_pset(const char * param, const char * value, printQueryOpt * popt, bool quiet
} }
else { else
{
fprintf(stderr, "Unknown option: %s\n", param); fprintf(stderr, "Unknown option: %s\n", param);
return false; return false;
} }
@ -1202,7 +1345,8 @@ do_shell(const char *command)
{ {
int result; int result;
if (!command) { if (!command)
{
char *sys; char *sys;
char *shellName; char *shellName;
@ -1220,7 +1364,8 @@ do_shell(const char *command)
else else
result = system(command); result = system(command);
if (result==127 || result==-1) { if (result == 127 || result == -1)
{
perror("system"); perror("system");
return false; return false;
} }

View File

@ -11,36 +11,33 @@
typedef enum _backslashResult { typedef enum _backslashResult
{
CMD_UNKNOWN = 0, /* not done parsing yet (internal only) */ CMD_UNKNOWN = 0, /* not done parsing yet (internal only) */
CMD_SEND, /* query complete; send off */ CMD_SEND, /* query complete; send off */
CMD_SKIP_LINE, /* keep building query */ CMD_SKIP_LINE, /* keep building query */
CMD_TERMINATE, /* quit program */ CMD_TERMINATE, /* quit program */
CMD_NEWEDIT, /* query buffer was changed (e.g., via \e) */ CMD_NEWEDIT, /* query buffer was changed (e.g., via \e) */
CMD_ERROR /* the execution of the backslash command resulted CMD_ERROR /* the execution of the backslash command
in an error */ * resulted in an error */
} backslashResult; } backslashResult;
backslashResult backslashResult HandleSlashCmds(PsqlSettings *pset,
HandleSlashCmds(PsqlSettings *pset,
const char *line, const char *line,
PQExpBuffer query_buf, PQExpBuffer query_buf,
const char **end_of_cmd); const char **end_of_cmd);
bool bool do_connect(const char *new_dbname,
do_connect(const char *new_dbname,
const char *new_user, const char *new_user,
PsqlSettings *pset); PsqlSettings *pset);
bool bool process_file(const char *filename,
process_file(const char *filename,
PsqlSettings *pset); PsqlSettings *pset);
bool bool do_pset(const char *param,
do_pset(const char * param,
const char *value, const char *value,
printQueryOpt * popt, printQueryOpt * popt,
bool quiet); bool quiet);

View File

@ -39,15 +39,19 @@
* "Safe" wrapper around strdup() * "Safe" wrapper around strdup()
* (Using this also avoids writing #ifdef HAVE_STRDUP in every file :) * (Using this also avoids writing #ifdef HAVE_STRDUP in every file :)
*/ */
char * xstrdup(const char * string) char *
xstrdup(const char *string)
{ {
char *tmp; char *tmp;
if (!string) {
if (!string)
{
fprintf(stderr, "xstrdup: Cannot duplicate null pointer.\n"); fprintf(stderr, "xstrdup: Cannot duplicate null pointer.\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
tmp = strdup(string); tmp = strdup(string);
if (!tmp) { if (!tmp)
{
perror("strdup"); perror("strdup");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -72,7 +76,8 @@ setQFout(const char *fname, PsqlSettings *pset)
#ifdef USE_ASSERT_CHECKING #ifdef USE_ASSERT_CHECKING
assert(pset); assert(pset);
#else #else
if (!pset) return false; if (!pset)
return false;
#endif #endif
/* Close old file/pipe */ /* Close old file/pipe */
@ -150,13 +155,16 @@ simple_prompt(const char *prompt, int maxlen, bool echo)
char *destination; char *destination;
#ifdef HAVE_TERMIOS_H #ifdef HAVE_TERMIOS_H
struct termios t_orig, t; struct termios t_orig,
t;
#endif #endif
destination = (char *) malloc(maxlen + 2); destination = (char *) malloc(maxlen + 2);
if (!destination) if (!destination)
return NULL; return NULL;
if (prompt) fputs(prompt, stdout); if (prompt)
fputs(prompt, stdout);
#ifdef HAVE_TERMIOS_H #ifdef HAVE_TERMIOS_H
if (!echo) if (!echo)
@ -171,17 +179,21 @@ simple_prompt(const char *prompt, int maxlen, bool echo)
fgets(destination, maxlen, stdin); fgets(destination, maxlen, stdin);
#ifdef HAVE_TERMIOS_H #ifdef HAVE_TERMIOS_H
if (!echo) { if (!echo)
{
tcsetattr(0, TCSADRAIN, &t_orig); tcsetattr(0, TCSADRAIN, &t_orig);
puts(""); puts("");
} }
#endif #endif
length = strlen(destination); length = strlen(destination);
if (length > 0 && destination[length - 1] != '\n') { if (length > 0 && destination[length - 1] != '\n')
{
/* eat rest of the line */ /* eat rest of the line */
char buf[512]; char buf[512];
do {
do
{
fgets(buf, 512, stdin); fgets(buf, 512, stdin);
} while (buf[strlen(buf) - 1] != '\n'); } while (buf[strlen(buf) - 1] != '\n');
} }
@ -213,10 +225,12 @@ interpolate_var(const char * name, PsqlSettings * pset)
assert(name); assert(name);
assert(pset); assert(pset);
#else #else
if (!name || !pset) return NULL; if (!name || !pset)
return NULL;
#endif #endif
if (strspn(name, VALID_VARIABLE_CHARS) == strlen(name)) { if (strspn(name, VALID_VARIABLE_CHARS) == strlen(name))
{
var = GetVariable(pset->vars, name); var = GetVariable(pset->vars, name);
if (var) if (var)
return var; return var;
@ -225,41 +239,50 @@ interpolate_var(const char * name, PsqlSettings * pset)
} }
/* otherwise return magic variable */ /* 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) */ /*
* (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) if (strcmp(name, "Version") == 0)
return PG_VERSION_STR; return PG_VERSION_STR;
if (strcmp(name, "Database")==0) { if (strcmp(name, "Database") == 0)
{
if (PQdb(pset->db)) if (PQdb(pset->db))
return PQdb(pset->db); return PQdb(pset->db);
else else
return ""; return "";
} }
if (strcmp(name, "User")==0) { if (strcmp(name, "User") == 0)
{
if (PQuser(pset->db)) if (PQuser(pset->db))
return PQuser(pset->db); return PQuser(pset->db);
else else
return ""; return "";
} }
if (strcmp(name, "Host")==0) { if (strcmp(name, "Host") == 0)
{
if (PQhost(pset->db)) if (PQhost(pset->db))
return PQhost(pset->db); return PQhost(pset->db);
else else
return ""; return "";
} }
if (strcmp(name, "Port")==0) { if (strcmp(name, "Port") == 0)
{
if (PQport(pset->db)) if (PQport(pset->db))
return PQport(pset->db); return PQport(pset->db);
else else
return ""; return "";
} }
/* env vars (if env vars are all caps there should be no prob, otherwise /*
you're on your own */ * env vars (if env vars are all caps there should be no prob,
* otherwise you're on your own
*/
if ((var = getenv(name))) if ((var = getenv(name)))
return var; return var;
@ -302,7 +325,8 @@ handle_sigint(SIGNAL_ARGS)
/* Try to send cancel request */ /* Try to send cancel request */
if (PQrequestCancel(cancelConn)) if (PQrequestCancel(cancelConn))
safe_write_stderr("\nCANCEL request sent\n"); safe_write_stderr("\nCANCEL request sent\n");
else { else
{
safe_write_stderr("\nCould not send cancel request: "); safe_write_stderr("\nCould not send cancel request: ");
safe_write_stderr(PQerrorMessage(cancelConn)); safe_write_stderr(PQerrorMessage(cancelConn));
} }
@ -322,13 +346,15 @@ PSQLexec(PsqlSettings *pset, const char *query)
PGresult *res; PGresult *res;
const char *var; const char *var;
if (!pset->db) { if (!pset->db)
{
fputs("You are not currently connected to a database.\n", stderr); fputs("You are not currently connected to a database.\n", stderr);
return NULL; return NULL;
} }
var = GetVariable(pset->vars, "echo_secret"); var = GetVariable(pset->vars, "echo_secret");
if (var) { if (var)
{
printf("********* QUERY *********\n%s\n*************************\n\n", query); printf("********* QUERY *********\n%s\n*************************\n\n", query);
fflush(stdout); fflush(stdout);
} }
@ -347,7 +373,8 @@ PSQLexec(PsqlSettings *pset, const char *query)
{ {
fputs("The connection to the server was lost. Attempting reset: ", stderr); fputs("The connection to the server was lost. Attempting reset: ", stderr);
PQreset(pset->db); PQreset(pset->db);
if (PQstatus(pset->db) == CONNECTION_BAD) { if (PQstatus(pset->db) == CONNECTION_BAD)
{
fputs("Failed.\n", stderr); fputs("Failed.\n", stderr);
PQfinish(pset->db); PQfinish(pset->db);
PQclear(res); PQclear(res);
@ -364,7 +391,8 @@ PSQLexec(PsqlSettings *pset, const char *query)
PQresultStatus(res) == PGRES_COPY_OUT) PQresultStatus(res) == PGRES_COPY_OUT)
) )
return res; return res;
else { else
{
fprintf(stderr, "%s", PQerrorMessage(pset->db)); fprintf(stderr, "%s", PQerrorMessage(pset->db));
PQclear(res); PQclear(res);
return NULL; return NULL;
@ -392,13 +420,16 @@ SendQuery(PsqlSettings *pset, const char *query)
PGresult *results; PGresult *results;
PGnotify *notify; PGnotify *notify;
if (!pset->db) { if (!pset->db)
{
fputs("You are not currently connected to a database.\n", stderr); fputs("You are not currently connected to a database.\n", stderr);
return false; return false;
} }
if (GetVariableBool(pset->vars, "singlestep")) { if (GetVariableBool(pset->vars, "singlestep"))
{
char buf[3]; char buf[3];
fprintf(stdout, "***(Single step mode: Verify query)*********************************************\n" fprintf(stdout, "***(Single step mode: Verify query)*********************************************\n"
"QUERY: %s\n" "QUERY: %s\n"
"***(press return to proceed or enter x and return to cancel)********************\n", "***(press return to proceed or enter x and return to cancel)********************\n",
@ -432,7 +463,8 @@ SendQuery(PsqlSettings *pset, const char *query)
PsqlSettings settings_copy = *pset; PsqlSettings settings_copy = *pset;
settings_copy.queryFout = stdout; settings_copy.queryFout = stdout;
if (!setQFout(pset->gfname, &settings_copy)) { if (!setQFout(pset->gfname, &settings_copy))
{
success = false; success = false;
break; break;
} }
@ -491,7 +523,8 @@ SendQuery(PsqlSettings *pset, const char *query)
{ {
fputs("The connection to the server was lost. Attempting reset: ", stderr); fputs("The connection to the server was lost. Attempting reset: ", stderr);
PQreset(pset->db); PQreset(pset->db);
if (PQstatus(pset->db) == CONNECTION_BAD) { if (PQstatus(pset->db) == CONNECTION_BAD)
{
fputs("Failed.\n", stderr); fputs("Failed.\n", stderr);
PQfinish(pset->db); PQfinish(pset->db);
PQclear(results); PQclear(results);

View File

@ -33,7 +33,8 @@
* returns a malloc'ed structure with the options, or NULL on parsing error * returns a malloc'ed structure with the options, or NULL on parsing error
*/ */
struct copy_options { struct copy_options
{
char *table; char *table;
char *file; char *file;
bool from; bool from;
@ -66,7 +67,8 @@ parse_slash_copy(const char *args)
line = xstrdup(args); line = xstrdup(args);
if (!(result = calloc(1, sizeof (struct copy_options)))) { if (!(result = calloc(1, sizeof(struct copy_options))))
{
perror("calloc"); perror("calloc");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -74,8 +76,10 @@ parse_slash_copy(const char *args)
token = strtokx(line, " \t", "\"", '\\', &quote, NULL); token = strtokx(line, " \t", "\"", '\\', &quote, NULL);
if (!token) if (!token)
error = true; error = true;
else { else
if (!quote && strcasecmp(token, "binary")==0) { {
if (!quote && strcasecmp(token, "binary") == 0)
{
result->binary = true; result->binary = true;
token = strtokx(NULL, " \t", "\"", '\\', &quote, NULL); token = strtokx(NULL, " \t", "\"", '\\', &quote, NULL);
if (!token) if (!token)
@ -89,19 +93,23 @@ parse_slash_copy(const char *args)
assert(error || result->table); assert(error || result->table);
#endif #endif
if (!error) { if (!error)
{
token = strtokx(NULL, " \t", NULL, '\\', NULL, NULL); token = strtokx(NULL, " \t", NULL, '\\', NULL, NULL);
if (!token) if (!token)
error = true; error = true;
else { else
if (strcasecmp(token, "with")==0) { {
if (strcasecmp(token, "with") == 0)
{
token = strtokx(NULL, " \t", NULL, '\\', NULL, NULL); token = strtokx(NULL, " \t", NULL, '\\', NULL, NULL);
if (!token || strcasecmp(token, "oids") != 0) if (!token || strcasecmp(token, "oids") != 0)
error = true; error = true;
else else
result->oids = true; result->oids = true;
if (!error) { if (!error)
{
token = strtokx(NULL, " \t", NULL, '\\', NULL, NULL); token = strtokx(NULL, " \t", NULL, '\\', NULL, NULL);
if (!token) if (!token)
error = true; error = true;
@ -117,7 +125,8 @@ parse_slash_copy(const char *args)
} }
} }
if (!error) { if (!error)
{
token = strtokx(NULL, " \t", "'", '\\', NULL, NULL); token = strtokx(NULL, " \t", "'", '\\', NULL, NULL);
if (!token) if (!token)
error = true; error = true;
@ -129,16 +138,20 @@ parse_slash_copy(const char *args)
assert(error || result->file); assert(error || result->file);
#endif #endif
if (!error) { if (!error)
{
token = strtokx(NULL, " \t", NULL, '\\', NULL, NULL); token = strtokx(NULL, " \t", NULL, '\\', NULL, NULL);
if (token) { if (token)
{
if (strcasecmp(token, "using") != 0) if (strcasecmp(token, "using") != 0)
error = true; error = true;
else { else
{
token = strtokx(NULL, " \t", NULL, '\\', NULL, NULL); token = strtokx(NULL, " \t", NULL, '\\', NULL, NULL);
if (!token || strcasecmp(token, "delimiters") != 0) if (!token || strcasecmp(token, "delimiters") != 0)
error = true; error = true;
else { else
{
token = strtokx(NULL, " \t", "'", '\\', NULL, NULL); token = strtokx(NULL, " \t", "'", '\\', NULL, NULL);
if (token) if (token)
result->delim = xstrdup(token); result->delim = xstrdup(token);
@ -151,7 +164,8 @@ parse_slash_copy(const char *args)
free(line); free(line);
if (error) { if (error)
{
fputs("Parse error at ", stderr); fputs("Parse error at ", stderr);
if (!token) if (!token)
fputs("end of line.", stderr); fputs("end of line.", stderr);
@ -204,10 +218,14 @@ do_copy(const char * args, PsqlSettings *pset)
strcat(query, "TO stdout"); strcat(query, "TO stdout");
if (options->delim) { 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) */ /*
* 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); strncat(query, " USING DELIMITERS '", 2);
strcat(query, options->delim); strcat(query, options->delim);
strcat(query, "'"); strcat(query, "'");
@ -227,7 +245,8 @@ do_copy(const char * args, PsqlSettings *pset)
copystream = fopen(options->file, "wb"); copystream = fopen(options->file, "wb");
#endif #endif
if (!copystream) { if (!copystream)
{
fprintf(stderr, fprintf(stderr,
"Unable to open file %s which to copy: %s\n", "Unable to open file %s which to copy: %s\n",
options->from ? "from" : "to", strerror(errno)); options->from ? "from" : "to", strerror(errno));
@ -258,7 +277,8 @@ do_copy(const char * args, PsqlSettings *pset)
PQclear(result); PQclear(result);
if (!GetVariable(pset->vars, "quiet")) { if (!GetVariable(pset->vars, "quiet"))
{
if (success) if (success)
puts("Successfully copied."); puts("Successfully copied.");
else else

View File

@ -36,15 +36,19 @@
bool 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 */ char descbuf[384 + 2 * REGEXP_CUTOFF]; /* observe/adjust this
* if you change the
* query */
PGresult *res; PGresult *res;
bool description = GetVariableBool(pset->vars, "description"); bool description = GetVariableBool(pset->vars, "description");
printQueryOpt myopt = pset->popt; printQueryOpt myopt = pset->popt;
descbuf[0] = '\0'; descbuf[0] = '\0';
/* There are two kinds of aggregates: ones that work on particular types /*
ones that work on all */ * There are two kinds of aggregates: ones that work on particular
* types ones that work on all
*/
strcat(descbuf, strcat(descbuf,
"SELECT a.aggname AS \"Name\", t.typname AS \"Type\""); "SELECT a.aggname AS \"Name\", t.typname AS \"Type\"");
if (description) if (description)
@ -53,7 +57,8 @@ describeAggregates(const char * name, PsqlSettings * pset)
strcat(descbuf, strcat(descbuf,
"\nFROM pg_aggregate a, pg_type t\n" "\nFROM pg_aggregate a, pg_type t\n"
"WHERE a.aggbasetype = t.oid\n"); "WHERE a.aggbasetype = t.oid\n");
if (name) { if (name)
{
strcat(descbuf, " AND a.aggname ~* '^"); strcat(descbuf, " AND a.aggname ~* '^");
strncat(descbuf, name, REGEXP_CUTOFF); strncat(descbuf, name, REGEXP_CUTOFF);
strcat(descbuf, "'\n"); strcat(descbuf, "'\n");
@ -103,9 +108,8 @@ describeFunctions(const char * name, PsqlSettings * pset)
printQueryOpt myopt = pset->popt; printQueryOpt myopt = pset->popt;
/* /*
* we skip in/out funcs by excluding functions that take * we skip in/out funcs by excluding functions that take some
* some arguments, but have no types defined for those * arguments, but have no types defined for those arguments
* arguments
*/ */
descbuf[0] = '\0'; descbuf[0] = '\0';
@ -158,7 +162,8 @@ describeTypes(const char * name, PsqlSettings * pset)
strcat(descbuf, "\nFROM pg_type\n" strcat(descbuf, "\nFROM pg_type\n"
"WHERE typrelid = 0 AND typname !~ '^_.*'\n"); "WHERE typrelid = 0 AND typname !~ '^_.*'\n");
if (name) { if (name)
{
strcat(descbuf, " AND typname ~* '^"); strcat(descbuf, " AND typname ~* '^");
strncat(descbuf, name, REGEXP_CUTOFF); strncat(descbuf, name, REGEXP_CUTOFF);
strcat(descbuf, "' "); strcat(descbuf, "' ");
@ -189,7 +194,8 @@ describeTypes(const char * name, PsqlSettings * pset)
bool 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 */ char descbuf[1536 + 3 * 32]; /* 32 is max length for operator
* name */
PGresult *res; PGresult *res;
bool description = GetVariableBool(pset->vars, "description"); bool description = GetVariableBool(pset->vars, "description");
printQueryOpt myopt = pset->popt; printQueryOpt myopt = pset->popt;
@ -329,7 +335,8 @@ permissionsList(const char * name, PsqlSettings *pset)
"FROM pg_class\n" "FROM pg_class\n"
"WHERE ( relkind = 'r' OR relkind = 'S') AND\n" "WHERE ( relkind = 'r' OR relkind = 'S') AND\n"
" relname !~ '^pg_'\n"); " relname !~ '^pg_'\n");
if (name) { if (name)
{
strcat(descbuf, " AND rename ~ '^"); strcat(descbuf, " AND rename ~ '^");
strncat(descbuf, name, REGEXP_CUTOFF); strncat(descbuf, name, REGEXP_CUTOFF);
strcat(descbuf, "'\n"); strcat(descbuf, "'\n");
@ -340,10 +347,10 @@ permissionsList(const char * name, PsqlSettings *pset)
if (!res) if (!res)
return false; return false;
if (PQntuples(res) == 0) { if (PQntuples(res) == 0)
fputs("Couldn't find any tables.\n", pset->queryFout); fputs("Couldn't find any tables.\n", pset->queryFout);
} else
else { {
myopt.topt.tuples_only = false; myopt.topt.tuples_only = false;
myopt.nullPrint = NULL; myopt.nullPrint = NULL;
sprintf(descbuf, "Access permissions for database \"%s\"", PQdb(pset->db)); sprintf(descbuf, "Access permissions for database \"%s\"", PQdb(pset->db));
@ -380,7 +387,8 @@ objectDescription(const char * object, PsqlSettings *pset)
strcat(descbuf, "SELECT DISTINCT a.aggname as \"Name\", 'aggregate'::text as \"What\", d.description as \"Description\"\n" strcat(descbuf, "SELECT DISTINCT a.aggname as \"Name\", 'aggregate'::text as \"What\", d.description as \"Description\"\n"
"FROM pg_aggregate a, pg_description d\n" "FROM pg_aggregate a, pg_description d\n"
"WHERE a.oid = d.objoid\n"); "WHERE a.oid = d.objoid\n");
if (object) { if (object)
{
strcat(descbuf, " AND a.aggname ~* '^"); strcat(descbuf, " AND a.aggname ~* '^");
strncat(descbuf, object, REGEXP_CUTOFF); strncat(descbuf, object, REGEXP_CUTOFF);
strcat(descbuf, "'\n"); strcat(descbuf, "'\n");
@ -391,7 +399,8 @@ objectDescription(const char * object, PsqlSettings *pset)
strcat(descbuf, "SELECT DISTINCT p.proname as \"Name\", 'function'::text as \"What\", d.description as \"Description\"\n" strcat(descbuf, "SELECT DISTINCT p.proname as \"Name\", 'function'::text as \"What\", d.description as \"Description\"\n"
"FROM pg_proc p, pg_description d\n" "FROM pg_proc p, pg_description d\n"
"WHERE p.oid = d.objoid AND (p.pronargs = 0 or oid8types(p.proargtypes) != '')\n"); "WHERE p.oid = d.objoid AND (p.pronargs = 0 or oid8types(p.proargtypes) != '')\n");
if (object) { if (object)
{
strcat(descbuf, " AND p.proname ~* '^"); strcat(descbuf, " AND p.proname ~* '^");
strncat(descbuf, object, REGEXP_CUTOFF); strncat(descbuf, object, REGEXP_CUTOFF);
strcat(descbuf, "'\n"); strcat(descbuf, "'\n");
@ -403,7 +412,8 @@ objectDescription(const char * object, PsqlSettings *pset)
"FROM pg_operator o, pg_description d\n" "FROM pg_operator o, pg_description d\n"
// must get comment via associated function // must get comment via associated function
"WHERE RegprocToOid(o.oprcode) = d.objoid\n"); "WHERE RegprocToOid(o.oprcode) = d.objoid\n");
if (object) { if (object)
{
strcat(descbuf, " AND o.oprname = '"); strcat(descbuf, " AND o.oprname = '");
strncat(descbuf, object, REGEXP_CUTOFF); strncat(descbuf, object, REGEXP_CUTOFF);
strcat(descbuf, "'\n"); strcat(descbuf, "'\n");
@ -414,7 +424,8 @@ objectDescription(const char * object, PsqlSettings *pset)
strcat(descbuf, "SELECT DISTINCT t.typname as \"Name\", 'type'::text as \"What\", d.description as \"Description\"\n" strcat(descbuf, "SELECT DISTINCT t.typname as \"Name\", 'type'::text as \"What\", d.description as \"Description\"\n"
"FROM pg_type t, pg_description d\n" "FROM pg_type t, pg_description d\n"
"WHERE t.oid = d.objoid\n"); "WHERE t.oid = d.objoid\n");
if (object) { if (object)
{
strcat(descbuf, " AND t.typname ~* '^"); strcat(descbuf, " AND t.typname ~* '^");
strncat(descbuf, object, REGEXP_CUTOFF); strncat(descbuf, object, REGEXP_CUTOFF);
strcat(descbuf, "'\n"); strcat(descbuf, "'\n");
@ -425,7 +436,8 @@ objectDescription(const char * object, PsqlSettings *pset)
strcat(descbuf, "SELECT DISTINCT c.relname as \"Name\", 'relation'::text||'('||c.relkind||')' as \"What\", d.description as \"Description\"\n" strcat(descbuf, "SELECT DISTINCT c.relname as \"Name\", 'relation'::text||'('||c.relkind||')' as \"What\", d.description as \"Description\"\n"
"FROM pg_class c, pg_description d\n" "FROM pg_class c, pg_description d\n"
"WHERE c.oid = d.objoid\n"); "WHERE c.oid = d.objoid\n");
if (object) { if (object)
{
strcat(descbuf, " AND c.relname ~* '^"); strcat(descbuf, " AND c.relname ~* '^");
strncat(descbuf, object, REGEXP_CUTOFF); strncat(descbuf, object, REGEXP_CUTOFF);
strcat(descbuf, "'\n"); strcat(descbuf, "'\n");
@ -436,7 +448,8 @@ objectDescription(const char * object, PsqlSettings *pset)
strcat(descbuf, "SELECT DISTINCT r.rulename as \"Name\", 'rule'::text as \"What\", d.description as \"Description\"\n" strcat(descbuf, "SELECT DISTINCT r.rulename as \"Name\", 'rule'::text as \"What\", d.description as \"Description\"\n"
"FROM pg_rewrite r, pg_description d\n" "FROM pg_rewrite r, pg_description d\n"
"WHERE r.oid = d.objoid AND r.rulename !~ '^_RET'\n"); "WHERE r.oid = d.objoid AND r.rulename !~ '^_RET'\n");
if (object) { if (object)
{
strcat(descbuf, " AND r.rulename ~* '^"); strcat(descbuf, " AND r.rulename ~* '^");
strncat(descbuf, object, REGEXP_CUTOFF); strncat(descbuf, object, REGEXP_CUTOFF);
strcat(descbuf, "'\n"); strcat(descbuf, "'\n");
@ -447,7 +460,8 @@ objectDescription(const char * object, PsqlSettings *pset)
strcat(descbuf, "SELECT DISTINCT t.tgname as \"Name\", 'trigger'::text as \"What\", d.description as \"Description\"\n" strcat(descbuf, "SELECT DISTINCT t.tgname as \"Name\", 'trigger'::text as \"What\", d.description as \"Description\"\n"
"FROM pg_trigger t, pg_description d\n" "FROM pg_trigger t, pg_description d\n"
"WHERE t.oid = d.objoid\n"); "WHERE t.oid = d.objoid\n");
if (object) { if (object)
{
strcat(descbuf, " AND t.tgname ~* '^"); strcat(descbuf, " AND t.tgname ~* '^");
strncat(descbuf, object, REGEXP_CUTOFF); strncat(descbuf, object, REGEXP_CUTOFF);
strcat(descbuf, "'\n"); strcat(descbuf, "'\n");
@ -480,11 +494,14 @@ objectDescription(const char * object, PsqlSettings *pset)
* and pass it to the underlying printTable() function. * and pass it to the underlying printTable() function.
* *
*/ */
static void * xmalloc(size_t size) static void *
xmalloc(size_t size)
{ {
void *tmp; void *tmp;
tmp = malloc(size); tmp = malloc(size);
if (!tmp) { if (!tmp)
{
perror("malloc"); perror("malloc");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -496,7 +513,9 @@ bool
describeTableDetails(const char *name, PsqlSettings *pset) describeTableDetails(const char *name, PsqlSettings *pset)
{ {
char descbuf[512 + NAMEDATALEN]; char descbuf[512 + NAMEDATALEN];
PGresult *res = NULL, *res2 = NULL, *res3 = NULL; PGresult *res = NULL,
*res2 = NULL,
*res3 = NULL;
printTableOpt myopt = pset->popt.topt; printTableOpt myopt = pset->popt.topt;
bool description = GetVariableBool(pset->vars, "description"); bool description = GetVariableBool(pset->vars, "description");
int i; int i;
@ -513,7 +532,8 @@ describeTableDetails(const char * name, PsqlSettings * pset)
headers[0] = "Attribute"; headers[0] = "Attribute";
headers[1] = "Type"; headers[1] = "Type";
headers[2] = "Info"; headers[2] = "Info";
if (description) { if (description)
{
headers[3] = "Description"; headers[3] = "Description";
headers[4] = NULL; headers[4] = NULL;
} }
@ -535,7 +555,8 @@ describeTableDetails(const char * name, PsqlSettings * pset)
return false; return false;
/* Did we get anything? */ /* Did we get anything? */
if (PQntuples(res)==0) { if (PQntuples(res) == 0)
{
if (!GetVariableBool(pset->vars, "quiet")) if (!GetVariableBool(pset->vars, "quiet"))
fprintf(stdout, "Did not find any class named \"%s\".\n", name); fprintf(stdout, "Did not find any class named \"%s\".\n", name);
PQclear(res); PQclear(res);
@ -557,17 +578,20 @@ describeTableDetails(const char * name, PsqlSettings * pset)
/* Generate table cells to be printed */ /* Generate table cells to be printed */
cells = calloc(PQntuples(res) * cols + 1, sizeof(*cells)); cells = calloc(PQntuples(res) * cols + 1, sizeof(*cells));
if (!cells) { if (!cells)
{
perror("calloc"); perror("calloc");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
for (i = 0; i < PQntuples(res); i++) { for (i = 0; i < PQntuples(res); i++)
{
int4 attypmod = atoi(PQgetvalue(res, i, 3)); int4 attypmod = atoi(PQgetvalue(res, i, 3));
char *attype = PQgetvalue(res, i, 1); char *attype = PQgetvalue(res, i, 1);
/* Name */ /* Name */
cells[i*cols + 0] = PQgetvalue(res, i, 0); /* don't free this afterwards */ cells[i * cols + 0] = PQgetvalue(res, i, 0); /* don't free this
* afterwards */
/* Type */ /* Type */
cells[i * cols + 1] = xmalloc(NAMEDATALEN + 16); cells[i * cols + 1] = xmalloc(NAMEDATALEN + 16);
@ -584,11 +608,13 @@ describeTableDetails(const char * name, PsqlSettings * pset)
strcpy(cells[i * cols + 1], attype); strcpy(cells[i * cols + 1], attype);
/* Info */ /* Info */
cells[i*cols + 2] = xmalloc(128 + 128); /* I'm cutting off the default string at 128 */ cells[i * cols + 2] = xmalloc(128 + 128); /* I'm cutting off the
* default string at 128 */
cells[i * cols + 2][0] = '\0'; cells[i * cols + 2][0] = '\0';
if (strcmp(PQgetvalue(res, i, 4), "t") == 0) if (strcmp(PQgetvalue(res, i, 4), "t") == 0)
strcat(cells[i * cols + 2], "not null"); strcat(cells[i * cols + 2], "not null");
if (strcmp(PQgetvalue(res, i, 5), "t") == 0) { if (strcmp(PQgetvalue(res, i, 5), "t") == 0)
{
/* handle "default" here */ /* handle "default" here */
strcpy(descbuf, "SELECT substring(d.adsrc for 128) FROM pg_attrdef d, pg_class c\n" strcpy(descbuf, "SELECT substring(d.adsrc for 128) FROM pg_attrdef d, pg_class c\n"
"WHERE c.relname = '"); "WHERE c.relname = '");
@ -597,8 +623,10 @@ describeTableDetails(const char * name, PsqlSettings * pset)
strcat(descbuf, PQgetvalue(res, i, 6)); strcat(descbuf, PQgetvalue(res, i, 6));
res3 = PSQLexec(pset, descbuf); res3 = PSQLexec(pset, descbuf);
if (!res) return false; if (!res)
if (cells[i*cols+2][0]) strcat(cells[i*cols+2], " "); return false;
if (cells[i * cols + 2][0])
strcat(cells[i * cols + 2], " ");
strcat(cells[i * cols + 2], "default "); strcat(cells[i * cols + 2], "default ");
strcat(cells[i * cols + 2], PQgetvalue(res3, 0, 0)); strcat(cells[i * cols + 2], PQgetvalue(res3, 0, 0));
} }
@ -616,13 +644,15 @@ describeTableDetails(const char * name, PsqlSettings * pset)
sprintf(title, "Table \"%s\"", name); sprintf(title, "Table \"%s\"", name);
/* Make footers */ /* Make footers */
if (view_def) { if (view_def)
{
footers = xmalloc(2 * sizeof(*footers)); footers = xmalloc(2 * sizeof(*footers));
footers[0] = xmalloc(20 + strlen(view_def)); footers[0] = xmalloc(20 + strlen(view_def));
sprintf(footers[0], "View definition: %s", view_def); sprintf(footers[0], "View definition: %s", view_def);
footers[1] = NULL; footers[1] = NULL;
} }
else { else
{
/* display indices */ /* display indices */
strcpy(descbuf, "SELECT c2.relname\n" strcpy(descbuf, "SELECT c2.relname\n"
"FROM pg_class c, pg_class c2, pg_index i\n" "FROM pg_class c, pg_class c2, pg_index i\n"
@ -634,10 +664,12 @@ describeTableDetails(const char * name, PsqlSettings * pset)
if (!res3) if (!res3)
return false; return false;
if (PQntuples(res3) > 0) { if (PQntuples(res3) > 0)
{
footers = xmalloc((PQntuples(res3) + 1) * sizeof(*footers)); footers = xmalloc((PQntuples(res3) + 1) * sizeof(*footers));
for (i=0; i<PQntuples(res3); i++) { for (i = 0; i < PQntuples(res3); i++)
{
footers[i] = xmalloc(10 + NAMEDATALEN); footers[i] = xmalloc(10 + NAMEDATALEN);
if (PQntuples(res3) == 1) if (PQntuples(res3) == 1)
sprintf(footers[i], "Index: %s", PQgetvalue(res3, i, 0)); sprintf(footers[i], "Index: %s", PQgetvalue(res3, i, 0));
@ -658,7 +690,8 @@ describeTableDetails(const char * name, PsqlSettings * pset)
/* clean up */ /* clean up */
free(title); free(title);
for (i = 0; i<PQntuples(res); i++) { for (i = 0; i < PQntuples(res); i++)
{
free(cells[i * cols + 1]); free(cells[i * cols + 1]);
free(cells[i * cols + 2]); free(cells[i * cols + 2]);
} }
@ -708,7 +741,8 @@ listTables(const char * infotype, const char * name, PsqlSettings * pset)
descbuf[0] = '\0'; descbuf[0] = '\0';
/* tables */ /* tables */
if (showTables) { if (showTables)
{
strcat(descbuf, "SELECT u.usename as \"Owner\", c.relname as \"Name\", 'table'::text as \"Type\""); strcat(descbuf, "SELECT u.usename as \"Owner\", c.relname as \"Name\", 'table'::text as \"Type\"");
if (description) if (description)
strcat(descbuf, ", obj_description(c.oid) as \"Description\""); strcat(descbuf, ", obj_description(c.oid) as \"Description\"");
@ -716,7 +750,8 @@ listTables(const char * infotype, const char * name, PsqlSettings * pset)
"WHERE c.relowner = u.usesysid AND c.relkind = 'r'\n" "WHERE c.relowner = u.usesysid AND c.relkind = 'r'\n"
" AND not exists (select 1 from pg_views where viewname = c.relname)\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"); strcat(descbuf, showSystem ? " AND c.relname ~ '^pg_'\n" : " AND c.relname !~ '^pg_'\n");
if (name) { if (name)
{
strcat(descbuf, " AND c.relname ~ '^"); strcat(descbuf, " AND c.relname ~ '^");
strncat(descbuf, name, REGEXP_CUTOFF); strncat(descbuf, name, REGEXP_CUTOFF);
strcat(descbuf, "'\n"); strcat(descbuf, "'\n");
@ -724,7 +759,8 @@ listTables(const char * infotype, const char * name, PsqlSettings * pset)
} }
/* views */ /* views */
if (showViews) { if (showViews)
{
if (descbuf[0]) if (descbuf[0])
strcat(descbuf, "\nUNION\n\n"); strcat(descbuf, "\nUNION\n\n");
@ -735,7 +771,8 @@ listTables(const char * infotype, const char * name, PsqlSettings * pset)
"WHERE c.relowner = u.usesysid AND c.relkind = 'r'\n" "WHERE c.relowner = u.usesysid AND c.relkind = 'r'\n"
" AND exists (select 1 from pg_views where viewname = c.relname)\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"); strcat(descbuf, showSystem ? " AND c.relname ~ '^pg_'\n" : " AND c.relname !~ '^pg_'\n");
if (name) { if (name)
{
strcat(descbuf, " AND c.relname ~ '^"); strcat(descbuf, " AND c.relname ~ '^");
strncat(descbuf, name, REGEXP_CUTOFF); strncat(descbuf, name, REGEXP_CUTOFF);
strcat(descbuf, "'\n"); strcat(descbuf, "'\n");
@ -743,7 +780,8 @@ listTables(const char * infotype, const char * name, PsqlSettings * pset)
} }
/* indices, sequences */ /* indices, sequences */
if (showIndices || showSeq) { if (showIndices || showSeq)
{
if (descbuf[0]) if (descbuf[0])
strcat(descbuf, "\nUNION\n\n"); strcat(descbuf, "\nUNION\n\n");
@ -766,7 +804,8 @@ listTables(const char * infotype, const char * name, PsqlSettings * pset)
strcat(descbuf, " AND (c.relkind != 'i' OR c.relname !~ '^xinx')\n"); strcat(descbuf, " AND (c.relkind != 'i' OR c.relname !~ '^xinx')\n");
strcat(descbuf, showSystem ? " AND c.relname ~ '^pg_'\n" : " AND c.relname !~ '^pg_'\n"); strcat(descbuf, showSystem ? " AND c.relname ~ '^pg_'\n" : " AND c.relname !~ '^pg_'\n");
if (name) { if (name)
{
strcat(descbuf, " AND c.relname ~ '^"); strcat(descbuf, " AND c.relname ~ '^");
strncat(descbuf, name, REGEXP_CUTOFF); strncat(descbuf, name, REGEXP_CUTOFF);
strcat(descbuf, "'\n"); strcat(descbuf, "'\n");
@ -774,7 +813,8 @@ listTables(const char * infotype, const char * name, PsqlSettings * pset)
} }
/* real system catalogue tables */ /* real system catalogue tables */
if (showSystem && showTables) { if (showSystem && showTables)
{
if (descbuf[0]) if (descbuf[0])
strcat(descbuf, "\nUNION\n\n"); strcat(descbuf, "\nUNION\n\n");
@ -783,7 +823,8 @@ listTables(const char * infotype, const char * name, PsqlSettings * pset)
strcat(descbuf, ", obj_description(c.oid) as \"Description\""); strcat(descbuf, ", obj_description(c.oid) as \"Description\"");
strcat(descbuf, "\nFROM pg_class c, pg_user u\n" strcat(descbuf, "\nFROM pg_class c, pg_user u\n"
"WHERE c.relowner = u.usesysid AND c.relkind = 's'\n"); "WHERE c.relowner = u.usesysid AND c.relkind = 's'\n");
if (name) { if (name)
{
strcat(descbuf, " AND c.relname ~ '^"); strcat(descbuf, " AND c.relname ~ '^");
strncat(descbuf, name, REGEXP_CUTOFF); strncat(descbuf, name, REGEXP_CUTOFF);
strcat(descbuf, "'\n"); strcat(descbuf, "'\n");
@ -800,7 +841,8 @@ listTables(const char * infotype, const char * name, PsqlSettings * pset)
if (PQntuples(res) == 0) if (PQntuples(res) == 0)
fprintf(pset->queryFout, "No matching classes found.\n"); fprintf(pset->queryFout, "No matching classes found.\n");
else { else
{
myopt.topt.tuples_only = false; myopt.topt.tuples_only = false;
myopt.nullPrint = NULL; myopt.nullPrint = NULL;
myopt.title = "List of classes"; myopt.title = "List of classes";

View File

@ -34,21 +34,27 @@
*/ */
#define ON(var) (var ? "on" : "off") #define ON(var) (var ? "on" : "off")
void usage(void) void
usage(void)
{ {
const char *env; const char *env;
const char *user; const char *user;
#ifndef WIN32 #ifndef WIN32
struct passwd *pw = NULL; struct passwd *pw = NULL;
#endif #endif
/* Find default user, in case we need it. */ /* Find default user, in case we need it. */
user = getenv("USER"); user = getenv("USER");
if (!user) { if (!user)
{
#ifndef WIN32 #ifndef WIN32
pw = getpwuid(getuid()); pw = getpwuid(getuid());
if (pw) user = pw->pw_name; if (pw)
else { user = pw->pw_name;
else
{
perror("getpwuid()"); perror("getpwuid()");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -64,7 +70,8 @@ void usage(void)
/* Display default database */ /* Display default database */
env = getenv("PGDATABASE"); env = getenv("PGDATABASE");
if (!env) env=user; if (!env)
env = user;
fprintf(stderr, " -d dbname Specify database name to connect to (default: %s)\n", env); 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 Echo all input in non-interactive mode\n");
@ -101,7 +108,8 @@ void usage(void)
/* Display default user */ /* Display default user */
env = getenv("PGUSER"); env = getenv("PGUSER");
if (!env) env=user; if (!env)
env = user;
fprintf(stderr, " -U [username] Specifiy username, \"?\"=prompt (default user: %s)\n", env); 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, " -x Turn on expanded table output (-P expanded)\n");
@ -112,7 +120,8 @@ void usage(void)
fprintf(stderr, "Consult the documentation for the complete details.\n"); fprintf(stderr, "Consult the documentation for the complete details.\n");
#ifndef WIN32 #ifndef WIN32
if (pw) free(pw); if (pw)
free(pw);
#endif #endif
} }
@ -125,10 +134,12 @@ void usage(void)
*/ */
#ifndef TIOCGWINSZ #ifndef TIOCGWINSZ
struct winsize { struct winsize
{
int ws_row; int ws_row;
int ws_col; int ws_col;
}; };
#endif #endif
void void
@ -197,7 +208,8 @@ slashUsage(PsqlSettings *pset)
fprintf(fout, " \\z -- list table access permissions\n"); fprintf(fout, " \\z -- list table access permissions\n");
fprintf(fout, " \\! [<cmd>] -- shell escape or command\n"); fprintf(fout, " \\! [<cmd>] -- shell escape or command\n");
if (usePipe) { if (usePipe)
{
pclose(fout); pclose(fout);
pqsignal(SIGPIPE, SIG_DFL); pqsignal(SIGPIPE, SIG_DFL);
} }

View File

@ -13,4 +13,3 @@ void print_copyright(void);
#endif #endif

View File

@ -10,9 +10,11 @@
/* (of course there is no runtime command for doing that :) */ /* (of course there is no runtime command for doing that :) */
#ifdef USE_READLINE #ifdef USE_READLINE
static bool useReadline; static bool useReadline;
#endif #endif
#ifdef USE_HISTORY #ifdef USE_HISTORY
static bool useHistory; static bool useHistory;
#endif #endif
@ -28,12 +30,14 @@ gets_interactive(const char *prompt)
char *s; char *s;
#ifdef USE_READLINE #ifdef USE_READLINE
if (useReadline) { if (useReadline)
{
s = readline(prompt); s = readline(prompt);
fputc('\r', stdout); fputc('\r', stdout);
fflush(stdout); fflush(stdout);
} }
else { else
{
#endif #endif
fputs(prompt, stdout); fputs(prompt, stdout);
fflush(stdout); fflush(stdout);
@ -65,9 +69,11 @@ gets_fromFile(FILE *source)
initPQExpBuffer(&buffer); initPQExpBuffer(&buffer);
while (fgets(line, 1024, source) != NULL) { while (fgets(line, 1024, source) != NULL)
{
appendPQExpBufferStr(&buffer, line); appendPQExpBufferStr(&buffer, line);
if (buffer.data[buffer.len-1] == '\n') { if (buffer.data[buffer.len - 1] == '\n')
{
buffer.data[buffer.len - 1] = '\0'; buffer.data[buffer.len - 1] = '\0';
return buffer.data; return buffer.data;
} }
@ -93,22 +99,27 @@ void
initializeInput(int flags) initializeInput(int flags)
{ {
#ifdef USE_READLINE #ifdef USE_READLINE
if (flags == 1) { if (flags == 1)
{
useReadline = true; useReadline = true;
rl_readline_name = "psql"; rl_readline_name = "psql";
} }
#endif #endif
#ifdef USE_HISTORY #ifdef USE_HISTORY
if (flags == 1) { if (flags == 1)
{
const char *home; const char *home;
useHistory = true; useHistory = true;
using_history(); using_history();
home = getenv("HOME"); home = getenv("HOME");
if (home) { if (home)
{
char *psql_history = (char *) malloc(strlen(home) + 20); char *psql_history = (char *) malloc(strlen(home) + 20);
if (psql_history) {
if (psql_history)
{
sprintf(psql_history, "%s/.psql_history", home); sprintf(psql_history, "%s/.psql_history", home);
read_history(psql_history); read_history(psql_history);
free(psql_history); free(psql_history);
@ -124,8 +135,10 @@ bool
saveHistory(const char *fname) saveHistory(const char *fname)
{ {
#ifdef USE_HISTORY #ifdef USE_HISTORY
if (useHistory) { if (useHistory)
if (write_history(fname) != 0) { {
if (write_history(fname) != 0)
{
perror(fname); perror(fname);
return false; return false;
} }
@ -144,14 +157,17 @@ void
finishInput(void) finishInput(void)
{ {
#ifdef USE_HISTORY #ifdef USE_HISTORY
if (useHistory) { if (useHistory)
{
char *home; char *home;
char *psql_history; char *psql_history;
home = getenv("HOME"); home = getenv("HOME");
if (home) { if (home)
{
psql_history = (char *) malloc(strlen(home) + 20); psql_history = (char *) malloc(strlen(home) + 20);
if (psql_history) { if (psql_history)
{
sprintf(psql_history, "%s/.psql_history", home); sprintf(psql_history, "%s/.psql_history", home);
write_history(psql_history); write_history(psql_history);
free(psql_history); free(psql_history);

View File

@ -24,7 +24,8 @@
static char notice[80]; static char notice[80];
static void static void
_my_notice_handler(void * arg, const char * message) { _my_notice_handler(void *arg, const char *message)
{
(void) arg; (void) arg;
strncpy(notice, message, 79); strncpy(notice, message, 79);
notice[79] = '\0'; notice[79] = '\0';
@ -51,12 +52,14 @@ handle_transaction(PsqlSettings * pset)
if (!res) if (!res)
return false; return false;
if (notice[0]) { if (notice[0])
{
if ((!commit && strcmp(notice, "NOTICE: UserAbortTransactionBlock and not in in-progress state\n") != 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)) (commit && strcmp(notice, "NOTICE: EndTransactionBlock and not inprogress/abort state\n") != 0))
fputs(notice, stderr); fputs(notice, stderr);
} }
else if (!GetVariableBool(pset->vars, "quiet")) { else if (!GetVariableBool(pset->vars, "quiet"))
{
if (commit) if (commit)
puts("Warning: Your transaction in progress has been committed."); puts("Warning: Your transaction in progress has been committed.");
else else
@ -85,12 +88,14 @@ do_lo_export(PsqlSettings * pset, const char * loid_arg, const char * filename_a
if (var && strcmp(var, "nothing") == 0) if (var && strcmp(var, "nothing") == 0)
own_transaction = false; own_transaction = false;
if (!pset->db) { if (!pset->db)
{
fputs("You are not connected to a database.\n", stderr); fputs("You are not connected to a database.\n", stderr);
return false; return false;
} }
if (own_transaction) { if (own_transaction)
{
if (!handle_transaction(pset)) if (!handle_transaction(pset))
return false; return false;
@ -101,17 +106,22 @@ do_lo_export(PsqlSettings * pset, const char * loid_arg, const char * filename_a
} }
status = lo_export(pset->db, atol(loid_arg), (char *) filename_arg); status = lo_export(pset->db, atol(loid_arg), (char *) filename_arg);
if (status != 1) { /* of course this status is documented nowhere :( */ if (status != 1)
{ /* of course this status is documented
* nowhere :( */
fputs(PQerrorMessage(pset->db), stderr); fputs(PQerrorMessage(pset->db), stderr);
if (own_transaction) { if (own_transaction)
{
res = PQexec(pset->db, "ROLLBACK"); res = PQexec(pset->db, "ROLLBACK");
PQclear(res); PQclear(res);
} }
return false; return false;
} }
if (own_transaction) { if (own_transaction)
if (!(res = PSQLexec(pset, "COMMIT"))) { {
if (!(res = PSQLexec(pset, "COMMIT")))
{
res = PQexec(pset->db, "ROLLBACK"); res = PQexec(pset->db, "ROLLBACK");
PQclear(res); PQclear(res);
return false; return false;
@ -145,12 +155,14 @@ do_lo_import(PsqlSettings * pset, const char * filename_arg, const char * commen
if (var && strcmp(var, "nothing") == 0) if (var && strcmp(var, "nothing") == 0)
own_transaction = false; own_transaction = false;
if (!pset->db) { if (!pset->db)
{
fputs("You are not connected to a database.\n", stderr); fputs("You are not connected to a database.\n", stderr);
return false; return false;
} }
if (own_transaction) { if (own_transaction)
{
if (!handle_transaction(pset)) if (!handle_transaction(pset))
return false; return false;
@ -161,9 +173,11 @@ do_lo_import(PsqlSettings * pset, const char * filename_arg, const char * commen
} }
loid = lo_import(pset->db, (char *) filename_arg); loid = lo_import(pset->db, (char *) filename_arg);
if (loid == InvalidOid) { if (loid == InvalidOid)
{
fputs(PQerrorMessage(pset->db), stderr); fputs(PQerrorMessage(pset->db), stderr);
if (own_transaction) { if (own_transaction)
{
res = PQexec(pset->db, "ROLLBACK"); res = PQexec(pset->db, "ROLLBACK");
PQclear(res); PQclear(res);
} }
@ -171,7 +185,8 @@ do_lo_import(PsqlSettings * pset, const char * filename_arg, const char * commen
} }
/* insert description if given */ /* insert description if given */
if (comment_arg) { if (comment_arg)
{
sprintf(buf, "INSERT INTO pg_description VALUES (%d, '", loid); sprintf(buf, "INSERT INTO pg_description VALUES (%d, '", loid);
for (i = 0; i < strlen(comment_arg); i++) for (i = 0; i < strlen(comment_arg); i++)
if (comment_arg[i] == '\'') if (comment_arg[i] == '\'')
@ -180,8 +195,10 @@ do_lo_import(PsqlSettings * pset, const char * filename_arg, const char * commen
strncat(buf, &comment_arg[i], 1); strncat(buf, &comment_arg[i], 1);
strcat(buf, "')"); strcat(buf, "')");
if (!(res = PSQLexec(pset, buf))) { if (!(res = PSQLexec(pset, buf)))
if (own_transaction) { {
if (own_transaction)
{
res = PQexec(pset->db, "ROLLBACK"); res = PQexec(pset->db, "ROLLBACK");
PQclear(res); PQclear(res);
} }
@ -189,8 +206,10 @@ do_lo_import(PsqlSettings * pset, const char * filename_arg, const char * commen
} }
} }
if (own_transaction) { if (own_transaction)
if (!(res = PSQLexec(pset, "COMMIT"))) { {
if (!(res = PSQLexec(pset, "COMMIT")))
{
res = PQexec(pset->db, "ROLLBACK"); res = PQexec(pset->db, "ROLLBACK");
PQclear(res); PQclear(res);
return false; return false;
@ -212,7 +231,8 @@ do_lo_import(PsqlSettings * pset, const char * filename_arg, const char * commen
* *
* removes a large object out of the database * 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; PGresult *res;
int status; int status;
@ -224,12 +244,14 @@ bool do_lo_unlink(PsqlSettings * pset, const char * loid_arg)
if (var && strcmp(var, "nothing") == 0) if (var && strcmp(var, "nothing") == 0)
own_transaction = false; own_transaction = false;
if (!pset->db) { if (!pset->db)
{
fputs("You are not connected to a database.\n", stderr); fputs("You are not connected to a database.\n", stderr);
return false; return false;
} }
if (own_transaction) { if (own_transaction)
{
if (!handle_transaction(pset)) if (!handle_transaction(pset))
return false; return false;
@ -240,9 +262,11 @@ bool do_lo_unlink(PsqlSettings * pset, const char * loid_arg)
} }
status = lo_unlink(pset->db, loid); status = lo_unlink(pset->db, loid);
if (status == -1) { if (status == -1)
{
fputs(PQerrorMessage(pset->db), stderr); fputs(PQerrorMessage(pset->db), stderr);
if (own_transaction) { if (own_transaction)
{
res = PQexec(pset->db, "ROLLBACK"); res = PQexec(pset->db, "ROLLBACK");
PQclear(res); PQclear(res);
} }
@ -251,8 +275,10 @@ bool do_lo_unlink(PsqlSettings * pset, const char * loid_arg)
/* remove the comment as well */ /* remove the comment as well */
sprintf(buf, "DELETE FROM pg_description WHERE objoid = %d", loid); sprintf(buf, "DELETE FROM pg_description WHERE objoid = %d", loid);
if (!(res = PSQLexec(pset, buf))) { if (!(res = PSQLexec(pset, buf)))
if (own_transaction) { {
if (own_transaction)
{
res = PQexec(pset->db, "ROLLBACK"); res = PQexec(pset->db, "ROLLBACK");
PQclear(res); PQclear(res);
} }
@ -260,8 +286,10 @@ bool do_lo_unlink(PsqlSettings * pset, const char * loid_arg)
} }
if (own_transaction) { if (own_transaction)
if (!(res = PSQLexec(pset, "COMMIT"))) { {
if (!(res = PSQLexec(pset, "COMMIT")))
{
res = PQexec(pset->db, "ROLLBACK"); res = PQexec(pset->db, "ROLLBACK");
PQclear(res); PQclear(res);
return false; return false;
@ -282,7 +310,8 @@ bool do_lo_unlink(PsqlSettings * pset, const char * loid_arg)
* *
* Show all large objects in database, with comments if desired * Show all large objects in database, with comments if desired
*/ */
bool do_lo_list(PsqlSettings * pset) bool
do_lo_list(PsqlSettings *pset)
{ {
PGresult *res; PGresult *res;
char descbuf[512]; char descbuf[512];

View File

@ -40,7 +40,9 @@ MainLoop(PsqlSettings *pset, FILE *source)
int paren_level; int paren_level;
unsigned int query_start; unsigned int query_start;
int i, prevlen, thislen; int i,
prevlen,
thislen;
/* Save the prior command source */ /* Save the prior command source */
FILE *prev_cmd_source; FILE *prev_cmd_source;
@ -60,7 +62,8 @@ MainLoop(PsqlSettings *pset, FILE *source)
query_buf = createPQExpBuffer(); query_buf = createPQExpBuffer();
if (!query_buf) { if (!query_buf)
{
perror("createPQExpBuffer"); perror("createPQExpBuffer");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -76,6 +79,7 @@ MainLoop(PsqlSettings *pset, FILE *source)
{ {
if (slashCmdStatus == CMD_NEWEDIT) if (slashCmdStatus == CMD_NEWEDIT)
{ {
/* /*
* just returned from editing the line? then just copy to the * just returned from editing the line? then just copy to the
* input buffer * input buffer
@ -89,9 +93,10 @@ MainLoop(PsqlSettings *pset, FILE *source)
} }
else else
{ {
/* /*
* otherwise, set interactive prompt if necessary * otherwise, set interactive prompt if necessary and get
* and get another line * another line
*/ */
if (pset->cur_cmd_interactive) if (pset->cur_cmd_interactive)
{ {
@ -121,9 +126,10 @@ MainLoop(PsqlSettings *pset, FILE *source)
/* /*
* query_buf holds query already accumulated. line is the malloc'd * query_buf holds query already accumulated. line is the
* new line of input (note it must be freed before looping around!) * malloc'd new line of input (note it must be freed before
* query_start is the next command start location within the line. * looping around!) query_start is the next command start location
* within the line.
*/ */
/* No more input. Time to quit, or \i done */ /* No more input. Time to quit, or \i done */
@ -141,8 +147,10 @@ MainLoop(PsqlSettings *pset, FILE *source)
/* strip trailing backslashes, they don't have a clear meaning */ /* strip trailing backslashes, they don't have a clear meaning */
while (1) { while (1)
{
char *cp = strrchr(line, '\\'); char *cp = strrchr(line, '\\');
if (cp && (*(cp + 1) == '\0')) if (cp && (*(cp + 1) == '\0'))
*cp = '\0'; *cp = '\0';
else else
@ -159,12 +167,16 @@ MainLoop(PsqlSettings *pset, FILE *source)
len = strlen(line); len = strlen(line);
thislen = PQmblen(line); thislen = PQmblen(line);
for (i = 0; line[i]; i += (thislen = PQmblen(&line[i])) ) { 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; if (interpol_char && interpol_char[0] != '\0' && interpol_char[0] == line[i])
{
size_t in_length,
out_length;
const char *value; const char *value;
char *new; char *new;
bool closer; /* did we have a closing delimiter or just an end of line? */ bool closer; /* did we have a closing delimiter
* or just an end of line? */
in_length = strcspn(&line[i + thislen], interpol_char); in_length = strcspn(&line[i + thislen], interpol_char);
closer = line[i + thislen + in_length] == line[i]; closer = line[i + thislen + in_length] == line[i];
@ -173,7 +185,8 @@ MainLoop(PsqlSettings *pset, FILE *source)
out_length = strlen(value); out_length = strlen(value);
new = malloc(len + out_length - (in_length + (closer ? 2 : 1)) + 1); new = malloc(len + out_length - (in_length + (closer ? 2 : 1)) + 1);
if (!new) { if (!new)
{
perror("malloc"); perror("malloc");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -191,7 +204,8 @@ MainLoop(PsqlSettings *pset, FILE *source)
} }
/* nothing left on line? then ignore */ /* nothing left on line? then ignore */
if (line[0] == '\0') { if (line[0] == '\0')
{
free(line); free(line);
continue; continue;
} }
@ -204,8 +218,8 @@ MainLoop(PsqlSettings *pset, FILE *source)
/* /*
* Parse line, looking for command separators. * Parse line, looking for command separators.
* *
* The current character is at line[i], the prior character at * The current character is at line[i], the prior character at line[i
* line[i - prevlen], the next character at line[i + thislen]. * - prevlen], the next character at line[i + thislen].
*/ */
prevlen = 0; prevlen = 0;
thislen = (len > 0) ? PQmblen(line) : 0; thislen = (len > 0) ? PQmblen(line) : 0;
@ -213,7 +227,8 @@ MainLoop(PsqlSettings *pset, FILE *source)
#define ADVANCE_1 (prevlen = thislen, i += thislen, thislen = PQmblen(line+i)) #define ADVANCE_1 (prevlen = thislen, i += thislen, thislen = PQmblen(line+i))
success = true; success = true;
for (i = 0; i < len; ADVANCE_1) { for (i = 0; i < len; ADVANCE_1)
{
if (!success && die_on_error) if (!success && die_on_error)
break; break;
@ -226,7 +241,8 @@ MainLoop(PsqlSettings *pset, FILE *source)
/* in quote? */ /* in quote? */
if (in_quote) { if (in_quote)
{
/* end of quote */ /* end of quote */
if (line[i] == in_quote && !was_bslash) if (line[i] == in_quote && !was_bslash)
in_quote = '\0'; in_quote = '\0';
@ -237,15 +253,18 @@ MainLoop(PsqlSettings *pset, FILE *source)
in_quote = line[i]; in_quote = line[i];
/* in extended comment? */ /* in extended comment? */
else if (xcomment != NULL) { else if (xcomment != NULL)
if (line[i] == '*' && line[i + thislen] == '/') { {
if (line[i] == '*' && line[i + thislen] == '/')
{
xcomment = NULL; xcomment = NULL;
ADVANCE_1; ADVANCE_1;
} }
} }
/* start of extended comment? */ /* start of extended comment? */
else if (line[i] == '/' && line[i + thislen] == '*') { else if (line[i] == '/' && line[i + thislen] == '*')
{
xcomment = &line[i]; xcomment = &line[i];
ADVANCE_1; ADVANCE_1;
} }
@ -266,11 +285,17 @@ MainLoop(PsqlSettings *pset, FILE *source)
paren_level--; paren_level--;
/* semicolon? then send query */ /* semicolon? then send query */
else if (line[i] == ';' && !was_bslash && paren_level==0) { else if (line[i] == ';' && !was_bslash && paren_level == 0)
{
line[i] = '\0'; line[i] = '\0';
/* is there anything else on the line? */ /* is there anything else on the line? */
if (line[query_start + strspn(line + query_start, " \t")]!='\0') { if (line[query_start + strspn(line + query_start, " \t")] != '\0')
/* insert a cosmetic newline, if this is not the first line in the buffer */ {
/*
* insert a cosmetic newline, if this is not the first
* line in the buffer
*/
if (query_buf->len > 0) if (query_buf->len > 0)
appendPQExpBufferChar(query_buf, '\n'); appendPQExpBufferChar(query_buf, '\n');
/* append the line to the query buffer */ /* append the line to the query buffer */
@ -285,14 +310,20 @@ MainLoop(PsqlSettings *pset, FILE *source)
} }
/* backslash command */ /* backslash command */
else if (was_bslash) { else if (was_bslash)
{
const char *end_of_cmd = NULL; const char *end_of_cmd = NULL;
line[i - prevlen] = '\0'; /* overwrites backslash */ line[i - prevlen] = '\0'; /* overwrites backslash */
/* is there anything else on the line? */ /* is there anything else on the line? */
if (line[query_start + strspn(line + query_start, " \t")]!='\0') { if (line[query_start + strspn(line + query_start, " \t")] != '\0')
/* insert a cosmetic newline, if this is not the first line in the buffer */ {
/*
* insert a cosmetic newline, if this is not the first
* line in the buffer
*/
if (query_buf->len > 0) if (query_buf->len > 0)
appendPQExpBufferChar(query_buf, '\n'); appendPQExpBufferChar(query_buf, '\n');
/* append the line to the query buffer */ /* append the line to the query buffer */
@ -305,14 +336,16 @@ MainLoop(PsqlSettings *pset, FILE *source)
success = slashCmdStatus != CMD_ERROR; success = slashCmdStatus != CMD_ERROR;
if (slashCmdStatus == CMD_SEND) { if (slashCmdStatus == CMD_SEND)
{
success = SendQuery(pset, query_buf->data); success = SendQuery(pset, query_buf->data);
resetPQExpBuffer(query_buf); resetPQExpBuffer(query_buf);
query_start = i + thislen; query_start = i + thislen;
} }
/* is there anything left after the backslash command? */ /* is there anything left after the backslash command? */
if (end_of_cmd) { if (end_of_cmd)
{
i += end_of_cmd - &line[i]; i += end_of_cmd - &line[i];
query_start = i; query_start = i;
} }
@ -322,20 +355,23 @@ MainLoop(PsqlSettings *pset, FILE *source)
} }
if (!success && die_on_error && !pset->cur_cmd_interactive) { if (!success && die_on_error && !pset->cur_cmd_interactive)
{
successResult = EXIT_USER; successResult = EXIT_USER;
break; break;
} }
if (slashCmdStatus == CMD_TERMINATE) { if (slashCmdStatus == CMD_TERMINATE)
{
successResult = EXIT_SUCCESS; successResult = EXIT_SUCCESS;
break; break;
} }
/* Put the rest of the line in the query buffer. */ /* Put the rest of the line in the query buffer. */
if (line[query_start + strspn(line + query_start, " \t")]!='\0') { if (line[query_start + strspn(line + query_start, " \t")] != '\0')
{
if (query_buf->len > 0) if (query_buf->len > 0)
appendPQExpBufferChar(query_buf, '\n'); appendPQExpBufferChar(query_buf, '\n');
appendPQExpBufferStr(query_buf, line + query_start); appendPQExpBufferStr(query_buf, line + query_start);
@ -345,14 +381,16 @@ MainLoop(PsqlSettings *pset, FILE *source)
/* In single line mode, send off the query if any */ /* In single line mode, send off the query if any */
if (query_buf->data[0] != '\0' && GetVariableBool(pset->vars, "singleline")) { if (query_buf->data[0] != '\0' && GetVariableBool(pset->vars, "singleline"))
{
success = SendQuery(pset, query_buf->data); success = SendQuery(pset, query_buf->data);
resetPQExpBuffer(query_buf); resetPQExpBuffer(query_buf);
} }
/* Have we lost the db connection? */ /* Have we lost the db connection? */
if (pset->db == NULL && !pset->cur_cmd_interactive) { if (pset->db == NULL && !pset->cur_cmd_interactive)
{
successResult = EXIT_BADCONN; successResult = EXIT_BADCONN;
break; break;
} }
@ -365,4 +403,3 @@ MainLoop(PsqlSettings *pset, FILE *source)
return successResult; return successResult;
} /* MainLoop() */ } /* MainLoop() */

View File

@ -7,4 +7,4 @@
int int
MainLoop(PsqlSettings *pset, FILE *source); MainLoop(PsqlSettings *pset, FILE *source);
#endif MAINLOOP_H #endif /* MAINLOOP_H */

View File

@ -44,9 +44,11 @@ print_unaligned_text(const char * title, char ** headers, char ** cells, char **
fprintf(fout, "%s\n", title); fprintf(fout, "%s\n", title);
/* print headers and count columns */ /* print headers and count columns */
for (ptr = headers; *ptr; ptr++) { for (ptr = headers; *ptr; ptr++)
{
col_count++; col_count++;
if (!opt_barebones) { if (!opt_barebones)
{
if (col_count > 1) if (col_count > 1)
fputs(opt_fieldsep, fout); fputs(opt_fieldsep, fout);
fputs(*ptr, fout); fputs(*ptr, fout);
@ -57,7 +59,8 @@ print_unaligned_text(const char * title, char ** headers, char ** cells, char **
/* print cells */ /* print cells */
i = 0; i = 0;
for (ptr = cells; *ptr; ptr++) { for (ptr = cells; *ptr; ptr++)
{
fputs(*ptr, fout); fputs(*ptr, fout);
if ((i + 1) % col_count) if ((i + 1) % col_count)
fputs(opt_fieldsep, fout); fputs(opt_fieldsep, fout);
@ -94,13 +97,14 @@ print_unaligned_vertical(const char * title, char ** headers, char ** cells, cha
fprintf(fout, "%s\n", title); fprintf(fout, "%s\n", title);
/* count columns */ /* count columns */
for (ptr = headers; *ptr; ptr++) { for (ptr = headers; *ptr; ptr++)
col_count++; col_count++;
}
/* print records */ /* print records */
for (i=0, ptr = cells; *ptr; i++, ptr++) { for (i = 0, ptr = cells; *ptr; i++, ptr++)
if (i % col_count == 0) { {
if (i % col_count == 0)
{
if (!opt_barebones) if (!opt_barebones)
fprintf(fout, "-- RECORD %d\n", record++); fprintf(fout, "-- RECORD %d\n", record++);
else else
@ -111,7 +115,8 @@ print_unaligned_vertical(const char * title, char ** headers, char ** cells, cha
/* print footers */ /* print footers */
if (!opt_barebones && footers) { if (!opt_barebones && footers)
{
fputs("--- END ---\n", fout); fputs("--- END ---\n", fout);
for (ptr = footers; *ptr; ptr++) for (ptr = footers; *ptr; ptr++)
fprintf(fout, "%s\n", *ptr); fprintf(fout, "%s\n", *ptr);
@ -129,17 +134,21 @@ print_unaligned_vertical(const char * title, char ** headers, char ** cells, cha
static void 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; unsigned int i,
j;
if (border == 1) if (border == 1)
fputc('-', fout); fputc('-', fout);
else if (border == 2) else if (border == 2)
fputs("+-", fout); fputs("+-", fout);
for (i=0; i<col_count; i++) { for (i = 0; i < col_count; i++)
{
for (j = 0; j < widths[i]; j++) for (j = 0; j < widths[i]; j++)
fputc('-', fout); fputc('-', fout);
if (i<col_count-1) { if (i < col_count - 1)
{
if (border == 0) if (border == 0)
fputc(' ', fout); fputc(' ', fout);
else else
@ -163,8 +172,10 @@ print_aligned_text(const char * title, char ** headers, char ** cells, char ** f
FILE *fout) FILE *fout)
{ {
unsigned int col_count = 0; unsigned int col_count = 0;
unsigned int i, tmp; unsigned int i,
unsigned int * widths, total_w; tmp;
unsigned int *widths,
total_w;
char **ptr; char **ptr;
/* count columns */ /* count columns */
@ -172,7 +183,8 @@ print_aligned_text(const char * title, char ** headers, char ** cells, char ** f
col_count++; col_count++;
widths = calloc(col_count, sizeof(*widths)); widths = calloc(col_count, sizeof(*widths));
if (!widths) { if (!widths)
{
perror("calloc"); perror("calloc");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -197,7 +209,8 @@ print_aligned_text(const char * title, char ** headers, char ** cells, char ** f
total_w += widths[i]; total_w += widths[i];
/* print title */ /* print title */
if (title && !opt_barebones) { if (title && !opt_barebones)
{
if (strlen(title) >= total_w) if (strlen(title) >= total_w)
fprintf(fout, "%s\n", title); fprintf(fout, "%s\n", title);
else else
@ -205,7 +218,8 @@ print_aligned_text(const char * title, char ** headers, char ** cells, char ** f
} }
/* print headers */ /* print headers */
if (!opt_barebones) { if (!opt_barebones)
{
if (opt_border == 2) if (opt_border == 2)
_print_horizontal_line(col_count, widths, opt_border, fout); _print_horizontal_line(col_count, widths, opt_border, fout);
@ -214,11 +228,13 @@ print_aligned_text(const char * title, char ** headers, char ** cells, char ** f
else if (opt_border == 1) else if (opt_border == 1)
fputc(' ', fout); fputc(' ', fout);
for (i=0; i<col_count; i++) { for (i = 0; i < col_count; i++)
{
/* centered */ /* 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), ""); 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 (i < col_count - 1)
{
if (opt_border == 0) if (opt_border == 0)
fputc(' ', fout); fputc(' ', fout);
else else
@ -236,9 +252,11 @@ print_aligned_text(const char * title, char ** headers, char ** cells, char ** f
} }
/* print cells */ /* print cells */
for (i=0, ptr = cells; *ptr; i++, ptr++) { for (i = 0, ptr = cells; *ptr; i++, ptr++)
{
/* beginning of line */ /* beginning of line */
if (i % col_count == 0) { if (i % col_count == 0)
{
if (opt_border == 2) if (opt_border == 2)
fputs("| ", fout); fputs("| ", fout);
else if (opt_border == 1) else if (opt_border == 1)
@ -248,7 +266,8 @@ print_aligned_text(const char * title, char ** headers, char ** cells, char ** f
/* content */ /* content */
if (opt_align[(i) % col_count] == 'r') if (opt_align[(i) % col_count] == 'r')
fprintf(fout, "%*s", widths[i % col_count], cells[i]); fprintf(fout, "%*s", widths[i % col_count], cells[i]);
else { else
{
if ((i + 1) % col_count == 0 && opt_border != 2) if ((i + 1) % col_count == 0 && opt_border != 2)
fputs(cells[i], fout); fputs(cells[i], fout);
else else
@ -256,14 +275,16 @@ print_aligned_text(const char * title, char ** headers, char ** cells, char ** f
} }
/* divider */ /* divider */
if ((i+1) % col_count) { if ((i + 1) % col_count)
{
if (opt_border == 0) if (opt_border == 0)
fputc(' ', fout); fputc(' ', fout);
else else
fputs(" | ", fout); fputs(" | ", fout);
} }
/* end of line */ /* end of line */
else { else
{
if (opt_border == 2) if (opt_border == 2)
fputs(" |", fout); fputs(" |", fout);
fputc('\n', fout); fputc('\n', fout);
@ -294,11 +315,15 @@ print_aligned_vertical(const char * title, char ** headers, char ** cells, char
unsigned int col_count = 0; unsigned int col_count = 0;
unsigned int record = 1; unsigned int record = 1;
char **ptr; char **ptr;
unsigned int i, tmp, hwidth=0, dwidth=0; unsigned int i,
tmp,
hwidth = 0,
dwidth = 0;
char *divider; char *divider;
/* count columns and find longest header */ /* count columns and find longest header */
for (ptr = headers; *ptr; ptr++) { for (ptr = headers; *ptr; ptr++)
{
col_count++; col_count++;
if ((tmp = strlen(*ptr)) > hwidth) if ((tmp = strlen(*ptr)) > hwidth)
hwidth = tmp; /* don't wanna call strlen twice */ hwidth = tmp; /* don't wanna call strlen twice */
@ -315,32 +340,39 @@ print_aligned_vertical(const char * title, char ** headers, char ** cells, char
/* make horizontal border */ /* make horizontal border */
divider = malloc(hwidth + dwidth + 10); divider = malloc(hwidth + dwidth + 10);
if (!divider) { if (!divider)
{
perror("malloc"); perror("malloc");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
divider[0] = '\0'; divider[0] = '\0';
if (opt_border == 2) if (opt_border == 2)
strcat(divider, "+-"); strcat(divider, "+-");
for (i=0; i<hwidth; i++) strcat(divider, opt_border > 0 ? "-" : " "); for (i = 0; i < hwidth; i++)
strcat(divider, opt_border > 0 ? "-" : " ");
if (opt_border > 0) if (opt_border > 0)
strcat(divider, "-+-"); strcat(divider, "-+-");
else else
strcat(divider, " "); strcat(divider, " ");
for (i=0; i<dwidth; i++) strcat(divider, opt_border > 0 ? "-" : " "); for (i = 0; i < dwidth; i++)
strcat(divider, opt_border > 0 ? "-" : " ");
if (opt_border == 2) if (opt_border == 2)
strcat(divider, "-+"); strcat(divider, "-+");
/* print records */ /* print records */
for (i=0, ptr = cells; *ptr; i++, ptr++) { for (i = 0, ptr = cells; *ptr; i++, ptr++)
if (i % col_count == 0) { {
if (!opt_barebones) { if (i % col_count == 0)
{
if (!opt_barebones)
{
char *div_copy = strdup(divider); char *div_copy = strdup(divider);
char *record_str = malloc(32); char *record_str = malloc(32);
size_t record_str_len; size_t record_str_len;
if (!div_copy || !record_str) { if (!div_copy || !record_str)
{
perror("malloc"); perror("malloc");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -350,10 +382,13 @@ print_aligned_vertical(const char * title, char ** headers, char ** cells, char
else else
sprintf(record_str, "[ RECORD %d ]", record++); sprintf(record_str, "[ RECORD %d ]", record++);
record_str_len = strlen(record_str); record_str_len = strlen(record_str);
if (record_str_len + opt_border > strlen(div_copy)) { if (record_str_len + opt_border > strlen(div_copy))
{
void *new; void *new;
new = realloc(div_copy, record_str_len + opt_border); new = realloc(div_copy, record_str_len + opt_border);
if (!new) { if (!new)
{
perror("realloc"); perror("realloc");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -387,7 +422,8 @@ print_aligned_vertical(const char * title, char ** headers, char ** cells, char
/* print footers */ /* print footers */
if (!opt_barebones && footers && *footers) { if (!opt_barebones && footers && *footers)
{
if (opt_border < 2) if (opt_border < 2)
fputc('\n', fout); fputc('\n', fout);
for (ptr = footers; *ptr; ptr++) for (ptr = footers; *ptr; ptr++)
@ -411,8 +447,10 @@ static void
html_escaped_print(const char *in, FILE *fout) html_escaped_print(const char *in, FILE *fout)
{ {
const char *p; const char *p;
for (p = in; *p; p++) for (p = in; *p; p++)
switch (*p) { switch (*p)
{
case '&': case '&':
fputs("&amp;", fout); fputs("&amp;", fout);
break; break;
@ -448,7 +486,8 @@ print_html_text(const char * title, char ** headers, char ** cells, char ** foot
fputs(">\n", fout); fputs(">\n", fout);
/* print title */ /* print title */
if (!opt_barebones && title) { if (!opt_barebones && title)
{
fputs(" <caption>", fout); fputs(" <caption>", fout);
html_escaped_print(title, fout); html_escaped_print(title, fout);
fputs("</caption>\n", fout); fputs("</caption>\n", fout);
@ -457,9 +496,11 @@ print_html_text(const char * title, char ** headers, char ** cells, char ** foot
/* print headers and count columns */ /* print headers and count columns */
if (!opt_barebones) if (!opt_barebones)
fputs(" <tr>\n", fout); fputs(" <tr>\n", fout);
for (i=0, ptr = headers; *ptr; i++, ptr++) { for (i = 0, ptr = headers; *ptr; i++, ptr++)
{
col_count++; col_count++;
if (!opt_barebones) { if (!opt_barebones)
{
fputs(" <th align=center>", fout); fputs(" <th align=center>", fout);
html_escaped_print(*ptr, fout); html_escaped_print(*ptr, fout);
fputs("</th>\n", fout); fputs("</th>\n", fout);
@ -469,12 +510,14 @@ print_html_text(const char * title, char ** headers, char ** cells, char ** foot
fputs(" </tr>\n", fout); fputs(" </tr>\n", fout);
/* print cells */ /* print cells */
for (i=0, ptr = cells; *ptr; i++, ptr++) { for (i = 0, ptr = cells; *ptr; i++, ptr++)
{
if (i % col_count == 0) if (i % col_count == 0)
fputs(" <tr valign=top>\n", fout); fputs(" <tr valign=top>\n", fout);
fprintf(fout, " <td align=%s>", opt_align[(i) % col_count] == 'r' ? "right" : "left"); fprintf(fout, " <td align=%s>", opt_align[(i) % col_count] == 'r' ? "right" : "left");
if ( (*ptr)[strspn(*ptr, " \t")] == '\0' ) /* is string only whitespace? */ if ((*ptr)[strspn(*ptr, " \t")] == '\0') /* is string only
* whitespace? */
fputs("&nbsp;", fout); fputs("&nbsp;", fout);
else else
html_escaped_print(*ptr, fout); html_escaped_print(*ptr, fout);
@ -489,7 +532,8 @@ print_html_text(const char * title, char ** headers, char ** cells, char ** foot
/* print footers */ /* print footers */
if (footers && !opt_barebones) if (footers && !opt_barebones)
for (ptr = footers; *ptr; ptr++) { for (ptr = footers; *ptr; ptr++)
{
html_escaped_print(*ptr, fout); html_escaped_print(*ptr, fout);
fputs("<br>\n", fout); fputs("<br>\n", fout);
} }
@ -516,7 +560,8 @@ print_html_vertical(const char * title, char ** headers, char ** cells, char **
fputs(">\n", fout); fputs(">\n", fout);
/* print title */ /* print title */
if (!opt_barebones && title) { if (!opt_barebones && title)
{
fputs(" <caption>", fout); fputs(" <caption>", fout);
html_escaped_print(title, fout); html_escaped_print(title, fout);
fputs("</caption>\n", fout); fputs("</caption>\n", fout);
@ -527,8 +572,10 @@ print_html_vertical(const char * title, char ** headers, char ** cells, char **
col_count++; col_count++;
/* print records */ /* print records */
for (i=0, ptr = cells; *ptr; i++, ptr++) { for (i = 0, ptr = cells; *ptr; i++, ptr++)
if (i % col_count == 0) { {
if (i % col_count == 0)
{
if (!opt_barebones) if (!opt_barebones)
fprintf(fout, "\n <tr><td colspan=2 align=center>Record %d</td></tr>\n", record++); fprintf(fout, "\n <tr><td colspan=2 align=center>Record %d</td></tr>\n", record++);
else else
@ -540,7 +587,8 @@ print_html_vertical(const char * title, char ** headers, char ** cells, char **
fputs("</th>\n", fout); fputs("</th>\n", fout);
fprintf(fout, " <td align=%s>", opt_align[i % col_count] == 'r' ? "right" : "left"); fprintf(fout, " <td align=%s>", opt_align[i % col_count] == 'r' ? "right" : "left");
if ( (*ptr)[strspn(*ptr, " \t")] == '\0' ) /* is string only whitespace? */ if ((*ptr)[strspn(*ptr, " \t")] == '\0') /* is string only
* whitespace? */
fputs("&nbsp;", fout); fputs("&nbsp;", fout);
else else
html_escaped_print(*ptr, fout); html_escaped_print(*ptr, fout);
@ -551,7 +599,8 @@ print_html_vertical(const char * title, char ** headers, char ** cells, char **
/* print footers */ /* print footers */
if (footers && !opt_barebones) if (footers && !opt_barebones)
for (ptr = footers; *ptr; ptr++) { for (ptr = footers; *ptr; ptr++)
{
html_escaped_print(*ptr, fout); html_escaped_print(*ptr, fout);
fputs("<br>\n", fout); fputs("<br>\n", fout);
} }
@ -570,8 +619,10 @@ static void
latex_escaped_print(const char *in, FILE *fout) latex_escaped_print(const char *in, FILE *fout)
{ {
const char *p; const char *p;
for (p = in; *p; p++) for (p = in; *p; p++)
switch (*p) { switch (*p)
{
case '&': case '&':
fputs("\\&", fout); fputs("\\&", fout);
break; break;
@ -612,7 +663,8 @@ print_latex_text(const char * title, char ** headers, char ** cells, char ** foo
/* print title */ /* print title */
if (!opt_barebones && title) { if (!opt_barebones && title)
{
fputs("\begin{center}\n", fout); fputs("\begin{center}\n", fout);
latex_escaped_print(title, fout); latex_escaped_print(title, fout);
fputs("\n\end{center}\n\n", fout); fputs("\n\end{center}\n\n", fout);
@ -622,14 +674,19 @@ print_latex_text(const char * title, char ** headers, char ** cells, char ** foo
fputs("\\begin{tabular}{", fout); fputs("\\begin{tabular}{", fout);
if (opt_border == 0) if (opt_border == 0)
fputs(opt_align, fout); fputs(opt_align, fout);
else if (opt_border==1) { else if (opt_border == 1)
for (cp = opt_align; *cp; cp++) { {
if (cp != opt_align) fputc('|', fout); for (cp = opt_align; *cp; cp++)
{
if (cp != opt_align)
fputc('|', fout);
fputc(*cp, fout); fputc(*cp, fout);
} }
} }
else if (opt_border==2) { else if (opt_border == 2)
for (cp = opt_align; *cp; cp++) { {
for (cp = opt_align; *cp; cp++)
{
fputc('|', fout); fputc('|', fout);
fputc(*cp, fout); fputc(*cp, fout);
} }
@ -641,22 +698,26 @@ print_latex_text(const char * title, char ** headers, char ** cells, char ** foo
fputs("\\hline\n", fout); fputs("\\hline\n", fout);
/* print headers and count columns */ /* print headers and count columns */
for (i=0, ptr = headers; *ptr; i++, ptr++) { for (i = 0, ptr = headers; *ptr; i++, ptr++)
{
col_count++; col_count++;
if (!opt_barebones) { if (!opt_barebones)
{
if (i != 0) if (i != 0)
fputs(" & ", fout); fputs(" & ", fout);
latex_escaped_print(*ptr, fout); latex_escaped_print(*ptr, fout);
} }
} }
if (!opt_barebones) { if (!opt_barebones)
{
fputs(" \\\\\n", fout); fputs(" \\\\\n", fout);
fputs("\\hline\n", fout); fputs("\\hline\n", fout);
} }
/* print cells */ /* print cells */
for (i=0, ptr = cells; *ptr; i++, ptr++) { for (i = 0, ptr = cells; *ptr; i++, ptr++)
{
latex_escaped_print(*ptr, fout); latex_escaped_print(*ptr, fout);
if ((i + 1) % col_count == 0) if ((i + 1) % col_count == 0)
@ -674,7 +735,8 @@ print_latex_text(const char * title, char ** headers, char ** cells, char ** foo
/* print footers */ /* print footers */
if (footers && !opt_barebones) if (footers && !opt_barebones)
for (ptr = footers; *ptr; ptr++) { for (ptr = footers; *ptr; ptr++)
{
latex_escaped_print(*ptr, fout); latex_escaped_print(*ptr, fout);
fputs(" \\\\\n", fout); fputs(" \\\\\n", fout);
} }
@ -697,7 +759,8 @@ print_latex_vertical(const char * title, char ** headers, char ** cells, char **
(void) opt_align; /* currently unused parameter */ (void) opt_align; /* currently unused parameter */
/* print title */ /* print title */
if (!opt_barebones && title) { if (!opt_barebones && title)
{
fputs("\begin{center}\n", fout); fputs("\begin{center}\n", fout);
latex_escaped_print(title, fout); latex_escaped_print(title, fout);
fputs("\n\end{center}\n\n", fout); fputs("\n\end{center}\n\n", fout);
@ -720,10 +783,13 @@ print_latex_vertical(const char * title, char ** headers, char ** cells, char **
/* print records */ /* print records */
for (i=0, ptr = cells; *ptr; i++, ptr++) { for (i = 0, ptr = cells; *ptr; i++, ptr++)
{
/* new record */ /* new record */
if (i % col_count == 0) { if (i % col_count == 0)
if (!opt_barebones) { {
if (!opt_barebones)
{
if (opt_border == 2) if (opt_border == 2)
fputs("\\hline\n", fout); fputs("\\hline\n", fout);
fprintf(fout, "\\multicolumn{2}{c}{Record %d} \\\\\n", record++); fprintf(fout, "\\multicolumn{2}{c}{Record %d} \\\\\n", record++);
@ -747,7 +813,8 @@ print_latex_vertical(const char * title, char ** headers, char ** cells, char **
/* print footers */ /* print footers */
if (footers && !opt_barebones) if (footers && !opt_barebones)
for (ptr = footers; *ptr; ptr++) { for (ptr = footers; *ptr; ptr++)
{
latex_escaped_print(*ptr, fout); latex_escaped_print(*ptr, fout);
fputs(" \\\\\n", fout); fputs(" \\\\\n", fout);
} }
@ -796,8 +863,11 @@ printTable(const char * title, char ** headers, char ** cells, char ** footers,
) )
{ {
const char *pagerprog; const char *pagerprog;
#ifdef TIOCGWINSZ #ifdef TIOCGWINSZ
unsigned int col_count=0, row_count=0, lines; unsigned int col_count = 0,
row_count = 0,
lines;
char **ptr; char **ptr;
int result; int result;
struct winsize screen_size; struct winsize screen_size;
@ -819,17 +889,20 @@ printTable(const char * title, char ** headers, char ** cells, char ** footers,
lines += 5; lines += 5;
result = ioctl(fileno(stdout), TIOCGWINSZ, &screen_size); result = ioctl(fileno(stdout), TIOCGWINSZ, &screen_size);
if (result==-1 || lines > screen_size.ws_row) { if (result == -1 || lines > screen_size.ws_row)
{
#endif #endif
pagerprog = getenv("PAGER"); pagerprog = getenv("PAGER");
if (!pagerprog) pagerprog = DEFAULT_PAGER; if (!pagerprog)
pagerprog = DEFAULT_PAGER;
pager = popen(pagerprog, "w"); pager = popen(pagerprog, "w");
#ifdef TIOCGWINSZ #ifdef TIOCGWINSZ
} }
#endif #endif
} }
if (pager) { if (pager)
{
output = pager; output = pager;
pqsignal(SIGPIPE, SIG_IGN); pqsignal(SIGPIPE, SIG_IGN);
} }
@ -839,7 +912,8 @@ printTable(const char * title, char ** headers, char ** cells, char ** footers,
/* print the stuff */ /* print the stuff */
switch (opt->format) { switch (opt->format)
{
case PRINT_UNALIGNED: case PRINT_UNALIGNED:
if (opt->expanded) if (opt->expanded)
print_unaligned_vertical(title, headers, cells, footers, opt->fieldSep, opt->tuples_only, output); print_unaligned_vertical(title, headers, cells, footers, opt->fieldSep, opt->tuples_only, output);
@ -868,7 +942,8 @@ printTable(const char * title, char ** headers, char ** cells, char ** footers,
fprintf(stderr, "+ Oops, you shouldn't see this!\n"); fprintf(stderr, "+ Oops, you shouldn't see this!\n");
} }
if (pager) { if (pager)
{
pclose(pager); pclose(pager);
pqsignal(SIGPIPE, SIG_DFL); pqsignal(SIGPIPE, SIG_DFL);
} }
@ -891,7 +966,8 @@ printQuery(PGresult * result, const printQueryOpt * opt, FILE * fout)
nfields = PQnfields(result); nfields = PQnfields(result);
headers = calloc(nfields + 1, sizeof(*headers)); headers = calloc(nfields + 1, sizeof(*headers));
if (!headers) { if (!headers)
{
perror("calloc"); perror("calloc");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -902,12 +978,14 @@ printQuery(PGresult * result, const printQueryOpt * opt, FILE * fout)
/* set cells */ /* set cells */
cells = calloc(nfields * PQntuples(result) + 1, sizeof(*cells)); cells = calloc(nfields * PQntuples(result) + 1, sizeof(*cells));
if (!cells) { if (!cells)
{
perror("calloc"); perror("calloc");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
for (i=0; i< nfields * PQntuples(result); i++) { for (i = 0; i < nfields * PQntuples(result); i++)
{
if (PQgetisnull(result, i / nfields, i % nfields)) if (PQgetisnull(result, i / nfields, i % nfields))
cells[i] = opt->nullPrint ? opt->nullPrint : ""; cells[i] = opt->nullPrint ? opt->nullPrint : "";
else else
@ -918,9 +996,11 @@ printQuery(PGresult * result, const printQueryOpt * opt, FILE * fout)
if (opt->footers) if (opt->footers)
footers = opt->footers; footers = opt->footers;
else if (!opt->topt.expanded) { else if (!opt->topt.expanded)
{
footers = calloc(2, sizeof(*footers)); footers = calloc(2, sizeof(*footers));
if (!footers) { if (!footers)
{
perror("calloc"); perror("calloc");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -937,13 +1017,16 @@ printQuery(PGresult * result, const printQueryOpt * opt, FILE * fout)
/* set alignment */ /* set alignment */
align = calloc(nfields + 1, sizeof(*align)); align = calloc(nfields + 1, sizeof(*align));
if (!align) { if (!align)
{
perror("calloc"); perror("calloc");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
for (i=0; i<nfields; i++) { for (i = 0; i < nfields; i++)
{
Oid ftype = PQftype(result, i); Oid ftype = PQftype(result, i);
if (ftype == 20 || /* int8 */ if (ftype == 20 || /* int8 */
ftype == 21 || /* int2 */ ftype == 21 || /* int2 */
ftype == 23 || /* int4 */ ftype == 23 || /* int4 */
@ -965,7 +1048,8 @@ printQuery(PGresult * result, const printQueryOpt * opt, FILE * fout)
free(headers); free(headers);
free(cells); free(cells);
if (footers) { if (footers)
{
free(footers[0]); free(footers[0]);
free(footers); free(footers);
} }

View File

@ -7,7 +7,8 @@
#include <stdio.h> #include <stdio.h>
#include <libpq-fe.h> #include <libpq-fe.h>
enum printFormat { enum printFormat
{
PRINT_NOTHING = 0, /* to make sure someone initializes this */ PRINT_NOTHING = 0, /* to make sure someone initializes this */
PRINT_UNALIGNED, PRINT_UNALIGNED,
PRINT_ALIGNED, PRINT_ALIGNED,
@ -17,12 +18,16 @@ enum printFormat {
}; };
typedef struct _printTableOpt { typedef struct _printTableOpt
{
enum printFormat format; /* one of the above */ enum printFormat format; /* one of the above */
bool expanded; /* expanded/vertical output (if supported by output format) */ bool expanded; /* expanded/vertical output (if supported
bool pager; /* use pager for output (if to stdout and stdout is a tty) */ * 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. */ 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 */ 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 *fieldSep; /* field separator for unaligned text mode */
char *tableAttr; /* attributes for HTML <table ...> */ char *tableAttr; /* attributes for HTML <table ...> */
} printTableOpt; } printTableOpt;
@ -39,19 +44,20 @@ typedef struct _printTableOpt {
* - align is an 'l' or an 'r' for every column, if the output format needs it. * - 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 void printTable(const char *title, char **headers, char **cells, char **footers,
printTable(const char * title, char ** headers, char ** cells, char ** footers,
const char *align, const char *align,
const printTableOpt * opt, FILE *fout); const printTableOpt * opt, FILE *fout);
typedef struct _printQueryOpt { typedef struct _printQueryOpt
{
printTableOpt topt; /* the options above */ printTableOpt topt; /* the options above */
char *nullPrint; /* how to print null entities */ char *nullPrint; /* how to print null entities */
bool quote; /* quote all values as much as possible */ bool quote; /* quote all values as much as possible */
char *title; /* override title */ char *title; /* override title */
char ** footers; /* override footer (default is "(xx rows)") */ char **footers; /* override footer (default is "(xx
* rows)") */
} printQueryOpt; } printQueryOpt;
/* /*

View File

@ -99,9 +99,12 @@ get_prompt(PsqlSettings *pset, promptStatus_t status)
if (pset->db) if (pset->db)
strncpy(buf, PQdb(pset->db), MAX_PROMPT_SIZE); strncpy(buf, PQdb(pset->db), MAX_PROMPT_SIZE);
break; break;
case '~': { case '~':
{
const char *var; const char *var;
if (pset->db) {
if (pset->db)
{
if (strcmp(PQdb(pset->db), PQuser(pset->db)) == 0 || if (strcmp(PQdb(pset->db), PQuser(pset->db)) == 0 ||
((var = getenv("PGDATABASE")) && strcmp(var, PQdb(pset->db)) == 0)) ((var = getenv("PGDATABASE")) && strcmp(var, PQdb(pset->db)) == 0))
strcpy(buf, "~"); strcpy(buf, "~");
@ -113,8 +116,10 @@ get_prompt(PsqlSettings *pset, promptStatus_t status)
/* DB server hostname (long/short) */ /* DB server hostname (long/short) */
case 'M': case 'M':
case 'm': case 'm':
if (pset->db) { if (pset->db)
if (PQhost(pset->db)) { {
if (PQhost(pset->db))
{
strncpy(buf, PQhost(pset->db), MAX_PROMPT_SIZE); strncpy(buf, PQhost(pset->db), MAX_PROMPT_SIZE);
if (*p == 'm') if (*p == 'm')
buf[strcspn(buf, ".")] = '\0'; buf[strcspn(buf, ".")] = '\0';
@ -125,7 +130,8 @@ get_prompt(PsqlSettings *pset, promptStatus_t status)
break; break;
/* DB server port number */ /* DB server port number */
case '>': case '>':
if (pset->db) { if (pset->db)
{
if (PQhost(pset->db)) if (PQhost(pset->db))
strncpy(buf, PQport(pset->db), MAX_PROMPT_SIZE); strncpy(buf, PQport(pset->db), MAX_PROMPT_SIZE);
else else
@ -138,11 +144,20 @@ get_prompt(PsqlSettings *pset, promptStatus_t status)
strncpy(buf, PQuser(pset->db), MAX_PROMPT_SIZE); strncpy(buf, PQuser(pset->db), MAX_PROMPT_SIZE);
break; break;
case '0': case '1': case '2': case '3': case '4': case '0':
case '5': case '6': case '7': case '8': case '9': case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
{ {
long int l; long int l;
char *end; char *end;
l = strtol(p, &end, 0); l = strtol(p, &end, 0);
sprintf(buf, "%c", (unsigned char) l); sprintf(buf, "%c", (unsigned char) l);
p = end - 1; p = end - 1;
@ -150,7 +165,8 @@ get_prompt(PsqlSettings *pset, promptStatus_t status)
} }
case 'R': case 'R':
switch(status) { switch (status)
{
case PROMPT_READY: case PROMPT_READY:
if (!pset->db) if (!pset->db)
buf[0] = '!'; buf[0] = '!';
@ -196,11 +212,13 @@ get_prompt(PsqlSettings *pset, promptStatus_t status)
FILE *fd = NULL; FILE *fd = NULL;
char *file = strdup(p + 1); char *file = strdup(p + 1);
int cmdend; int cmdend;
cmdend = strcspn(file, "`"); cmdend = strcspn(file, "`");
file[cmdend] = '\0'; file[cmdend] = '\0';
if (file) if (file)
fd = popen(file, "r"); fd = popen(file, "r");
if (fd) { if (fd)
{
fgets(buf, MAX_PROMPT_SIZE - 1, fd); fgets(buf, MAX_PROMPT_SIZE - 1, fd);
pclose(fd); pclose(fd);
} }
@ -217,6 +235,7 @@ get_prompt(PsqlSettings *pset, promptStatus_t status)
char *name; char *name;
const char *val; const char *val;
int nameend; int nameend;
name = strdup(p + 1); name = strdup(p + 1);
nameend = strcspn(name, "$"); nameend = strcspn(name, "$");
name[nameend] = '\0'; name[nameend] = '\0';
@ -245,12 +264,10 @@ get_prompt(PsqlSettings *pset, promptStatus_t status)
esc = false; esc = false;
} }
if (!esc) { if (!esc)
strncat(destination, buf, MAX_PROMPT_SIZE - strlen(destination)); strncat(destination, buf, MAX_PROMPT_SIZE - strlen(destination));
} }
}
destination[MAX_PROMPT_SIZE] = '\0'; destination[MAX_PROMPT_SIZE] = '\0';
return destination; return destination;
} }

View File

@ -3,7 +3,8 @@
#include "settings.h" #include "settings.h"
typedef enum _promptStatus { typedef enum _promptStatus
{
PROMPT_READY, PROMPT_READY,
PROMPT_CONTINUE, PROMPT_CONTINUE,
PROMPT_COMMENT, PROMPT_COMMENT,

File diff suppressed because it is too large Load Diff

View File

@ -5,7 +5,7 @@
* *
* Copyright (c) 1994, Regents of the University of California * 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\ \tVACUUM [VERBOSE] [ANALYZE] [table]\n\
\tor\n\ \tor\n\
\tVACUUM [VERBOSE] ANALYZE [table [(column_name1, ...column_nameN)]];"}, \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! */
}; };

View File

@ -29,15 +29,18 @@ typedef struct _psqlSettings
char *gfname; /* one-shot file output argument for \g */ char *gfname; /* one-shot file output argument for \g */
bool notty; /* stdin or stdout is not a tty (as determined on startup) */ bool notty; /* stdin or stdout is not a tty (as
* determined on startup) */
bool useReadline; /* use libreadline routines */ bool useReadline; /* use libreadline routines */
bool useHistory; bool useHistory;
bool getPassword; /* prompt the user for a username and bool getPassword; /* prompt the user for a username and
password */ * password */
FILE * cur_cmd_source; /* describe the status of the current main loop */ FILE *cur_cmd_source; /* describe the status of the current main
* loop */
bool cur_cmd_interactive; bool cur_cmd_interactive;
bool has_client_encoding; /* was PGCLIENTENCODING set on startup? */ bool has_client_encoding; /* was PGCLIENTENCODING set on
* startup? */
} PsqlSettings; } PsqlSettings;

View File

@ -46,7 +46,9 @@ showVersion(PsqlSettings *pset, bool verbose);
/* Structures to pass information between the option parsing routine /* Structures to pass information between the option parsing routine
* and the main function * and the main function
*/ */
enum _actions { ACT_NOTHING = 0, enum _actions
{
ACT_NOTHING = 0,
ACT_SINGLE_SLASH, ACT_SINGLE_SLASH,
ACT_LIST_DB, ACT_LIST_DB,
ACT_SHOW_VER, ACT_SHOW_VER,
@ -54,7 +56,8 @@ enum _actions { ACT_NOTHING = 0,
ACT_FILE ACT_FILE
}; };
struct adhoc_opts { struct adhoc_opts
{
char *dbname; char *dbname;
char *host; char *host;
char *port; char *port;
@ -118,7 +121,8 @@ main(int argc, char **argv)
if (options.action == ACT_LIST_DB || options.action == ACT_SHOW_VER) if (options.action == ACT_LIST_DB || options.action == ACT_SHOW_VER)
options.dbname = "template1"; options.dbname = "template1";
if (options.username) { if (options.username)
{
if (strcmp(options.username, "?") == 0) if (strcmp(options.username, "?") == 0)
username = simple_prompt("Username: ", 100, true); username = simple_prompt("Username: ", 100, true);
else else
@ -129,12 +133,14 @@ main(int argc, char **argv)
password = simple_prompt("Password: ", 100, false); password = simple_prompt("Password: ", 100, false);
/* loop until we have a password if requested by backend */ /* loop until we have a password if requested by backend */
do { do
{
need_pass = false; need_pass = false;
settings.db = PQsetdbLogin(options.host, options.port, NULL, NULL, options.dbname, username, password); settings.db = PQsetdbLogin(options.host, options.port, NULL, NULL, options.dbname, username, password);
if (PQstatus(settings.db) == CONNECTION_BAD && if (PQstatus(settings.db) == CONNECTION_BAD &&
strcmp(PQerrorMessage(settings.db), "fe_sendauth: no password supplied\n")==0) { strcmp(PQerrorMessage(settings.db), "fe_sendauth: no password supplied\n") == 0)
{
need_pass = true; need_pass = true;
free(password); free(password);
password = NULL; password = NULL;
@ -145,19 +151,23 @@ main(int argc, char **argv)
free(username); free(username);
free(password); free(password);
if (PQstatus(settings.db) == CONNECTION_BAD) { if (PQstatus(settings.db) == CONNECTION_BAD)
{
fprintf(stderr, "Connection to database '%s' failed.\n%s\n", PQdb(settings.db), PQerrorMessage(settings.db)); fprintf(stderr, "Connection to database '%s' failed.\n%s\n", PQdb(settings.db), PQerrorMessage(settings.db));
PQfinish(settings.db); PQfinish(settings.db);
exit(EXIT_BADCONN); exit(EXIT_BADCONN);
} }
if (options.action == ACT_LIST_DB) { if (options.action == ACT_LIST_DB)
{
int success = listAllDbs(&settings); int success = listAllDbs(&settings);
PQfinish(settings.db); PQfinish(settings.db);
exit(!success); exit(!success);
} }
if (options.action == ACT_SHOW_VER) { if (options.action == ACT_SHOW_VER)
{
showVersion(&settings, true); showVersion(&settings, true);
PQfinish(settings.db); PQfinish(settings.db);
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
@ -215,6 +225,7 @@ main(int argc, char **argv)
#ifdef WIN32 #ifdef WIN32
/* getopt is not in the standard includes on 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 #endif
static void static void
@ -255,6 +266,7 @@ parse_options(int argc, char *argv[], PsqlSettings * pset, struct adhoc_opts * o
}; };
int optindex; int optindex;
#endif #endif
extern char *optarg; extern char *optarg;
@ -266,7 +278,11 @@ parse_options(int argc, char *argv[], PsqlSettings * pset, struct adhoc_opts * o
#ifdef HAVE_GETOPT_LONG #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 #else
/* Be sure to leave the '-' in here, so we can catch accidental long options. */
/*
* 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) while ((c = getopt(argc, argv, "Ac:d:eEf:F:lh:Hno:p:P:qsStT:uU:v:VWx?-")) != -1)
#endif #endif
{ {
@ -326,12 +342,14 @@ parse_options(int argc, char *argv[], PsqlSettings * pset, struct adhoc_opts * o
equal_loc = strchr(value, '='); equal_loc = strchr(value, '=');
if (!equal_loc) if (!equal_loc)
result = do_pset(value, NULL, &pset->popt, true); result = do_pset(value, NULL, &pset->popt, true);
else { else
{
*equal_loc = '\0'; *equal_loc = '\0';
result = do_pset(value, equal_loc + 1, &pset->popt, true); result = do_pset(value, equal_loc + 1, &pset->popt, true);
} }
if (!result) { if (!result)
{
fprintf(stderr, "Couldn't set printing paramter %s.\n", value); fprintf(stderr, "Couldn't set printing paramter %s.\n", value);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -371,15 +389,19 @@ parse_options(int argc, char *argv[], PsqlSettings * pset, struct adhoc_opts * o
value = xstrdup(optarg); value = xstrdup(optarg);
equal_loc = strchr(value, '='); equal_loc = strchr(value, '=');
if (!equal_loc) { if (!equal_loc)
if (!DeleteVariable(pset->vars, value)) { {
if (!DeleteVariable(pset->vars, value))
{
fprintf(stderr, "Couldn't delete variable %s.\n", value); fprintf(stderr, "Couldn't delete variable %s.\n", value);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
} }
else { else
{
*equal_loc = '\0'; *equal_loc = '\0';
if (!SetVariable(pset->vars, value, equal_loc+1)) { if (!SetVariable(pset->vars, value, equal_loc + 1))
{
fprintf(stderr, "Couldn't set variable %s to %s.\n", value, equal_loc); fprintf(stderr, "Couldn't set variable %s to %s.\n", value, equal_loc);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -412,8 +434,12 @@ parse_options(int argc, char *argv[], PsqlSettings * pset, struct adhoc_opts * o
} }
} }
/* if we still have arguments, use it as the database name and username */ /*
while (argc - optind >= 1) { * if we still have arguments, use it as the database name and
* username
*/
while (argc - optind >= 1)
{
if (!options->dbname) if (!options->dbname)
options->dbname = argv[optind]; options->dbname = argv[optind];
else if (!options->username) else if (!options->username)
@ -449,9 +475,11 @@ process_psqlrc(PsqlSettings * pset)
/* Look for one in the home dir */ /* Look for one in the home dir */
home = getenv("HOME"); home = getenv("HOME");
if (home) { if (home)
{
psqlrc = (char *) malloc(strlen(home) + 20); psqlrc = (char *) malloc(strlen(home) + 20);
if (!psqlrc) { if (!psqlrc)
{
perror("malloc"); perror("malloc");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -459,7 +487,8 @@ process_psqlrc(PsqlSettings * pset)
sprintf(psqlrc, "%s/.psqlrc-" PG_RELEASE "." PG_VERSION "." PG_SUBVERSION, home); sprintf(psqlrc, "%s/.psqlrc-" PG_RELEASE "." PG_VERSION "." PG_SUBVERSION, home);
if (access(psqlrc, R_OK) == 0) if (access(psqlrc, R_OK) == 0)
process_file(psqlrc, pset); process_file(psqlrc, pset);
else { else
{
sprintf(psqlrc, "%s/.psqlrc", home); sprintf(psqlrc, "%s/.psqlrc", home);
if (access(psqlrc, R_OK) == 0) if (access(psqlrc, R_OK) == 0)
process_file(psqlrc, pset); process_file(psqlrc, pset);
@ -484,21 +513,27 @@ showVersion(PsqlSettings *pset, bool verbose)
{ {
PGresult *res; PGresult *res;
char *versionstr = NULL; char *versionstr = NULL;
long int release = 0, version = 0, subversion = 0; long int release = 0,
version = 0,
subversion = 0;
/* get backend version */ /* get backend version */
res = PSQLexec(pset, "SELECT version()"); res = PSQLexec(pset, "SELECT version()");
if (PQresultStatus(res) == PGRES_TUPLES_OK) if (PQresultStatus(res) == PGRES_TUPLES_OK)
versionstr = PQgetvalue(res, 0, 0); versionstr = PQgetvalue(res, 0, 0);
if (!verbose) { if (!verbose)
if (versionstr) puts(versionstr); {
if (versionstr)
puts(versionstr);
PQclear(res); PQclear(res);
return; return;
} }
if (strncmp(versionstr, "PostgreSQL ", 11) == 0) { if (strncmp(versionstr, "PostgreSQL ", 11) == 0)
{
char *tmp; char *tmp;
release = strtol(&versionstr[11], &tmp, 10); release = strtol(&versionstr[11], &tmp, 10);
version = strtol(tmp + 1, &tmp, 10); version = strtol(tmp + 1, &tmp, 10);
subversion = strtol(tmp + 1, &tmp, 10); subversion = strtol(tmp + 1, &tmp, 10);

View File

@ -2,11 +2,13 @@
#include <c.h> #include <c.h>
#include "stringutils.h" #include "stringutils.h"
//#include <ctype.h> //
#include <ctype.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <assert.h> #include <assert.h>
//#include <stdio.h> //
#include <stdio.h>
#include <postgres.h> #include <postgres.h>
#ifndef HAVE_STRDUP #ifndef HAVE_STRDUP
@ -34,21 +36,26 @@ unescape_quotes(char *source, char quote, char escape);
* *
* Note that the string s is _not_ overwritten in this implementation. * Note that the string s is _not_ overwritten in this implementation.
*/ */
char * strtokx(const char *s, char *
strtokx(const char *s,
const char *delim, const char *delim,
const char *quote, const char *quote,
char escape, char escape,
char *was_quoted, char *was_quoted,
unsigned int *token_pos) unsigned int *token_pos)
{ {
static char * storage = NULL; /* store the local copy of the users string here */ static char *storage = NULL;/* store the local copy of the users
static char * string = NULL; /* pointer into storage where to continue on next call */ * string here */
static char *string = NULL; /* pointer into storage where to continue
* on next call */
/* variously abused variables: */ /* variously abused variables: */
unsigned int offset; unsigned int offset;
char *start; char *start;
char *cp = NULL; char *cp = NULL;
if (s) { if (s)
{
free(storage); free(storage);
storage = strdup(s); storage = strdup(s);
string = storage; string = storage;
@ -61,7 +68,8 @@ char * strtokx(const char *s,
offset = strspn(string, delim); offset = strspn(string, delim);
/* end of string reached */ /* end of string reached */
if (string[offset] == '\0') { if (string[offset] == '\0')
{
/* technically we don't need to free here, but we're nice */ /* technically we don't need to free here, but we're nice */
free(storage); free(storage);
storage = NULL; storage = NULL;
@ -73,9 +81,11 @@ char * strtokx(const char *s,
if (quote) if (quote)
cp = strchr(quote, string[offset]); cp = strchr(quote, string[offset]);
if (cp) { if (cp)
{
/* okay, we have a quoting character, now scan for the closer */ /* okay, we have a quoting character, now scan for the closer */
char *p; char *p;
start = &string[offset + 1]; start = &string[offset + 1];
if (token_pos) if (token_pos)
@ -91,7 +101,8 @@ char * strtokx(const char *s,
); );
/* not yet end of string? */ /* not yet end of string? */
if (*p != '\0') { if (*p != '\0')
{
*p = '\0'; *p = '\0';
string = p + 1; string = p + 1;
if (was_quoted) if (was_quoted)
@ -99,7 +110,8 @@ char * strtokx(const char *s,
unescape_quotes(start, *cp, escape); unescape_quotes(start, *cp, escape);
return start; return start;
} }
else { else
{
if (was_quoted) if (was_quoted)
*was_quoted = *cp; *was_quoted = *cp;
string = p; string = p;
@ -119,13 +131,15 @@ char * strtokx(const char *s,
if (was_quoted) if (was_quoted)
*was_quoted = 0; *was_quoted = 0;
if (start[offset] != '\0') { if (start[offset] != '\0')
{
start[offset] = '\0'; start[offset] = '\0';
string = &start[offset] + 1; string = &start[offset] + 1;
return start; return start;
} }
else { else
{
string = &start[offset]; string = &start[offset];
return start; return start;
} }
@ -143,14 +157,16 @@ static void
unescape_quotes(char *source, char quote, char escape) unescape_quotes(char *source, char quote, char escape)
{ {
char *p; char *p;
char *destination, *tmp; char *destination,
*tmp;
#ifdef USE_ASSERT_CHECKING #ifdef USE_ASSERT_CHECKING
assert(source); assert(source);
#endif #endif
destination = (char *) calloc(1, strlen(source) + 1); destination = (char *) calloc(1, strlen(source) + 1);
if (!destination) { if (!destination)
{
perror("calloc"); perror("calloc");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -161,7 +177,8 @@ unescape_quotes(char *source, char quote, char escape)
{ {
char c; char c;
if (*p == escape && *(p+1) && quote == *(p+1)) { if (*p == escape && *(p + 1) && quote == *(p + 1))
{
c = *(p + 1); c = *(p + 1);
p++; p++;
} }

View File

@ -3,8 +3,7 @@
/* The cooler version of strtok() which knows about quotes and doesn't /* The cooler version of strtok() which knows about quotes and doesn't
* overwrite your input */ * overwrite your input */
extern char * extern char *strtokx(const char *s,
strtokx(const char *s,
const char *delim, const char *delim,
const char *quote, const char *quote,
char escape, char escape,

View File

@ -6,16 +6,19 @@
#include <assert.h> #include <assert.h>
VariableSpace CreateVariableSpace(void) VariableSpace
CreateVariableSpace(void)
{ {
struct _variable *ptr; struct _variable *ptr;
ptr = calloc(1, sizeof *ptr); ptr = calloc(1, sizeof *ptr);
if (!ptr) return NULL; if (!ptr)
return NULL;
ptr->name = strdup("@"); ptr->name = strdup("@");
ptr->value = strdup(""); ptr->value = strdup("");
if (!ptr->name || !ptr->value) { if (!ptr->name || !ptr->value)
{
free(ptr->name); free(ptr->name);
free(ptr->value); free(ptr->value);
free(ptr); free(ptr);
@ -27,16 +30,19 @@ VariableSpace CreateVariableSpace(void)
const char * GetVariable(VariableSpace space, const char * name) const char *
GetVariable(VariableSpace space, const char *name)
{ {
struct _variable *current; struct _variable *current;
if (!space) if (!space)
return NULL; 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 #ifdef USE_ASSERT_CHECKING
assert(current->name); assert(current->name);
assert(current->value); assert(current->value);
@ -50,16 +56,19 @@ const char * GetVariable(VariableSpace space, const char * name)
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) if (!space)
return false; return false;
@ -67,14 +76,17 @@ bool SetVariable(VariableSpace space, const char * name, const char * value)
if (!value) if (!value)
return DeleteVariable(space, name); 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 #ifdef USE_ASSERT_CHECKING
assert(current->name); assert(current->name);
assert(current->value); assert(current->value);
#endif #endif
if (strcmp(current->name, name)==0) { if (strcmp(current->name, name) == 0)
{
free(current->value); free(current->value);
current->value = strdup(value); current->value = strdup(value);
return current->value ? true : false; return current->value ? true : false;
@ -93,21 +105,26 @@ bool SetVariable(VariableSpace space, const char * name, const char * value)
bool DeleteVariable(VariableSpace space, const char * name) bool
DeleteVariable(VariableSpace space, const char *name)
{ {
struct _variable *current, *previous; struct _variable *current,
*previous;
if (!space) if (!space)
return false; 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 #ifdef USE_ASSERT_CHECKING
assert(current->name); assert(current->name);
assert(current->value); assert(current->value);
#endif #endif
if (strcmp(current->name, name)==0) { if (strcmp(current->name, name) == 0)
{
free(current->name); free(current->name);
free(current->value); free(current->value);
if (previous) if (previous)
@ -122,7 +139,8 @@ bool DeleteVariable(VariableSpace space, const char * name)
void DestroyVariableSpace(VariableSpace space) void
DestroyVariableSpace(VariableSpace space)
{ {
if (!space) if (!space)
return; return;

View File

@ -13,7 +13,8 @@
#define VALID_VARIABLE_CHARS "abcdefghijklmnopqrstuvwxyz0123456789_" #define VALID_VARIABLE_CHARS "abcdefghijklmnopqrstuvwxyz0123456789_"
struct _variable { struct _variable
{
char *name; char *name;
char *value; char *value;
struct _variable *next; struct _variable *next;