aboutsummaryrefslogtreecommitdiff
path: root/src/bin/psql/psql.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/bin/psql/psql.c')
-rw-r--r--src/bin/psql/psql.c3771
1 files changed, 2041 insertions, 1730 deletions
diff --git a/src/bin/psql/psql.c b/src/bin/psql/psql.c
index 0b77a3ff5f1..3a58f8ad321 100644
--- a/src/bin/psql/psql.c
+++ b/src/bin/psql/psql.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* psql.c--
- * an interactive front-end to postgreSQL
+ * an interactive front-end to postgreSQL
*
* Copyright (c) 1996, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/bin/psql/Attic/psql.c,v 1.90 1997/09/05 00:09:30 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/bin/psql/Attic/psql.c,v 1.91 1997/09/07 04:55:20 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -17,7 +17,7 @@
#include <signal.h>
#include <errno.h>
#include <sys/types.h>
-#include <sys/param.h> /* for MAXPATHLEN */
+#include <sys/param.h> /* for MAXPATHLEN */
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
@@ -35,17 +35,17 @@
#endif
#ifdef HAVE_LIBREADLINE
-# ifdef HAVE_READLINE_H
-# include <readline.h>
-# if defined(HAVE_HISTORY)
-# include <history.h>
-# endif
-# else
-# include <readline/readline.h>
-# if defined(HAVE_READLINE_HISTORY_H)
-# include <readline/history.h>
-# endif
-# endif
+#ifdef HAVE_READLINE_H
+#include <readline.h>
+#if defined(HAVE_HISTORY)
+#include <history.h>
+#endif
+#else
+#include <readline/readline.h>
+#if defined(HAVE_READLINE_HISTORY_H)
+#include <readline/history.h>
+#endif
+#endif
#endif
/* This prompt string is assumed to have at least 3 characters by code in MainLoop().
@@ -54,80 +54,84 @@
#define PROMPT "=> "
#define PROMPT_READY '='
-#define PROMPT_CONTINUE '-'
+#define PROMPT_CONTINUE '-'
#define PROMPT_COMMENT '*'
#define PROMPT_QUOTE '\''
/* Backslash command handling:
- * 0 - send currently constructed query to backend (i.e. we got a \g)
- * 1 - skip processing of this line, continue building up query
- * 2 - terminate processing of this query entirely
- * 3 - new query supplied by edit
+ * 0 - send currently constructed query to backend (i.e. we got a \g)
+ * 1 - skip processing of this line, continue building up query
+ * 2 - terminate processing of this query entirely
+ * 3 - new query supplied by edit
*/
-#define CMD_UNKNOWN -1
-#define CMD_SEND 0
+#define CMD_UNKNOWN -1
+#define CMD_SEND 0
#define CMD_SKIP_LINE 1
#define CMD_TERMINATE 2
-#define CMD_NEWEDIT 3
+#define CMD_NEWEDIT 3
#define MAX_QUERY_BUFFER 20000
-#define COPYBUFSIZ 8192
+#define COPYBUFSIZ 8192
#define DEFAULT_FIELD_SEP "|"
-#define DEFAULT_EDITOR "vi"
+#define DEFAULT_EDITOR "vi"
#define DEFAULT_SHELL "/bin/sh"
-typedef struct _psqlSettings {
- PGconn *db; /* connection to backend */
- FILE *queryFout; /* where to send the query results */
- PQprintOpt opt; /* options to be passed to PQprint */
- char *prompt; /* prompt to display */
- char *gfname; /* one-shot file output argument for \g */
- bool notty; /* input or output is not a tty */
- bool pipe; /* queryFout is from a popen() */
- bool echoQuery; /* echo the query before sending it */
- bool quiet; /* run quietly, no messages, no promt */
- bool singleStep; /* prompt before for each query */
- bool singleLineMode; /* query terminated by newline */
- bool useReadline;/* use libreadline routines */
- bool getPassword;/* prompt the user for a username and password */
-} PsqlSettings;
+typedef struct _psqlSettings
+{
+ PGconn *db; /* connection to backend */
+ FILE *queryFout; /* where to send the query results */
+ PQprintOpt opt; /* options to be passed to PQprint */
+ char *prompt; /* prompt to display */
+ char *gfname; /* one-shot file output argument for \g */
+ bool notty; /* input or output is not a tty */
+ bool pipe; /* queryFout is from a popen() */
+ bool echoQuery; /* echo the query before sending it */
+ bool quiet; /* run quietly, no messages, no promt */
+ bool singleStep; /* prompt before for each query */
+ bool singleLineMode; /* query terminated by newline */
+ bool useReadline;/* use libreadline routines */
+ bool getPassword;/* prompt the user for a username and
+ * password */
+} PsqlSettings;
/* declarations for functions in this file */
-static void usage(char *progname);
-static void slashUsage();
-static void handleCopyOut(PGresult * res, bool quiet, FILE * copystream);
+static void usage(char *progname);
+static void slashUsage();
+static void handleCopyOut(PGresult * res, bool quiet, FILE * copystream);
static void
handleCopyIn(PGresult * res, const bool mustprompt,
- FILE * copystream);
-static int tableList(PsqlSettings * ps, bool deep_tablelist, char info_type);
-static int tableDesc(PsqlSettings * ps, char *table);
-static int rightsList(PsqlSettings * ps);
-static void prompt_for_password(char *username, char *password);
-static char * make_connect_string(char *host, char *port, char *dbname,
- char *username, char *password);
-
-static char *gets_noreadline(char *prompt, FILE * source);
-static char *gets_readline(char *prompt, FILE * source);
-static char *gets_fromFile(char *prompt, FILE * source);
-static int listAllDbs(PsqlSettings * settings);
+ FILE * copystream);
+static int tableList(PsqlSettings * ps, bool deep_tablelist, char info_type);
+static int tableDesc(PsqlSettings * ps, char *table);
+static int rightsList(PsqlSettings * ps);
+static void prompt_for_password(char *username, char *password);
+static char *
+make_connect_string(char *host, char *port, char *dbname,
+ char *username, char *password);
+
+static char *gets_noreadline(char *prompt, FILE * source);
+static char *gets_readline(char *prompt, FILE * source);
+static char *gets_fromFile(char *prompt, FILE * source);
+static int listAllDbs(PsqlSettings * settings);
static void
SendQuery(bool * success_p, PsqlSettings * settings, const char *query,
- const bool copy_in, const bool copy_out, FILE * copystream);
+ const bool copy_in, const bool copy_out, FILE * copystream);
static int
HandleSlashCmds(PsqlSettings * settings,
- char *line,
- char *query);
-static int MainLoop(PsqlSettings * settings, FILE * source);
+ char *line,
+ char *query);
+static int MainLoop(PsqlSettings * settings, FILE * source);
+
/* probably should move this into libpq */
void
PQprint(FILE * fp,
- PGresult * res,
- PQprintOpt * po
+ PGresult * res,
+ PQprintOpt * po
);
-static FILE *setFout(PsqlSettings * ps, char *fname);
+static FILE *setFout(PsqlSettings * ps, char *fname);
/*
* usage print out usage for command line arguments
@@ -136,28 +140,28 @@ static FILE *setFout(PsqlSettings * ps, char *fname);
static void
usage(char *progname)
{
- fprintf(stderr, "Usage: %s [options] [dbname]\n", progname);
- fprintf(stderr, "\t -a authsvc set authentication service\n");
- fprintf(stderr, "\t -A turn off alignment when printing out attributes\n");
- fprintf(stderr, "\t -c query run single query (slash commands too)\n");
- fprintf(stderr, "\t -d dbName specify database name\n");
- fprintf(stderr, "\t -e echo the query sent to the backend\n");
- fprintf(stderr, "\t -f filename use file as a source of queries\n");
- fprintf(stderr, "\t -F sep set the field separator (default is '|')\n");
- fprintf(stderr, "\t -h host set database server host\n");
- fprintf(stderr, "\t -H turn on html3.0 table output\n");
- fprintf(stderr, "\t -l list available databases\n");
- fprintf(stderr, "\t -n don't use readline library\n");
- fprintf(stderr, "\t -o filename send output to filename or (|pipe)\n");
- fprintf(stderr, "\t -p port set port number\n");
- fprintf(stderr, "\t -q run quietly (no messages, no prompts)\n");
- fprintf(stderr, "\t -s single step mode (prompts for each query)\n");
- fprintf(stderr, "\t -S single line mode (i.e. query terminated by newline)\n");
- fprintf(stderr, "\t -t turn off printing of headings and row count\n");
- fprintf(stderr, "\t -T html set html3.0 table command options (cf. -H)\n");
- fprintf(stderr, "\t -u ask for a username and password for authentication\n");
- fprintf(stderr, "\t -x turn on expanded output (field names on left)\n");
- exit(1);
+ fprintf(stderr, "Usage: %s [options] [dbname]\n", progname);
+ fprintf(stderr, "\t -a authsvc set authentication service\n");
+ fprintf(stderr, "\t -A turn off alignment when printing out attributes\n");
+ fprintf(stderr, "\t -c query run single query (slash commands too)\n");
+ fprintf(stderr, "\t -d dbName specify database name\n");
+ fprintf(stderr, "\t -e echo the query sent to the backend\n");
+ fprintf(stderr, "\t -f filename use file as a source of queries\n");
+ fprintf(stderr, "\t -F sep set the field separator (default is '|')\n");
+ fprintf(stderr, "\t -h host set database server host\n");
+ fprintf(stderr, "\t -H turn on html3.0 table output\n");
+ fprintf(stderr, "\t -l list available databases\n");
+ fprintf(stderr, "\t -n don't use readline library\n");
+ fprintf(stderr, "\t -o filename send output to filename or (|pipe)\n");
+ fprintf(stderr, "\t -p port set port number\n");
+ fprintf(stderr, "\t -q run quietly (no messages, no prompts)\n");
+ fprintf(stderr, "\t -s single step mode (prompts for each query)\n");
+ fprintf(stderr, "\t -S single line mode (i.e. query terminated by newline)\n");
+ fprintf(stderr, "\t -t turn off printing of headings and row count\n");
+ fprintf(stderr, "\t -T html set html3.0 table command options (cf. -H)\n");
+ fprintf(stderr, "\t -u ask for a username and password for authentication\n");
+ fprintf(stderr, "\t -x turn on expanded output (field names on left)\n");
+ exit(1);
}
/*
@@ -167,412 +171,458 @@ usage(char *progname)
static char *
on(bool f)
{
- return f ? "on" : "off";
+ return f ? "on" : "off";
}
static void
slashUsage(PsqlSettings * ps)
{
- int usePipe = 0;
- char *pagerenv;
- FILE *fout;
-
- if (ps->notty == 0 &&
- (pagerenv = getenv("PAGER")) &&
- (pagerenv[0] != '\0') &&
- (fout = popen(pagerenv, "w")))
- {
- usePipe = 1;
- pqsignal(SIGPIPE, SIG_IGN);
- }
- else
- fout = stdout;
-
- fprintf(fout, " \\? -- help\n");
- fprintf(fout, " \\a -- toggle field-alignment (currenty %s)\n", on(ps->opt.align));
- fprintf(fout, " \\C [<captn>] -- set html3 caption (currently '%s')\n", ps->opt.caption ? ps->opt.caption : "");
- fprintf(fout, " \\connect <dbname|-> <user> -- connect to new database (currently '%s')\n", PQdb(ps->db));
- fprintf(fout, " \\copy table {from | to} <fname>\n");
- fprintf(fout, " \\d [<table>] -- list tables and indices in database or columns in <table>, * for all\n");
- fprintf(fout, " \\di -- list only indices in database\n");
- fprintf(fout, " \\ds -- list only sequences in database\n");
- fprintf(fout, " \\dt -- list only tables in database\n");
- fprintf(fout, " \\e [<fname>] -- edit the current query buffer or <fname>, \\E execute too\n");
- fprintf(fout, " \\f [<sep>] -- change field separater (currently '%s')\n", ps->opt.fieldSep);
- fprintf(fout, " \\g [<fname>] [|<cmd>] -- send query to backend [and results in <fname> or pipe]\n");
- fprintf(fout, " \\h [<cmd>] -- help on syntax of sql commands, * for all commands\n");
- fprintf(fout, " \\H -- toggle html3 output (currently %s)\n", on(ps->opt.html3));
- fprintf(fout, " \\i <fname> -- read and execute queries from filename\n");
- fprintf(fout, " \\l -- list all databases\n");
- fprintf(fout, " \\m -- toggle monitor-like table display (currently %s)\n", on(ps->opt.standard));
- fprintf(fout, " \\o [<fname>] [|<cmd>] -- send all query results to stdout, <fname>, or pipe\n");
- fprintf(fout, " \\p -- print the current query buffer\n");
- fprintf(fout, " \\q -- quit\n");
- fprintf(fout, " \\r -- reset(clear) the query buffer\n");
- fprintf(fout, " \\s [<fname>] -- print history or save it in <fname>\n");
- fprintf(fout, " \\t -- toggle table headings and row count (currently %s)\n", on(ps->opt.header));
- fprintf(fout, " \\T [<html>] -- set html3.0 <table ...> options (currently '%s')\n", ps->opt.tableOpt ? ps->opt.tableOpt : "");
- fprintf(fout, " \\x -- toggle expanded output (currently %s)\n", on(ps->opt.expanded));
- fprintf(fout, " \\z -- list current grant/revoke permissions\n");
- fprintf(fout, " \\! [<cmd>] -- shell escape or command\n");
-
- if (usePipe)
- {
- pclose(fout);
- pqsignal(SIGPIPE, SIG_DFL);
- }
+ int usePipe = 0;
+ char *pagerenv;
+ FILE *fout;
+
+ if (ps->notty == 0 &&
+ (pagerenv = getenv("PAGER")) &&
+ (pagerenv[0] != '\0') &&
+ (fout = popen(pagerenv, "w")))
+ {
+ usePipe = 1;
+ pqsignal(SIGPIPE, SIG_IGN);
+ }
+ else
+ fout = stdout;
+
+ fprintf(fout, " \\? -- help\n");
+ fprintf(fout, " \\a -- toggle field-alignment (currenty %s)\n", on(ps->opt.align));
+ fprintf(fout, " \\C [<captn>] -- set html3 caption (currently '%s')\n", ps->opt.caption ? ps->opt.caption : "");
+ fprintf(fout, " \\connect <dbname|-> <user> -- connect to new database (currently '%s')\n", PQdb(ps->db));
+ fprintf(fout, " \\copy table {from | to} <fname>\n");
+ fprintf(fout, " \\d [<table>] -- list tables and indices in database or columns in <table>, * for all\n");
+ fprintf(fout, " \\di -- list only indices in database\n");
+ fprintf(fout, " \\ds -- list only sequences in database\n");
+ fprintf(fout, " \\dt -- list only tables in database\n");
+ fprintf(fout, " \\e [<fname>] -- edit the current query buffer or <fname>, \\E execute too\n");
+ fprintf(fout, " \\f [<sep>] -- change field separater (currently '%s')\n", ps->opt.fieldSep);
+ fprintf(fout, " \\g [<fname>] [|<cmd>] -- send query to backend [and results in <fname> or pipe]\n");
+ fprintf(fout, " \\h [<cmd>] -- help on syntax of sql commands, * for all commands\n");
+ fprintf(fout, " \\H -- toggle html3 output (currently %s)\n", on(ps->opt.html3));
+ fprintf(fout, " \\i <fname> -- read and execute queries from filename\n");
+ fprintf(fout, " \\l -- list all databases\n");
+ fprintf(fout, " \\m -- toggle monitor-like table display (currently %s)\n", on(ps->opt.standard));
+ fprintf(fout, " \\o [<fname>] [|<cmd>] -- send all query results to stdout, <fname>, or pipe\n");
+ fprintf(fout, " \\p -- print the current query buffer\n");
+ fprintf(fout, " \\q -- quit\n");
+ fprintf(fout, " \\r -- reset(clear) the query buffer\n");
+ fprintf(fout, " \\s [<fname>] -- print history or save it in <fname>\n");
+ fprintf(fout, " \\t -- toggle table headings and row count (currently %s)\n", on(ps->opt.header));
+ fprintf(fout, " \\T [<html>] -- set html3.0 <table ...> options (currently '%s')\n", ps->opt.tableOpt ? ps->opt.tableOpt : "");
+ fprintf(fout, " \\x -- toggle expanded output (currently %s)\n", on(ps->opt.expanded));
+ fprintf(fout, " \\z -- list current grant/revoke permissions\n");
+ fprintf(fout, " \\! [<cmd>] -- shell escape or command\n");
+
+ if (usePipe)
+ {
+ pclose(fout);
+ pqsignal(SIGPIPE, SIG_DFL);
+ }
}
static PGresult *
PSQLexec(PsqlSettings * ps, char *query)
{
- PGresult *res;
- res = PQexec(ps->db, query);
- if (!res)
- fputs(PQerrorMessage(ps->db), stderr);
- else {
- if (PQresultStatus(res) == PGRES_COMMAND_OK ||
- PQresultStatus(res) == PGRES_TUPLES_OK)
- return res;
- if (!ps->quiet)
- fputs(PQerrorMessage(ps->db), stderr);
- PQclear(res);
- }
- return NULL;
+ PGresult *res;
+
+ res = PQexec(ps->db, query);
+ if (!res)
+ fputs(PQerrorMessage(ps->db), stderr);
+ else
+ {
+ if (PQresultStatus(res) == PGRES_COMMAND_OK ||
+ PQresultStatus(res) == PGRES_TUPLES_OK)
+ return res;
+ if (!ps->quiet)
+ fputs(PQerrorMessage(ps->db), stderr);
+ PQclear(res);
+ }
+ return NULL;
}
+
/*
* listAllDbs
- *
+ *
* list all the databases in the system returns 0 if all went well
- *
- *
+ *
+ *
*/
static int
listAllDbs(PsqlSettings * ps)
{
- PGresult *results;
- char *query = "select * from pg_database;";
-
- if (!(results = PSQLexec(ps, query)))
- return 1;
- else {
- PQprint(ps->queryFout,
- results,
- &ps->opt);
- PQclear(results);
- return 0;
- }
+ PGresult *results;
+ char *query = "select * from pg_database;";
+
+ if (!(results = PSQLexec(ps, query)))
+ return 1;
+ else
+ {
+ PQprint(ps->queryFout,
+ results,
+ &ps->opt);
+ PQclear(results);
+ return 0;
+ }
}
/*
* List The Database Tables returns 0 if all went well
- *
+ *
*/
int
tableList(PsqlSettings * ps, bool deep_tablelist, char info_type)
{
- char listbuf[256];
- int nColumns;
- int i;
- char *rk;
- char *rr;
-
- PGresult *res;
-
- listbuf[0] = '\0';
- strcat(listbuf, "SELECT usename, relname, relkind, relhasrules");
- strcat(listbuf, " FROM pg_class, pg_user ");
- switch (info_type) {
- case 't': strcat(listbuf, "WHERE ( relkind = 'r') ");
- break;
- case 'i': strcat(listbuf, "WHERE ( relkind = 'i') ");
- break;
- case 'S': strcat(listbuf, "WHERE ( relkind = 'S') ");
- break;
- case 'b':
- default: strcat(listbuf, "WHERE ( relkind = 'r' OR relkind = 'i' OR relkind = 'S') ");
- break;
- }
+ char listbuf[256];
+ int nColumns;
+ int i;
+ char *rk;
+ char *rr;
+
+ PGresult *res;
+
+ listbuf[0] = '\0';
+ strcat(listbuf, "SELECT usename, relname, relkind, relhasrules");
+ strcat(listbuf, " FROM pg_class, pg_user ");
+ switch (info_type)
+ {
+ case 't':
+ strcat(listbuf, "WHERE ( relkind = 'r') ");
+ break;
+ case 'i':
+ strcat(listbuf, "WHERE ( relkind = 'i') ");
+ break;
+ case 'S':
+ strcat(listbuf, "WHERE ( relkind = 'S') ");
+ break;
+ case 'b':
+ default:
+ strcat(listbuf, "WHERE ( relkind = 'r' OR relkind = 'i' OR relkind = 'S') ");
+ break;
+ }
strcat(listbuf, " and relname !~ '^pg_'");
strcat(listbuf, " and relname !~ '^xin[vx][0-9]+'");
- /*
- * the usesysid = relowner won't work on stock 1.0 dbs, need to add in
- * the int4oideq function
- */
- strcat(listbuf, " and usesysid = relowner");
- strcat(listbuf, " ORDER BY relname ");
- if (!(res = PSQLexec(ps, listbuf)))
- return -1;
- /* first, print out the attribute names */
- nColumns = PQntuples(res);
- if (nColumns > 0) {
- if (deep_tablelist) {
- /* describe everything here */
- char **table;
- table = (char **) malloc(nColumns * sizeof(char *));
- if (table == NULL)
- perror("malloc");
- /* load table table */
- for (i = 0; i < nColumns; i++) {
- table[i] = (char *) malloc(PQgetlength(res, i, 1) * sizeof(char) + 1);
- if (table[i] == NULL)
- perror("malloc");
- strcpy(table[i], PQgetvalue(res, i, 1));
- }
-
- PQclear(res); /* PURIFY */
- for (i = 0; i < nColumns; i++) {
- tableDesc(ps, table[i]);
- }
- free(table);
- } else {
- /* Display the information */
-
- printf("\nDatabase = %s\n", PQdb(ps->db));
- printf(" +------------------+----------------------------------+----------+\n");
- printf(" | Owner | Relation | Type |\n");
- printf(" +------------------+----------------------------------+----------+\n");
-
- /* next, print out the instances */
- for (i = 0; i < PQntuples(res); i++) {
- printf(" | %-16.16s", PQgetvalue(res, i, 0));
- printf(" | %-32.32s | ", PQgetvalue(res, i, 1));
- rk = PQgetvalue(res, i, 2);
- rr = PQgetvalue(res, i, 3);
- if (strcmp(rk, "r") == 0)
- printf("%-8.8s |", (rr[0] == 't') ? "view?" : "table");
+ /*
+ * the usesysid = relowner won't work on stock 1.0 dbs, need to add in
+ * the int4oideq function
+ */
+ strcat(listbuf, " and usesysid = relowner");
+ strcat(listbuf, " ORDER BY relname ");
+ if (!(res = PSQLexec(ps, listbuf)))
+ return -1;
+ /* first, print out the attribute names */
+ nColumns = PQntuples(res);
+ if (nColumns > 0)
+ {
+ if (deep_tablelist)
+ {
+ /* describe everything here */
+ char **table;
+
+ table = (char **) malloc(nColumns * sizeof(char *));
+ if (table == NULL)
+ perror("malloc");
+
+ /* load table table */
+ for (i = 0; i < nColumns; i++)
+ {
+ table[i] = (char *) malloc(PQgetlength(res, i, 1) * sizeof(char) + 1);
+ if (table[i] == NULL)
+ perror("malloc");
+ strcpy(table[i], PQgetvalue(res, i, 1));
+ }
+
+ PQclear(res); /* PURIFY */
+ for (i = 0; i < nColumns; i++)
+ {
+ tableDesc(ps, table[i]);
+ }
+ free(table);
+ }
else
- if (strcmp(rk, "i") == 0)
- printf("%-8.8s |", "index");
- else
- printf("%-8.8s |", "sequence");
- printf("\n");
- }
- printf(" +------------------+----------------------------------+----------+\n");
- PQclear(res);
+ {
+ /* Display the information */
+
+ printf("\nDatabase = %s\n", PQdb(ps->db));
+ printf(" +------------------+----------------------------------+----------+\n");
+ printf(" | Owner | Relation | Type |\n");
+ printf(" +------------------+----------------------------------+----------+\n");
+
+ /* next, print out the instances */
+ for (i = 0; i < PQntuples(res); i++)
+ {
+ printf(" | %-16.16s", PQgetvalue(res, i, 0));
+ printf(" | %-32.32s | ", PQgetvalue(res, i, 1));
+ rk = PQgetvalue(res, i, 2);
+ rr = PQgetvalue(res, i, 3);
+ if (strcmp(rk, "r") == 0)
+ printf("%-8.8s |", (rr[0] == 't') ? "view?" : "table");
+ else if (strcmp(rk, "i") == 0)
+ printf("%-8.8s |", "index");
+ else
+ printf("%-8.8s |", "sequence");
+ printf("\n");
+ }
+ printf(" +------------------+----------------------------------+----------+\n");
+ PQclear(res);
+ }
+ return (0);
+
+ }
+ else
+ {
+ PQclear(res); /* PURIFY */
+ switch (info_type)
+ {
+ case 't':
+ fprintf(stderr, "Couldn't find any tables!\n");
+ break;
+ case 'i':
+ fprintf(stderr, "Couldn't find any indices!\n");
+ break;
+ case 'S':
+ fprintf(stderr, "Couldn't find any sequences!\n");
+ break;
+ case 'b':
+ default:
+ fprintf(stderr, "Couldn't find any tables, sequences or indices!\n");
+ break;
+ }
+ return (-1);
}
- return (0);
-
- } else {
- PQclear(res); /* PURIFY */
- switch (info_type) {
- case 't': fprintf(stderr, "Couldn't find any tables!\n");
- break;
- case 'i': fprintf(stderr, "Couldn't find any indices!\n");
- break;
- case 'S': fprintf(stderr, "Couldn't find any sequences!\n");
- break;
- case 'b':
- default: fprintf(stderr, "Couldn't find any tables, sequences or indices!\n");
- break;
- }
- return (-1);
- }
}
/*
* List Tables Grant/Revoke Permissions returns 0 if all went well
- *
+ *
*/
int
rightsList(PsqlSettings * ps)
{
- char listbuf[256];
- int nColumns;
- int i;
-
- PGresult *res;
-
- listbuf[0] = '\0';
- strcat(listbuf, "SELECT relname, relacl");
- strcat(listbuf, " FROM pg_class, pg_user ");
- strcat(listbuf, "WHERE ( relkind = 'r' OR relkind = 'i') ");
- strcat(listbuf, " and relname !~ '^pg_'");
- strcat(listbuf, " and relname !~ '^xin[vx][0-9]+'");
- strcat(listbuf, " and usesysid = relowner");
- strcat(listbuf, " ORDER BY relname ");
- if (!(res = PSQLexec(ps, listbuf)))
- return -1;
-
- nColumns = PQntuples(res);
- if(nColumns > 0) {
- /* Display the information */
-
- printf("\nDatabase = %s\n", PQdb(ps->db));
- printf(" +------------------+----------------------------------------------------+\n");
- printf(" | Relation | Grant/Revoke Permissions |\n");
- printf(" +------------------+----------------------------------------------------+\n");
-
- /* next, print out the instances */
- for (i = 0; i < PQntuples(res); i++) {
- printf(" | %-16.16s", PQgetvalue(res, i, 0));
- printf(" | %-50.50s | ", PQgetvalue(res, i, 1));
- printf("\n");
- }
- printf(" +------------------+----------------------------------------------------+\n");
- PQclear(res);
- return (0);
- } else {
- fprintf(stderr, "Couldn't find any tables!\n");
- return (-1);
- }
+ char listbuf[256];
+ int nColumns;
+ int i;
+
+ PGresult *res;
+
+ listbuf[0] = '\0';
+ strcat(listbuf, "SELECT relname, relacl");
+ strcat(listbuf, " FROM pg_class, pg_user ");
+ strcat(listbuf, "WHERE ( relkind = 'r' OR relkind = 'i') ");
+ strcat(listbuf, " and relname !~ '^pg_'");
+ strcat(listbuf, " and relname !~ '^xin[vx][0-9]+'");
+ strcat(listbuf, " and usesysid = relowner");
+ strcat(listbuf, " ORDER BY relname ");
+ if (!(res = PSQLexec(ps, listbuf)))
+ return -1;
+
+ nColumns = PQntuples(res);
+ if (nColumns > 0)
+ {
+ /* Display the information */
+
+ printf("\nDatabase = %s\n", PQdb(ps->db));
+ printf(" +------------------+----------------------------------------------------+\n");
+ printf(" | Relation | Grant/Revoke Permissions |\n");
+ printf(" +------------------+----------------------------------------------------+\n");
+
+ /* next, print out the instances */
+ for (i = 0; i < PQntuples(res); i++)
+ {
+ printf(" | %-16.16s", PQgetvalue(res, i, 0));
+ printf(" | %-50.50s | ", PQgetvalue(res, i, 1));
+ printf("\n");
+ }
+ printf(" +------------------+----------------------------------------------------+\n");
+ PQclear(res);
+ return (0);
+ }
+ else
+ {
+ fprintf(stderr, "Couldn't find any tables!\n");
+ return (-1);
+ }
}
+
/*
* Describe a table
- *
+ *
* Describe the columns in a database table. returns 0 if all went well
- *
- *
+ *
+ *
*/
int
tableDesc(PsqlSettings * ps, char *table)
{
- char descbuf[256];
- int nColumns;
- char *rtype;
- int i;
- int rsize;
-
- PGresult *res;
-
- /* Build the query */
-
- for(i = strlen(table); i >= 0; i--)
- if (isupper(table[i]))
- table[i] = tolower(table[i]);
-
- descbuf[0] = '\0';
- strcat(descbuf, "SELECT a.attnum, a.attname, t.typname, a.attlen, a.attnotnull");
- strcat(descbuf, " FROM pg_class c, pg_attribute a, pg_type t ");
- strcat(descbuf, " WHERE c.relname = '");
- strcat(descbuf, table);
- strcat(descbuf, "'");
- strcat(descbuf, " and a.attnum > 0 ");
- strcat(descbuf, " and a.attrelid = c.oid ");
- strcat(descbuf, " and a.atttypid = t.oid ");
- strcat(descbuf, " ORDER BY attnum ");
- if (!(res = PSQLexec(ps, descbuf)))
- return -1;
- /* first, print out the attribute names */
- nColumns = PQntuples(res);
- if (nColumns > 0) {
- /*
- * * Display the information
- */
+ char descbuf[256];
+ int nColumns;
+ char *rtype;
+ int i;
+ int rsize;
+
+ PGresult *res;
+
+ /* Build the query */
+
+ for (i = strlen(table); i >= 0; i--)
+ if (isupper(table[i]))
+ table[i] = tolower(table[i]);
+
+ descbuf[0] = '\0';
+ strcat(descbuf, "SELECT a.attnum, a.attname, t.typname, a.attlen, a.attnotnull");
+ strcat(descbuf, " FROM pg_class c, pg_attribute a, pg_type t ");
+ strcat(descbuf, " WHERE c.relname = '");
+ strcat(descbuf, table);
+ strcat(descbuf, "'");
+ strcat(descbuf, " and a.attnum > 0 ");
+ strcat(descbuf, " and a.attrelid = c.oid ");
+ strcat(descbuf, " and a.atttypid = t.oid ");
+ strcat(descbuf, " ORDER BY attnum ");
+ if (!(res = PSQLexec(ps, descbuf)))
+ return -1;
+ /* first, print out the attribute names */
+ nColumns = PQntuples(res);
+ if (nColumns > 0)
+ {
- printf("\nTable = %s\n", table);
- printf("+----------------------------------+----------------------------------+-------+\n");
- printf("| Field | Type | Length|\n");
- printf("+----------------------------------+----------------------------------+-------+\n");
-
- /* next, print out the instances */
- for (i = 0; i < PQntuples(res); i++) {
- printf("| %-32.32s | ", PQgetvalue(res, i, 1));
- rtype = PQgetvalue(res, i, 2);
- rsize = atoi(PQgetvalue(res, i, 3));
- if (strcmp(rtype, "text") == 0) {
- printf("%-32.32s |", rtype);
- printf("%6s |", "var");
- } else if (strcmp(rtype, "bpchar") == 0) {
- printf("%-32.32s |", "(bp)char");
- printf("%6i |", rsize > 0 ? rsize - 4 : 0);
- } else if (strcmp(rtype, "varchar") == 0) {
- printf("%-32.32s |", rtype);
- printf("%6i |", rsize > 0 ? rsize - 4 : 0);
- } else {
- /* array types start with an underscore */
- if (rtype[0] != '_')
- printf("%-32.32s |", rtype);
- else {
- char *newname;
- newname = malloc(strlen(rtype) + 2);
- strcpy(newname, rtype + 1);
- strcat(newname, "[]");
- printf("%-32.32s |", newname);
- free(newname);
- }
- if (rsize > 0)
- printf("%6i |", rsize);
- else
- printf("%6s |", "var");
- }
- printf("\n");
- }
- printf("+----------------------------------+----------------------------------+-------+\n");
+ /*
+ * * Display the information
+ */
+
+ printf("\nTable = %s\n", table);
+ printf("+----------------------------------+----------------------------------+-------+\n");
+ printf("| Field | Type | Length|\n");
+ printf("+----------------------------------+----------------------------------+-------+\n");
+
+ /* next, print out the instances */
+ for (i = 0; i < PQntuples(res); i++)
+ {
+ printf("| %-32.32s | ", PQgetvalue(res, i, 1));
+ rtype = PQgetvalue(res, i, 2);
+ rsize = atoi(PQgetvalue(res, i, 3));
+ if (strcmp(rtype, "text") == 0)
+ {
+ printf("%-32.32s |", rtype);
+ printf("%6s |", "var");
+ }
+ else if (strcmp(rtype, "bpchar") == 0)
+ {
+ printf("%-32.32s |", "(bp)char");
+ printf("%6i |", rsize > 0 ? rsize - 4 : 0);
+ }
+ else if (strcmp(rtype, "varchar") == 0)
+ {
+ printf("%-32.32s |", rtype);
+ printf("%6i |", rsize > 0 ? rsize - 4 : 0);
+ }
+ else
+ {
+ /* array types start with an underscore */
+ if (rtype[0] != '_')
+ printf("%-32.32s |", rtype);
+ else
+ {
+ char *newname;
+
+ newname = malloc(strlen(rtype) + 2);
+ strcpy(newname, rtype + 1);
+ strcat(newname, "[]");
+ printf("%-32.32s |", newname);
+ free(newname);
+ }
+ if (rsize > 0)
+ printf("%6i |", rsize);
+ else
+ printf("%6s |", "var");
+ }
+ printf("\n");
+ }
+ printf("+----------------------------------+----------------------------------+-------+\n");
- PQclear(res);
- return (0);
+ PQclear(res);
+ return (0);
- } else {
- fprintf(stderr, "Couldn't find table %s!\n", table);
- return (-1);
- }
+ }
+ else
+ {
+ fprintf(stderr, "Couldn't find table %s!\n", table);
+ return (-1);
+ }
}
typedef char *(*READ_ROUTINE) (char *prompt, FILE * source);
/*
- * gets_noreadline prompt source gets a line of input without calling
+ * gets_noreadline prompt source gets a line of input without calling
* readline, the source is ignored
*/
-static char *
+static char *
gets_noreadline(char *prompt, FILE * source)
{
- fputs(prompt, stdout);
- fflush(stdout);
- return (gets_fromFile(prompt, stdin));
+ fputs(prompt, stdout);
+ fflush(stdout);
+ return (gets_fromFile(prompt, stdin));
}
/*
* gets_readline prompt source the routine to get input from GNU readline(),
* the source is ignored the prompt argument is used as the prompting string
*/
-static char *
+static char *
gets_readline(char *prompt, FILE * source)
{
- char *s;
+ char *s;
+
#ifdef HAVE_LIBREADLINE
- s = readline(prompt);
+ s = readline(prompt);
#else
- char buf[500];
- printf("%s", prompt);
- s = fgets(buf, 500, stdin);
+ char buf[500];
+
+ printf("%s", prompt);
+ s = fgets(buf, 500, stdin);
#endif
- fputc('\r', stdout);
- fflush(stdout);
- return s;
+ fputc('\r', stdout);
+ fflush(stdout);
+ return s;
}
/*
* gets_fromFile prompt source
- *
+ *
* the routine to read from a file, the prompt argument is ignored the source
* argument is a FILE *
*/
-static char *
+static char *
gets_fromFile(char *prompt, FILE * source)
{
- char *line;
- int len;
+ char *line;
+ int len;
- line = malloc(MAX_QUERY_BUFFER + 1);
+ line = malloc(MAX_QUERY_BUFFER + 1);
- /* read up to MAX_QUERY_BUFFER characters */
- if (fgets(line, MAX_QUERY_BUFFER, source) == NULL)
+ /* read up to MAX_QUERY_BUFFER characters */
+ if (fgets(line, MAX_QUERY_BUFFER, source) == NULL)
{
- free(line);
- return NULL;
+ free(line);
+ return NULL;
}
- line[MAX_QUERY_BUFFER - 1] = '\0';
- len = strlen(line);
- if (len == MAX_QUERY_BUFFER) {
- fprintf(stderr, "line read exceeds maximum length. Truncating at %d\n",
- MAX_QUERY_BUFFER);
- }
- return line;
+ line[MAX_QUERY_BUFFER - 1] = '\0';
+ len = strlen(line);
+ if (len == MAX_QUERY_BUFFER)
+ {
+ fprintf(stderr, "line read exceeds maximum length. Truncating at %d\n",
+ MAX_QUERY_BUFFER);
+ }
+ return line;
}
/*
@@ -581,113 +631,131 @@ gets_fromFile(char *prompt, FILE * source)
*/
static void
SendQuery(bool * success_p, PsqlSettings * settings, const char *query,
- const bool copy_in, const bool copy_out, FILE * copystream)
+ const bool copy_in, const bool copy_out, FILE * copystream)
{
- PGresult *results;
- PGnotify *notify;
+ PGresult *results;
+ PGnotify *notify;
- if (settings->singleStep)
- fprintf(stdout, "\n**************************************"
- "*****************************************\n");
+ if (settings->singleStep)
+ fprintf(stdout, "\n**************************************"
+ "*****************************************\n");
- if (settings->echoQuery || settings->singleStep) {
- fprintf(stderr, "QUERY: %s\n", query);
- fflush(stderr);
- }
- if (settings->singleStep) {
- fprintf(stdout, "\n**************************************"
- "*****************************************\n");
- fflush(stdout);
- printf("\npress return to continue ..\n");
- gets_fromFile("", stdin);
- }
- results = PQexec(settings->db, query);
- if (results == NULL) {
- fprintf(stderr, "%s", PQerrorMessage(settings->db));
- *success_p = false;
- } else {
- switch (PQresultStatus(results)) {
- case PGRES_TUPLES_OK:
- if (settings->gfname) {
- PsqlSettings ps = *settings;
- FILE *fp;
- ps.queryFout = stdout;
- fp = setFout(&ps, settings->gfname);
- if (!fp || fp == stdout) {
- *success_p = false;
- break;
- } else
- *success_p = true;
- PQprint(fp,
- results,
- &(settings->opt));
- if (ps.pipe)
- pclose(fp);
- else
- fclose(fp);
- free(settings->gfname);
- settings->gfname = NULL;
- break;
- } else {
- *success_p = true;
- PQprint(settings->queryFout,
- results,
- &(settings->opt));
- fflush(settings->queryFout);
- }
- break;
- case PGRES_EMPTY_QUERY:
- *success_p = true;
- break;
- case PGRES_COMMAND_OK:
- *success_p = true;
- if (!settings->quiet)
- printf("%s\n", PQcmdStatus(results));
- break;
- case PGRES_COPY_OUT:
- *success_p = true;
- if (copy_out) {
- handleCopyOut(results, settings->quiet, copystream);
- } else {
- if (!settings->quiet)
- printf("Copy command returns...\n");
-
- handleCopyOut(results, settings->quiet, stdout);
- }
- break;
- case PGRES_COPY_IN:
- *success_p = true;
- if (copy_in)
- handleCopyIn(results, false, copystream);
- else
- handleCopyIn(results, !settings->quiet, stdin);
- break;
- case PGRES_NONFATAL_ERROR:
- case PGRES_FATAL_ERROR:
- case PGRES_BAD_RESPONSE:
- *success_p = false;
- fprintf(stderr, "%s", PQerrorMessage(settings->db));
- break;
+ if (settings->echoQuery || settings->singleStep)
+ {
+ fprintf(stderr, "QUERY: %s\n", query);
+ fflush(stderr);
}
-
- if (PQstatus(settings->db) == CONNECTION_BAD) {
- fprintf(stderr,
- "We have lost the connection to the backend, so "
- "further processing is impossible. "
- "Terminating.\n");
- exit(2); /* we are out'ta here */
+ if (settings->singleStep)
+ {
+ fprintf(stdout, "\n**************************************"
+ "*****************************************\n");
+ fflush(stdout);
+ printf("\npress return to continue ..\n");
+ gets_fromFile("", stdin);
}
- /* check for asynchronous returns */
- notify = PQnotifies(settings->db);
- if (notify) {
- fprintf(stderr,
- "ASYNC NOTIFY of '%s' from backend pid '%d' received\n",
- notify->relname, notify->be_pid);
- free(notify);
+ results = PQexec(settings->db, query);
+ if (results == NULL)
+ {
+ fprintf(stderr, "%s", PQerrorMessage(settings->db));
+ *success_p = false;
+ }
+ else
+ {
+ switch (PQresultStatus(results))
+ {
+ case PGRES_TUPLES_OK:
+ if (settings->gfname)
+ {
+ PsqlSettings ps = *settings;
+ FILE *fp;
+
+ ps.queryFout = stdout;
+ fp = setFout(&ps, settings->gfname);
+ if (!fp || fp == stdout)
+ {
+ *success_p = false;
+ break;
+ }
+ else
+ *success_p = true;
+ PQprint(fp,
+ results,
+ &(settings->opt));
+ if (ps.pipe)
+ pclose(fp);
+ else
+ fclose(fp);
+ free(settings->gfname);
+ settings->gfname = NULL;
+ break;
+ }
+ else
+ {
+ *success_p = true;
+ PQprint(settings->queryFout,
+ results,
+ &(settings->opt));
+ fflush(settings->queryFout);
+ }
+ break;
+ case PGRES_EMPTY_QUERY:
+ *success_p = true;
+ break;
+ case PGRES_COMMAND_OK:
+ *success_p = true;
+ if (!settings->quiet)
+ printf("%s\n", PQcmdStatus(results));
+ break;
+ case PGRES_COPY_OUT:
+ *success_p = true;
+ if (copy_out)
+ {
+ handleCopyOut(results, settings->quiet, copystream);
+ }
+ else
+ {
+ if (!settings->quiet)
+ printf("Copy command returns...\n");
+
+ handleCopyOut(results, settings->quiet, stdout);
+ }
+ break;
+ case PGRES_COPY_IN:
+ *success_p = true;
+ if (copy_in)
+ handleCopyIn(results, false, copystream);
+ else
+ handleCopyIn(results, !settings->quiet, stdin);
+ break;
+ case PGRES_NONFATAL_ERROR:
+ case PGRES_FATAL_ERROR:
+ case PGRES_BAD_RESPONSE:
+ *success_p = false;
+ fprintf(stderr, "%s", PQerrorMessage(settings->db));
+ break;
+ }
+
+ if (PQstatus(settings->db) == CONNECTION_BAD)
+ {
+ fprintf(stderr,
+ "We have lost the connection to the backend, so "
+ "further processing is impossible. "
+ "Terminating.\n");
+ exit(2); /* we are out'ta here */
+ }
+ /* check for asynchronous returns */
+ notify = PQnotifies(settings->db);
+ if (notify)
+ {
+ fprintf(stderr,
+ "ASYNC NOTIFY of '%s' from backend pid '%d' received\n",
+ notify->relname, notify->be_pid);
+ free(notify);
+ }
+ if (results)
+ PQclear(results);
}
- if(results) PQclear(results);
- }
}
@@ -695,28 +763,30 @@ SendQuery(bool * success_p, PsqlSettings * settings, const char *query,
static void
editFile(char *fname)
{
- char *editorName;
- char *sys;
- editorName = getenv("EDITOR");
- if (!editorName)
- editorName = DEFAULT_EDITOR;
- sys = malloc(strlen(editorName) + strlen(fname) + 32 + 1);
- if (!sys) {
- perror("malloc");
- exit(1);
- }
- sprintf(sys, "exec '%s' '%s'", editorName, fname);
- system(sys);
- free(sys);
+ char *editorName;
+ char *sys;
+
+ editorName = getenv("EDITOR");
+ if (!editorName)
+ editorName = DEFAULT_EDITOR;
+ sys = malloc(strlen(editorName) + strlen(fname) + 32 + 1);
+ if (!sys)
+ {
+ perror("malloc");
+ exit(1);
+ }
+ sprintf(sys, "exec '%s' '%s'", editorName, fname);
+ system(sys);
+ free(sys);
}
-static bool
+static bool
toggle(PsqlSettings * settings, bool * sw, char *msg)
{
- *sw = !*sw;
- if (!settings->quiet)
- printf("turned %s %s\n", on(*sw), msg);
- return *sw;
+ *sw = !*sw;
+ if (!settings->quiet)
+ printf("turned %s %s\n", on(*sw), msg);
+ return *sw;
}
@@ -724,117 +794,138 @@ toggle(PsqlSettings * settings, bool * sw, char *msg)
static void
unescape(char *dest, const char *source)
{
- /*-----------------------------------------------------------------------------
- Return as the string <dest> the value of string <source> with escape
- sequences turned into the bytes they represent.
- -----------------------------------------------------------------------------*/
- char *p;
- bool esc; /* Last character we saw was the escape
- * character (/) */
-
- esc = false; /* Haven't seen escape character yet */
- for (p = (char *) source; *p; p++) {
- char c; /* Our output character */
-
- if (esc) {
- switch (*p) {
- case 'n':
- c = '\n';
- break;
- case 'r':
- c = '\r';
- break;
- case 't':
- c = '\t';
- break;
- case 'f':
- c = '\f';
- break;
- case '\\':
- c = '\\';
- break;
- default:
- c = *p;
- }
- esc = false;
- } else if (*p == '\\') {
- esc = true;
- c = ' '; /* meaningless, but compiler doesn't know
- * that */
- } else {
- c = *p;
- esc = false;
+ /*-----------------------------------------------------------------------------
+ Return as the string <dest> the value of string <source> with escape
+ sequences turned into the bytes they represent.
+ -----------------------------------------------------------------------------*/
+ char *p;
+ bool esc; /* Last character we saw was the escape
+ * character (/) */
+
+ esc = false; /* Haven't seen escape character yet */
+ for (p = (char *) source; *p; p++)
+ {
+ char c; /* Our output character */
+
+ if (esc)
+ {
+ switch (*p)
+ {
+ case 'n':
+ c = '\n';
+ break;
+ case 'r':
+ c = '\r';
+ break;
+ case 't':
+ c = '\t';
+ break;
+ case 'f':
+ c = '\f';
+ break;
+ case '\\':
+ c = '\\';
+ break;
+ default:
+ c = *p;
+ }
+ esc = false;
+ }
+ else if (*p == '\\')
+ {
+ esc = true;
+ c = ' '; /* meaningless, but compiler doesn't know
+ * that */
+ }
+ else
+ {
+ c = *p;
+ esc = false;
+ }
+ if (!esc)
+ *dest++ = c;
}
- if (!esc)
- *dest++ = c;
- }
- *dest = '\0'; /* Terminating null character */
+ *dest = '\0'; /* Terminating null character */
}
static void
parse_slash_copy(const char *args, char *table, const int table_len,
- char *file, const int file_len,
- bool * from_p, bool * error_p)
+ char *file, const int file_len,
+ bool * from_p, bool * error_p)
{
- char work_args[200];
- /*
- * A copy of the \copy command arguments, except that we modify it as we
- * parse to suit our parsing needs.
- */
- char *table_tok, *fromto_tok;
-
- strncpy(work_args, args, sizeof(work_args));
- work_args[sizeof(work_args) - 1] = '\0';
-
- *error_p = false; /* initial assumption */
-
- table_tok = strtok(work_args, " ");
- if (table_tok == NULL) {
- fprintf(stderr, "\\copy needs arguments.\n");
- *error_p = true;
- } else {
- strncpy(table, table_tok, table_len);
- file[table_len - 1] = '\0';
-
- fromto_tok = strtok(NULL, " ");
- if (fromto_tok == NULL) {
- fprintf(stderr, "'FROM' or 'TO' must follow table name.\n");
- *error_p = true;
- } else {
- if (strcasecmp(fromto_tok, "from") == 0)
- *from_p = true;
- else if (strcasecmp(fromto_tok, "to") == 0)
- *from_p = false;
- else {
- fprintf(stderr,
- "Unrecognized token found where "
- "'FROM' or 'TO' expected: '%s'.\n",
- fromto_tok);
+ char work_args[200];
+
+ /*
+ * A copy of the \copy command arguments, except that we modify it as
+ * we parse to suit our parsing needs.
+ */
+ char *table_tok,
+ *fromto_tok;
+
+ strncpy(work_args, args, sizeof(work_args));
+ work_args[sizeof(work_args) - 1] = '\0';
+
+ *error_p = false; /* initial assumption */
+
+ table_tok = strtok(work_args, " ");
+ if (table_tok == NULL)
+ {
+ fprintf(stderr, "\\copy needs arguments.\n");
*error_p = true;
- }
- if (!*error_p) {
- char *file_tok;
-
- file_tok = strtok(NULL, " ");
- if (file_tok == NULL) {
- fprintf(stderr, "A file pathname must follow '%s'.\n",
- fromto_tok);
- *error_p = true;
- } else {
- strncpy(file, file_tok, file_len);
- file[file_len - 1] = '\0';
- if (strtok(NULL, " ") != NULL) {
- fprintf(stderr,
- "You have extra tokens after the filename.\n");
+ }
+ else
+ {
+ strncpy(table, table_tok, table_len);
+ file[table_len - 1] = '\0';
+
+ fromto_tok = strtok(NULL, " ");
+ if (fromto_tok == NULL)
+ {
+ fprintf(stderr, "'FROM' or 'TO' must follow table name.\n");
*error_p = true;
- }
}
- }
+ else
+ {
+ if (strcasecmp(fromto_tok, "from") == 0)
+ *from_p = true;
+ else if (strcasecmp(fromto_tok, "to") == 0)
+ *from_p = false;
+ else
+ {
+ fprintf(stderr,
+ "Unrecognized token found where "
+ "'FROM' or 'TO' expected: '%s'.\n",
+ fromto_tok);
+ *error_p = true;
+ }
+ if (!*error_p)
+ {
+ char *file_tok;
+
+ file_tok = strtok(NULL, " ");
+ if (file_tok == NULL)
+ {
+ fprintf(stderr, "A file pathname must follow '%s'.\n",
+ fromto_tok);
+ *error_p = true;
+ }
+ else
+ {
+ strncpy(file, file_tok, file_len);
+ file[file_len - 1] = '\0';
+ if (strtok(NULL, " ") != NULL)
+ {
+ fprintf(stderr,
+ "You have extra tokens after the filename.\n");
+ *error_p = true;
+ }
+ }
+ }
+ }
}
- }
}
@@ -842,120 +933,140 @@ parse_slash_copy(const char *args, char *table, const int table_len,
static void
do_copy(const char *args, PsqlSettings * settings)
{
- /*---------------------------------------------------------------------------
- Execute a \copy command (frontend copy). We have to open a file, then
- submit a COPY query to the backend and either feed it data from the
- file or route its response into the file.
-
- We do a text copy with default (tab) column delimiters. Some day, we
- should do all the things a backend copy can do.
-
- ----------------------------------------------------------------------------*/
- char query[200];
- /* The COPY command we send to the back end */
- bool from;
- /* The direction of the copy is from a file to a table. */
- char file[MAXPATHLEN + 1];
- /* The pathname of the file from/to which we copy */
- char table[NAMEDATALEN];
- /* The name of the table from/to which we copy */
- bool syntax_error;
- /* The \c command has invalid syntax */
- FILE *copystream;
-
- parse_slash_copy(args, table, sizeof(table), file, sizeof(file),
- &from, &syntax_error);
-
- if (!syntax_error) {
- strcpy(query, "COPY ");
- strcat(query, table);
-
- if (from)
- strcat(query, " FROM stdin");
- else
- strcat(query, " TO stdout");
+ /*---------------------------------------------------------------------------
+ Execute a \copy command (frontend copy). We have to open a file, then
+ submit a COPY query to the backend and either feed it data from the
+ file or route its response into the file.
- if (from) {
- copystream = fopen(file, "r");
- } else {
- copystream = fopen(file, "w");
- }
- if (copystream == NULL)
- fprintf(stderr,
- "Unable to open file %s which to copy, errno = %s (%d).",
- from ? "from" : "to", strerror(errno), errno);
- else {
- bool success; /* The query succeeded at the backend */
-
- SendQuery(&success, settings, query, from, !from, copystream);
- fclose(copystream);
- if (!settings->quiet) {
- if (success)
- printf("Successfully copied.\n");
+ We do a text copy with default (tab) column delimiters. Some day, we
+ should do all the things a backend copy can do.
+
+ ----------------------------------------------------------------------------*/
+ char query[200];
+
+ /* The COPY command we send to the back end */
+ bool from;
+
+ /* The direction of the copy is from a file to a table. */
+ char file[MAXPATHLEN + 1];
+
+ /* The pathname of the file from/to which we copy */
+ char table[NAMEDATALEN];
+
+ /* The name of the table from/to which we copy */
+ bool syntax_error;
+
+ /* The \c command has invalid syntax */
+ FILE *copystream;
+
+ parse_slash_copy(args, table, sizeof(table), file, sizeof(file),
+ &from, &syntax_error);
+
+ if (!syntax_error)
+ {
+ strcpy(query, "COPY ");
+ strcat(query, table);
+
+ if (from)
+ strcat(query, " FROM stdin");
+ else
+ strcat(query, " TO stdout");
+
+ if (from)
+ {
+ copystream = fopen(file, "r");
+ }
else
- printf("Copy failed.\n");
- }
+ {
+ copystream = fopen(file, "w");
+ }
+ if (copystream == NULL)
+ fprintf(stderr,
+ "Unable to open file %s which to copy, errno = %s (%d).",
+ from ? "from" : "to", strerror(errno), errno);
+ else
+ {
+ bool success; /* The query succeeded at the
+ * backend */
+
+ SendQuery(&success, settings, query, from, !from, copystream);
+ fclose(copystream);
+ if (!settings->quiet)
+ {
+ if (success)
+ printf("Successfully copied.\n");
+ else
+ printf("Copy failed.\n");
+ }
+ }
}
- }
}
static void
do_connect(const char *new_dbname,
- const char *new_user,
- PsqlSettings *settings)
+ const char *new_user,
+ PsqlSettings * settings)
{
- if (!new_dbname)
- fprintf(stderr, "\\connect must be followed by a database name\n");
- else {
- PGconn *olddb = settings->db;
- static char *userenv = NULL;
- char *old_userenv = NULL;
- const char *dbparam;
-
- if (new_user != NULL) {
- /*
- PQsetdb() does not allow us to specify the user,
- so we have to do it via PGUSER
- */
- if (userenv != NULL)
- old_userenv = userenv;
- userenv = malloc(strlen("PGUSER=") + strlen(new_user) + 1);
- sprintf(userenv,"PGUSER=%s",new_user);
- /* putenv() may continue to use memory as part of environment */
- putenv(userenv);
- /* can delete old memory if we malloc'ed it */
- if (old_userenv != NULL)
- free(old_userenv);
- }
+ if (!new_dbname)
+ fprintf(stderr, "\\connect must be followed by a database name\n");
+ else
+ {
+ PGconn *olddb = settings->db;
+ static char *userenv = NULL;
+ char *old_userenv = NULL;
+ const char *dbparam;
+
+ if (new_user != NULL)
+ {
+
+ /*
+ * PQsetdb() does not allow us to specify the user, so we have
+ * to do it via PGUSER
+ */
+ if (userenv != NULL)
+ old_userenv = userenv;
+ userenv = malloc(strlen("PGUSER=") + strlen(new_user) + 1);
+ sprintf(userenv, "PGUSER=%s", new_user);
+ /* putenv() may continue to use memory as part of environment */
+ putenv(userenv);
+ /* can delete old memory if we malloc'ed it */
+ if (old_userenv != NULL)
+ free(old_userenv);
+ }
- if (strcmp(new_dbname,"-") != 0)
- dbparam = new_dbname;
- else dbparam = PQdb(olddb);
-
- settings->db = PQsetdb(PQhost(olddb), PQport(olddb),
- NULL, NULL, dbparam);
- if (!settings->quiet) {
- if (!new_user)
- printf("connecting to new database: %s\n", dbparam);
- else if (dbparam != new_dbname)
- printf("connecting as new user: %s\n", new_user);
- else
- printf("connecting to new database: %s as user: %s\n",
- dbparam,new_user);
- }
+ if (strcmp(new_dbname, "-") != 0)
+ dbparam = new_dbname;
+ else
+ dbparam = PQdb(olddb);
- if (PQstatus(settings->db) == CONNECTION_BAD) {
- fprintf(stderr, "%s\n", PQerrorMessage(settings->db));
- fprintf(stderr,"Could not connect to new database. exiting\n");
- exit(2);
- } else {
- PQfinish(olddb);
- free(settings->prompt);
- settings->prompt = malloc(strlen(PQdb(settings->db)) + 10);
- sprintf(settings->prompt, "%s%s", PQdb(settings->db), PROMPT);
+ settings->db = PQsetdb(PQhost(olddb), PQport(olddb),
+ NULL, NULL, dbparam);
+ if (!settings->quiet)
+ {
+ if (!new_user)
+ printf("connecting to new database: %s\n", dbparam);
+ else if (dbparam != new_dbname)
+ printf("connecting as new user: %s\n", new_user);
+ else
+ printf("connecting to new database: %s as user: %s\n",
+ dbparam, new_user);
+ }
+
+ if (PQstatus(settings->db) == CONNECTION_BAD)
+ {
+ fprintf(stderr, "%s\n", PQerrorMessage(settings->db));
+ fprintf(stderr, "Could not connect to new database. exiting\n");
+ exit(2);
+ }
+ else
+ {
+ PQfinish(olddb);
+ free(settings->prompt);
+ settings->prompt = malloc(strlen(PQdb(settings->db)) + 10);
+ sprintf(settings->prompt, "%s%s", PQdb(settings->db), PROMPT);
+ }
}
- }
}
@@ -963,66 +1074,83 @@ static void
do_edit(const char *filename_arg, char *query, int *status_p)
{
- int fd;
- char tmp[64];
- char *fname;
- int cc;
- const int ql = strlen(query);
- bool error;
-
- if (filename_arg) {
- fname = (char *) filename_arg;
- error = false;
- } else {
- sprintf(tmp, "/tmp/psql.%ld.%ld", (long) geteuid(), (long) getpid());
- fname = tmp;
- unlink(tmp);
- if (ql > 0) {
- if ((fd = open(tmp, O_EXCL | O_CREAT | O_WRONLY, 0600)) == -1) {
- perror(tmp);
- error = true;
- } else {
- if (query[ql - 1] != '\n')
- strcat(query, "\n");
- if (write(fd, query, ql) != ql) {
- perror(tmp);
- close(fd);
- unlink(tmp);
- error = true;
- } else
- error = false;
- close(fd);
- }
- } else
- error = false;
- }
-
- if (error)
- *status_p = CMD_SKIP_LINE;
- else {
- editFile(fname);
- if ((fd = open(fname, O_RDONLY)) == -1) {
- perror(fname);
- if (!filename_arg)
- unlink(fname);
- *status_p = CMD_SKIP_LINE;
- } else {
- if ((cc = read(fd, query, MAX_QUERY_BUFFER)) == -1) {
- perror(fname);
- close(fd);
- if (!filename_arg)
- unlink(fname);
+ int fd;
+ char tmp[64];
+ char *fname;
+ int cc;
+ const int ql = strlen(query);
+ bool error;
+
+ if (filename_arg)
+ {
+ fname = (char *) filename_arg;
+ error = false;
+ }
+ else
+ {
+ sprintf(tmp, "/tmp/psql.%ld.%ld", (long) geteuid(), (long) getpid());
+ fname = tmp;
+ unlink(tmp);
+ if (ql > 0)
+ {
+ if ((fd = open(tmp, O_EXCL | O_CREAT | O_WRONLY, 0600)) == -1)
+ {
+ perror(tmp);
+ error = true;
+ }
+ else
+ {
+ if (query[ql - 1] != '\n')
+ strcat(query, "\n");
+ if (write(fd, query, ql) != ql)
+ {
+ perror(tmp);
+ close(fd);
+ unlink(tmp);
+ error = true;
+ }
+ else
+ error = false;
+ close(fd);
+ }
+ }
+ else
+ error = false;
+ }
+
+ if (error)
*status_p = CMD_SKIP_LINE;
- } else {
- query[cc] = '\0';
- close(fd);
- if (!filename_arg)
- unlink(fname);
- rightTrim(query);
- *status_p = CMD_NEWEDIT;
- }
+ else
+ {
+ editFile(fname);
+ if ((fd = open(fname, O_RDONLY)) == -1)
+ {
+ perror(fname);
+ if (!filename_arg)
+ unlink(fname);
+ *status_p = CMD_SKIP_LINE;
+ }
+ else
+ {
+ if ((cc = read(fd, query, MAX_QUERY_BUFFER)) == -1)
+ {
+ perror(fname);
+ close(fd);
+ if (!filename_arg)
+ unlink(fname);
+ *status_p = CMD_SKIP_LINE;
+ }
+ else
+ {
+ query[cc] = '\0';
+ close(fd);
+ if (!filename_arg)
+ unlink(fname);
+ rightTrim(query);
+ *status_p = CMD_NEWEDIT;
+ }
+ }
}
- }
}
@@ -1031,78 +1159,85 @@ static void
do_help(PsqlSettings * ps, const char *topic)
{
- if (!topic) {
- char left_center_right; /* Which column we're
- * displaying */
- int i; /* Index into QL_HELP[] */
-
- printf("type \\h <cmd> where <cmd> is one of the following:\n");
-
- left_center_right = 'L';/* Start with left column */
- i = 0;
- while (QL_HELP[i].cmd != NULL) {
- switch (left_center_right) {
- case 'L':
- printf(" %-25s", QL_HELP[i].cmd);
- left_center_right = 'C';
- break;
- case 'C':
- printf("%-25s", QL_HELP[i].cmd);
- left_center_right = 'R';
- break;
- case 'R':
- printf("%-25s\n", QL_HELP[i].cmd);
- left_center_right = 'L';
- break;
- };
- i++;
- }
- if (left_center_right != 'L')
- puts("\n");
- printf("type \\h * for a complete description of all commands\n");
- } else {
- int i; /* Index into QL_HELP[] */
- bool help_found; /* We found the help he asked for */
-
- int usePipe = 0;
- char *pagerenv;
- FILE *fout;
-
- if (strcmp(topic, "*") == 0 &&
- (ps->notty == 0) &&
- (pagerenv = getenv("PAGER")) &&
- (pagerenv[0] != '\0') &&
- (fout = popen(pagerenv, "w")))
+ if (!topic)
{
- usePipe = 1;
- pqsignal(SIGPIPE, SIG_IGN);
+ char left_center_right; /* Which column we're
+ * displaying */
+ int i; /* Index into QL_HELP[] */
+
+ printf("type \\h <cmd> where <cmd> is one of the following:\n");
+
+ left_center_right = 'L';/* Start with left column */
+ i = 0;
+ while (QL_HELP[i].cmd != NULL)
+ {
+ switch (left_center_right)
+ {
+ case 'L':
+ printf(" %-25s", QL_HELP[i].cmd);
+ left_center_right = 'C';
+ break;
+ case 'C':
+ printf("%-25s", QL_HELP[i].cmd);
+ left_center_right = 'R';
+ break;
+ case 'R':
+ printf("%-25s\n", QL_HELP[i].cmd);
+ left_center_right = 'L';
+ break;
+ };
+ i++;
+ }
+ if (left_center_right != 'L')
+ puts("\n");
+ printf("type \\h * for a complete description of all commands\n");
}
else
- fout = stdout;
-
- help_found = false; /* Haven't found it yet */
- for (i = 0; QL_HELP[i].cmd; i++) {
- if (strcmp(QL_HELP[i].cmd, topic) == 0 ||
- strcmp(topic, "*") == 0) {
- help_found = true;
- fprintf(fout, "Command: %s\n", QL_HELP[i].cmd);
- fprintf(fout, "Description: %s\n", QL_HELP[i].help);
- fprintf(fout, "Syntax:\n");
- fprintf(fout, "%s\n", QL_HELP[i].syntax);
- fprintf(fout, "\n");
- }
- }
-
- if (usePipe)
{
- pclose(fout);
- pqsignal(SIGPIPE, SIG_DFL);
- }
+ int i; /* Index into QL_HELP[] */
+ bool help_found; /* We found the help he asked for */
+
+ int usePipe = 0;
+ char *pagerenv;
+ FILE *fout;
+
+ if (strcmp(topic, "*") == 0 &&
+ (ps->notty == 0) &&
+ (pagerenv = getenv("PAGER")) &&
+ (pagerenv[0] != '\0') &&
+ (fout = popen(pagerenv, "w")))
+ {
+ usePipe = 1;
+ pqsignal(SIGPIPE, SIG_IGN);
+ }
+ else
+ fout = stdout;
+
+ help_found = false; /* Haven't found it yet */
+ for (i = 0; QL_HELP[i].cmd; i++)
+ {
+ if (strcmp(QL_HELP[i].cmd, topic) == 0 ||
+ strcmp(topic, "*") == 0)
+ {
+ help_found = true;
+ fprintf(fout, "Command: %s\n", QL_HELP[i].cmd);
+ fprintf(fout, "Description: %s\n", QL_HELP[i].help);
+ fprintf(fout, "Syntax:\n");
+ fprintf(fout, "%s\n", QL_HELP[i].syntax);
+ fprintf(fout, "\n");
+ }
+ }
+
+ if (usePipe)
+ {
+ pclose(fout);
+ pqsignal(SIGPIPE, SIG_DFL);
+ }
- if (!help_found)
- fprintf(stderr,"command not found, "
- "try \\h with no arguments to see available help\n");
- }
+ if (!help_found)
+ fprintf(stderr, "command not found, "
+ "try \\h with no arguments to see available help\n");
+ }
}
@@ -1111,813 +1246,955 @@ static void
do_shell(const char *command)
{
- if (!command) {
- char *sys;
- char *shellName;
-
- shellName = getenv("SHELL");
- if (shellName == NULL)
- shellName = DEFAULT_SHELL;
- sys = malloc(strlen(shellName) + 16);
- if (!sys) {
- perror("malloc");
- exit(1);
+ if (!command)
+ {
+ char *sys;
+ char *shellName;
+
+ shellName = getenv("SHELL");
+ if (shellName == NULL)
+ shellName = DEFAULT_SHELL;
+ sys = malloc(strlen(shellName) + 16);
+ if (!sys)
+ {
+ perror("malloc");
+ exit(1);
+ }
+ sprintf(sys, "exec %s", shellName);
+ system(sys);
+ free(sys);
}
- sprintf(sys, "exec %s", shellName);
- system(sys);
- free(sys);
- } else
- system(command);
+ else
+ system(command);
}
/*
* HandleSlashCmds:
- *
+ *
* Handles all the different commands that start with \ db_ptr is a pointer to
* the TgDb* structure line is the current input line prompt_ptr is a pointer
* to the prompt string, a pointer is used because the prompt can be used
* with a connection to a new database.
* Returns a status:
- * 0 - send currently constructed query to backend (i.e. we got a \g)
- * 1 - skip processing of this line, continue building up query
- * 2 - terminate processing of this query entirely
- * 3 - new query supplied by edit
+ * 0 - send currently constructed query to backend (i.e. we got a \g)
+ * 1 - skip processing of this line, continue building up query
+ * 2 - terminate processing of this query entirely
+ * 3 - new query supplied by edit
*/
static int
HandleSlashCmds(PsqlSettings * settings,
- char *line,
- char *query)
+ char *line,
+ char *query)
{
- int status = CMD_SKIP_LINE;
- char *optarg;
- /*
- * Pointer inside the <cmd> string to the argument of the slash command,
- * assuming it is a one-character slash command. If it's not a
- * one-character command, this is meaningless.
- */
- char *optarg2;
- /*
- * Pointer inside the <cmd> string to the argument of the slash command
- * assuming it's not a one-character command. If it's a one-character
- * command, this is meaningless.
- */
- char *cmd;
- /*
- * String: value of the slash command, less the slash and with escape
- * sequences decoded.
- */
- int blank_loc;
- /* Offset within <cmd> of first blank */
-
- cmd = malloc(strlen(line)); /* unescaping better not make string grow. */
-
- unescape(cmd, line + 1); /* sets cmd string */
-
- if (strlen(cmd) >= 1 && cmd[strlen(cmd)-1] == ';') /* strip trailing ; */
- cmd[strlen(cmd)-1] = '\0';
-
- /*
- * Originally, there were just single character commands. Now, we define
- * some longer, friendly commands, but we have to keep the old single
- * character commands too. \c used to be what \connect is now.
- * Complicating matters is the fact that with the single-character
- * commands, you can start the argument right after the single character,
- * so "\copy" would mean "connect to database named 'opy'".
- */
-
- if (strlen(cmd) > 1)
- optarg = cmd + 1 + strspn(cmd + 1, " \t");
- else
- optarg = NULL;
-
- blank_loc = strcspn(cmd, " \t");
- if (blank_loc == 0 || !cmd[blank_loc])
- optarg2 = NULL;
- else
- optarg2 = cmd + blank_loc + strspn(cmd + blank_loc, " \t");
-
- switch (cmd[0]) {
- case 'a': /* toggles to align fields on output */
- toggle(settings, &settings->opt.align, "field alignment");
- break;
- case 'C': /* define new caption */
- if (settings->opt.caption)
- {
- free(settings->opt.caption);
- settings->opt.caption = NULL;
- }
- if (optarg && !(settings->opt.caption = strdup(optarg))) {
- perror("malloc");
- exit(CMD_TERMINATE);
- }
- break;
- case 'c':{
- if (strncmp(cmd, "copy ", strlen("copy ")) == 0)
- do_copy(optarg2, settings);
- else if (strncmp(cmd, "connect ", strlen("connect ")) == 0 ||
- strcmp(cmd, "connect") == 0 /* issue error message */) {
- char *optarg3 = NULL;
- int blank_loc2;
-
- if (optarg2) {
- blank_loc2 = strcspn(optarg2, " \t");
- if (blank_loc2 == 0 || *(optarg2 + blank_loc2) == '\0')
- optarg3 = NULL;
- else {
- optarg3 = optarg2 + blank_loc2 +
- strspn(optarg2 + blank_loc2, " \t");
- *(optarg2 + blank_loc2) = '\0';
- }
- }
- do_connect(optarg2, optarg3, settings);
- }
- else {
- char *optarg3 = NULL;
- int blank_loc2;
-
- if (optarg) {
- blank_loc2 = strcspn(optarg, " \t");
- if (blank_loc2 == 0 || *(optarg + blank_loc2) == '\0')
- optarg3 = NULL;
- else {
- optarg3 = optarg + blank_loc2 +
- strspn(optarg + blank_loc2, " \t");
- *(optarg + blank_loc2) = '\0';
- }
- }
- do_connect(optarg, optarg3, settings);
- }
- }
- break;
- case 'd': /* \d describe tables or columns in a table */
- if (strncmp(cmd, "dt", 2) == 0) { /* only tables */
- tableList(settings, 0, 't');
- } else if (strncmp(cmd, "di", 2) == 0) { /* only indices */
- tableList(settings, 0, 'i');
- } else if (strncmp(cmd, "ds", 2) == 0) { /* only sequences */
- tableList(settings, 0, 'S');
- } else if (!optarg) { /* show tables, sequences and indices */
- tableList(settings, 0, 'b');
- } else if (strcmp(optarg, "*") == 0) { /* show everything */
- if (tableList(settings, 0, 'b') == 0)
- tableList(settings, 1, 'b');
- } else { /* describe the specified table */
- tableDesc(settings, optarg);
- }
- break;
- case 'e': /* edit */
- {
- do_edit(optarg, query, &status);
- break;
- }
- case 'E':
+ int status = CMD_SKIP_LINE;
+ char *optarg;
+
+ /*
+ * Pointer inside the <cmd> string to the argument of the slash
+ * command, assuming it is a one-character slash command. If it's not
+ * a one-character command, this is meaningless.
+ */
+ char *optarg2;
+
+ /*
+ * Pointer inside the <cmd> string to the argument of the slash
+ * command assuming it's not a one-character command. If it's a
+ * one-character command, this is meaningless.
+ */
+ char *cmd;
+
+ /*
+ * String: value of the slash command, less the slash and with escape
+ * sequences decoded.
+ */
+ int blank_loc;
+
+ /* Offset within <cmd> of first blank */
+
+ cmd = malloc(strlen(line)); /* unescaping better not make string grow. */
+
+ unescape(cmd, line + 1); /* sets cmd string */
+
+ if (strlen(cmd) >= 1 && cmd[strlen(cmd) - 1] == ';') /* strip trailing ; */
+ cmd[strlen(cmd) - 1] = '\0';
+
+ /*
+ * Originally, there were just single character commands. Now, we
+ * define some longer, friendly commands, but we have to keep the old
+ * single character commands too. \c used to be what \connect is now.
+ * Complicating matters is the fact that with the single-character
+ * commands, you can start the argument right after the single
+ * character, so "\copy" would mean "connect to database named 'opy'".
+ */
+
+ if (strlen(cmd) > 1)
+ optarg = cmd + 1 + strspn(cmd + 1, " \t");
+ else
+ optarg = NULL;
+
+ blank_loc = strcspn(cmd, " \t");
+ if (blank_loc == 0 || !cmd[blank_loc])
+ optarg2 = NULL;
+ else
+ optarg2 = cmd + blank_loc + strspn(cmd + blank_loc, " \t");
+
+ switch (cmd[0])
{
- FILE *fd;
- static char *lastfile;
- struct stat st, st2;
- if (optarg) {
- if (lastfile)
- free(lastfile);
- lastfile = malloc(strlen(optarg + 1));
- if (!lastfile) {
- perror("malloc");
- exit(CMD_TERMINATE);
- }
- strcpy(lastfile, optarg);
- } else if (!lastfile) {
- fprintf(stderr, "\\r must be followed by a file name initially\n");
+ case 'a': /* toggles to align fields on output */
+ toggle(settings, &settings->opt.align, "field alignment");
break;
- }
- stat(lastfile, &st);
- editFile(lastfile);
- if ((stat(lastfile, &st2) == -1) || ((fd = fopen(lastfile, "r")) == NULL)) {
- perror(lastfile);
+ case 'C': /* define new caption */
+ if (settings->opt.caption)
+ {
+ free(settings->opt.caption);
+ settings->opt.caption = NULL;
+ }
+ if (optarg && !(settings->opt.caption = strdup(optarg)))
+ {
+ perror("malloc");
+ exit(CMD_TERMINATE);
+ }
break;
- }
- if (st2.st_mtime == st.st_mtime) {
- if (!settings->quiet)
- fprintf(stderr, "warning: %s not modified. query not executed\n", lastfile);
- fclose(fd);
+ case 'c':
+ {
+ if (strncmp(cmd, "copy ", strlen("copy ")) == 0)
+ do_copy(optarg2, settings);
+ else if (strncmp(cmd, "connect ", strlen("connect ")) == 0 ||
+ strcmp(cmd, "connect") == 0 /* issue error message */ )
+ {
+ char *optarg3 = NULL;
+ int blank_loc2;
+
+ if (optarg2)
+ {
+ blank_loc2 = strcspn(optarg2, " \t");
+ if (blank_loc2 == 0 || *(optarg2 + blank_loc2) == '\0')
+ optarg3 = NULL;
+ else
+ {
+ optarg3 = optarg2 + blank_loc2 +
+ strspn(optarg2 + blank_loc2, " \t");
+ *(optarg2 + blank_loc2) = '\0';
+ }
+ }
+ do_connect(optarg2, optarg3, settings);
+ }
+ else
+ {
+ char *optarg3 = NULL;
+ int blank_loc2;
+
+ if (optarg)
+ {
+ blank_loc2 = strcspn(optarg, " \t");
+ if (blank_loc2 == 0 || *(optarg + blank_loc2) == '\0')
+ optarg3 = NULL;
+ else
+ {
+ optarg3 = optarg + blank_loc2 +
+ strspn(optarg + blank_loc2, " \t");
+ *(optarg + blank_loc2) = '\0';
+ }
+ }
+ do_connect(optarg, optarg3, settings);
+ }
+ }
break;
- }
- MainLoop(settings, fd);
- fclose(fd);
- break;
- }
- case 'f':
- {
- char *fs = DEFAULT_FIELD_SEP;
- if (optarg)
- fs = optarg;
- if (settings->opt.fieldSep)
- free(settings->opt.fieldSep);
- if (!(settings->opt.fieldSep = strdup(fs))) {
- perror("malloc");
- exit(CMD_TERMINATE);
- }
- if (!settings->quiet)
- printf("field separator changed to '%s'\n", settings->opt.fieldSep);
- break;
- }
- case 'g': /* \g means send query */
- if (!optarg)
- settings->gfname = NULL;
- else if (!(settings->gfname = strdup(optarg))) {
- perror("malloc");
- exit(CMD_TERMINATE);
- }
- status = CMD_SEND;
- break;
- case 'h': /* help */
- {
- do_help(settings, optarg);
- break;
- }
- case 'i': /* \i is include file */
- {
- FILE *fd;
+ case 'd': /* \d describe tables or columns in a
+ * table */
+ if (strncmp(cmd, "dt", 2) == 0)
+ { /* only tables */
+ tableList(settings, 0, 't');
+ }
+ else if (strncmp(cmd, "di", 2) == 0)
+ { /* only indices */
+ tableList(settings, 0, 'i');
+ }
+ else if (strncmp(cmd, "ds", 2) == 0)
+ { /* only sequences */
+ tableList(settings, 0, 'S');
+ }
+ else if (!optarg)
+ { /* show tables, sequences and indices */
+ tableList(settings, 0, 'b');
+ }
+ else if (strcmp(optarg, "*") == 0)
+ { /* show everything */
+ if (tableList(settings, 0, 'b') == 0)
+ tableList(settings, 1, 'b');
+ }
+ else
+ { /* describe the specified table */
+ tableDesc(settings, optarg);
+ }
+ break;
+ case 'e': /* edit */
+ {
+ do_edit(optarg, query, &status);
+ break;
+ }
+ case 'E':
+ {
+ FILE *fd;
+ static char *lastfile;
+ struct stat st,
+ st2;
+
+ if (optarg)
+ {
+ if (lastfile)
+ free(lastfile);
+ lastfile = malloc(strlen(optarg + 1));
+ if (!lastfile)
+ {
+ perror("malloc");
+ exit(CMD_TERMINATE);
+ }
+ strcpy(lastfile, optarg);
+ }
+ else if (!lastfile)
+ {
+ fprintf(stderr, "\\r must be followed by a file name initially\n");
+ break;
+ }
+ stat(lastfile, &st);
+ editFile(lastfile);
+ if ((stat(lastfile, &st2) == -1) || ((fd = fopen(lastfile, "r")) == NULL))
+ {
+ perror(lastfile);
+ break;
+ }
+ if (st2.st_mtime == st.st_mtime)
+ {
+ if (!settings->quiet)
+ fprintf(stderr, "warning: %s not modified. query not executed\n", lastfile);
+ fclose(fd);
+ break;
+ }
+ MainLoop(settings, fd);
+ fclose(fd);
+ break;
+ }
+ case 'f':
+ {
+ char *fs = DEFAULT_FIELD_SEP;
+
+ if (optarg)
+ fs = optarg;
+ if (settings->opt.fieldSep)
+ free(settings->opt.fieldSep);
+ if (!(settings->opt.fieldSep = strdup(fs)))
+ {
+ perror("malloc");
+ exit(CMD_TERMINATE);
+ }
+ if (!settings->quiet)
+ printf("field separator changed to '%s'\n", settings->opt.fieldSep);
+ break;
+ }
+ case 'g': /* \g means send query */
+ if (!optarg)
+ settings->gfname = NULL;
+ else if (!(settings->gfname = strdup(optarg)))
+ {
+ perror("malloc");
+ exit(CMD_TERMINATE);
+ }
+ status = CMD_SEND;
+ break;
+ case 'h': /* help */
+ {
+ do_help(settings, optarg);
+ break;
+ }
+ case 'i': /* \i is include file */
+ {
+ FILE *fd;
- if (!optarg) {
- fprintf(stderr, "\\i must be followed by a file name\n");
+ if (!optarg)
+ {
+ fprintf(stderr, "\\i must be followed by a file name\n");
+ break;
+ }
+ if ((fd = fopen(optarg, "r")) == NULL)
+ {
+ fprintf(stderr, "file named %s could not be opened\n", optarg);
+ break;
+ }
+ MainLoop(settings, fd);
+ fclose(fd);
+ break;
+ }
+ case 'l': /* \l is list database */
+ listAllDbs(settings);
break;
- }
- if ((fd = fopen(optarg, "r")) == NULL) {
- fprintf(stderr, "file named %s could not be opened\n", optarg);
+ case 'H':
+ if (toggle(settings, &settings->opt.html3, "HTML3.0 tabular output"))
+ settings->opt.standard = 0;
break;
- }
- MainLoop(settings, fd);
- fclose(fd);
- break;
- }
- case 'l': /* \l is list database */
- listAllDbs(settings);
- break;
- case 'H':
- if (toggle(settings, &settings->opt.html3, "HTML3.0 tabular output"))
- settings->opt.standard = 0;
- break;
- case 'o':
- setFout(settings, optarg);
- break;
- case 'p':
- if (query) {
- fputs(query, stdout);
- fputc('\n', stdout);
- }
- break;
- case 'q': /* \q is quit */
- status = CMD_TERMINATE;
- break;
- case 'r': /* reset(clear) the buffer */
- query[0] = '\0';
- if (!settings->quiet)
- printf("buffer reset(cleared)\n");
- break;
- case 's': /* \s is save history to a file */
- if (!optarg)
- optarg = "/dev/tty";
+ case 'o':
+ setFout(settings, optarg);
+ break;
+ case 'p':
+ if (query)
+ {
+ fputs(query, stdout);
+ fputc('\n', stdout);
+ }
+ break;
+ case 'q': /* \q is quit */
+ status = CMD_TERMINATE;
+ break;
+ case 'r': /* reset(clear) the buffer */
+ query[0] = '\0';
+ if (!settings->quiet)
+ printf("buffer reset(cleared)\n");
+ break;
+ case 's': /* \s is save history to a file */
+ if (!optarg)
+ optarg = "/dev/tty";
#ifdef HAVE_HISTORY
- if (write_history(optarg) != 0)
- fprintf(stderr, "cannot write history to %s\n", optarg);
+ if (write_history(optarg) != 0)
+ fprintf(stderr, "cannot write history to %s\n", optarg);
#endif
- break;
- case 'm': /* monitor like type-setting */
- if (toggle(settings, &settings->opt.standard, "standard SQL separaters and padding")) {
- settings->opt.html3 = settings->opt.expanded = 0;
- settings->opt.align = settings->opt.header = 1;
- if (settings->opt.fieldSep)
- free(settings->opt.fieldSep);
- settings->opt.fieldSep = strdup("|");
- if (!settings->quiet)
- printf("field separator changed to '%s'\n", settings->opt.fieldSep);
- } else {
- if (settings->opt.fieldSep)
- free(settings->opt.fieldSep);
- settings->opt.fieldSep = strdup(DEFAULT_FIELD_SEP);
- if (!settings->quiet)
- printf("field separator changed to '%s'\n", settings->opt.fieldSep);
- }
- break;
- case 'z': /* list table rights (grant/revoke) */
- rightsList(settings);
- break;
- case 't': /* toggle headers */
- toggle(settings, &settings->opt.header, "output headings and row count");
- break;
- case 'T': /* define html <table ...> option */
- if (settings->opt.tableOpt)
- free(settings->opt.tableOpt);
- if (!optarg)
- settings->opt.tableOpt = NULL;
- else if (!(settings->opt.tableOpt = strdup(optarg))) {
- perror("malloc");
- exit(CMD_TERMINATE);
+ break;
+ case 'm': /* monitor like type-setting */
+ if (toggle(settings, &settings->opt.standard, "standard SQL separaters and padding"))
+ {
+ settings->opt.html3 = settings->opt.expanded = 0;
+ settings->opt.align = settings->opt.header = 1;
+ if (settings->opt.fieldSep)
+ free(settings->opt.fieldSep);
+ settings->opt.fieldSep = strdup("|");
+ if (!settings->quiet)
+ printf("field separator changed to '%s'\n", settings->opt.fieldSep);
+ }
+ else
+ {
+ if (settings->opt.fieldSep)
+ free(settings->opt.fieldSep);
+ settings->opt.fieldSep = strdup(DEFAULT_FIELD_SEP);
+ if (!settings->quiet)
+ printf("field separator changed to '%s'\n", settings->opt.fieldSep);
+ }
+ break;
+ case 'z': /* list table rights (grant/revoke) */
+ rightsList(settings);
+ break;
+ case 't': /* toggle headers */
+ toggle(settings, &settings->opt.header, "output headings and row count");
+ break;
+ case 'T': /* define html <table ...> option */
+ if (settings->opt.tableOpt)
+ free(settings->opt.tableOpt);
+ if (!optarg)
+ settings->opt.tableOpt = NULL;
+ else if (!(settings->opt.tableOpt = strdup(optarg)))
+ {
+ perror("malloc");
+ exit(CMD_TERMINATE);
+ }
+ break;
+ case 'x':
+ toggle(settings, &settings->opt.expanded, "expanded table representation");
+ break;
+ case '!':
+ do_shell(optarg);
+ break;
+ default:
+ case '?': /* \? is help */
+ slashUsage(settings);
+ break;
}
- break;
- case 'x':
- toggle(settings, &settings->opt.expanded, "expanded table representation");
- break;
- case '!':
- do_shell(optarg);
- break;
- default:
- case '?': /* \? is help */
- slashUsage(settings);
- break;
- }
- free(cmd);
- return status;
-} /* HandleSlashCmds() */
+ free(cmd);
+ return status;
+} /* HandleSlashCmds() */
/* MainLoop()
* Main processing loop for reading lines of input
- * and sending them to the backend.
- *
+ * and sending them to the backend.
+ *
* This loop is re-entrant. May be called by \i command
- * which reads input from a file.
+ * which reads input from a file.
* db_ptr must be initialized and set.
*/
static int
MainLoop(PsqlSettings * settings, FILE * source)
{
- char *line; /* line of input */
- char *xcomment; /* start of extended comment */
- int len; /* length of the line */
- char query[MAX_QUERY_BUFFER]; /* multi-line query storage */
- int successResult = 1;
- int slashCmdStatus = CMD_SEND;
- /*
- * slashCmdStatus can be:
- * CMD_UNKNOWN - send currently constructed query to backend (i.e. we got a \g)
- * CMD_SEND - send currently constructed query to backend (i.e. we got a \g)
- * CMD_SKIP_LINE - skip processing of this line, continue building up query
- * CMD_TERMINATE - terminate processing of this query entirely
- * CMD_NEWEDIT - new query supplied by edit
- */
-
- bool querySent = false;
- bool interactive;
- READ_ROUTINE GetNextLine;
- bool eof = 0;
- /* We've reached the end of our command input. */
- bool success;
- bool in_quote;
- int paren_level;
- char *query_start;
-
- interactive = ((source == stdin) && !settings->notty);
- if (interactive) {
- if (settings->prompt)
- free(settings->prompt);
- settings->prompt =
- malloc(strlen(PQdb(settings->db)) + strlen(PROMPT) + 1);
- if (settings->quiet)
- settings->prompt[0] = '\0';
- else
- sprintf(settings->prompt, "%s%s", PQdb(settings->db), PROMPT);
- if (settings->useReadline) {
-#ifdef HAVE_HISTORY
- using_history();
-#endif
- GetNextLine = gets_readline;
- } else
- GetNextLine = gets_noreadline;
- } else
- GetNextLine = gets_fromFile;
-
- query[0] = '\0';
- xcomment = NULL;
- in_quote = false;
- paren_level = 0;
- slashCmdStatus = CMD_UNKNOWN; /* set default */
-
- /* main loop to get queries and execute them */
- while (!eof) {
- /* just returned from editing the line? then just copy to the input buffer */
- if (slashCmdStatus == CMD_NEWEDIT) {
- paren_level = 0;
- line = strdup(query);
- query[0] = '\0';
-
- /* otherwise, get another line and set interactive prompt if necessary */
- } else {
- if (interactive && !settings->quiet) {
- if (in_quote)
- settings->prompt[strlen(settings->prompt)-3] = PROMPT_QUOTE;
- else if (xcomment != NULL)
- settings->prompt[strlen(settings->prompt)-3] = PROMPT_COMMENT;
- else if (query[0] != '\0' && !querySent)
- settings->prompt[strlen(settings->prompt)-3] = PROMPT_CONTINUE;
+ char *line; /* line of input */
+ char *xcomment; /* start of extended comment */
+ int len; /* length of the line */
+ char query[MAX_QUERY_BUFFER]; /* multi-line query
+ * storage */
+ int successResult = 1;
+ int slashCmdStatus = CMD_SEND;
+
+ /*
+ * slashCmdStatus can be: CMD_UNKNOWN - send currently constructed
+ * query to backend (i.e. we got a \g) CMD_SEND - send
+ * currently constructed query to backend (i.e. we got a \g)
+ * CMD_SKIP_LINE - skip processing of this line, continue building
+ * up query CMD_TERMINATE - terminate processing of this query
+ * entirely CMD_NEWEDIT - new query supplied by edit
+ */
+
+ bool querySent = false;
+ bool interactive;
+ READ_ROUTINE GetNextLine;
+ bool eof = 0;
+
+ /* We've reached the end of our command input. */
+ bool success;
+ bool in_quote;
+ int paren_level;
+ char *query_start;
+
+ interactive = ((source == stdin) && !settings->notty);
+ if (interactive)
+ {
+ if (settings->prompt)
+ free(settings->prompt);
+ settings->prompt =
+ malloc(strlen(PQdb(settings->db)) + strlen(PROMPT) + 1);
+ if (settings->quiet)
+ settings->prompt[0] = '\0';
else
- settings->prompt[strlen(settings->prompt)-3] = PROMPT_READY;
- }
- line = GetNextLine(settings->prompt, source);
+ sprintf(settings->prompt, "%s%s", PQdb(settings->db), PROMPT);
+ if (settings->useReadline)
+ {
#ifdef HAVE_HISTORY
- if (interactive && settings->useReadline && line != NULL)
- add_history(line); /* save non-empty lines in history */
+ using_history();
#endif
+ GetNextLine = gets_readline;
+ }
+ else
+ GetNextLine = gets_noreadline;
}
+ else
+ GetNextLine = gets_fromFile;
- /* query - pointer to current command
- * query_start - placeholder for next command
- */
+ query[0] = '\0';
+ xcomment = NULL;
+ in_quote = false;
+ paren_level = 0;
+ slashCmdStatus = CMD_UNKNOWN; /* set default */
- /* not currently inside an extended comment? */
- if (xcomment == NULL) {
- query_start = line;
-
- /* otherwise, continue the extended comment... */
- } else {
- query_start = line;
- xcomment = line;
- };
-
- if (line == NULL) { /* No more input. Time to quit */
- if (!settings->quiet)
- printf("EOF\n"); /* Goes on prompt line */
- eof = true;
- } else {
- /* remove whitespaces on the right, incl. \n's */
- line = rightTrim(line);
-
- /* echo back if input is from file */
- if (!interactive && !settings->singleStep && !settings->quiet)
- fprintf(stderr, "%s\n", line);
-
- /* nothing on line after trimming? then ignore */
- if (line[0] == '\0') {
- free(line);
- continue;
- }
+ /* main loop to get queries and execute them */
+ while (!eof)
+ {
- len = strlen(line);
+ /*
+ * just returned from editing the line? then just copy to the
+ * input buffer
+ */
+ if (slashCmdStatus == CMD_NEWEDIT)
+ {
+ paren_level = 0;
+ line = strdup(query);
+ query[0] = '\0';
- if (settings->singleLineMode) {
- SendQuery(&success, settings, line, false, false, 0);
- successResult &= success;
- querySent = true;
+ /*
+ * otherwise, get another line and set interactive prompt if
+ * necessary
+ */
+ }
+ else
+ {
+ if (interactive && !settings->quiet)
+ {
+ if (in_quote)
+ settings->prompt[strlen(settings->prompt) - 3] = PROMPT_QUOTE;
+ else if (xcomment != NULL)
+ settings->prompt[strlen(settings->prompt) - 3] = PROMPT_COMMENT;
+ else if (query[0] != '\0' && !querySent)
+ settings->prompt[strlen(settings->prompt) - 3] = PROMPT_CONTINUE;
+ else
+ settings->prompt[strlen(settings->prompt) - 3] = PROMPT_READY;
+ }
+ line = GetNextLine(settings->prompt, source);
+#ifdef HAVE_HISTORY
+ if (interactive && settings->useReadline && line != NULL)
+ add_history(line); /* save non-empty lines in history */
+#endif
+ }
- } else {
- int i;
+ /*
+ * query - pointer to current command query_start - placeholder
+ * for next command
+ */
- for (i = 0; i < len; i++) {
- if (querySent && !isspace(line[i])) {
- query[0] = '\0';
- querySent = false;
- }
-
- /* inside a quote? */
- if (in_quote && (line[i] != '\'')) {
- continue;
-
- /* inside an extended comment? */
- } else if (xcomment != NULL) {
- if (line[i] == '*' && line[i+1] == '/') {
- xcomment = NULL;
- i++;
- };
- continue;
-
- /* possible backslash command? */
- } else if (line[i] == '\\') {
- char hold_char = line[i];
-
- line[i] = '\0';
- if (query_start[0] != '\0') {
- if (query[0] != '\0') {
- strcat(query, "\n");
- strcat(query, query_start);
- } else {
- strcpy(query, query_start);
- };
- }
- line[i] = hold_char;
- query_start = line + i;
- break; /* handle command */
+ /* not currently inside an extended comment? */
+ if (xcomment == NULL)
+ {
+ query_start = line;
- /* start an extended comment? */
- } else if (line[i] == '/' && line[i+1] == '*') {
- xcomment = line + i;
- i++;
- continue;
-
- /* single-line comment? truncate line */
- } else if ((line[i] == '-' && line[i+1] == '-') ||
- (line[i] == '/' && line[i+1] == '/')) {
- /* print comment at top of query */
- if (settings->singleStep)
- fprintf(stdout, "%s\n", line + i);
- line[i] = '\0'; /* remove comment */
- break;
+ /* otherwise, continue the extended comment... */
+ }
+ else
+ {
+ query_start = line;
+ xcomment = line;
+ };
+
+ if (line == NULL)
+ { /* No more input. Time to quit */
+ if (!settings->quiet)
+ printf("EOF\n");/* Goes on prompt line */
+ eof = true;
+ }
+ else
+ {
+ /* remove whitespaces on the right, incl. \n's */
+ line = rightTrim(line);
+
+ /* echo back if input is from file */
+ if (!interactive && !settings->singleStep && !settings->quiet)
+ fprintf(stderr, "%s\n", line);
+
+ /* nothing on line after trimming? then ignore */
+ if (line[0] == '\0')
+ {
+ free(line);
+ continue;
+ }
- } else if (line[i] == '\'') {
- in_quote ^= 1;
+ len = strlen(line);
- /* semi-colon? then send query now */
- } else if (!paren_level && line[i] == ';') {
- char hold_char = line[i + 1];
+ if (settings->singleLineMode)
+ {
+ SendQuery(&success, settings, line, false, false, 0);
+ successResult &= success;
+ querySent = true;
- line[i + 1] = '\0';
- if (query_start[0] != '\0') {
- if (query[0] != '\0') {
- strcat(query, "\n");
- strcat(query, query_start);
- } else
- strcpy(query, query_start);
}
- SendQuery(&success, settings, query, false, false, 0);
- successResult &= success;
- line[i + 1] = hold_char;
- query_start = line + i + 1;
- querySent = true;
+ else
+ {
+ int i;
+
+ for (i = 0; i < len; i++)
+ {
+ if (querySent && !isspace(line[i]))
+ {
+ query[0] = '\0';
+ querySent = false;
+ }
+
+ /* inside a quote? */
+ if (in_quote && (line[i] != '\''))
+ {
+ continue;
+
+ /* inside an extended comment? */
+ }
+ else if (xcomment != NULL)
+ {
+ if (line[i] == '*' && line[i + 1] == '/')
+ {
+ xcomment = NULL;
+ i++;
+ };
+ continue;
+
+ /* possible backslash command? */
+ }
+ else if (line[i] == '\\')
+ {
+ char hold_char = line[i];
+
+ line[i] = '\0';
+ if (query_start[0] != '\0')
+ {
+ if (query[0] != '\0')
+ {
+ strcat(query, "\n");
+ strcat(query, query_start);
+ }
+ else
+ {
+ strcpy(query, query_start);
+ };
+ }
+ line[i] = hold_char;
+ query_start = line + i;
+ break; /* handle command */
+
+ /* start an extended comment? */
+ }
+ else if (line[i] == '/' && line[i + 1] == '*')
+ {
+ xcomment = line + i;
+ i++;
+ continue;
+
+ /* single-line comment? truncate line */
+ }
+ else if ((line[i] == '-' && line[i + 1] == '-') ||
+ (line[i] == '/' && line[i + 1] == '/'))
+ {
+ /* print comment at top of query */
+ if (settings->singleStep)
+ fprintf(stdout, "%s\n", line + i);
+ line[i] = '\0'; /* remove comment */
+ break;
+
+ }
+ else if (line[i] == '\'')
+ {
+ in_quote ^= 1;
+
+ /* semi-colon? then send query now */
+ }
+ else if (!paren_level && line[i] == ';')
+ {
+ char hold_char = line[i + 1];
+
+ line[i + 1] = '\0';
+ if (query_start[0] != '\0')
+ {
+ if (query[0] != '\0')
+ {
+ strcat(query, "\n");
+ strcat(query, query_start);
+ }
+ else
+ strcpy(query, query_start);
+ }
+ SendQuery(&success, settings, query, false, false, 0);
+ successResult &= success;
+ line[i + 1] = hold_char;
+ query_start = line + i + 1;
+ querySent = true;
+
+ }
+ else if (line[i] == '(')
+ {
+ paren_level++;
+
+ }
+ else if (paren_level && line[i] == ')')
+ {
+ paren_level--;
+ };
+ }
+ }
- } else if (line[i] == '(') {
- paren_level++;
+ /* nothing on line after trimming? then ignore */
+ if (line[0] == '\0')
+ {
+ free(line);
+ continue;
+ }
- } else if (paren_level && line[i] == ')') {
- paren_level--;
- };
- }
- }
+ slashCmdStatus = CMD_UNKNOWN;
+ if (!in_quote && query_start[0] == '\\')
+ {
+ slashCmdStatus = HandleSlashCmds(settings,
+ query_start,
+ query);
+ if (slashCmdStatus == CMD_SKIP_LINE)
+ {
+ if (query[0] == '\0')
+ paren_level = 0;
+ free(line);
+ continue;
+ }
+ if (slashCmdStatus == CMD_TERMINATE)
+ {
+ free(line);
+ break;
+ }
+ free(line);
+ }
+ else if (strlen(query) + strlen(query_start) > MAX_QUERY_BUFFER)
+ {
+ fprintf(stderr, "query buffer max length of %d exceeded\n",
+ MAX_QUERY_BUFFER);
+ fprintf(stderr, "query line ignored\n");
+ free(line);
+ }
+ else
+ {
+ if (query_start[0] != '\0')
+ {
+
+ querySent = false;
+ if (query[0] != '\0')
+ {
+ strcat(query, "\n");
+ strcat(query, query_start);
+ }
+ else
+ strcpy(query, query_start);
+ }
+ free(line); /* PURIFY */
+ }
- /* nothing on line after trimming? then ignore */
- if (line[0] == '\0') {
- free(line);
- continue;
- }
-
- slashCmdStatus = CMD_UNKNOWN;
- if (!in_quote && query_start[0] == '\\') {
- slashCmdStatus = HandleSlashCmds(settings,
- query_start,
- query);
- if (slashCmdStatus == CMD_SKIP_LINE) {
- if (query[0] == '\0')
- paren_level = 0;
- free(line);
- continue;
- }
- if (slashCmdStatus == CMD_TERMINATE) {
- free(line);
- break;
- }
- free(line);
- } else if (strlen(query) + strlen(query_start) > MAX_QUERY_BUFFER) {
- fprintf(stderr, "query buffer max length of %d exceeded\n",
- MAX_QUERY_BUFFER);
- fprintf(stderr, "query line ignored\n");
- free (line);
- } else {
- if (query_start[0] != '\0') {
-
- querySent = false;
- if (query[0] != '\0') {
- strcat(query, "\n");
- strcat(query, query_start);
- } else
- strcpy(query, query_start);
- }
- free(line); /* PURIFY */
- }
-
- /* had a backslash-g? force the query to be sent */
- if (slashCmdStatus == CMD_SEND) {
+ /* had a backslash-g? force the query to be sent */
+ if (slashCmdStatus == CMD_SEND)
+ {
#if FALSE
- if (! querySent) {
- SendQuery(&success, settings, query, false, false, 0);
- successResult &= success;
- }
+ if (!querySent)
+ {
+ SendQuery(&success, settings, query, false, false, 0);
+ successResult &= success;
+ }
#else
- SendQuery(&success, settings, query, false, false, 0);
- successResult &= success;
+ SendQuery(&success, settings, query, false, false, 0);
+ successResult &= success;
#endif
- querySent = true;
- }
- }
- } /* while */
- return successResult;
-} /* MainLoop() */
+ querySent = true;
+ }
+ }
+ } /* while */
+ return successResult;
+} /* MainLoop() */
int
main(int argc, char **argv)
{
- extern char *optarg;
- extern int optind;
-
- char *dbname = NULL;
- char *host = NULL;
- char *port = NULL;
- char *qfilename = NULL;
- char errbuf[ERROR_MSG_LENGTH];
-
- PsqlSettings settings;
-
- char *singleQuery = NULL;
-
- bool listDatabases = 0;
- int successResult = 1;
- bool singleSlashCmd = 0;
- int c;
-
- memset(&settings, 0, sizeof settings);
- settings.opt.align = 1;
- settings.opt.header = 1;
- settings.queryFout = stdout;
- settings.opt.fieldSep = strdup(DEFAULT_FIELD_SEP);
- settings.opt.pager = 1;
- if (!isatty(0) || !isatty(1))
- settings.quiet = settings.notty = 1;
+ extern char *optarg;
+ extern int optind;
+
+ char *dbname = NULL;
+ char *host = NULL;
+ char *port = NULL;
+ char *qfilename = NULL;
+ char errbuf[ERROR_MSG_LENGTH];
+
+ PsqlSettings settings;
+
+ char *singleQuery = NULL;
+
+ bool listDatabases = 0;
+ int successResult = 1;
+ bool singleSlashCmd = 0;
+ int c;
+
+ memset(&settings, 0, sizeof settings);
+ settings.opt.align = 1;
+ settings.opt.header = 1;
+ settings.queryFout = stdout;
+ settings.opt.fieldSep = strdup(DEFAULT_FIELD_SEP);
+ settings.opt.pager = 1;
+ if (!isatty(0) || !isatty(1))
+ settings.quiet = settings.notty = 1;
#ifdef HAVE_LIBREADLINE
- else
- settings.useReadline = 1;
+ else
+ settings.useReadline = 1;
#endif
#ifdef PSQL_ALWAYS_GET_PASSWORDS
- settings.getPassword = 1;
+ settings.getPassword = 1;
#else
- settings.getPassword = 0;
+ settings.getPassword = 0;
#endif
- while ((c = getopt(argc, argv, "Aa:c:d:ef:F:lh:Hnso:p:qStT:ux")) != EOF) {
- switch (c) {
- case 'A':
- settings.opt.align = 0;
- break;
- case 'a':
- fe_setauthsvc(optarg, errbuf);
- break;
- case 'c':
- singleQuery = strdup(optarg);
- if (singleQuery[0] == '\\') {
- singleSlashCmd = 1;
- }
- break;
- case 'd':
- dbname = optarg;
- break;
- case 'e':
- settings.echoQuery = 1;
- break;
- case 'f':
- qfilename = optarg;
- break;
- case 'F':
- settings.opt.fieldSep = strdup(optarg);
- break;
- case 'l':
- listDatabases = 1;
- break;
- case 'h':
- host = optarg;
- break;
- case 'H':
- settings.opt.html3 = 1;
- break;
- case 'n':
- settings.useReadline = 0;
- break;
- case 'o':
- setFout(&settings, optarg);
- break;
- case 'p':
- port = optarg;
- break;
- case 'q':
- settings.quiet = 1;
- break;
- case 's':
- settings.singleStep = 1;
- break;
- case 'S':
- settings.singleLineMode = 1;
- break;
- case 't':
- settings.opt.header = 0;
- break;
- case 'T':
- settings.opt.tableOpt = strdup(optarg);
- break;
- case 'u':
- settings.getPassword = 1;
- break;
- case 'x':
- settings.opt.expanded = 1;
- break;
- default:
- usage(argv[0]);
- break;
+ while ((c = getopt(argc, argv, "Aa:c:d:ef:F:lh:Hnso:p:qStT:ux")) != EOF)
+ {
+ switch (c)
+ {
+ case 'A':
+ settings.opt.align = 0;
+ break;
+ case 'a':
+ fe_setauthsvc(optarg, errbuf);
+ break;
+ case 'c':
+ singleQuery = strdup(optarg);
+ if (singleQuery[0] == '\\')
+ {
+ singleSlashCmd = 1;
+ }
+ break;
+ case 'd':
+ dbname = optarg;
+ break;
+ case 'e':
+ settings.echoQuery = 1;
+ break;
+ case 'f':
+ qfilename = optarg;
+ break;
+ case 'F':
+ settings.opt.fieldSep = strdup(optarg);
+ break;
+ case 'l':
+ listDatabases = 1;
+ break;
+ case 'h':
+ host = optarg;
+ break;
+ case 'H':
+ settings.opt.html3 = 1;
+ break;
+ case 'n':
+ settings.useReadline = 0;
+ break;
+ case 'o':
+ setFout(&settings, optarg);
+ break;
+ case 'p':
+ port = optarg;
+ break;
+ case 'q':
+ settings.quiet = 1;
+ break;
+ case 's':
+ settings.singleStep = 1;
+ break;
+ case 'S':
+ settings.singleLineMode = 1;
+ break;
+ case 't':
+ settings.opt.header = 0;
+ break;
+ case 'T':
+ settings.opt.tableOpt = strdup(optarg);
+ break;
+ case 'u':
+ settings.getPassword = 1;
+ break;
+ case 'x':
+ settings.opt.expanded = 1;
+ break;
+ default:
+ usage(argv[0]);
+ break;
+ }
}
- }
- /* if we still have an argument, use it as the database name */
- if (argc - optind == 1)
- dbname = argv[optind];
-
- if (listDatabases)
- dbname = "template1";
-
- if(settings.getPassword) {
- char username[9];
- char password[9];
- char *connect_string;
-
- prompt_for_password(username, password);
-
- /* now use PQconnectdb so we can pass these options */
- connect_string = make_connect_string(host, port, dbname, username, password);
- settings.db = PQconnectdb(connect_string);
- free(connect_string);
- } else {
- settings.db = PQsetdb(host, port, NULL, NULL, dbname);
- }
-
- dbname = PQdb(settings.db);
-
- if (PQstatus(settings.db) == CONNECTION_BAD) {
- fprintf(stderr, "Connection to database '%s' failed.\n", dbname);
- fprintf(stderr, "%s", PQerrorMessage(settings.db));
- PQfinish(settings.db);
- exit(1);
- }
- if (listDatabases) {
- exit(listAllDbs(&settings));
- }
- if (!settings.quiet && !singleQuery && !qfilename) {
- printf("Welcome to the POSTGRESQL interactive sql monitor:\n");
- printf(" Please read the file COPYRIGHT for copyright terms "
- "of POSTGRESQL\n\n");
- printf(" type \\? for help on slash commands\n");
- printf(" type \\q to quit\n");
- printf(" type \\g or terminate with semicolon to execute query\n");
- printf(" You are currently connected to the database: %s\n\n", dbname);
- }
- if (qfilename || singleSlashCmd) {
- /*
- * read in a file full of queries instead of reading in queries
- * interactively
- */
- char *line;
-
- if (singleSlashCmd) {
- /* Not really a query, but "Do what I mean, not what I say." */
- line = singleQuery;
- } else {
- line = malloc(strlen(qfilename) + 5);
- sprintf(line, "\\i %s", qfilename);
+ /* if we still have an argument, use it as the database name */
+ if (argc - optind == 1)
+ dbname = argv[optind];
+
+ if (listDatabases)
+ dbname = "template1";
+
+ if (settings.getPassword)
+ {
+ char username[9];
+ char password[9];
+ char *connect_string;
+
+ prompt_for_password(username, password);
+
+ /* now use PQconnectdb so we can pass these options */
+ connect_string = make_connect_string(host, port, dbname, username, password);
+ settings.db = PQconnectdb(connect_string);
+ free(connect_string);
}
- HandleSlashCmds(&settings, line, "");
- free (line); /* PURIFY */
- } else {
- if (singleQuery) {
- bool success; /* The query succeeded at the backend */
- SendQuery(&success, &settings, singleQuery, false, false, 0);
- successResult = success;
- } else
- successResult = MainLoop(&settings, stdin);
- }
-
- PQfinish(settings.db);
- free(settings.opt.fieldSep); /* PURIFY */
- if(settings.prompt) free(settings.prompt); /* PURIFY */
-
- return !successResult;
+ else
+ {
+ settings.db = PQsetdb(host, port, NULL, NULL, dbname);
+ }
+
+ dbname = PQdb(settings.db);
+
+ if (PQstatus(settings.db) == CONNECTION_BAD)
+ {
+ fprintf(stderr, "Connection to database '%s' failed.\n", dbname);
+ fprintf(stderr, "%s", PQerrorMessage(settings.db));
+ PQfinish(settings.db);
+ exit(1);
+ }
+ if (listDatabases)
+ {
+ exit(listAllDbs(&settings));
+ }
+ if (!settings.quiet && !singleQuery && !qfilename)
+ {
+ printf("Welcome to the POSTGRESQL interactive sql monitor:\n");
+ printf(" Please read the file COPYRIGHT for copyright terms "
+ "of POSTGRESQL\n\n");
+ printf(" type \\? for help on slash commands\n");
+ printf(" type \\q to quit\n");
+ printf(" type \\g or terminate with semicolon to execute query\n");
+ printf(" You are currently connected to the database: %s\n\n", dbname);
+ }
+ if (qfilename || singleSlashCmd)
+ {
+
+ /*
+ * read in a file full of queries instead of reading in queries
+ * interactively
+ */
+ char *line;
+
+ if (singleSlashCmd)
+ {
+ /* Not really a query, but "Do what I mean, not what I say." */
+ line = singleQuery;
+ }
+ else
+ {
+ line = malloc(strlen(qfilename) + 5);
+ sprintf(line, "\\i %s", qfilename);
+ }
+ HandleSlashCmds(&settings, line, "");
+ free(line); /* PURIFY */
+ }
+ else
+ {
+ if (singleQuery)
+ {
+ bool success; /* The query succeeded at the
+ * backend */
+
+ SendQuery(&success, &settings, singleQuery, false, false, 0);
+ successResult = success;
+ }
+ else
+ successResult = MainLoop(&settings, stdin);
+ }
+
+ PQfinish(settings.db);
+ free(settings.opt.fieldSep);/* PURIFY */
+ if (settings.prompt)
+ free(settings.prompt); /* PURIFY */
+
+ return !successResult;
}
-#define COPYBUFSIZ 8192
+#define COPYBUFSIZ 8192
static void
handleCopyOut(PGresult * res, bool quiet, FILE * copystream)
{
- bool copydone;
- char copybuf[COPYBUFSIZ];
- int ret;
-
- copydone = false; /* Can't be done; haven't started. */
-
- while (!copydone) {
- ret = PQgetline(res->conn, copybuf, COPYBUFSIZ);
-
- if (copybuf[0] == '\\' &&
- copybuf[1] == '.' &&
- copybuf[2] == '\0') {
- copydone = true; /* don't print this... */
- } else {
- fputs(copybuf, copystream);
- switch (ret) {
- case EOF:
- copydone = true;
- /* FALLTHROUGH */
- case 0:
- fputc('\n', copystream);
- break;
- case 1:
- break;
- }
+ bool copydone;
+ char copybuf[COPYBUFSIZ];
+ int ret;
+
+ copydone = false; /* Can't be done; haven't started. */
+
+ while (!copydone)
+ {
+ ret = PQgetline(res->conn, copybuf, COPYBUFSIZ);
+
+ if (copybuf[0] == '\\' &&
+ copybuf[1] == '.' &&
+ copybuf[2] == '\0')
+ {
+ copydone = true; /* don't print this... */
+ }
+ else
+ {
+ fputs(copybuf, copystream);
+ switch (ret)
+ {
+ case EOF:
+ copydone = true;
+ /* FALLTHROUGH */
+ case 0:
+ fputc('\n', copystream);
+ break;
+ case 1:
+ break;
+ }
+ }
}
- }
- fflush(copystream);
- PQendcopy(res->conn);
+ fflush(copystream);
+ PQendcopy(res->conn);
}
@@ -1925,51 +2202,59 @@ handleCopyOut(PGresult * res, bool quiet, FILE * copystream)
static void
handleCopyIn(PGresult * res, const bool mustprompt, FILE * copystream)
{
- bool copydone = false;
- bool firstload;
- bool linedone;
- char copybuf[COPYBUFSIZ];
- char *s;
- int buflen;
- int c;
-
- if (mustprompt) {
- fputs("Enter info followed by a newline\n", stdout);
- fputs("End with a backslash and a "
- "period on a line by itself.\n", stdout);
- }
- while (!copydone) { /* for each input line ... */
- if (mustprompt) {
- fputs(">> ", stdout);
- fflush(stdout);
+ bool copydone = false;
+ bool firstload;
+ bool linedone;
+ char copybuf[COPYBUFSIZ];
+ char *s;
+ int buflen;
+ int c;
+
+ if (mustprompt)
+ {
+ fputs("Enter info followed by a newline\n", stdout);
+ fputs("End with a backslash and a "
+ "period on a line by itself.\n", stdout);
}
- firstload = true;
- linedone = false;
- while (!linedone) { /* for each buffer ... */
- s = copybuf;
- buflen = COPYBUFSIZ;
- for (; buflen > 1 &&
- !(linedone = (c = getc(copystream)) == '\n' || c == EOF);
- --buflen) {
- *s++ = c;
- }
- if (c == EOF) {
- PQputline(res->conn, "\\.");
- copydone = true;
- break;
- }
- *s = '\0';
- PQputline(res->conn, copybuf);
- if (firstload) {
- if (!strcmp(copybuf, "\\.")) {
- copydone = true;
- }
- firstload = false;
- }
+ while (!copydone)
+ { /* for each input line ... */
+ if (mustprompt)
+ {
+ fputs(">> ", stdout);
+ fflush(stdout);
+ }
+ firstload = true;
+ linedone = false;
+ while (!linedone)
+ { /* for each buffer ... */
+ s = copybuf;
+ buflen = COPYBUFSIZ;
+ for (; buflen > 1 &&
+ !(linedone = (c = getc(copystream)) == '\n' || c == EOF);
+ --buflen)
+ {
+ *s++ = c;
+ }
+ if (c == EOF)
+ {
+ PQputline(res->conn, "\\.");
+ copydone = true;
+ break;
+ }
+ *s = '\0';
+ PQputline(res->conn, copybuf);
+ if (firstload)
+ {
+ if (!strcmp(copybuf, "\\."))
+ {
+ copydone = true;
+ }
+ firstload = false;
+ }
+ }
+ PQputline(res->conn, "\n");
}
- PQputline(res->conn, "\n");
- }
- PQendcopy(res->conn);
+ PQendcopy(res->conn);
}
@@ -1978,131 +2263,157 @@ handleCopyIn(PGresult * res, const bool mustprompt, FILE * copystream)
* try to open fname and return a FILE *, if it fails, use stdout, instead
*/
-static FILE *
+static FILE *
setFout(PsqlSettings * ps, char *fname)
{
- if (ps->queryFout && ps->queryFout != stdout) {
- if (ps->pipe)
- pclose(ps->queryFout);
- else
- fclose(ps->queryFout);
- }
- if (!fname) {
- ps->queryFout = stdout;
- pqsignal(SIGPIPE, SIG_DFL);
- }
- else {
- if (*fname == '|') {
- pqsignal(SIGPIPE, SIG_IGN);
- ps->queryFout = popen(fname + 1, "w");
- ps->pipe = 1;
- } else {
- ps->queryFout = fopen(fname, "w");
- pqsignal(SIGPIPE, SIG_DFL);
- ps->pipe = 0;
+ if (ps->queryFout && ps->queryFout != stdout)
+ {
+ if (ps->pipe)
+ pclose(ps->queryFout);
+ else
+ fclose(ps->queryFout);
}
- if (!ps->queryFout) {
- perror(fname);
- ps->queryFout = stdout;
+ if (!fname)
+ {
+ ps->queryFout = stdout;
+ pqsignal(SIGPIPE, SIG_DFL);
}
- }
- return ps->queryFout;
+ else
+ {
+ if (*fname == '|')
+ {
+ pqsignal(SIGPIPE, SIG_IGN);
+ ps->queryFout = popen(fname + 1, "w");
+ ps->pipe = 1;
+ }
+ else
+ {
+ ps->queryFout = fopen(fname, "w");
+ pqsignal(SIGPIPE, SIG_DFL);
+ ps->pipe = 0;
+ }
+ if (!ps->queryFout)
+ {
+ perror(fname);
+ ps->queryFout = stdout;
+ }
+ }
+ return ps->queryFout;
}
-static void prompt_for_password(char *username, char *password)
+static void
+prompt_for_password(char *username, char *password)
{
- int length;
+ int length;
+
#ifdef HAVE_TERMIOS_H
- struct termios t_orig, t;
+ struct termios t_orig,
+ t;
+
#endif
- printf("Username: ");
- fgets(username, 9, stdin);
- length = strlen(username);
- /* skip rest of the line */
- if (length > 0 && username[length-1] != '\n') {
- static char buf[512];
- do {
- fgets(buf, 512, stdin);
- } while (buf[strlen(buf)-1] != '\n');
- }
- if(length > 0 && username[length-1] == '\n') username[length-1] = '\0';
-
- printf("Password: ");
+ printf("Username: ");
+ fgets(username, 9, stdin);
+ length = strlen(username);
+ /* skip rest of the line */
+ if (length > 0 && username[length - 1] != '\n')
+ {
+ static char buf[512];
+
+ do
+ {
+ fgets(buf, 512, stdin);
+ } while (buf[strlen(buf) - 1] != '\n');
+ }
+ if (length > 0 && username[length - 1] == '\n')
+ username[length - 1] = '\0';
+
+ printf("Password: ");
#ifdef HAVE_TERMIOS_H
- tcgetattr(0, &t);
- t_orig = t;
- t.c_lflag &= ~ECHO;
- tcsetattr(0, TCSADRAIN, &t);
+ tcgetattr(0, &t);
+ t_orig = t;
+ t.c_lflag &= ~ECHO;
+ tcsetattr(0, TCSADRAIN, &t);
#endif
- fgets(password, 9, stdin);
+ fgets(password, 9, stdin);
#ifdef HAVE_TERMIOS_H
- tcsetattr(0, TCSADRAIN, &t_orig);
+ tcsetattr(0, TCSADRAIN, &t_orig);
#endif
- length = strlen(password);
- /* skip rest of the line */
- if (length > 0 && password[length-1] != '\n') {
- static char buf[512];
- do {
- fgets(buf, 512, stdin);
- } while (buf[strlen(buf)-1] != '\n');
- }
- if(length > 0 && password[length-1] == '\n') password[length-1] = '\0';
-
- printf("\n\n");
+ length = strlen(password);
+ /* skip rest of the line */
+ if (length > 0 && password[length - 1] != '\n')
+ {
+ static char buf[512];
+
+ do
+ {
+ fgets(buf, 512, stdin);
+ } while (buf[strlen(buf) - 1] != '\n');
+ }
+ if (length > 0 && password[length - 1] == '\n')
+ password[length - 1] = '\0';
+
+ printf("\n\n");
}
-static char *make_connect_string(char *host, char *port, char *dbname,
- char *username, char *password)
+static char *
+make_connect_string(char *host, char *port, char *dbname,
+ char *username, char *password)
{
- int connect_string_len = 0;
- char *connect_string;
-
- if(host)
- connect_string_len += 6 + strlen(host); /* 6 == "host=" + " " */
- if(username)
- connect_string_len += 6 + strlen(username); /* 6 == "user=" + " " */
- if(password)
- connect_string_len += 10 + strlen(password); /* 10 == "password=" + " " */
- if(port)
- connect_string_len += 6 + strlen(port); /* 6 == "port=" + " " */
- if(dbname)
- connect_string_len += 8 + strlen(dbname); /* 8 == "dbname=" + " " */
- connect_string_len += 18; /* "authtype=password" + null */
-
- connect_string = (char *)malloc(connect_string_len);
- if(!connect_string) {
- return 0;
- }
- connect_string[0] = '\0';
- if(host) {
- strcat(connect_string, "host=");
- strcat(connect_string, host);
- strcat(connect_string, " ");
- }
- if(username) {
- strcat(connect_string, "user=");
- strcat(connect_string, username);
- strcat(connect_string, " ");
- }
- if(password) {
- strcat(connect_string, "password=");
- strcat(connect_string, password);
- strcat(connect_string, " ");
- }
- if(port) {
- strcat(connect_string, "port=");
- strcat(connect_string, port);
- strcat(connect_string, " ");
- }
- if(dbname) {
- strcat(connect_string, "dbname=");
- strcat(connect_string, dbname);
- strcat(connect_string, " ");
- }
- strcat(connect_string, "authtype=password");
-
- return connect_string;
+ int connect_string_len = 0;
+ char *connect_string;
+
+ if (host)
+ connect_string_len += 6 + strlen(host); /* 6 == "host=" + " " */
+ if (username)
+ connect_string_len += 6 + strlen(username); /* 6 == "user=" + " " */
+ if (password)
+ connect_string_len += 10 + strlen(password); /* 10 == "password=" + "
+ * " */
+ if (port)
+ connect_string_len += 6 + strlen(port); /* 6 == "port=" + " " */
+ if (dbname)
+ connect_string_len += 8 + strlen(dbname); /* 8 == "dbname=" + " " */
+ connect_string_len += 18; /* "authtype=password" + null */
+
+ connect_string = (char *) malloc(connect_string_len);
+ if (!connect_string)
+ {
+ return 0;
+ }
+ connect_string[0] = '\0';
+ if (host)
+ {
+ strcat(connect_string, "host=");
+ strcat(connect_string, host);
+ strcat(connect_string, " ");
+ }
+ if (username)
+ {
+ strcat(connect_string, "user=");
+ strcat(connect_string, username);
+ strcat(connect_string, " ");
+ }
+ if (password)
+ {
+ strcat(connect_string, "password=");
+ strcat(connect_string, password);
+ strcat(connect_string, " ");
+ }
+ if (port)
+ {
+ strcat(connect_string, "port=");
+ strcat(connect_string, port);
+ strcat(connect_string, " ");
+ }
+ if (dbname)
+ {
+ strcat(connect_string, "dbname=");
+ strcat(connect_string, dbname);
+ strcat(connect_string, " ");
+ }
+ strcat(connect_string, "authtype=password");
+
+ return connect_string;
}
-