*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/bin/psql/Attic/psql.c,v 1.5 1996/07/20 08:44:45 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/bin/psql/Attic/psql.c,v 1.6 1996/07/23 03:03:43 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
-#include <unistd.h>
#include <fcntl.h>
+
#include "libpq-fe.h"
#include "stringutils.h"
#include "history.h"
#else
#include <readline/readline.h>
-#include <readline/history.h>
+#include <history.h>
#endif
#endif
#define MAX_QUERY_BUFFER 20000
+#define MAX_FIELD_SEP_LENGTH 40
#define COPYBUFSIZ 8192
-#define DEFAULT_FIELD_SEP "|"
+#define DEFAULT_FIELD_SEP " "
#define DEFAULT_EDITOR "vi"
#define DEFAULT_SHELL "/bin/sh"
typedef struct _psqlSettings {
- PGconn *db; /* connection to backend */
- FILE *queryFout; /* where to send the query results */
- PQprintOpt opt; /* options to be passed to PQprint */
- char *prompt; /* prompt to display */
- char *gfname; /* one-shot file output argument for \g */
- bool notty; /* input or output is not a tty */
- bool pipe; /* queryFout is from a popen() */
- bool echoQuery; /* echo the query before sending it */
- bool 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 */
+ int echoQuery; /* if 1, echo the query before sending it */
+ int quiet; /* run quietly, no messages, no promt */
+ int singleStep; /* if 1, prompt for each query */
+ int singleLineMode; /* if 1, query terminated by newline */
+ int useReadline; /* use the readline routines or not */
+ int printHeader; /* print output field headers or not */
+ int fillAlign; /* fill align the fields */
+ FILE *queryFout; /* where to send the query results */
+ char fieldSep[MAX_FIELD_SEP_LENGTH]; /* field separator */
} PsqlSettings;
/* declarations for functions in this file */
static void usage(char* progname);
static void slashUsage();
-static void handleCopyOut(PGresult *res, bool quiet);
-static void handleCopyIn(PGresult *res, bool quiet);
-static int tableList(PsqlSettings *ps, bool deep_tablelist);
-static int tableDesc(PsqlSettings *ps, char *table);
+static void handleCopyOut(PGresult *res, int quiet);
+static void handleCopyIn(PGresult *res, int quiet);
+static int tableList(PGconn* conn, int deep_tablelist);
+static int tableDesc(PGconn* conn, 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);
-int SendQuery(PsqlSettings *settings, char* query);
-int HandleSlashCmds(PsqlSettings *settings,
+int listAllDbs(PGconn *db, PsqlSettings *settings);
+int SendQuery(PGconn* db, char* query, PsqlSettings *settings);
+int HandleSlashCmds(PGconn** db_ptr,
char *line,
- char *query);
-int MainLoop(PsqlSettings *settings, FILE *source);
-/* probably should move this into libpq */
-void PQprint(FILE *fp,
- PGresult *res,
- PQprintOpt *po
- );
+ char** prompt_ptr,
+ char *query,
+ PsqlSettings *settings);
+int MainLoop(PGconn** db_ptr, FILE *source, PsqlSettings *settings);
+FILE* setFout(char *fname);
-FILE* setFout(PsqlSettings *ps, char *fname);
/*
* usage
{
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 -A turn off fill-justification 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 -h help information\n");
+ fprintf(stderr,"\t -H host set database server host\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 -o filename send output to filename\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 attribute headers\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)");
+ fprintf(stderr,"\t -T turn off printing of attribute names\n");
exit(1);
}
* print out usage for the backslash commands
*/
-char *on(bool f)
-{
- return f? "on": "off";
-}
-
static void
-slashUsage(PsqlSettings *ps)
+slashUsage()
{
- 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 \\C <dbname> -- connect to new database (currently '%s')\n", PQdb(ps->db));
+ fprintf(stderr,"\t \\a -- toggle fill-justification of display of attributes\n");
fprintf(stderr,"\t \\d [<table>] -- list tables in database or columns in <table>\n");
fprintf(stderr,"\t \\d * -- list tables in database and columns in all tables\n");
fprintf(stderr,"\t \\e [<fname>] -- edit the current query buffer or <fname>\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\n");
+ fprintf(stderr,"\t \\f <sep> -- change field separator\n");
+ fprintf(stderr,"\t \\g -- query to backend\n");
+ fprintf(stderr,"\t \\h <command> -- help on syntax of sql commands\n");
fprintf(stderr,"\t \\h * -- complete description of all sql 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 \\g -- send query to backend\n");
+ fprintf(stderr,"\t \\i <fname> -- read queries from filename\n");
fprintf(stderr,"\t \\l -- list all databases\n");
- fprintf(stderr,"\t \\o [<fname>] -- send query results to <fname> or stdout\n");
- fprintf(stderr,"\t \\o |<cmd> -- pipe query results through <cmd>\n");
+ fprintf(stderr,"\t \\o [<fname>] -- send query results file named <fname> or stdout\n");
fprintf(stderr,"\t \\p -- print the current query buffer\n");
fprintf(stderr,"\t \\q -- quit\n");
- fprintf(stderr,"\t \\r [<fname>] -- edit <fname> then send contents to backend\n");
- fprintf(stderr,"\t \\s [<fname>] -- print history or save it in <fname>\n");
- fprintf(stderr,"\t \\S -- toggle standard sql type-setting (currently %s)\n", on(ps->opt.standard));
- fprintf(stderr,"\t \\t -- toggle table output header (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 \\z -- zorch current query buffer (i.e clear it)\n");
- fprintf(stderr,"\t \\! [<cmd>] -- shell escape or command\n");
+ fprintf(stderr,"\t \\s [<fname>] -- save or print history\n");
+ fprintf(stderr,"\t \\t -- toggle output field headers (defaults to on)\n");
+ fprintf(stderr,"\t \\! [<cmd>] -- shell escape\n");
fprintf(stderr,"\t \\? -- help\n");
}
-PGresult *
-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)
- return res;
- if (!ps->quiet)
- fputs(PQerrorMessage(ps->db), stderr);
- PQclear(res);
- }
- return NULL;
-}
/*
* listAllDbs
*
*
*
*/
-
-int
-listAllDbs(PsqlSettings *ps)
+int
+listAllDbs(PGconn *db, PsqlSettings *settings)
{
PGresult *results;
char* query = "select * from pg_database;";
- if (!(results=PSQLexec(ps, query)))
+ results = PQexec(db, query);
+ if (results == NULL) {
+ fprintf(stderr,"%s", PQerrorMessage(db));
return 1;
+ }
+
+ if (PQresultStatus(results) != PGRES_TUPLES_OK)
+ {
+ fprintf(stderr,"Unexpected error from executing: %s\n", query);
+ return 2;
+ }
else
{
- PQprint(ps->queryFout,
- results,
- &ps->opt);
+ PQdisplayTuples(results,
+ settings->queryFout,
+ settings->fillAlign,
+ settings->fieldSep,
+ settings->printHeader,
+ settings->quiet);
PQclear(results);
return 0;
}
}
/*
+ * tableList (PGconn* conn)
*
* List The Database Tables
* returns 0 if all went well
*
*/
int
-tableList (PsqlSettings *ps, bool deep_tablelist)
+tableList (PGconn* conn, int deep_tablelist)
{
char listbuf[256];
int nColumns;
int i;
+ char* ru;
char* rk;
char* rr;
add in the int4oideq function */
strcat(listbuf," and usesysid = relowner");
strcat(listbuf," ORDER BY relname ");
- if (!(res=PSQLexec(ps, listbuf)))
- return -1;
+ res = PQexec(conn,listbuf);
+ if (res == NULL) {
+ fprintf(stderr,"%s", PQerrorMessage(conn));
+ return (-1);
+ }
+
+ if ((PQresultStatus(res) != PGRES_TUPLES_OK) || (PQntuples(res) <= 0)) {
+ fprintf(stderr,"No tables found in database %s.\n", PQdb(conn));
+ PQclear(res);
+ return (-1);
+ }
/* first, print out the attribute names */
nColumns = PQntuples(res);
PQclear(res);
for (i=0; i < nColumns; i++) {
- tableDesc(ps, table[i]);
+ tableDesc(conn,table[i]);
}
free(table);
}
else {
/* Display the information */
- printf ("\nDatabase = %s\n", PQdb(ps->db));
+ printf ("\nDatabase = %s\n", PQdb(conn));
printf (" +------------------+----------------------------------+----------+\n");
printf (" | Owner | Relation | Type |\n");
printf (" +------------------+----------------------------------+----------+\n");
}
/*
- * Describe a table
+ * Describe a table (PGconn* conn, char* table)
*
* Describe the columns in a database table.
* returns 0 if all went well
*
*/
int
-tableDesc (PsqlSettings *ps, char *table)
+tableDesc (PGconn* conn, char* table)
{
char descbuf[256];
int nColumns;
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;
+ res = PQexec(conn,descbuf);
+ if (res == NULL) {
+ fprintf(stderr,"%s", PQerrorMessage(conn));
+ return (-1);
+ }
+ if ((PQresultStatus(res) != PGRES_TUPLES_OK) || (PQntuples(res) <= 0)) {
+ fprintf(stderr,"Couldn't find table %s!\n", table);
+ PQclear(res);
+ 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");
+ printf ("+----------------------------------+----------------------------------+-------+\n");
+ printf ("| Field | Type | Length|\n");
+ printf ("+----------------------------------+----------------------------------+-------+\n");
/* next, print out the instances */
for (i=0; i < PQntuples(res); i++) {
rsize = atoi(PQgetvalue(res,i,3));
if (strcmp(rtype, "text") == 0) {
printf ("%-32.32s |", rtype);
- printf ("%6s |", "var" );
+ printf ("%-6s |", "var" );
}
else if (strcmp(rtype, "bpchar") == 0) {
printf ("%-32.32s |", "char");
- printf ("%6i |", rsize > 0 ? rsize - 4 : 0 );
+ printf ("%-6i |", rsize > 0 ? rsize - 4 : 0 );
}
else if (strcmp(rtype, "varchar") == 0) {
printf ("%-32.32s |", rtype);
- printf ("%6i |", rsize > 0 ? rsize - 4 : 0 );
+ printf ("%-6i |", rsize > 0 ? rsize - 4 : 0 );
}
else {
/* array types start with an underscore */
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);
return (readline(prompt));
}
+
/*
* gets_fromFile prompt source
*
}
/*
- * SendQuery: send the query string to the backend
+ * SendQuery:
+ SendQuery: send the query string to the backend
+ *
* return 0 if the query executed successfully
* returns 1 otherwise
*/
int
-SendQuery(PsqlSettings *settings, char *query)
+SendQuery(PGconn* db, char* query, PsqlSettings *settings)
{
PGresult* results;
PGnotify* notify;
gets_fromFile("",stdin);
}
- results = PQexec(settings->db, query);
+ results = PQexec(db, query);
if (results == NULL) {
- fprintf(stderr,"%s",PQerrorMessage(settings->db));
+ fprintf(stderr,"%s",PQerrorMessage(db));
return 1;
}
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)
- {
- status = 1;
- break;
- }
- PQprint(fp,
- results,
- &(settings->opt));
- if (ps.pipe)
- pclose(fp);
- else
- fclose(fp);
- settings->gfname=NULL;
- break;
- } else
- {
- PQprint(settings->queryFout,
- results,
- &(settings->opt));
- fflush(settings->queryFout);
- }
+ PQdisplayTuples(results,
+ settings->queryFout,
+ settings->fillAlign,
+ settings->fieldSep,
+ settings->printHeader,
+ settings->quiet);
PQclear(results);
break;
case PGRES_EMPTY_QUERY:
break;
case PGRES_COMMAND_OK:
if (!settings->quiet)
- fprintf(stdout,"%s\n", PQcmdStatus(results));
+ fprintf(stdout,"%s\n",PQcmdStatus(results));
break;
case PGRES_COPY_OUT:
handleCopyOut(results, settings->quiet);
case PGRES_FATAL_ERROR:
case PGRES_BAD_RESPONSE:
status = 1;
- fprintf(stderr,"%s",PQerrorMessage(settings->db));
+ fprintf(stderr,"%s",PQerrorMessage(db));
break;
+
}
/* check for asynchronous returns */
- notify = PQnotifies(settings->db);
+ notify = PQnotifies(db);
if (notify) {
fprintf(stderr,"ASYNC NOTIFY of '%s' from backend pid '%d' received\n",
notify->relname, notify->be_pid);
}
-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);
-}
-
-bool
-toggle(PsqlSettings *settings, bool *sw, char *msg)
-{
- *sw= !*sw;
- if (!settings->quiet)
- fprintf(stderr, "turned %s %s\n", on(*sw), msg);
- return *sw;
-}
-
-char *
-decode(char *s)
-{
- char *p, *d;
- bool esc=0;
- for (d=p=s; *p; p++)
- {
- char c=*p;
- if (esc)
- {
- switch(*p)
- {
- case 'n':
- c='\n';
- break;
- case 'r':
- c='\r';
- break;
- case 't':
- c='\t';
- break;
- case 'f':
- c='\f';
- break;
- }
- esc=0;
- } else
- if (c=='\\')
- {
- esc=1;
- continue;
- }
- *d++=c;
- }
- *d='\0';
-}
-
/*
HandleSlashCmds:
2 - terminate processing of this query entirely
*/
int
-HandleSlashCmds(PsqlSettings *settings,
+HandleSlashCmds(PGconn** db_ptr,
char* line,
- char *query)
+ char** prompt_ptr,
+ char *query,
+ PsqlSettings *settings)
{
- int status = 1;
+ int status = 0;
+ PGconn* db = *db_ptr;
+ char* dbname = PQdb(db);
char *optarg = NULL;
int len;
len = strlen(line);
if (len > 2)
- {
optarg = leftTrim(line+2);
- decode(optarg);
- }
switch (line[1])
{
- 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);
- if (!optarg)
- settings->opt.caption=NULL;
- else
- if (!(settings->opt.caption=dupstr(optarg)))
- {
- perror("malloc");
- exit(1);
- }
+ case 'a': /* toggles to fill fields on output */
+ if (settings->fillAlign)
+ settings->fillAlign = 0;
+ else
+ settings->fillAlign = 1;
+ if (!settings->quiet)
+ fprintf(stderr,"turning %s fill-justification\n",
+ (settings->fillAlign) ? "on" : "off" );
break;
- case 'C': /* \C means connect to new database */
+ case 'c': /* \c means connect to new database */
{
- char *dbname=PQdb(settings->db);
if (!optarg) {
fprintf(stderr,"\\c must be followed by a database name\n");
+ status = 1;
break;
}
- {
- PGconn *olddb=settings->db;
+ if (strcmp(optarg, dbname) == 0) {
+ fprintf(stderr,"already connected to %s\n", dbname);
+ status = 1;
+ break;
+ }
+ else {
+ PGconn *olddb;
- printf("closing connection to database: %s\n", dbname);
- settings->db = PQsetdb(PQhost(olddb), PQport(olddb), NULL, NULL, optarg);
+ printf("closing connection to database:%s\n", dbname);
+ olddb = db;
+ db = PQsetdb(PQhost(olddb), PQport(olddb), NULL, NULL, optarg);
+ *db_ptr = db;
printf("connecting to new database: %s\n", optarg);
- if (PQstatus(settings->db) == CONNECTION_BAD) {
- fprintf(stderr,"%s\n", PQerrorMessage(settings->db));
+ if (PQstatus(db) == CONNECTION_BAD) {
+ fprintf(stderr,"%s\n", PQerrorMessage(db));
printf("reconnecting to %s\n", dbname);
- settings->db = PQsetdb(PQhost(olddb), PQport(olddb),
+ db = PQsetdb(PQhost(olddb), PQport(olddb),
NULL, NULL, dbname);
- if (PQstatus(settings->db) == CONNECTION_BAD) {
+ *db_ptr = db;
+ if (PQstatus(db) == CONNECTION_BAD) {
fprintf(stderr,
- "could not reconnect to %s. exiting\n", dbname);
+ "could not reconnect to %s. exiting\n", dbname);
exit(2);
}
+ status = 1;
break;
}
PQfinish(olddb);
- free(settings->prompt);
- settings->prompt = malloc(strlen(PQdb(settings->db)) + 10);
- sprintf(settings->prompt,"%s=> ", PQdb(settings->db));
+ free(*prompt_ptr);
+ *prompt_ptr = malloc(strlen(optarg) + 10);
+ sprintf(*prompt_ptr,"%s=> ", optarg);
+ status = 1;
break;
}
}
break;
case 'd': /* \d describe tables or columns in a table */
+ {
if (!optarg) {
- tableList(settings, 0);
+ tableList(db,0);
+ status = 1;
break;
- }
- if (strcmp(optarg, "*") == 0 ) {
- tableList(settings, 0);
- tableList(settings, 1);
+ }
+ if ( strcmp(optarg,"*") == 0 ) {
+ tableList(db, 0);
+ tableList(db, 1);
}
else {
- tableDesc(settings, optarg);
+ tableDesc(db,optarg);
}
+ status = 1;
break;
+ }
case 'e':
{
+ char s[256];
int fd;
- char tmp[64];
- char *fname;
- int cc;
int ql = strlen(query);
+ int f_arg = 0;
+ int cc;
if (optarg)
- fname=optarg;
+ {
+ f_arg = 1;
+ strcpy(s, optarg);
+ }
else
- {
- sprintf(tmp, "/tmp/psql.%d.%d", getuid(), getpid());
- fname=tmp;
- unlink(tmp);
+ {
+ sprintf(s, "/tmp/psql.%d.%d", geteuid(), getpid());
+ unlink(s);
if (ql)
{
- if ((fd=open(tmp, O_EXCL|O_CREAT|O_WRONLY, 0600))==-1)
+ if ((fd=open(s, O_EXCL|O_CREAT|O_WRONLY, 0600))==-1)
{
- perror(tmp);
+ perror(s);
break;
}
if (query[ql-1]!='\n')
strcat(query, "\n");
if (write(fd, query, ql)!=ql)
{
- perror(tmp);
+ perror(s);
close(fd);
- unlink(tmp);
+ unlink(s);
break;
}
close(fd);
}
}
- editFile(fname);
- if ((fd=open(fname, O_RDONLY))==-1)
{
- perror(fname);
- if (!optarg)
- unlink(fname);
+ char sys[256];
+ char *editorName;
+ editorName = getenv("EDITOR");
+ if (editorName == NULL)
+ editorName = DEFAULT_EDITOR;
+ sprintf(sys, "exec %s %s", editorName, s);
+ system(sys);
+ }
+ if ((fd=open(s, O_RDONLY))==-1)
+ {
+ if (!f_arg)
+ unlink(s);
break;
}
if ((cc=read(fd, query, MAX_QUERY_BUFFER))==-1)
{
- perror(fname);
+ perror(s);
close(fd);
- if (!optarg)
- unlink(fname);
+ if (!f_arg)
+ unlink(s);
break;
}
query[cc]='\0';
close(fd);
- if (!optarg)
- unlink(fname);
+ if (!f_arg)
+ unlink(s);
rightTrim(query);
if (query[strlen(query)-1]==';')
return 0;
break;
}
- case 'f':
- {
- char *fs=DEFAULT_FIELD_SEP;
- if (optarg)
- fs=optarg;
- if (settings->opt.fieldSep);
- free(settings->opt.fieldSep);
- if (!(settings->opt.fieldSep=dupstr(fs)))
- {
- perror("malloc");
- exit(1);
- }
- if (!settings->quiet)
- fprintf(stderr, "field separater changed to '%s'\n", settings->opt.fieldSep);
- break;
- }
+ case 'f':
+ if (optarg)
+ strcpy(settings->fieldSep,optarg);
+ else
+ strcpy(settings->fieldSep,DEFAULT_FIELD_SEP);
+ break;
case 'g': /* \g means send query */
- settings->gfname = optarg;
status = 0;
- break;
+ break;
+ case 'i': /* \i is include file */
+ {
+ FILE* fd;
+
+ if (!optarg) {
+ fprintf(stderr,"\\i must be followed by a file name\n");
+ status = 1;
+ break;
+ }
+
+ if ( (fd = fopen(optarg, "r")) == NULL)
+ {
+ fprintf(stderr,"file named %s could not be opened\n",optarg);
+ status = 1;
+ break;
+ }
+ MainLoop(&db, fd, settings);
+ fclose(fd);
+ status = 1;
+ break;
+ }
case 'h':
{
char* cmd;
numCmds = numCmds - 1;
- if (strcmp(cmd, "*") == 0 ) {
+ if ( strcmp(cmd,"*") == 0 ) {
all_help=1;
}
if (i == numCmds && ! all_help)
printf("command not found, try \\h with no arguments to see available help\n");
}
+ status = 1;
break;
}
- case 'i': /* \i is include file */
- {
- FILE* fd;
-
- 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;
- case 'H':
- if (toggle(settings, &settings->opt.html3, "HTML3.0 tablular output"))
- settings->opt.standard = 0;
+ listAllDbs(db,settings);
+ status = 1;
break;
case 'o':
- setFout(settings, optarg);
+ settings->queryFout = setFout(optarg);
break;
case 'p':
if (query) {
fputs(query, stdout);
fputc('\n', stdout);
+ status = 1;
}
break;
case 'q': /* \q is quit */
status = 2;
break;
case 'r':
- {
- 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(1);
- }
- strcpy(lastfile, optarg);
- } else
- if (!lastfile) {
- fprintf(stderr, "\\r must be followed by a file name initially\n");
- break;
+ query[0] = '\0';
+ status = 1;
+ break;
+ case 's': /* \s is save history to a file */
+ {
+ char* fname;
+
+ if (!optarg) {
+ fprintf(stderr,"\\s must be followed by a file name\n");
+ status = 1;
+ 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);
+
+ fname = optarg;
+ if (write_history(fname) != 0)
+ {
+ fprintf(stderr,"cannot write history to %s\n",fname);
+ }
+ status = 1;
break;
- }
- MainLoop(settings, fd);
- fclose(fd);
- break;
}
- case 's': /* \s is save history to a file */
- if (!optarg) optarg="/dev/tty";
- if (write_history(optarg) != 0)
- fprintf(stderr,"cannot write history to %s\n",optarg);
- break;
- case 'S': /* standard SQL output */
- 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=dupstr("|");
- if (!settings->quiet)
- fprintf(stderr, "field separater changed to '%s'\n",
- settings->opt.fieldSep);
- } else {
- free(settings->opt.fieldSep);
- settings->opt.fieldSep=dupstr(DEFAULT_FIELD_SEP);
+ case 't':
+ if ( settings->printHeader )
+ settings->printHeader = 0;
+ else
+ settings->printHeader = 1;
if (!settings->quiet)
- fprintf(stderr, "field separater changed to '%s'\n",
- settings->opt.fieldSep);
- }
- break;
- case 't': /* toggle headers */
- toggle(settings, &settings->opt.header, "output headers");
- 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=dupstr(optarg))) {
- perror("malloc");
- exit(1);
- }
- break;
- case 'x':
- toggle(settings, &settings->opt.expanded,
- "expanded table representation");
- break;
- case 'z': /* zorch buffer */
- query[0]='\0';
- if (!settings->quiet) fprintf(stderr, "zorched current query buffer\n");
- break;
+ fprintf(stderr,"turning %s printing of field headers\n",
+ (settings->printHeader) ? "on" : "off" );
+ break;
case '!':
if (!optarg) {
- char *sys;
- char *shellName;
- shellName = getenv("SHELL");
- if (shellName == NULL) shellName = DEFAULT_SHELL;
- sys = malloc(strlen(shellName)+16);
- if (!sys) {
- perror("malloc");
- exit(1);
- }
- sprintf(sys,"exec %s", shellName);
- system(sys);
- free(sys);
- } else system(optarg);
+ char sys[256];
+ char *shellName;
+ shellName = getenv("SHELL");
+ if (shellName == NULL)
+ shellName = DEFAULT_SHELL;
+ sprintf(sys,"exec %s", shellName);
+ system(sys);
+ }
+ else
+ system(optarg);
break;
default:
case '?': /* \? is help */
- slashUsage(settings);
+ slashUsage();
+ status = 1;
break;
}
return status;
*db_ptr must be initialized and set
*/
-
int
-MainLoop(PsqlSettings *settings, FILE* source)
+MainLoop(PGconn** db_ptr,
+ FILE* source,
+ PsqlSettings *settings)
{
+ char* prompt; /* readline prompt */
char* line; /* line of input*/
int len; /* length of the line */
char query[MAX_QUERY_BUFFER]; /* multi-line query storage */
+ PGconn* db = *db_ptr;
+ char* dbname = PQdb(db);
int exitStatus = 0;
+
int slashCmdStatus = 0;
/* slashCmdStatus can be:
0 - send currently constructed query to backend (i.e. we got a \g)
2 - terminate processing of this query entirely
*/
- bool sendQuery = 0;
- bool querySent = 0;
- bool interactive;
+ int send_query = 0;
+ int interactive;
READ_ROUTINE GetNextLine;
- interactive = ((source == stdin) && !settings->notty);
-#define PROMPT "=> "
+ interactive = (source == stdin);
+
if (interactive) {
- if (settings->prompt)
- free(settings->prompt);
- settings->prompt = malloc(strlen(PQdb(settings->db)) + strlen(PROMPT) + 1);
+ prompt = malloc(strlen(dbname) + 10);
if (settings->quiet)
- settings->prompt[0] = '\0';
+ prompt[0] = '\0';
else
- sprintf(settings->prompt,"%s%s", PQdb(settings->db), PROMPT);
+ sprintf(prompt,"%s=> ", dbname);
if (settings->useReadline) {
using_history();
GetNextLine = gets_readline;
query[0] = '\0';
/* main loop for getting queries and executing them */
- while ((line = GetNextLine(settings->prompt, source)) != NULL)
+ while ((line = GetNextLine(prompt, source)) != NULL)
{
exitStatus = 0;
line = rightTrim(line); /* remove whitespaces on the right, incl. \n's */
free(line);
continue;
}
- if (line[0] != '\\' && querySent)
- {
- query[0]='\0';
- querySent = 0;
- }
len = strlen(line);
/* 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] == ';') ;
+ send_query = settings->singleLineMode || (line[len-1] == ';') ;
/* 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 (len > 2 && !send_query)
{
if (line[len-1]=='g' && line[len-2]=='\\')
{
- sendQuery = 1;
+ send_query = 1;
line[len-2]='\0';
}
}
/* slash commands have to be on their own line */
if (line[0] == '\\') {
- slashCmdStatus = HandleSlashCmds(settings,
+ slashCmdStatus = HandleSlashCmds(db_ptr,
line,
- query);
+ &prompt,
+ query,
+ settings);
+ db = *db_ptr; /* in case \c changed the database */
if (slashCmdStatus == 1)
continue;
if (slashCmdStatus == 2)
break;
if (slashCmdStatus == 0)
- sendQuery = 1;
+ send_query = 1;
}
else
if (strlen(query) + len > MAX_QUERY_BUFFER)
else
strcpy(query,line);
- if (sendQuery && query[0] != '\0')
+ if (send_query && query[0] != '\0')
{
/* echo the line read from the file,
unless we are in single_step mode, because single_step mode
will echo anyway */
- if (!interactive && !settings->singleStep && !settings->quiet)
- fprintf(stderr,"%s\n", query);
+ if (!interactive && !settings->singleStep)
+ fprintf(stderr,"%s\n",query);
- exitStatus = SendQuery(settings, query);
- querySent = 1;
+ exitStatus = SendQuery(db, query, settings);
+ query[0] = '\0';
}
free(line); /* free storage malloc'd by GetNextLine */
} /* while */
- return exitStatus;
+ return exitStatus;
}
int
main(int argc, char** argv)
{
extern char* optarg;
- extern int optind;
+ extern int optind, opterr;
+ PGconn *db;
char* dbname = NULL;
char* host = NULL;
char* port = NULL;
char* singleQuery = NULL;
- bool listDatabases = 0 ;
+ int listDatabases = 0 ;
int exitStatus = 0;
- bool singleSlashCmd = 0;
+ int singleSlashCmd = 0;
int c;
- memset(&settings, 0, sizeof settings);
- settings.opt.align = 1;
- settings.opt.header = 1;
- settings.queryFout = stdout;
- settings.opt.fieldSep=dupstr(DEFAULT_FIELD_SEP);
- if (!isatty(0) || !isatty(1))
- settings.quiet = settings.notty = 1;
- else
-#ifndef NOREADLINE
- settings.useReadline = 1;
+
+#ifdef NOREADLINE
+ settings.useReadline = 0;
+#else
+ settings.useReadline = 1;
#endif
- while ((c = getopt(argc, argv, "Aa:c:d:ef:F:lhH:nso:p:qStTx")) != EOF) {
+ settings.quiet = 0;
+ settings.fillAlign = 1;
+ settings.printHeader = 1;
+ settings.echoQuery = 0;
+ settings.singleStep = 0;
+ settings.singleLineMode = 0;
+ settings.queryFout = stdout;
+ strcpy(settings.fieldSep, DEFAULT_FIELD_SEP);
+
+ while ((c = getopt(argc, argv, "Aa:c:d:ef:F:lhH:nso:p:qST")) != EOF) {
switch (c) {
case 'A':
- settings.opt.align = 0;
+ settings.fillAlign = 0;
break;
case 'a':
fe_setauthsvc(optarg, errbuf);
qfilename = optarg;
break;
case 'F':
- settings.opt.fieldSep=dupstr(optarg);
- break;
+ strncpy(settings.fieldSep,optarg,MAX_FIELD_SEP_LENGTH);
+ break;
case 'l':
listDatabases = 1;
break;
- case 'h':
- host = optarg;
- break;
case 'H':
- settings.opt.html3 = 1;
+ host = optarg;
break;
case 'n':
- settings.useReadline = 0;
- break;
+ settings.useReadline = 0;
+ break;
case 'o':
- setFout(&settings, optarg);
- break;
+ settings.queryFout = setFout(optarg);
+ break;
case 'p':
port = optarg;
break;
case 'S':
settings.singleLineMode = 1;
break;
- case 't':
- settings.opt.header = 0;
- break;
case 'T':
- settings.opt.tableOpt = dupstr(optarg);
- break;
- case 'x':
- settings.opt.expanded = 0;
- break;
+ settings.printHeader = 0;
+ break;
+ case 'h':
default:
usage(argv[0]);
break;
if (listDatabases)
dbname = "template1";
- settings.db = PQsetdb(host, port, NULL, NULL, dbname);
- dbname = PQdb(settings.db);
+ db = PQsetdb(host, port, NULL, NULL, dbname);
+ dbname = PQdb(db);
- if (PQstatus(settings.db) == CONNECTION_BAD) {
+ if (PQstatus(db) == CONNECTION_BAD) {
fprintf(stderr,"Connection to database '%s' failed.\n", dbname);
- fprintf(stderr,"%s",PQerrorMessage(settings.db));
+ fprintf(stderr,"%s",PQerrorMessage(db));
exit(1);
}
if (listDatabases) {
- exit(listAllDbs(&settings));
+ exit(listAllDbs(db,&settings));
}
if (!settings.quiet && !singleQuery && !qfilename) {
/* read in a file full of queries instead of reading in queries
interactively */
char *line;
+ char prompt[100];
if ( singleSlashCmd ) {
/* Not really a query, but "Do what I mean, not what I say." */
line = malloc(strlen(qfilename) + 5);
sprintf(line,"\\i %s", qfilename);
}
- HandleSlashCmds(&settings, line, "");
+ HandleSlashCmds(&db, line, (char**)prompt, "", &settings);
} else {
if (singleQuery) {
- exitStatus = SendQuery(&settings, singleQuery);
+ exitStatus = SendQuery(db, singleQuery, &settings);
}
else
- exitStatus = MainLoop(&settings, stdin);
+ exitStatus = MainLoop(&db, stdin, &settings);
}
- PQfinish(settings.db);
+ PQfinish(db);
return exitStatus;
}
-#define COPYBUFSIZ 8192
static void
-handleCopyOut(PGresult *res, bool quiet)
+handleCopyOut(PGresult *res, int quiet)
{
bool copydone = false;
char copybuf[COPYBUFSIZ];
static void
-handleCopyIn(PGresult *res, bool quiet)
+handleCopyIn(PGresult *res, int quiet)
{
bool copydone = false;
bool firstload;
PQendcopy(res->conn);
}
+
/* try to open fname and return a FILE*,
if it fails, use stdout, instead */
-
FILE*
-setFout(PsqlSettings *ps, char *fname)
+setFout(char *fname)
{
- if (ps->queryFout && ps->queryFout != stdout)
- {
- if (ps->pipe)
- pclose(ps->queryFout);
- else
- fclose(ps->queryFout);
+ FILE *queryFout;
+
+ if (!fname)
+ queryFout = stdout;
+ else {
+ queryFout = fopen(fname, "w");
+ if (!queryFout) {
+ perror(fname);
+ queryFout = stdout;
}
- if (!fname)
- ps->queryFout = stdout;
- else
- {
- if (*fname == '|')
- {
- signal(SIGPIPE, SIG_IGN);
- ps->queryFout = popen(fname+1, "w");
- ps->pipe = 1;
- }
- else
- {
- ps->queryFout = fopen(fname, "w");
- ps->pipe = 0;
- }
- if (!ps->queryFout) {
- perror(fname);
- ps->queryFout = stdout;
- }
- }
- return ps->queryFout;
+ }
+
+ return queryFout;
}
+