Commit 0365c51e authored by Bruce Momjian's avatar Bruce Momjian

Overhaul MainLoop input processing for quotes, comments, backslashes.

parent f64b8403
......@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/bin/psql/Attic/psql.c,v 1.28 1996/11/11 05:55:30 momjian Exp $
* $Header: /cvsroot/pgsql/src/bin/psql/Attic/psql.c,v 1.29 1996/11/14 16:08:03 momjian Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -58,117 +58,117 @@ typedef struct _psqlSettings {
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 useReadline;/* use libreadline routines */
} 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 handleCopyIn(PGresult *res, const bool mustprompt,
FILE *copystream);
static int tableList(PsqlSettings *ps, bool deep_tablelist);
static int tableDesc(PsqlSettings *ps, char *table);
char *gets_noreadline(char *prompt, FILE *source);
char *gets_readline(char *prompt, FILE *source);
char *gets_fromFile(char *prompt, FILE *source);
int listAllDbs(PsqlSettings *settings);
void SendQuery(bool *success_p, PsqlSettings *settings, const char *query,
const bool copy_in, const bool copy_out, FILE *copystream);
int HandleSlashCmds(PsqlSettings *settings,
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);
static int tableDesc(PsqlSettings * ps, char *table);
char *gets_noreadline(char *prompt, FILE * source);
char *gets_readline(char *prompt, FILE * source);
char *gets_fromFile(char *prompt, FILE * source);
int listAllDbs(PsqlSettings * settings);
void
SendQuery(bool * success_p, PsqlSettings * settings, const char *query,
const bool copy_in, const bool copy_out, FILE * copystream);
int
HandleSlashCmds(PsqlSettings * settings,
char *line,
char *query);
int MainLoop(PsqlSettings *settings, FILE *source);
int MainLoop(PsqlSettings * settings, FILE * source);
/* probably should move this into libpq */
void PQprint(FILE *fp,
PGresult *res,
PQprintOpt *po
);
void
PQprint(FILE * fp,
PGresult * res,
PQprintOpt * po
);
FILE *setFout(PsqlSettings *ps, char *fname);
FILE *setFout(PsqlSettings * ps, char *fname);
/*
* usage
* print out usage for command line arguments
* usage print out usage for command line arguments
*/
static void
usage(char *progname)
{
fprintf(stderr,"Usage: %s [options] [dbname]\n",progname);
fprintf(stderr,"\t -a authsvc set authentication service\n");
fprintf(stderr,"\t -A turn off alignment when printing out attributes\n");
fprintf(stderr,"\t -c query run single query (slash commands too)\n");
fprintf(stderr,"\t -d dbName specify database name\n");
fprintf(stderr,"\t -e echo the query sent to the backend\n");
fprintf(stderr,"\t -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 -x turn on expanded output (field names on left)\n");
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 -x turn on expanded output (field names on left)\n");
exit(1);
}
/*
* slashUsage
* print out usage for the backslash commands
* slashUsage print out usage for the backslash commands
*/
static char *on(bool f)
static char *
on(bool f)
{
return f? "on": "off";
return f ? "on" : "off";
}
static void
slashUsage(PsqlSettings *ps)
slashUsage(PsqlSettings * ps)
{
fprintf(stderr,"\t \\? -- help\n");
fprintf(stderr,"\t \\a -- toggle field-alignment (currenty %s)\n", on(ps->opt.align));
fprintf(stderr,"\t \\C [<captn>] -- set html3 caption (currently '%s')\n", ps->opt.caption? ps->opt.caption: "");
fprintf(stderr,"\t \\connect <dbname> -- connect to new database (currently '%s')\n", PQdb(ps->db));
fprintf(stderr,"\t \\copy <dbname> -- copy table to/from a file\n");
fprintf(stderr,"\t \\d [<table>] -- list tables in database or columns in <table>,* for all\n");
fprintf(stderr,"\t \\e [<fname>] -- edit the current query buffer or <fname>,\\E execute too\n");
fprintf(stderr,"\t \\f [<sep>] -- change field separater (currently '%s')\n", ps->opt.fieldSep);
fprintf(stderr,"\t \\g [<fname>] -- send query to backend [and place results in <fname>]\n");
fprintf(stderr,"\t \\g |<cmd> -- send query to backend and pipe results into <cmd>\n");
fprintf(stderr,"\t \\h [<cmd>] -- help on syntax of sql commands, * for all commands\n");
fprintf(stderr,"\t \\H -- toggle html3 output (currently %s)\n", on(ps->opt.html3));
fprintf(stderr,"\t \\i <fname> -- read and execute queries from filename\n");
fprintf(stderr,"\t \\l -- list all databases\n");
fprintf(stderr,"\t \\m -- toggle monitor-like table display (currently %s)\n", on(ps->opt.standard));
fprintf(stderr,"\t \\o [<fname>] -- send all query results to <fname> or stdout\n");
fprintf(stderr,"\t \\o |<cmd> -- pipe all query results through <cmd>\n");
fprintf(stderr,"\t \\p -- print the current query buffer\n");
fprintf(stderr,"\t \\q -- quit\n");
fprintf(stderr,"\t \\r -- reset(clear) the query buffer\n");
fprintf(stderr,"\t \\s [<fname>] -- print history or save it in <fname>\n");
fprintf(stderr,"\t \\t -- toggle table headings and row count (currently %s)\n", on(ps->opt.header));
fprintf(stderr,"\t \\T [<html>] -- set html3.0 <table ...> options (currently '%s')\n", ps->opt.tableOpt? ps->opt.tableOpt: "");
fprintf(stderr,"\t \\x -- toggle expanded output (currently %s)\n", on(ps->opt.expanded));
fprintf(stderr,"\t \\! [<cmd>] -- shell escape or command\n");
fprintf(stderr, " \\? -- help\n");
fprintf(stderr, " \\a -- toggle field-alignment (currenty %s)\n", on(ps->opt.align));
fprintf(stderr, " \\C [<captn>] -- set html3 caption (currently '%s')\n", ps->opt.caption ? ps->opt.caption : "");
fprintf(stderr, " \\connect <dbname> -- connect to new database (currently '%s')\n", PQdb(ps->db));
fprintf(stderr, " \\copy <dbname> -- copy table to/from a file\n");
fprintf(stderr, " \\d [<table>] -- list tables in database or columns in <table>, * for all\n");
fprintf(stderr, " \\e [<fname>] -- edit the current query buffer or <fname>, \\E execute too\n");
fprintf(stderr, " \\f [<sep>] -- change field separater (currently '%s')\n", ps->opt.fieldSep);
fprintf(stderr, " \\g [<fname>] [|<cmd>] -- send query to backend [and results in <fname> or pipe]\n");
fprintf(stderr, " \\h [<cmd>] -- help on syntax of sql commands, * for all commands\n");
fprintf(stderr, " \\H -- toggle html3 output (currently %s)\n", on(ps->opt.html3));
fprintf(stderr, " \\i <fname> -- read and execute queries from filename\n");
fprintf(stderr, " \\l -- list all databases\n");
fprintf(stderr, " \\m -- toggle monitor-like table display (currently %s)\n", on(ps->opt.standard));
fprintf(stderr, " \\o [<fname>] [|<cmd>] -- send all query results to stdout, <fname>, or pipe\n");
fprintf(stderr, " \\p -- print the current query buffer\n");
fprintf(stderr, " \\q -- quit\n");
fprintf(stderr, " \\r -- reset(clear) the query buffer\n");
fprintf(stderr, " \\s [<fname>] -- print history or save it in <fname>\n");
fprintf(stderr, " \\t -- toggle table headings and row count (currently %s)\n", on(ps->opt.header));
fprintf(stderr, " \\T [<html>] -- set html3.0 <table ...> options (currently '%s')\n", ps->opt.tableOpt ? ps->opt.tableOpt : "");
fprintf(stderr, " \\x -- toggle expanded output (currently %s)\n", on(ps->opt.expanded));
fprintf(stderr, " \\! [<cmd>] -- shell escape or command\n");
}
static PGresult *
PSQLexec(PsqlSettings *ps, char *query)
PSQLexec(PsqlSettings * ps, char *query)
{
PGresult *res = PQexec(ps->db, query);
if (!res)
fputs(PQerrorMessage(ps->db), stderr);
else
{
if (PQresultStatus(res)==PGRES_COMMAND_OK ||
PQresultStatus(res)==PGRES_TUPLES_OK)
else {
if (PQresultStatus(res) == PGRES_COMMAND_OK ||
PQresultStatus(res) == PGRES_TUPLES_OK)
return res;
if (!ps->quiet)
fputs(PQerrorMessage(ps->db), stderr);
......@@ -179,22 +179,20 @@ PSQLexec(PsqlSettings *ps, char *query)
/*
* listAllDbs
*
* list all the databases in the system
* returns 0 if all went well
* list all the databases in the system returns 0 if all went well
*
*
*/
int
listAllDbs(PsqlSettings *ps)
listAllDbs(PsqlSettings * ps)
{
PGresult *results;
char *query = "select * from pg_database;";
if (!(results=PSQLexec(ps, query)))
if (!(results = PSQLexec(ps, query)))
return 1;
else
{
else {
PQprint(ps->queryFout,
results,
&ps->opt);
......@@ -204,13 +202,11 @@ listAllDbs(PsqlSettings *ps)
}
/*
*
* List The Database Tables
* returns 0 if all went well
* List The Database Tables returns 0 if all went well
*
*/
int
tableList (PsqlSettings *ps, bool deep_tablelist)
tableList(PsqlSettings * ps, bool deep_tablelist)
{
char listbuf[256];
int nColumns;
......@@ -221,70 +217,70 @@ tableList (PsqlSettings *ps, bool deep_tablelist)
PGresult *res;
listbuf[0] = '\0';
strcat(listbuf,"SELECT usename, relname, relkind, relhasrules");
strcat(listbuf," FROM pg_class, pg_user ");
strcat(listbuf,"WHERE ( relkind = 'r' OR relkind = 'i') ");
strcat(listbuf," and relname !~ '^pg_'");
strcat(listbuf," and relname !~ '^Inv[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)))
strcat(listbuf, "SELECT usename, relname, relkind, relhasrules");
strcat(listbuf, " FROM pg_class, pg_user ");
strcat(listbuf, "WHERE ( relkind = 'r' OR relkind = 'i') ");
strcat(listbuf, " and relname !~ '^pg_'");
strcat(listbuf, " and relname !~ '^Inv[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 ) {
if (nColumns > 0) {
if (deep_tablelist) {
/* describe everything here */
char **table;
table = (char**)malloc(nColumns * sizeof(char*));
if ( table == NULL )
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 )
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));
strcpy(table[i], PQgetvalue(res, i, 1));
}
PQclear(res);
for (i=0; i < nColumns; i++) {
for (i = 0; i < nColumns; i++) {
tableDesc(ps, table[i]);
}
free(table);
}
else {
} else {
/* Display the information */
printf ("\nDatabase = %s\n", PQdb(ps->db));
printf (" +------------------+----------------------------------+----------+\n");
printf (" | Owner | Relation | Type |\n");
printf (" +------------------+----------------------------------+----------+\n");
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);
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" );
printf("%-8.8s |", (rr[0] == 't') ? "view?" : "table");
else
printf ("%-8.8s |", "index");
printf("%-8.8s |", "index");
printf("\n");
}
printf (" +------------------+----------------------------------+----------+\n");
printf(" +------------------+----------------------------------+----------+\n");
PQclear(res);
}
return (0);
} else {
fprintf (stderr, "Couldn't find any tables!\n");
fprintf(stderr, "Couldn't find any tables!\n");
return (-1);
}
}
......@@ -292,13 +288,12 @@ tableList (PsqlSettings *ps, bool deep_tablelist)
/*
* Describe a table
*
* Describe the columns in a database table.
* returns 0 if all went well
* Describe the columns in a database table. returns 0 if all went well
*
*
*/
int
tableDesc (PsqlSettings *ps, char *table)
tableDesc(PsqlSettings * ps, char *table)
{
char descbuf[256];
int nColumns;
......@@ -311,97 +306,93 @@ tableDesc (PsqlSettings *ps, char *table)
/* Build the query */
descbuf[0] = '\0';
strcat(descbuf,"SELECT a.attnum, a.attname, t.typname, a.attlen");
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 ");
strcat(descbuf, "SELECT a.attnum, a.attname, t.typname, a.attlen");
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)
{
if (nColumns > 0) {
/*
** Display the information
* * Display the information
*/
printf ("\nTable = %s\n", table);
printf ("+----------------------------------+----------------------------------+-------+\n");
printf ("| Field | Type | Length|\n");
printf ("+----------------------------------+----------------------------------+-------+\n");
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));
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 {
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);
printf("%-32.32s |", rtype);
else {
char *newname;
newname = malloc(strlen(rtype) + 2);
strcpy(newname, rtype+1);
strcpy(newname, rtype + 1);
strcat(newname, "[]");
printf ("%-32.32s |", newname);
printf("%-32.32s |", newname);
free(newname);
}
if (rsize > 0)
printf ("%6i |", rsize);
printf("%6i |", rsize);
else
printf ("%6s |", "var");
printf("%6s |", "var");
}
printf("\n");
}
printf ("+----------------------------------+----------------------------------+-------+\n");
printf("+----------------------------------+----------------------------------+-------+\n");
PQclear(res);
return (0);
} else {
fprintf (stderr, "Couldn't find table %s!\n", table);
fprintf(stderr, "Couldn't find table %s!\n", table);
return (-1);
}
}
typedef char *(*READ_ROUTINE)(char *prompt, FILE *source);
typedef char *(*READ_ROUTINE) (char *prompt, FILE * source);
/* gets_noreadline prompt source
gets a line of input without calling readline, the source is ignored
*/
/*
* gets_noreadline prompt source gets a line of input without calling
* readline, the source is ignored
*/
char *
gets_noreadline(char *prompt, FILE *source)
gets_noreadline(char *prompt, FILE * source)
{
fputs(prompt, stdout);
fflush(stdout);
return(gets_fromFile(prompt,stdin));
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
* 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
*/
char *
gets_readline(char *prompt, FILE *source)
gets_readline(char *prompt, FILE * source)
{
return (readline(prompt));
}
......@@ -409,40 +400,38 @@ gets_readline(char *prompt, FILE *source)
/*
* gets_fromFile prompt source
*
* the routine to read from a file, the prompt argument is ignored
* the source argument is a FILE *
* the routine to read from a file, the prompt argument is ignored the source
* argument is a FILE *
*/
char *
gets_fromFile(char *prompt, FILE *source)
gets_fromFile(char *prompt, FILE * source)
{
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)
return NULL;
line[MAX_QUERY_BUFFER-1] = '\0';
line[MAX_QUERY_BUFFER - 1] = '\0';
len = strlen(line);
if (len == MAX_QUERY_BUFFER)
{
if (len == MAX_QUERY_BUFFER) {
fprintf(stderr, "line read exceeds maximum length. Truncating at %d\n",
MAX_QUERY_BUFFER);
}
return line;
}
/*
* SendQuery: send the query string to the backend
* return *success_p = 1 if the query executed successfully
* returns *success_p = 0 otherwise
* SendQuery: send the query string to the backend return *success_p = 1 if
* the query executed successfully returns *success_p = 0 otherwise
*/
void
SendQuery(bool *success_p, PsqlSettings *settings, const char *query,
const bool copy_in, const bool copy_out, FILE *copystream) {
SendQuery(bool * success_p, PsqlSettings * settings, const char *query,
const bool copy_in, const bool copy_out, FILE * copystream)
{
PGresult *results;
PGnotify *notify;
......@@ -452,34 +441,33 @@ SendQuery(bool *success_p, PsqlSettings *settings, const char *query,
"*****************************************\n");
if (settings->echoQuery || settings->singleStep) {
fprintf(stderr,"QUERY: %s\n",query);
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);
gets_fromFile("", stdin);
}
results = PQexec(settings->db, query);
if (results == NULL) {
fprintf(stderr,"%s",PQerrorMessage(settings->db));
fprintf(stderr, "%s", PQerrorMessage(settings->db));
*success_p = false;
} else {
switch (PQresultStatus(results)) {
case PGRES_TUPLES_OK:
if (settings->gfname) {
PsqlSettings ps=*settings;
PsqlSettings ps = *settings;
FILE *fp;
ps.queryFout=stdout;
fp=setFout(&ps, settings->gfname);
if (!fp || fp==stdout) {
ps.queryFout = stdout;
fp = setFout(&ps, settings->gfname);
if (!fp || fp == stdout) {
*success_p = false;
break;
} else *success_p = true;
} else
*success_p = true;
PQprint(fp,
results,
&(settings->opt));
......@@ -487,7 +475,7 @@ SendQuery(bool *success_p, PsqlSettings *settings, const char *query,
pclose(fp);
else
fclose(fp);
settings->gfname=NULL;
settings->gfname = NULL;
break;
} else {
*success_p = true;
......@@ -504,7 +492,7 @@ SendQuery(bool *success_p, PsqlSettings *settings, const char *query,
case PGRES_COMMAND_OK:
*success_p = true;
if (!settings->quiet)
fprintf(stdout,"%s\n", PQcmdStatus(results));
fprintf(stdout, "%s\n", PQcmdStatus(results));
break;
case PGRES_COPY_OUT:
*success_p = true;
......@@ -537,10 +525,17 @@ SendQuery(bool *success_p, PsqlSettings *settings, const char *query,
case PGRES_FATAL_ERROR:
case PGRES_BAD_RESPONSE:
*success_p = false;
fprintf(stderr,"%s",PQerrorMessage(settings->db));
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) {
......@@ -562,9 +557,8 @@ editFile(char *fname)
editorName = getenv("EDITOR");
if (!editorName)
editorName = DEFAULT_EDITOR;
sys=malloc(strlen(editorName)+strlen(fname)+32+1);
if (!sys)
{
sys = malloc(strlen(editorName) + strlen(fname) + 32 + 1);
if (!sys) {
perror("malloc");
exit(1);
}
......@@ -574,9 +568,9 @@ editFile(char *fname)
}
static bool
toggle(PsqlSettings *settings, bool *sw, char *msg)
toggle(PsqlSettings * settings, bool * sw, char *msg)
{
*sw= !*sw;
*sw = !*sw;
if (!settings->quiet)
fprintf(stderr, "turned %s %s\n", on(*sw), msg);
return *sw;
......@@ -585,20 +579,22 @@ toggle(PsqlSettings *settings, bool *sw, char *msg)
static void
unescape(char *dest, const char *source) {
/*-----------------------------------------------------------------------------
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 (/) */
bool esc; /* Last character we saw was the escape
* character (/) */
esc = false; /* Haven't seen escape character yet */
for (p = (char *)source; *p; p++) {
for (p = (char *) source; *p; p++) {
char c; /* Our output character */
if (esc) {
switch(*p) {
switch (*p) {
case 'n':
c = '\n';
break;
......@@ -618,15 +614,16 @@ unescape(char *dest, const char *source) {
c = *p;
}
esc = false;
} else
if (*p == '\\') {
} else if (*p == '\\') {
esc = true;
c = ' '; /* meaningless, but compiler doesn't know that */
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 */
}
......@@ -636,16 +633,18 @@ unescape(char *dest, const char *source) {
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) {
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.
/*
* 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';
work_args[sizeof(work_args) - 1] = '\0';
*error_p = false; /* initial assumption */
......@@ -655,15 +654,17 @@ parse_slash_copy(const char *args, char *table, const int table_len,
*error_p = true;
} else {
strncpy(table, table_tok, table_len);
file[table_len-1] = '\0';
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;
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 "
......@@ -681,7 +682,7 @@ parse_slash_copy(const char *args, char *table, const int table_len,
*error_p = true;
} else {
strncpy(file, file_tok, file_len);
file[file_len-1] = '\0';
file[file_len - 1] = '\0';
if (strtok(NULL, " ") != NULL) {
fprintf(stderr,
"You have extra tokens after the filename.\n");
......@@ -696,8 +697,9 @@ parse_slash_copy(const char *args, char *table, const int table_len,
static void
do_copy(const char *args, PsqlSettings *settings) {
/*---------------------------------------------------------------------------
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.
......@@ -705,14 +707,14 @@ do_copy(const char *args, PsqlSettings *settings) {
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];
char file[MAXPATHLEN + 1];
/* The pathname of the file from/to which we copy */
char table[NAMEDATALEN+1];
char table[NAMEDATALEN + 1];
/* The name of the table from/to which we copy */
bool syntax_error;
/* The \c command has invalid syntax */
......@@ -756,20 +758,21 @@ do_copy(const char *args, PsqlSettings *settings) {
static void
do_connect(const char *new_dbname, PsqlSettings *settings) {
do_connect(const char *new_dbname, PsqlSettings * settings)
{
char *dbname=PQdb(settings->db);
char *dbname = PQdb(settings->db);
if (!new_dbname)
fprintf(stderr,"\\connect must be followed by a database name\n");
fprintf(stderr, "\\connect must be followed by a database name\n");
else {
PGconn *olddb=settings->db;
PGconn *olddb = settings->db;
printf("closing connection to database: %s\n", dbname);
settings->db = PQsetdb(PQhost(olddb), PQport(olddb),
NULL, NULL, new_dbname);
printf("connecting to new database: %s\n", new_dbname);
if (PQstatus(settings->db) == CONNECTION_BAD) {
fprintf(stderr,"%s\n", PQerrorMessage(settings->db));
fprintf(stderr, "%s\n", PQerrorMessage(settings->db));
printf("reconnecting to %s\n", dbname);
settings->db = PQsetdb(PQhost(olddb), PQport(olddb),
NULL, NULL, dbname);
......@@ -782,14 +785,15 @@ do_connect(const char *new_dbname, PsqlSettings *settings) {
PQfinish(olddb);
free(settings->prompt);
settings->prompt = malloc(strlen(PQdb(settings->db)) + 10);
sprintf(settings->prompt,"%s=> ", PQdb(settings->db));
sprintf(settings->prompt, "%s=> ", PQdb(settings->db));
}
}
}
static void
do_edit(const char *filename_arg, char *query, int *retcode_p) {
do_edit(const char *filename_arg, char *query, int *status_p)
{
int fd;
char tmp[64];
......@@ -799,53 +803,55 @@ do_edit(const char *filename_arg, char *query, int *retcode_p) {
bool error;
if (filename_arg) {
fname=(char *)filename_arg;
error=false;
fname = (char *) filename_arg;
error = false;
} else {
sprintf(tmp, "/tmp/psql.%ld.%ld", (long)geteuid(), (long)getpid());
fname=tmp;
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) {
if ((fd = open(tmp, O_EXCL | O_CREAT | O_WRONLY, 0600)) == -1) {
perror(tmp);
error=true;
error = true;
} else {
if (query[ql-1] != '\n')
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;
error = true;
} else
error = false;
close(fd);
}
} else error=false;
} else
error = false;
}
if (error) *retcode_p=1;
if (error)
*status_p = 1;
else {
editFile(fname);
if ((fd=open(fname, O_RDONLY))==-1) {
if ((fd = open(fname, O_RDONLY)) == -1) {
perror(fname);
if (!filename_arg)
unlink(fname);
*retcode_p=1;
*status_p = 1;
} else {
if ((cc=read(fd, query, MAX_QUERY_BUFFER))==-1) {
if ((cc = read(fd, query, MAX_QUERY_BUFFER)) == -1) {
perror(fname);
close(fd);
if (!filename_arg)
unlink(fname);
*retcode_p=1;
*status_p = 1;
} else {
query[cc]='\0';
query[cc] = '\0';
close(fd);
if (!filename_arg)
unlink(fname);
rightTrim(query);
if (query[strlen(query)-1]==';') *retcode_p=0;
else *retcode_p=1;
*status_p = 3;
}
}
}
......@@ -854,18 +860,20 @@ do_edit(const char *filename_arg, char *query, int *retcode_p) {
static void
do_help(const char *topic) {
do_help(const char *topic)
{
if (!topic) {
char left_center_right; /* Which column we're displaying */
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 */
left_center_right = 'L';/* Start with left column */
i = 0;
while (QL_HELP[i].cmd != NULL) {
switch(left_center_right) {
switch (left_center_right) {
case 'L':
printf(" %-25s", QL_HELP[i].cmd);
left_center_right = 'C';
......@@ -881,18 +889,19 @@ do_help(const char *topic) {
};
i++;
}
if (left_center_right != 'L') puts("\n");
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 */
help_found = false; /* Haven't found it yet */
for (i=0; QL_HELP[i].cmd; i++) {
for (i = 0; QL_HELP[i].cmd; i++) {
if (strcmp(QL_HELP[i].cmd, topic) == 0 ||
strcmp(topic, "*") == 0 ) {
strcmp(topic, "*") == 0) {
help_found = true;
printf("Command: %s\n",QL_HELP[i].cmd);
printf("Command: %s\n", QL_HELP[i].cmd);
printf("Description: %s\n", QL_HELP[i].help);
printf("Syntax:\n");
printf("%s\n", QL_HELP[i].syntax);
......@@ -908,7 +917,8 @@ do_help(const char *topic) {
static void
do_shell(const char *command) {
do_shell(const char *command)
{
if (!command) {
char *sys;
......@@ -917,79 +927,83 @@ do_shell(const char *command) {
shellName = getenv("SHELL");
if (shellName == NULL)
shellName = DEFAULT_SHELL;
sys = malloc(strlen(shellName)+16);
sys = malloc(strlen(shellName) + 16);
if (!sys) {
perror("malloc");
exit(1);
}
sprintf(sys,"exec %s", shellName);
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
*/
* 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
*/
int
HandleSlashCmds(PsqlSettings *settings,
HandleSlashCmds(PsqlSettings * settings,
char *line,
char *query)
{
int status = 1;
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.
/*
* 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.
/*
* 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.
/*
* 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 */
unescape(cmd, line + 1); /* sets cmd string */
/* 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'".
/*
* 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;
if (strlen(cmd) > 1)
optarg = cmd + 1 + strspn(cmd + 1, " \t");
else
optarg = NULL;
blank_loc = strcspn(cmd, " \t");
if (blank_loc == 0) optarg2 = NULL;
else optarg2 = cmd + blank_loc + strspn(cmd+blank_loc, " \t");
if (blank_loc == 0)
optarg2 = NULL;
else
optarg2 = cmd + blank_loc + strspn(cmd + blank_loc, " \t");
switch (cmd[0])
{
switch (cmd[0]) {
case 'a': /* toggles to align fields on output */
toggle(settings, &settings->opt.align, "field alignment");
break;
......@@ -997,15 +1011,13 @@ HandleSlashCmds(PsqlSettings *settings,
if (settings->opt.caption)
free(settings->opt.caption);
if (!optarg)
settings->opt.caption=NULL;
else
if (!(settings->opt.caption=strdup(optarg)))
{
settings->opt.caption = NULL;
else if (!(settings->opt.caption = strdup(optarg))) {
perror("malloc");
exit(1);
}
break;
case 'c': {
case 'c':{
if (strncmp(cmd, "copy ", strlen("copy ")) == 0)
do_copy(optarg2, settings);
else if (strncmp(cmd, "connect ", strlen("connect ")) == 0)
......@@ -1019,11 +1031,10 @@ HandleSlashCmds(PsqlSettings *settings,
tableList(settings, 0);
break;
}
if (strcmp(optarg, "*") == 0 ) {
if (strcmp(optarg, "*") == 0) {
tableList(settings, 0);
tableList(settings, 1);
}
else {
} else {
tableDesc(settings, optarg);
}
break;
......@@ -1037,31 +1048,26 @@ HandleSlashCmds(PsqlSettings *settings,
FILE *fd;
static char *lastfile;
struct stat st, st2;
if (optarg)
{
if (optarg) {
if (lastfile)
free(lastfile);
lastfile=malloc(strlen(optarg+1));
if (!lastfile)
{
lastfile = malloc(strlen(optarg + 1));
if (!lastfile) {
perror("malloc");
exit(1);
}
strcpy(lastfile, optarg);
} else if (!lastfile)
{
fprintf(stderr,"\\r must be followed by a file name initially\n");
} 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))
{
if ((stat(lastfile, &st2) == -1) || ((fd = fopen(lastfile, "r")) == NULL)) {
perror(lastfile);
break;
}
if (st2.st_mtime==st.st_mtime)
{
if (st2.st_mtime == st.st_mtime) {
if (!settings->quiet)
fprintf(stderr, "warning: %s not modified. query not executed\n", lastfile);
fclose(fd);
......@@ -1073,13 +1079,12 @@ HandleSlashCmds(PsqlSettings *settings,
}
case 'f':
{
char *fs=DEFAULT_FIELD_SEP;
char *fs = DEFAULT_FIELD_SEP;
if (optarg)
fs=optarg;
fs = optarg;
if (settings->opt.fieldSep);
free(settings->opt.fieldSep);
if (!(settings->opt.fieldSep=strdup(fs)))
{
if (!(settings->opt.fieldSep = strdup(fs))) {
perror("malloc");
exit(1);
}
......@@ -1101,13 +1106,11 @@ HandleSlashCmds(PsqlSettings *settings,
FILE *fd;
if (!optarg) {
fprintf(stderr,"\\i must be followed by a file name\n");
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);
if ((fd = fopen(optarg, "r")) == NULL) {
fprintf(stderr, "file named %s could not be opened\n", optarg);
break;
}
MainLoop(settings, fd);
......@@ -1125,8 +1128,7 @@ HandleSlashCmds(PsqlSettings *settings,
setFout(settings, optarg);
break;
case 'p':
if (query)
{
if (query) {
fputs(query, stdout);
fputc('\n', stdout);
}
......@@ -1135,29 +1137,27 @@ HandleSlashCmds(PsqlSettings *settings,
status = 2;
break;
case 'r': /* reset(clear) the buffer */
query[0]='\0';
query[0] = '\0';
if (!settings->quiet)
fprintf(stderr, "buffer reset(cleared)\n");
break;
case 's': /* \s is save history to a file */
if (!optarg)
optarg="/dev/tty";
optarg = "/dev/tty";
if (write_history(optarg) != 0)
fprintf(stderr,"cannot write history to %s\n",optarg);
fprintf(stderr, "cannot write history to %s\n", optarg);
break;
case 'm': /* monitor like type-setting */
if (toggle(settings, &settings->opt.standard, "standard SQL separaters and padding"))
{
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;
free(settings->opt.fieldSep);
settings->opt.fieldSep=strdup("|");
settings->opt.fieldSep = strdup("|");
if (!settings->quiet)
fprintf(stderr, "field separater changed to '%s'\n", settings->opt.fieldSep);
} else
{
} else {
free(settings->opt.fieldSep);
settings->opt.fieldSep=strdup(DEFAULT_FIELD_SEP);
settings->opt.fieldSep = strdup(DEFAULT_FIELD_SEP);
if (!settings->quiet)
fprintf(stderr, "field separater changed to '%s'\n", settings->opt.fieldSep);
}
......@@ -1169,10 +1169,8 @@ HandleSlashCmds(PsqlSettings *settings,
if (settings->opt.tableOpt)
free(settings->opt.tableOpt);
if (!optarg)
settings->opt.tableOpt=NULL;
else
if (!(settings->opt.tableOpt=strdup(optarg)))
{
settings->opt.tableOpt = NULL;
else if (!(settings->opt.tableOpt = strdup(optarg))) {
perror("malloc");
exit(1);
}
......@@ -1193,37 +1191,41 @@ HandleSlashCmds(PsqlSettings *settings,
}
/*
MainLoop: main processing loop for reading lines of input
and sending them to the backend
this loop is re-entrant. May be called by \i command
which reads input from a file
*db_ptr must be initialized and set
*/
* MainLoop: main processing loop for reading lines of input and sending them
* to the backend
*
* this loop is re-entrant. May be called by \i command which reads input from
* a file
*
* db_ptr must be initialized and set
*/
int
MainLoop(PsqlSettings *settings, FILE *source)
MainLoop(PsqlSettings * settings, FILE * source)
{
char *line; /* line of input */
int len; /* length of the line */
char query[MAX_QUERY_BUFFER]; /* multi-line query storage */
int exitStatus = 0;
int successResult = 1;
int slashCmdStatus = 0;
/* slashCmdStatus can be:
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
/*
* slashCmdStatus can be: 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
*/
bool sendQuery = 0;
bool querySent = 0;
bool querySent = false;
bool interactive;
READ_ROUTINE GetNextLine;
bool connected = 1;
/* We are connected to the backend (last time we looked) */
bool eof = 0;
/* We've reached the end of our command input. */
bool success;
bool in_quote;
bool was_bslash; /* backslash */
bool was_dash;
int paren_level;
char *query_start;
interactive = ((source == stdin) && !settings->notty);
#define PROMPT "=> "
......@@ -1235,73 +1237,126 @@ MainLoop(PsqlSettings *settings, FILE *source)
if (settings->quiet)
settings->prompt[0] = '\0';
else
sprintf(settings->prompt,"%s%s", PQdb(settings->db), PROMPT);
sprintf(settings->prompt, "%s%s", PQdb(settings->db), PROMPT);
if (settings->useReadline) {
using_history();
GetNextLine = gets_readline;
} else GetNextLine = gets_noreadline;
} else GetNextLine = gets_fromFile;
} else
GetNextLine = gets_noreadline;
} else
GetNextLine = gets_fromFile;
query[0] = '\0';
in_quote = false;
paren_level = 0;
slashCmdStatus = -1; /* set default */
/* main loop for getting queries and executing them */
while (connected && !eof) {
while (!eof) {
if (slashCmdStatus == 3) {
line = strdup(query);
query[0] = '\0';
} else {
line = GetNextLine(settings->prompt, source);
if (interactive && settings->useReadline && line != NULL)
add_history(line); /* save non-empty lines in history */
}
query_start = line;
if (line == NULL) { /* No more input. Time to quit */
printf("EOF\n"); /* Goes on prompt line */
eof = true;
} else {
exitStatus = 0;
line = rightTrim(line);
if (!interactive && !settings->singleStep && !settings->quiet)
fprintf(stderr, "%s\n", line);
/* remove whitespaces on the right, incl. \n's */
line = rightTrim(line);
if (line[0] == '\0') {
free(line);
continue;
}
/* filter out comment lines that begin with --,
this could be incorrect if -- is part of a quoted string.
But we won't go through the trouble of detecting that.
If you have -- in your quoted string, be careful and don't
start a line with it
*/
if (line[0] == '-' && line[1] == '-') {
if (settings->singleStep)
/* in single step mode, show comments */
fprintf(stdout,"%s\n",line);
free(line);
continue;
}
if (line[0] != '\\' && querySent) {
query[0]='\0';
querySent = 0;
}
len = strlen(line);
if (interactive && settings->useReadline)
add_history(line); /* save non-empty lines in history */
if (settings->singleLineMode) {
SendQuery(&success, settings, line, false, false, 0);
successResult &= success;
querySent = true;
} else {
int i;
was_bslash = false;
was_dash = false;
/* do the query immediately if we are doing single line queries
or if the last character is a semicolon
*/
sendQuery = settings->singleLineMode || (line[len-1] == ';') ;
for (i = 0; i < len; i++) {
if (!in_quote && line[i] == '\\') {
char hold_char = line[i];
/* normally, \ commands have to be start the line,
but for backwards compatibility with monitor,
check for \g at the end of line */
if (len > 2 && !sendQuery) {
if (line[len-1]=='g' && line[len-2]=='\\') {
sendQuery = 1;
line[len-2]='\0';
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 */
}
if (querySent && !isspace(line[i])) {
query[0] = '\0';
querySent = false;
}
if (!in_quote && was_dash && line[i] == '-') {
/* print comment at top of query */
if (settings->singleStep)
fprintf(stdout, "%s\n", line + i - 1);
line[i - 1] = '\0'; /* remove comment */
break;
}
was_dash = false;
if (!in_quote && !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;
}
if (was_bslash)
was_bslash = false;
else if (line[i] == '\\')
was_bslash = true;
else if (line[i] == '\'')
in_quote ^= 1;
else if (!in_quote && line[i] == '(')
paren_level++;
else if (!in_quote && paren_level && line[i] == ')')
paren_level--;
else if (!in_quote && line[i] == '-')
was_dash = true;
}
}
slashCmdStatus = -1;
/* slash commands have to be on their own line */
if (line[0] == '\\') {
if (!in_quote && query_start[0] == '\\') {
slashCmdStatus = HandleSlashCmds(settings,
line,
query_start,
query);
if (slashCmdStatus == 1) {
free(line);
......@@ -1311,45 +1366,32 @@ MainLoop(PsqlSettings *settings, FILE *source)
free(line);
break;
}
if (slashCmdStatus == 0)
sendQuery = 1;
} else if (strlen(query) + len > MAX_QUERY_BUFFER) {
fprintf(stderr,"query buffer max length of %d exceeded\n",
} 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");
} else if (query[0]!='\0') {
strcat(query,"\n");
strcat(query,line);
} else strcpy(query,line);
if (sendQuery && query[0] != '\0') {
/* echo the line read from the file,
unless we are in single_step mode, because single_step mode
will echo anyway
*/
bool success; /* The query succeeded at the backend */
if (!interactive && !settings->singleStep && !settings->quiet)
fprintf(stderr,"%s\n", query);
fprintf(stderr, "query line ignored\n");
} else {
if (query_start[0] != '\0') {
querySent = false;
if (query[0] != '\0') {
strcat(query, "\n");
strcat(query, query_start);
} else
strcpy(query, query_start);
}
}
if (slashCmdStatus == 0) {
SendQuery(&success, settings, query, false, false, 0);
exitStatus = success ? 0 : 1;
querySent = 1;
if (PQstatus(settings->db) == CONNECTION_BAD) {
connected = 0;
fprintf(stderr,
"We have lost the connection to the backend, so "
"further processing is impossible. "
"Terminating.\n");
}
successResult &= success;
querySent = true;
}
free(line); /* free storage malloc'd by GetNextLine */
}
} /* while */
return exitStatus;
return successResult;
}
int
main(int argc, char **argv)
{
......@@ -1366,8 +1408,8 @@ main(int argc, char **argv)
char *singleQuery = NULL;
bool listDatabases = 0 ;
int exitStatus = 0;
bool listDatabases = 0;
int successResult = 1;
bool singleSlashCmd = 0;
int c;
......@@ -1375,7 +1417,7 @@ main(int argc, char **argv)
settings.opt.align = 1;
settings.opt.header = 1;
settings.queryFout = stdout;
settings.opt.fieldSep=strdup(DEFAULT_FIELD_SEP);
settings.opt.fieldSep = strdup(DEFAULT_FIELD_SEP);
settings.opt.pager = 1;
if (!isatty(0) || !isatty(1))
settings.quiet = settings.notty = 1;
......@@ -1394,8 +1436,8 @@ main(int argc, char **argv)
break;
case 'c':
singleQuery = optarg;
if ( singleQuery[0] == '\\' ) {
singleSlashCmd=1;
if (singleQuery[0] == '\\') {
singleSlashCmd = 1;
}
break;
case 'd':
......@@ -1408,7 +1450,7 @@ main(int argc, char **argv)
qfilename = optarg;
break;
case 'F':
settings.opt.fieldSep=optarg;
settings.opt.fieldSep = optarg;
break;
case 'l':
listDatabases = 1;
......@@ -1462,14 +1504,13 @@ main(int argc, char **argv)
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));
fprintf(stderr, "Connection to database '%s' failed.\n", dbname);
fprintf(stderr, "%s", PQerrorMessage(settings.db));
exit(1);
}
if (listDatabases) {
exit(listAllDbs(&settings));
}
if (!settings.quiet && !singleQuery && !qfilename) {
printf("Welcome to the POSTGRES95 interactive sql monitor:\n");
printf(" Please read the file COPYRIGHT for copyright terms "
......@@ -1479,37 +1520,40 @@ main(int argc, char **argv)
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 */
/*
* read in a file full of queries instead of reading in queries
* interactively
*/
char *line;
if ( singleSlashCmd ) {
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);
sprintf(line, "\\i %s", qfilename);
}
HandleSlashCmds(&settings, line, "");
} else {
if (singleQuery) {
bool success; /* The query succeeded at the backend */
SendQuery(&success, &settings, singleQuery, false, false, 0);
exitStatus = success ? 0 : 1;
} else exitStatus = MainLoop(&settings, stdin);
successResult = success;
} else
successResult = MainLoop(&settings, stdin);
}
PQfinish(settings.db);
return exitStatus;
return !successResult;
}
#define COPYBUFSIZ 8192
static void
handleCopyOut(PGresult *res, bool quiet, FILE *copystream) {
handleCopyOut(PGresult * res, bool quiet, FILE * copystream)
{
bool copydone;
char copybuf[COPYBUFSIZ];
int ret;
......@@ -1521,14 +1565,14 @@ handleCopyOut(PGresult *res, bool quiet, FILE *copystream) {
if (copybuf[0] == '\\' &&
copybuf[1] == '.' &&
copybuf[2] =='\0') {
copybuf[2] == '\0') {
copydone = true; /* don't print this... */
} else {
fputs(copybuf, copystream);
switch (ret) {
case EOF:
copydone = true;
/*FALLTHROUGH*/
/* FALLTHROUGH */
case 0:
fputc('\n', copystream);
break;
......@@ -1544,7 +1588,8 @@ handleCopyOut(PGresult *res, bool quiet, FILE *copystream) {
static void
handleCopyIn(PGresult *res, const bool mustprompt, FILE *copystream) {
handleCopyIn(PGresult * res, const bool mustprompt, FILE * copystream)
{
bool copydone = false;
bool firstload;
bool linedone;
......@@ -1558,7 +1603,6 @@ handleCopyIn(PGresult *res, const bool mustprompt, FILE *copystream) {
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);
......@@ -1595,14 +1639,14 @@ handleCopyIn(PGresult *res, const bool mustprompt, FILE *copystream) {
/* try to open fname and return a FILE *,
if it fails, use stdout, instead */
/*
* try to open fname and return a FILE *, if it fails, use stdout, instead
*/
FILE *
setFout(PsqlSettings *ps, char *fname)
setFout(PsqlSettings * ps, char *fname)
{
if (ps->queryFout && ps->queryFout != stdout)
{
if (ps->queryFout && ps->queryFout != stdout) {
if (ps->pipe)
pclose(ps->queryFout);
else
......@@ -1610,16 +1654,12 @@ setFout(PsqlSettings *ps, char *fname)
}
if (!fname)
ps->queryFout = stdout;
else
{
if (*fname == '|')
{
else {
if (*fname == '|') {
signal(SIGPIPE, SIG_IGN);
ps->queryFout = popen(fname+1, "w");
ps->queryFout = popen(fname + 1, "w");
ps->pipe = 1;
}
else
{
} else {
ps->queryFout = fopen(fname, "w");
ps->pipe = 0;
}
......
......@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/bin/psql/stringutils.c,v 1.4 1996/09/16 06:06:17 scrappy Exp $
* $Header: /cvsroot/pgsql/src/bin/psql/stringutils.c,v 1.5 1996/11/14 16:08:05 momjian Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -19,8 +19,11 @@
/* all routines assume null-terminated strings! */
/* removes whitespaces from the left, right and both sides of a string */
/* The following routines remove whitespaces from the left, right
and both sides of a string */
/* MODIFIES the string passed in and returns the head of it */
char *leftTrim(char *s)
{
char *s2 = s;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment