diff --git a/src/bin/Makefile b/src/bin/Makefile index 67ed0b86ad..d3cfd5a3ab 100644 --- a/src/bin/Makefile +++ b/src/bin/Makefile @@ -7,24 +7,29 @@ # # # IDENTIFICATION -# $Header: /cvsroot/pgsql/src/bin/Makefile,v 1.1.1.1 1996/07/09 06:22:11 scrappy Exp $ +# $Header: /cvsroot/pgsql/src/bin/Makefile,v 1.2 1996/07/23 03:01:58 scrappy Exp $ # #------------------------------------------------------------------------- +MKDIR=../mk +-include $(MKDIR)/../Makefile.global + # # C programs # SUBDIR= monitor pg_id pg_version psql pg_dump +# +# Shell scripts +# +SUBDIR+= cleardbdir createdb createuser destroydb destroyuser initdb + +# +# TCL/TK programs +# ifeq ($(USE_TCL), true) SUBDIR += pgtclsh endif -# -# Shell scripts -# -SUBDIR+= cleardbdir createdb createuser destroydb destroyuser initdb - - -include ../mk/postgres.subdir.mk +include $(MKDIR)/postgres.subdir.mk diff --git a/src/bin/initdb/initdb.sh b/src/bin/initdb/initdb.sh index 4c15592608..dfdcc60862 100644 --- a/src/bin/initdb/initdb.sh +++ b/src/bin/initdb/initdb.sh @@ -12,7 +12,7 @@ # # # IDENTIFICATION -# $Header: /cvsroot/pgsql/src/bin/initdb/Attic/initdb.sh,v 1.3 1996/07/20 07:33:36 scrappy Exp $ +# $Header: /cvsroot/pgsql/src/bin/initdb/Attic/initdb.sh,v 1.4 1996/07/23 03:03:19 scrappy Exp $ # #------------------------------------------------------------------------- @@ -33,10 +33,6 @@ FILESDIR=$PGDATA/files PATH=$BINDIR:$PATH export PATH -# OPENLINK Added an fsync option to postmaster -# REQUIRES: pg95 compiled with -DOPENLINK_PATCHES, see README_OPENLINK -# FSYNC=-F - CMDNAME=`basename $0` # ---------------- @@ -63,9 +59,9 @@ done # ---------------- if test "$debug" -eq 1 then - BACKENDARGS="-boot -C $FSYNC -d" + BACKENDARGS="-boot -C -F -d" else - BACKENDARGS="-boot -C $FSYNC -Q" + BACKENDARGS="-boot -C -F -Q" fi @@ -220,9 +216,7 @@ then echo "vacuuming template1" fi - echo "vacuum" | postgres $FSYNC -Q template1 > /dev/null + echo "vacuum" | postgres -F -Q template1 > /dev/null fi rm -f /tmp/create.$$ - -sync diff --git a/src/bin/monitor/monitor.c b/src/bin/monitor/monitor.c index 21812898d9..7770b00ddc 100644 --- a/src/bin/monitor/monitor.c +++ b/src/bin/monitor/monitor.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/bin/monitor/Attic/monitor.c,v 1.4 1996/07/23 02:26:41 scrappy Exp $ + * $Header: /cvsroot/pgsql/src/bin/monitor/Attic/monitor.c,v 1.5 1996/07/23 03:03:24 scrappy Exp $ * *------------------------------------------------------------------------- */ @@ -20,7 +20,7 @@ #ifndef WIN32 #include #endif -#ifdef PORTNAME_sparc_solaris +#if defined(PORTNAME_sparc_solaris) || defined(PORTNAME_i386_solaris) #include /* for MAXHOSTNAMELEN on some */ #endif #include diff --git a/src/bin/pg4_dump/common.c b/src/bin/pg4_dump/common.c index f485c152c6..da66dc6929 100644 --- a/src/bin/pg4_dump/common.c +++ b/src/bin/pg4_dump/common.c @@ -16,7 +16,7 @@ #include #include #include /* for MAXHOSTNAMELEN on most */ -#ifdef PORTNAME_sparc_solaris +#if defined(PORTNAME_sparc_solaris) || defined(PORTNAME_i386_solaris) #include /* for MAXHOSTNAMELEN on some */ #endif diff --git a/src/bin/pg4_dump/pg4_dump.c b/src/bin/pg4_dump/pg4_dump.c index 6e6ee6fa57..a7f54004dc 100644 --- a/src/bin/pg4_dump/pg4_dump.c +++ b/src/bin/pg4_dump/pg4_dump.c @@ -28,7 +28,7 @@ #include #include #include /* for MAXHOSTNAMELEN on most */ -#ifdef PORTNAME_sparc_solaris +#if defined(PORTNAME_sparc_solaris) || defined(PORTNAME_i386_solaris) #include /* for MAXHOSTNAMELEN on some */ #endif diff --git a/src/bin/pgtclsh/Makefile b/src/bin/pgtclsh/Makefile index a99ab39f08..0e80d3b831 100644 --- a/src/bin/pgtclsh/Makefile +++ b/src/bin/pgtclsh/Makefile @@ -7,7 +7,7 @@ # # # IDENTIFICATION -# $Header: /cvsroot/pgsql/src/bin/pgtclsh/Attic/Makefile,v 1.1.1.1 1996/07/09 06:22:15 scrappy Exp $ +# $Header: /cvsroot/pgsql/src/bin/pgtclsh/Attic/Makefile,v 1.2 1996/07/23 03:03:36 scrappy Exp $ # #------------------------------------------------------------------------- @@ -15,7 +15,7 @@ MKDIR= ../../mk include $(MKDIR)/postgres.mk include ../Makefile.global -CFLAGS+= -I$(TCL_INCDIR) -I$(TK_INCDIR) +CFLAGS+= -I$(TCL_INCDIR) -I$(TK_INCDIR) -I$(X11_INCDIR) -I$(srcdir)/libpgtcl # try to find libpgtcl.a in either directory LIBPGTCL= -L$(srcdir)/libpgtcl/$(objdir) -L$(LIBDIR) -lpgtcl @@ -26,7 +26,7 @@ pgtclsh: $(objdir)/pgtclAppInit.o pgtksh: $(objdir)/pgtkAppInit.o $(CC) $(CDEBUG) -o $(objdir)/$(@F) $(objdir)/pgtkAppInit.o \ - $(LIBPGTCL) $(LIBPQ) -L$(TCL_LIBDIR) -L$(TK_LIBDIR) \ + $(LIBPGTCL) $(LIBPQ) -L$(TCL_LIBDIR) -L$(TK_LIBDIR) -L$(X11_LIBDIR) \ $(TK_LIB) $(TCL_LIB) -lX11 -lm $(LD_ADD) install:: localobj pgtclsh pgtksh diff --git a/src/bin/pgtclsh/pgtclAppInit.c b/src/bin/pgtclsh/pgtclAppInit.c index cc38ca34a7..a4ee17a032 100644 --- a/src/bin/pgtclsh/pgtclAppInit.c +++ b/src/bin/pgtclsh/pgtclAppInit.c @@ -109,6 +109,11 @@ Tcl_AppInit(interp) * then no user-specific startup file will be run under any conditions. */ +#if (TCL_MAJOR_VERSION <= 7) && (TCL_MINOR_VERSION < 5) tcl_RcFileName = "~/.tclshrc"; +#else + Tcl_SetVar(interp, "tcl_rcFileName", "~/.tclshrc", TCL_GLOBAL_ONLY); +#endif + return TCL_OK; } diff --git a/src/bin/pgtclsh/pgtkAppInit.c b/src/bin/pgtclsh/pgtkAppInit.c index 33763458b5..044b6790da 100644 --- a/src/bin/pgtclsh/pgtkAppInit.c +++ b/src/bin/pgtclsh/pgtkAppInit.c @@ -112,6 +112,11 @@ Tcl_AppInit(interp) * then no user-specific startup file will be run under any conditions. */ +#if (TCL_MAJOR_VERSION <= 7) && (TCL_MINOR_VERSION < 5) tcl_RcFileName = "~/.wishrc"; +#else + Tcl_SetVar(interp, "tcl_rcFileName", "~/.wishrc", TCL_GLOBAL_ONLY); +#endif + return TCL_OK; } diff --git a/src/bin/psql/psql.c b/src/bin/psql/psql.c index 4e33ed79df..2201c06426 100644 --- a/src/bin/psql/psql.c +++ b/src/bin/psql/psql.c @@ -7,7 +7,7 @@ * * * 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 $ * *------------------------------------------------------------------------- */ @@ -16,8 +16,8 @@ #include #include #include -#include #include + #include "libpq-fe.h" #include "stringutils.h" @@ -32,57 +32,52 @@ extern char *readline(char *); /* in rlstubs.c */ #include "history.h" #else #include -#include +#include #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 @@ -94,24 +89,22 @@ 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 -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); } @@ -120,60 +113,29 @@ usage(char* progname) * 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 [] -- set html3 caption (currently '%s')\n", ps->opt.caption? ps->opt.caption: ""); - fprintf(stderr,"\t \\C -- 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 [] -- list tables in database or columns in
\n"); fprintf(stderr,"\t \\d * -- list tables in database and columns in all tables\n"); fprintf(stderr,"\t \\e [] -- edit the current query buffer or \n"); - fprintf(stderr,"\t \\f [] -- change field separater (currently '%s')\n", ps->opt.fieldSep); - fprintf(stderr,"\t \\g [] -- send query to backend [and place results in ]\n"); - fprintf(stderr,"\t \\g | -- send query to backend and pipe results into \n"); - fprintf(stderr,"\t \\h [] -- help on syntax of sql commands\n"); + fprintf(stderr,"\t \\f -- change field separator\n"); + fprintf(stderr,"\t \\g -- query to backend\n"); + fprintf(stderr,"\t \\h -- 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 -- read and execute queries from filename\n"); + fprintf(stderr,"\t \\g -- send query to backend\n"); + fprintf(stderr,"\t \\i -- read queries from filename\n"); fprintf(stderr,"\t \\l -- list all databases\n"); - fprintf(stderr,"\t \\o [] -- send query results to or stdout\n"); - fprintf(stderr,"\t \\o | -- pipe query results through \n"); + fprintf(stderr,"\t \\o [] -- send query results file named or stdout\n"); fprintf(stderr,"\t \\p -- print the current query buffer\n"); fprintf(stderr,"\t \\q -- quit\n"); - fprintf(stderr,"\t \\r [] -- edit then send contents to backend\n"); - fprintf(stderr,"\t \\s [] -- print history or save it in \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 [] -- set html3.0
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 \\! [] -- shell escape or command\n"); + fprintf(stderr,"\t \\s [] -- save or print history\n"); + fprintf(stderr,"\t \\t -- toggle output field headers (defaults to on)\n"); + fprintf(stderr,"\t \\! [] -- 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 * @@ -182,37 +144,50 @@ PSQLexec(PsqlSettings *ps, char *query) * * */ - -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; @@ -228,8 +203,17 @@ tableList (PsqlSettings *ps, bool deep_tablelist) 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); @@ -252,14 +236,14 @@ tableList (PsqlSettings *ps, bool deep_tablelist) 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"); @@ -288,7 +272,7 @@ tableList (PsqlSettings *ps, bool deep_tablelist) } /* - * Describe a table + * Describe a table (PGconn* conn, char* table) * * Describe the columns in a database table. * returns 0 if all went well @@ -296,7 +280,7 @@ tableList (PsqlSettings *ps, bool deep_tablelist) * */ int -tableDesc (PsqlSettings *ps, char *table) +tableDesc (PGconn* conn, char* table) { char descbuf[256]; int nColumns; @@ -318,8 +302,16 @@ tableDesc (PsqlSettings *ps, char *table) 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) @@ -329,9 +321,9 @@ tableDesc (PsqlSettings *ps, char *table) */ 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++) { @@ -340,15 +332,15 @@ tableDesc (PsqlSettings *ps, char *table) 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 */ @@ -363,13 +355,13 @@ tableDesc (PsqlSettings *ps, char *table) 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); @@ -404,6 +396,7 @@ gets_readline(char* prompt, FILE* source) return (readline(prompt)); } + /* * gets_fromFile prompt source * @@ -433,12 +426,14 @@ gets_fromFile(char* prompt, FILE* 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; @@ -459,41 +454,20 @@ SendQuery(PsqlSettings *settings, char *query) 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: @@ -501,7 +475,7 @@ SendQuery(PsqlSettings *settings, char *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); @@ -513,12 +487,13 @@ SendQuery(PsqlSettings *settings, char *query) 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); @@ -529,71 +504,6 @@ SendQuery(PsqlSettings *settings, char *query) } -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: @@ -609,161 +519,189 @@ decode(char *s) 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"); + 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': /* 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); - } - 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 'g': /* \g means send query */ - settings->gfname = optarg; - status = 0; + case 'f': + if (optarg) + strcpy(settings->fieldSep,optarg); + else + strcpy(settings->fieldSep,DEFAULT_FIELD_SEP); break; + case 'g': /* \g means send query */ + status = 0; + 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; @@ -789,7 +727,7 @@ HandleSlashCmds(PsqlSettings *settings, numCmds = numCmds - 1; - if (strcmp(cmd, "*") == 0 ) { + if ( strcmp(cmd,"*") == 0 ) { all_help=1; } @@ -810,143 +748,74 @@ HandleSlashCmds(PsqlSettings *settings, 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; - } - 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; - } + query[0] = '\0'; + status = 1; + 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); - 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
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); + { + char* fname; + + if (!optarg) { + fprintf(stderr,"\\s must be followed by a file name\n"); + status = 1; + break; } - 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; + + fname = optarg; + if (write_history(fname) != 0) + { + fprintf(stderr,"cannot write history to %s\n",fname); + } + status = 1; + break; + } + case 't': + if ( settings->printHeader ) + settings->printHeader = 0; + else + settings->printHeader = 1; + if (!settings->quiet) + 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; @@ -961,14 +830,19 @@ HandleSlashCmds(PsqlSettings *settings, *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) @@ -976,21 +850,18 @@ MainLoop(PsqlSettings *settings, FILE* source) 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; @@ -1004,7 +875,7 @@ MainLoop(PsqlSettings *settings, FILE* source) 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 */ @@ -1024,11 +895,6 @@ MainLoop(PsqlSettings *settings, FILE* source) free(line); continue; } - if (line[0] != '\\' && querySent) - { - query[0]='\0'; - querySent = 0; - } len = strlen(line); @@ -1037,31 +903,34 @@ MainLoop(PsqlSettings *settings, FILE* source) /* 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) @@ -1077,29 +946,30 @@ MainLoop(PsqlSettings *settings, FILE* source) 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; @@ -1110,27 +980,31 @@ main(int argc, char** argv) 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); @@ -1151,23 +1025,20 @@ main(int argc, char** argv) 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': + case 'H': host = optarg; break; - case 'H': - settings.opt.html3 = 1; - 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; @@ -1180,15 +1051,10 @@ main(int argc, char** argv) 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; @@ -1201,16 +1067,16 @@ main(int argc, char** argv) 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) { @@ -1226,6 +1092,7 @@ main(int argc, char** argv) /* 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." */ @@ -1235,25 +1102,24 @@ main(int argc, char** argv) 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]; @@ -1287,7 +1153,7 @@ handleCopyOut(PGresult *res, bool quiet) static void -handleCopyIn(PGresult *res, bool quiet) +handleCopyIn(PGresult *res, int quiet) { bool copydone = false; bool firstload; @@ -1346,38 +1212,24 @@ handleCopyIn(PGresult *res, bool quiet) 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; } +