*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/bin/psql/Attic/psql.c,v 1.3 1996/07/16 06:58:12 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/bin/psql/Attic/psql.c,v 1.4 1996/07/18 05:48:40 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 <history.h>
+#include <readline/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 {
- 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 */
+ 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 */
} PsqlSettings;
/* declarations for functions in this file */
static void usage(char* progname);
static void slashUsage();
-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);
+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);
char* gets_noreadline(char* prompt, FILE* source);
char* gets_readline(char* prompt, FILE* source);
char* gets_fromFile(char* prompt, FILE* source);
-int listAllDbs(PGconn *db, PsqlSettings *settings);
-int SendQuery(PGconn* db, char* query, PsqlSettings *settings);
-int HandleSlashCmds(PGconn** db_ptr,
+int listAllDbs(PsqlSettings *settings);
+int SendQuery(PsqlSettings *settings, char* query);
+int HandleSlashCmds(PsqlSettings *settings,
char *line,
- char** prompt_ptr,
- char *query,
- PsqlSettings *settings);
-int MainLoop(PGconn** db_ptr, FILE *source, PsqlSettings *settings);
-FILE* setFout(char *fname);
+ char *query);
+int MainLoop(PsqlSettings *settings, FILE *source);
+/* probably should move this into libpq */
+void PQprint(FILE *fp,
+ PGresult *res,
+ PQprintOpt *po
+ );
+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 fill-justification when printing out attributes\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 help information\n");
- fprintf(stderr,"\t -H host set database server host\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\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 attribute names\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)");
exit(1);
}
* print out usage for the backslash commands
*/
+char *on(bool f)
+{
+ return f? "on": "off";
+}
+
static void
-slashUsage()
+slashUsage(PsqlSettings *ps)
{
- fprintf(stderr,"\t \\a -- toggle fill-justification of display of attributes\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 \\C <dbname> -- connect to new database (currently '%s')\n", PQdb(ps->db));
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 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 \\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 \\h * -- complete description of all sql commands\n");
- fprintf(stderr,"\t \\g -- send query to backend\n");
- fprintf(stderr,"\t \\i <fname> -- read queries from filename\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 \\o [<fname>] -- send query results file named <fname> or stdout\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 \\p -- print the current query buffer\n");
fprintf(stderr,"\t \\q -- quit\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 \\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 \\? -- 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(PGconn *db, PsqlSettings *settings)
+
+int
+listAllDbs(PsqlSettings *ps)
{
PGresult *results;
char* query = "select * from pg_database;";
- results = PQexec(db, query);
- if (results == NULL) {
- fprintf(stderr,"%s", PQerrorMessage(db));
+ if (!(results=PSQLexec(ps, query)))
return 1;
- }
-
- if (PQresultStatus(results) != PGRES_TUPLES_OK)
- {
- fprintf(stderr,"Unexpected error from executing: %s\n", query);
- return 2;
- }
else
{
- PQdisplayTuples(results,
- settings->queryFout,
- settings->fillAlign,
- settings->fieldSep,
- settings->printHeader,
- settings->quiet);
+ PQprint(ps->queryFout,
+ results,
+ &ps->opt);
PQclear(results);
return 0;
}
}
/*
- * tableList (PGconn* conn)
*
* List The Database Tables
* returns 0 if all went well
*
*/
int
-tableList (PGconn* conn, int deep_tablelist)
+tableList (PsqlSettings *ps, bool 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 ");
- 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);
- }
+ if (!(res=PSQLexec(ps, listbuf)))
+ return -1;
/* first, print out the attribute names */
nColumns = PQntuples(res);
PQclear(res);
for (i=0; i < nColumns; i++) {
- tableDesc(conn,table[i]);
+ tableDesc(ps, table[i]);
}
free(table);
}
else {
/* Display the information */
- printf ("\nDatabase = %s\n", PQdb(conn));
+ printf ("\nDatabase = %s\n", PQdb(ps->db));
printf (" +------------------+----------------------------------+----------+\n");
printf (" | Owner | Relation | Type |\n");
printf (" +------------------+----------------------------------+----------+\n");
}
/*
- * Describe a table (PGconn* conn, char* table)
+ * Describe a table
*
* Describe the columns in a database table.
* returns 0 if all went well
*
*/
int
-tableDesc (PGconn* conn, char* table)
+tableDesc (PsqlSettings *ps, 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 ");
- 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);
- }
+ if (!(res = PSQLexec(ps, descbuf)))
+ return -1;
/* first, print out the attribute names */
nColumns = PQntuples(res);
if (nColumns > 0)
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");
}
return (readline(prompt));
}
-
/*
* gets_fromFile prompt source
*
}
/*
- * SendQuery:
- SendQuery: send the query string to the backend
- *
+ * SendQuery: send the query string to the backend
* return 0 if the query executed successfully
* returns 1 otherwise
*/
int
-SendQuery(PGconn* db, char* query, PsqlSettings *settings)
+SendQuery(PsqlSettings *settings, char *query)
{
PGresult* results;
PGnotify* notify;
gets_fromFile("",stdin);
}
- results = PQexec(db, query);
+ results = PQexec(settings->db, query);
if (results == NULL) {
- fprintf(stderr,"%s",PQerrorMessage(db));
+ fprintf(stderr,"%s",PQerrorMessage(settings->db));
return 1;
}
switch (PQresultStatus(results)) {
case PGRES_TUPLES_OK:
- PQdisplayTuples(results,
- settings->queryFout,
- settings->fillAlign,
- settings->fieldSep,
- settings->printHeader,
- settings->quiet);
+ 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);
+ }
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(db));
+ fprintf(stderr,"%s",PQerrorMessage(settings->db));
break;
-
}
/* check for asynchronous returns */
- notify = PQnotifies(db);
+ notify = PQnotifies(settings->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(PGconn** db_ptr,
+HandleSlashCmds(PsqlSettings *settings,
char* line,
- char** prompt_ptr,
- char *query,
- PsqlSettings *settings)
+ char *query)
{
- int status = 0;
- PGconn* db = *db_ptr;
- char* dbname = PQdb(db);
+ int status = 1;
char *optarg = NULL;
int len;
len = strlen(line);
if (len > 2)
+ {
optarg = leftTrim(line+2);
+ decode(optarg);
+ }
switch (line[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" );
+ case 'a': /* toggles to align fields on output */
+ toggle(settings, &settings->opt.align, "field alignment");
break;
- case 'c': /* \c means connect to new database */
+ 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 */
{
+ char *dbname=PQdb(settings->db);
if (!optarg) {
fprintf(stderr,"\\c must be followed by a database name\n");
- status = 1;
- break;
- }
- if (strcmp(optarg, dbname) == 0) {
- fprintf(stderr,"already connected to %s\n", dbname);
- status = 1;
break;
}
- else {
- PGconn *olddb;
+ {
+ PGconn *olddb=settings->db;
- printf("closing connection to database:%s\n", dbname);
- olddb = db;
- db = PQsetdb(PQhost(olddb), PQport(olddb), NULL, NULL, optarg);
- *db_ptr = db;
+ printf("closing connection to database: %s\n", dbname);
+ settings->db = PQsetdb(PQhost(olddb), PQport(olddb), NULL, NULL, optarg);
printf("connecting to new database: %s\n", optarg);
- if (PQstatus(db) == CONNECTION_BAD) {
- fprintf(stderr,"%s\n", PQerrorMessage(db));
+ if (PQstatus(settings->db) == CONNECTION_BAD) {
+ fprintf(stderr,"%s\n", PQerrorMessage(settings->db));
printf("reconnecting to %s\n", dbname);
- db = PQsetdb(PQhost(olddb), PQport(olddb),
+ settings->db = PQsetdb(PQhost(olddb), PQport(olddb),
NULL, NULL, dbname);
- *db_ptr = db;
- if (PQstatus(db) == CONNECTION_BAD) {
+ if (PQstatus(settings->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(*prompt_ptr);
- *prompt_ptr = malloc(strlen(optarg) + 10);
- sprintf(*prompt_ptr,"%s=> ", optarg);
- status = 1;
+ free(settings->prompt);
+ settings->prompt = malloc(strlen(PQdb(settings->db)) + 10);
+ sprintf(settings->prompt,"%s=> ", PQdb(settings->db));
break;
}
}
break;
case 'd': /* \d describe tables or columns in a table */
- {
if (!optarg) {
- tableList(db,0);
- status = 1;
+ tableList(settings, 0);
break;
- }
- if ( strcmp(optarg,"*") == 0 ) {
- tableList(db, 0);
- tableList(db, 1);
+ }
+ if (strcmp(optarg, "*") == 0 ) {
+ tableList(settings, 0);
+ tableList(settings, 1);
}
else {
- tableDesc(db,optarg);
+ tableDesc(settings, optarg);
}
- status = 1;
break;
- }
case 'e':
{
- char s[256];
int fd;
- int ql = strlen(query);
- int f_arg = 0;
+ char tmp[64];
+ char *fname;
int cc;
+ int ql = strlen(query);
if (optarg)
- {
- f_arg = 1;
- strcpy(s, optarg);
- }
+ fname=optarg;
else
- {
- sprintf(s, "/tmp/psql.%d.%d", getuid(), getpid());
- unlink(s);
+ {
+ sprintf(tmp, "/tmp/psql.%d.%d", getuid(), getpid());
+ fname=tmp;
+ unlink(tmp);
if (ql)
{
- if ((fd=open(s, O_EXCL|O_CREAT|O_WRONLY, 0600))==-1)
+ if ((fd=open(tmp, O_EXCL|O_CREAT|O_WRONLY, 0600))==-1)
{
- perror(s);
+ perror(tmp);
break;
}
if (query[ql-1]!='\n')
strcat(query, "\n");
if (write(fd, query, ql)!=ql)
{
- perror(s);
+ perror(tmp);
close(fd);
- unlink(s);
+ unlink(tmp);
break;
}
close(fd);
}
}
+ editFile(fname);
+ if ((fd=open(fname, O_RDONLY))==-1)
{
- 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);
+ perror(fname);
+ if (!optarg)
+ unlink(fname);
break;
}
if ((cc=read(fd, query, MAX_QUERY_BUFFER))==-1)
{
- perror(s);
+ perror(fname);
close(fd);
- if (!f_arg)
- unlink(s);
+ if (!optarg)
+ unlink(fname);
break;
}
query[cc]='\0';
close(fd);
- if (!f_arg)
- unlink(s);
+ if (!optarg)
+ unlink(fname);
rightTrim(query);
if (query[strlen(query)-1]==';')
return 0;
break;
}
- 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;
+ 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 ( (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;
+ 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;
+ 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(db,settings);
- status = 1;
+ listAllDbs(settings);
+ break;
+ case 'H':
+ if (toggle(settings, &settings->opt.html3, "HTML3.0 tablular output"))
+ settings->opt.standard = 0;
break;
case 'o':
- settings->queryFout = setFout(optarg);
+ setFout(settings, optarg);
break;
case 'p':
if (query) {
fputs(query, stdout);
fputc('\n', stdout);
- status = 1;
}
break;
- case 'r':
- query[0] = '\0';
- status = 1;
- break;
case 'q': /* \q is quit */
status = 2;
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;
+ 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;
}
-
- fname = optarg;
- if (write_history(fname) != 0)
- {
- fprintf(stderr,"cannot write history to %s\n",fname);
- }
- status = 1;
- break;
+ stat(lastfile, &st);
+ editFile(lastfile);
+ if ((stat(lastfile, &st2) == -1) ||
+ ((fd = fopen(lastfile, "r")) == NULL)) {
+ perror(lastfile);
+ break;
}
- case 't':
- if ( settings->printHeader )
- settings->printHeader = 0;
- else
- settings->printHeader = 1;
+ if (st2.st_mtime==st.st_mtime) {
if (!settings->quiet)
- fprintf(stderr,"turning %s printing of field headers\n",
- (settings->printHeader) ? "on" : "off" );
+ fprintf(stderr, "warning: %s not modified. query not executed\n",
+ lastfile);
+ fclose(fd);
break;
- case '!':
- if (!optarg) {
- char sys[256];
- char *shellName;
- shellName = getenv("SHELL");
- if (shellName == NULL)
- shellName = DEFAULT_SHELL;
- sprintf(sys,"exec %s", shellName);
- system(sys);
+ }
+ 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);
+ 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
- system(optarg);
+ 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;
+ 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);
break;
default:
case '?': /* \? is help */
- slashUsage();
- status = 1;
+ slashUsage(settings);
break;
}
return status;
*db_ptr must be initialized and set
*/
+
int
-MainLoop(PGconn** db_ptr,
- FILE* source,
- PsqlSettings *settings)
+MainLoop(PsqlSettings *settings, FILE* source)
{
- 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
*/
- int send_query = 0;
- int interactive;
+ bool sendQuery = 0;
+ bool querySent = 0;
+ bool interactive;
READ_ROUTINE GetNextLine;
- interactive = (source == stdin);
-
+ interactive = ((source == stdin) && !settings->notty);
+#define PROMPT "=> "
if (interactive) {
- prompt = malloc(strlen(dbname) + 10);
+ if (settings->prompt)
+ free(settings->prompt);
+ settings->prompt = malloc(strlen(PQdb(settings->db)) + strlen(PROMPT) + 1);
if (settings->quiet)
- prompt[0] = '\0';
+ settings->prompt[0] = '\0';
else
- sprintf(prompt,"%s=> ", dbname);
+ sprintf(settings->prompt,"%s%s", PQdb(settings->db), PROMPT);
if (settings->useReadline) {
using_history();
GetNextLine = gets_readline;
query[0] = '\0';
/* main loop for getting queries and executing them */
- while ((line = GetNextLine(prompt, source)) != NULL)
+ while ((line = GetNextLine(settings->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 */
- send_query = settings->singleLineMode || (line[len-1] == ';') ;
+ sendQuery = 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 && !send_query)
+ if (len > 2 && !sendQuery)
{
if (line[len-1]=='g' && line[len-2]=='\\')
{
- send_query = 1;
+ sendQuery = 1;
line[len-2]='\0';
}
}
/* slash commands have to be on their own line */
if (line[0] == '\\') {
- slashCmdStatus = HandleSlashCmds(db_ptr,
+ slashCmdStatus = HandleSlashCmds(settings,
line,
- &prompt,
- query,
- settings);
- db = *db_ptr; /* in case \c changed the database */
+ query);
if (slashCmdStatus == 1)
continue;
if (slashCmdStatus == 2)
break;
if (slashCmdStatus == 0)
- send_query = 1;
+ sendQuery = 1;
}
else
if (strlen(query) + len > MAX_QUERY_BUFFER)
else
strcpy(query,line);
- if (send_query && query[0] != '\0')
+ 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 */
- if (!interactive && !settings->singleStep)
- fprintf(stderr,"%s\n",query);
+ if (!interactive && !settings->singleStep && !settings->quiet)
+ fprintf(stderr,"%s\n", query);
- exitStatus = SendQuery(db, query, settings);
- query[0] = '\0';
+ exitStatus = SendQuery(settings, query);
+ querySent = 1;
}
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, opterr;
+ extern int optind;
- PGconn *db;
char* dbname = NULL;
char* host = NULL;
char* port = NULL;
char* singleQuery = NULL;
- int listDatabases = 0 ;
+ bool listDatabases = 0 ;
int exitStatus = 0;
- int singleSlashCmd = 0;
+ bool singleSlashCmd = 0;
int c;
-
-#ifdef NOREADLINE
- settings.useReadline = 0;
-#else
- settings.useReadline = 1;
-#endif
-
- settings.quiet = 0;
- settings.fillAlign = 1;
- settings.printHeader = 1;
- settings.echoQuery = 0;
- settings.singleStep = 0;
- settings.singleLineMode = 0;
+ memset(&settings, 0, sizeof settings);
+ settings.opt.align = 1;
+ settings.opt.header = 1;
settings.queryFout = stdout;
- strcpy(settings.fieldSep, DEFAULT_FIELD_SEP);
+ settings.opt.fieldSep=dupstr(DEFAULT_FIELD_SEP);
+ if (!isatty(0) || !isatty(1))
+ settings.quiet = settings.notty = 1;
+ else
+#ifndef NOREADLINE
+ settings.useReadline = 1;
+#endif
- while ((c = getopt(argc, argv, "Aa:c:d:ef:F:lhH:nso:p:qST")) != EOF) {
+ while ((c = getopt(argc, argv, "Aa:c:d:ef:F:lhH:nso:p:qStTx")) != EOF) {
switch (c) {
case 'A':
- settings.fillAlign = 0;
+ settings.opt.align = 0;
break;
case 'a':
fe_setauthsvc(optarg, errbuf);
qfilename = optarg;
break;
case 'F':
- strncpy(settings.fieldSep,optarg,MAX_FIELD_SEP_LENGTH);
- break;
+ settings.opt.fieldSep=dupstr(optarg);
+ 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':
- settings.queryFout = setFout(optarg);
- break;
+ setFout(&settings, optarg);
+ break;
case 'p':
port = optarg;
break;
case 'S':
settings.singleLineMode = 1;
break;
+ case 't':
+ settings.opt.header = 0;
+ break;
case 'T':
- settings.printHeader = 0;
- break;
- case 'h':
+ settings.opt.tableOpt = dupstr(optarg);
+ break;
+ case 'x':
+ settings.opt.expanded = 0;
+ break;
default:
usage(argv[0]);
break;
if (listDatabases)
dbname = "template1";
- db = PQsetdb(host, port, NULL, NULL, dbname);
- dbname = PQdb(db);
+ settings.db = PQsetdb(host, port, NULL, NULL, dbname);
+ dbname = PQdb(settings.db);
- if (PQstatus(db) == CONNECTION_BAD) {
+ if (PQstatus(settings.db) == CONNECTION_BAD) {
fprintf(stderr,"Connection to database '%s' failed.\n", dbname);
- fprintf(stderr,"%s",PQerrorMessage(db));
+ fprintf(stderr,"%s",PQerrorMessage(settings.db));
exit(1);
}
if (listDatabases) {
- exit(listAllDbs(db,&settings));
+ exit(listAllDbs(&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(&db, line, (char**)prompt, "", &settings);
+ HandleSlashCmds(&settings, line, "");
} else {
if (singleQuery) {
- exitStatus = SendQuery(db, singleQuery, &settings);
+ exitStatus = SendQuery(&settings, singleQuery);
}
else
- exitStatus = MainLoop(&db, stdin, &settings);
+ exitStatus = MainLoop(&settings, stdin);
}
- PQfinish(db);
+ PQfinish(settings.db);
return exitStatus;
}
+#define COPYBUFSIZ 8192
static void
-handleCopyOut(PGresult *res, int quiet)
+handleCopyOut(PGresult *res, bool quiet)
{
bool copydone = false;
char copybuf[COPYBUFSIZ];
static void
-handleCopyIn(PGresult *res, int quiet)
+handleCopyIn(PGresult *res, bool 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(char *fname)
+setFout(PsqlSettings *ps, char *fname)
{
- FILE *queryFout;
-
- if (!fname)
- queryFout = stdout;
- else {
- queryFout = fopen(fname, "w");
- if (!queryFout) {
- perror(fname);
- queryFout = stdout;
+ if (ps->queryFout && ps->queryFout != stdout)
+ {
+ if (ps->pipe)
+ pclose(ps->queryFout);
+ else
+ fclose(ps->queryFout);
}
- }
-
- return queryFout;
+ 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;
}
-
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.2 1996/07/12 04:53:59 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.3 1996/07/18 05:48:56 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "libpq/pqcomm.h"
#include "libpq-fe.h"
-#include <signal.h>
/* the tuples array in a PGresGroup has to grow to accommodate the tuples */
/* returned. Each time, we grow by this much: */
static void addTuple(PGresult *res, PGresAttValue *tup);
static PGresAttValue* getTuple(PGconn *conn, PGresult *res, int binary);
static PGresult* makeEmptyPGresult(PGconn *conn, ExecStatusType status);
-static void fill(int length, int max, char filler, FILE *fp);
/*
* PQclear -
}
}
-/* simply send out max-length number of filler characters to fp */
-static void
-fill (int length, int max, char filler, FILE *fp)
-{
- int count;
- char filltmp[2];
-
- filltmp[0] = filler;
- filltmp[1] = 0;
- count = max - length;
- while (count-- >= 0)
- {
- fprintf(fp, "%s", filltmp);
- }
- }
-
-
-/*
- * PQdisplayTuples()
- *
- * a better version of PQprintTuples()
- * that can optionally do padding of fields with spaces and use different
- * field separators
- */
-void
-PQdisplayTuples(PGresult *res,
- FILE *fp, /* where to send the output */
- int fillAlign, /* pad the fields with spaces */
- char *fieldSep, /* field separator */
- int printHeader, /* display headers? */
- int quiet
- )
-{
-#define DEFAULT_FIELD_SEP " "
-
- char *pager;
- int i, j;
- int nFields;
- int nTuples;
- int fLength[MAX_FIELDS];
- int usePipe = 0;
-
- if (fieldSep == NULL)
- fieldSep == DEFAULT_FIELD_SEP;
-
- if (fp == NULL)
- fp = stdout;
- if (fp == stdout) {
- /* try to pipe to the pager program if possible */
- pager=getenv("PAGER");
- if (pager != NULL) {
- fp = popen(pager, "w");
- if (fp) {
- usePipe = 1;
- signal(SIGPIPE, SIG_IGN);
- } else
- fp = stdout;
- }
- }
-
- /* Get some useful info about the results */
- nFields = PQnfields(res);
- nTuples = PQntuples(res);
-
- /* Zero the initial field lengths */
- for (j=0 ; j < nFields; j++) {
- fLength[j] = strlen(PQfname(res,j));
- }
- /* Find the max length of each field in the result */
- /* will be somewhat time consuming for very large results */
- if (fillAlign) {
- for (i=0; i < nTuples; i++) {
- for (j=0 ; j < nFields; j++) {
- if (PQgetlength(res,i,j) > fLength[j])
- fLength[j] = PQgetlength(res,i,j);
- }
- }
- }
-
- if (printHeader) {
- /* first, print out the attribute names */
- for (i=0; i < nFields; i++) {
- fputs(PQfname(res,i), fp);
- if (fillAlign)
- fill (strlen (PQfname(res,i)), fLength[i], ' ', fp);
- fputs(fieldSep,fp);
- }
- fprintf(fp, "\n");
-
- /* Underline the attribute names */
- for (i=0; i < nFields; i++) {
- if (fillAlign)
- fill (0, fLength[i], '-', fp);
- fputs(fieldSep,fp);
- }
- fprintf(fp, "\n");
- }
-
- /* next, print out the instances */
- for (i=0; i < nTuples; i++) {
- for (j=0 ; j < nFields; j++) {
- fprintf(fp, "%s", PQgetvalue(res,i,j));
- if (fillAlign)
- fill (strlen (PQgetvalue(res,i,j)), fLength[j], ' ', fp);
- fputs(fieldSep,fp);
- }
- fprintf(fp, "\n");
- }
-
- if (!quiet)
- fprintf (fp, "\nQuery returned %d row%s.\n",PQntuples(res),
- (PQntuples(res) == 1) ? "" : "s");
-
- fflush(fp);
- if (usePipe) {
- pclose(fp);
- signal(SIGPIPE, SIG_DFL);
- }
-}
-
/*
- * PQprintTuples()
+ * print_tuples()
*
* This is the routine that prints out the tuples that
- * are returned from the backend.
+ * are returned from the backend.
* Right now all columns are of fixed length,
* this should be changed to allow wrap around for
* tuples values that are wider.
}
}
+/*
+ * new PQprintTuples routine (proff@suburbia.net)
+ * PQprintOpt is a typedef (structure) that containes
+ * various flags and options. consult libpq-fe.h for
+ * details
+ */
+
+void
+PQprint(FILE *fout,
+ PGresult *res,
+ PQprintOpt *po
+ )
+{
+ int nFields;
+
+ nFields = PQnfields(res);
+
+ if ( nFields > 0 ) { /* only print tuples with at least 1 field. */
+ int i,j;
+ int nTups;
+ int *fieldMax=NULL; /* keep -Wall happy */
+ unsigned char *fieldNotNum=NULL; /* keep -Wall happy */
+ char **fields=NULL; /*keep -Wall happy */
+ char **fieldNames;
+ int fieldMaxLen=0;
+ char *border=NULL;
+ int numFieldName;
+ int fs_len=strlen(po->fieldSep);
+ nTups = PQntuples(res);
+ if (!(fieldNames=(char **)calloc(nFields, sizeof (char *))))
+ {
+ perror("calloc");
+ exit(1);
+ }
+ if (!(fieldNotNum=(unsigned char *)calloc(nFields, 1)))
+ {
+ perror("calloc");
+ exit(1);
+ }
+ if (!(fieldMax=(int *)calloc(nFields, sizeof(int))))
+ {
+ perror("calloc");
+ exit(1);
+ }
+ for (numFieldName=0; po->fieldName && po->fieldName[numFieldName]; numFieldName++);
+ for (j=0; j < nFields; j++)
+ {
+ int len;
+ char *s=(j<numFieldName && po->fieldName[j][0])? po->fieldName[j]: PQfname(res, j);
+ fieldNames[j]=s;
+ len=s? strlen(s): 0;
+ fieldMax[j] = len;
+ /*
+ if (po->header && len<5)
+ len=5;
+ */
+ len+=fs_len;
+ if (len>fieldMaxLen)
+ fieldMaxLen=len;
+ }
+ if (!po->expanded && (po->align || po->html3))
+ {
+ if (!(fields=(char **)calloc(nFields*(nTups+1), sizeof(char *))))
+ {
+ perror("calloc");
+ exit(1);
+ }
+ } else
+ if (po->header && !po->html3)
+ {
+ if (po->expanded)
+ {
+ if (po->align)
+ fprintf(fout, "%-*s%s Value\n", fieldMaxLen-fs_len, "Field", po->fieldSep);
+ else
+ fprintf(fout, "%s%sValue\n", "Field", po->fieldSep);
+ } else
+ {
+ int len=0;
+ for (j=0; j < nFields; j++)
+ {
+ char *s=fieldNames[j];
+ fputs(s, fout);
+ len+=strlen(s)+fs_len;
+ if ((j+1)<nFields)
+ fputs(po->fieldSep, fout);
+ }
+ fputc('\n', fout);
+ for (len-=fs_len; len--; fputc('-', fout));
+ fputc('\n', fout);
+ }
+ }
+ if (po->expanded && po->html3)
+ {
+ if (po->caption)
+ fprintf(fout, "<centre><h2>%s</h2></centre>\n", po->caption);
+ else
+ fprintf(fout, "<centre><h2>Query retrieved %d tuples * %d fields</h2></centre>\n", nTups, nFields);
+ }
+ for (i = 0; i < nTups; i++) {
+ char buf[8192*2+1];
+ if (po->expanded)
+ {
+ if (po->html3)
+ fprintf(fout, "<table %s><caption align=high>%d</caption>\n", po->tableOpt? po->tableOpt: "", i);
+ else
+ fprintf(fout, "-- RECORD %d --\n", i);
+ }
+ for (j = 0; j < nFields; j++) {
+ char *pval, *p, *o;
+ int plen;
+ if ((plen=PQgetlength(res,i,j))<1 || !(pval=PQgetvalue(res,i,j)) || !*pval)
+ {
+ if (po->align || po->expanded)
+ continue;
+ goto efield;
+ }
+ for (p=pval, o=buf; *p; *(o++)=*(p++))
+ {
+ if ((fs_len==1 && (*p==*(po->fieldSep))) || *p=='\\')
+ *(o++)='\\';
+ if (po->align && !((*p >='0' && *p<='9') || *p=='.' || *p=='E' || *p=='e' || *p==' ' || *p=='-'))
+ fieldNotNum[j]=1;
+ }
+ *o='\0';
+ if (!po->expanded && (po->align || po->html3))
+ {
+ int n=strlen(buf);
+ if (n>fieldMax[j])
+ fieldMax[j]=n;
+ if (!(fields[i*nFields+j]=(char *)malloc(n+1)))
+ {
+ perror("malloc");
+ exit(1);
+ }
+ strcpy(fields[i*nFields+j], buf);
+ } else
+ {
+ if (po->expanded)
+ {
+ if (po->html3)
+ fprintf(fout, "<tr><td align=left><b>%s</b></td><td align=%s>%s</td></tr>\n",
+ fieldNames[j], fieldNotNum[j]? "left": "right", buf);
+ else
+ {
+ if (po->align)
+ fprintf(fout, "%-*s%s %s\n", fieldMaxLen-fs_len, fieldNames[j], po->fieldSep, buf);
+ else
+ fprintf(fout, "%s%s%s\n", fieldNames[j], po->fieldSep, buf);
+ }
+ }
+ else
+ {
+ if (!po->html3)
+ {
+ fputs(buf, fout);
+efield:
+ if ((j+1)<nFields)
+ fputs(po->fieldSep, fout);
+ else
+ fputc('\n', fout);
+ }
+ }
+ }
+ }
+ if (po->html3 && po->expanded)
+ fputs("</table>\n", fout);
+ }
+ if (!po->expanded && (po->align || po->html3))
+ {
+ if (po->html3)
+ {
+ if (po->header)
+ {
+ if (po->caption)
+ fprintf(fout, "<table %s><caption align=high>%s</caption>\n", po->tableOpt? po->tableOpt: "", po->caption);
+ else
+ fprintf(fout, "<table %s><caption align=high>Retrieved %d tuples * %d fields</caption>\n", po->tableOpt? po->tableOpt: "", nTups, nFields);
+ } else
+ fprintf(fout, "<table %s>", po->tableOpt? po->tableOpt: "");
+ }
+ if (po->header)
+ {
+ if (po->html3)
+ fputs("<tr>", fout);
+ else
+ {
+ int tot=0;
+ int n=0;
+ char *p;
+ for (; n<nFields; n++)
+ tot+=fieldMax[n]+fs_len+(po->standard? 2: 0);
+ if (po->standard)
+ tot+=fs_len*2+2;
+ if (!(p=border=malloc(tot+1)))
+ {
+ perror("malloc");
+ exit(1);
+ }
+ if (po->standard)
+ {
+ char *fs=po->fieldSep;
+ while (*fs++)
+ *p++='+';
+ }
+ for (j=0; j <nFields; j++)
+ {
+ int len;
+ for (len=fieldMax[j] + (po->standard? 2:0) ; len--; *p++='-');
+ if (po->standard || (j+1)<nFields)
+ {
+ char *fs=po->fieldSep;
+ while (*fs++)
+ *p++='+';
+ }
+ }
+ *p='\0';
+ if (po->standard)
+ fprintf(fout, "%s\n", border);
+ }
+ if (po->standard)
+ fputs(po->fieldSep, fout);
+ for (j=0; j < nFields; j++)
+ {
+ char *s=PQfname(res, j);
+ if (po->html3)
+ {
+ fprintf(fout, "<th align=%s>%s</th>", fieldNotNum[j]? "left": "right",
+ fieldNames[j]);
+ } else
+ {
+ int n=strlen(s);
+ if (n>fieldMax[j])
+ fieldMax[j]=n;
+ if (po->standard)
+ fprintf(fout, fieldNotNum[j]? " %-*s ": " %*s ", fieldMax[j], s);
+ else
+ fprintf(fout, fieldNotNum[j]? "%-*s": "%*s", fieldMax[j], s);
+ if (po->standard || (j+1)<nFields)
+ fputs(po->fieldSep, fout);
+ }
+ }
+ if (po->html3)
+ fputs("</tr>\n", fout);
+ else
+ fprintf(fout, "\n%s\n", border);
+ }
+ for (i = 0; i < nTups; i++)
+ {
+ if (po->html3)
+ fputs("<tr>", fout);
+ else
+ if (po->standard)
+ fputs(po->fieldSep, fout);
+
+ for (j = 0; j < nFields; j++)
+ {
+ char *p=fields[i*nFields+j];
+ if (po->html3)
+ fprintf(fout, "<td align=%s>%s</td>", fieldNotNum[j]? "left": "right", p? p: "");
+
+ else
+ {
+ fprintf(fout, fieldNotNum[j]? (po->standard? " %-*s ": "%-*s"): (po->standard? " %*s ": "%*s"), fieldMax[j], p? p: "");
+ if (po->standard || (j+1)<nFields)
+ fputs(po->fieldSep, fout);
+ }
+ if (p)
+ free(p);
+ }
+ if (po->html3)
+ fputs("</tr>", fout);
+ else
+ if (po->standard)
+ fprintf(fout, "\n%s", border);
+ fputc('\n', fout);
+ }
+ free(fields);
+ }
+ free(fieldMax);
+ free(fieldNotNum);
+ free(fieldNames);
+ if (border)
+ free(border);
+ if (po->html3 && !po->expanded)
+ fputs("</table>\n", fout);
+ }
+}
+
/* ----------------
* PQfn - Send a function call to the POSTGRES backend.