aboutsummaryrefslogtreecommitdiff
path: root/src/interfaces/libpq/fe-exec.c
diff options
context:
space:
mode:
authorMarc G. Fournier <scrappy@hub.org>1996-07-18 05:48:57 +0000
committerMarc G. Fournier <scrappy@hub.org>1996-07-18 05:48:57 +0000
commit72f76d38eb23e1fbca92f0e14b257c33e5ecccbc (patch)
tree94d8da6cbb3808247d4d9bf9f529d6f1df0eaf01 /src/interfaces/libpq/fe-exec.c
parentbc0bd47c6a8e020c523cc69a8a3c8e9dab8bb61b (diff)
downloadpostgresql-72f76d38eb23e1fbca92f0e14b257c33e5ecccbc.tar.gz
postgresql-72f76d38eb23e1fbca92f0e14b257c33e5ecccbc.zip
libpq and psql.c have been modified to do various things they didn't do
before (plus some optimisations/bug fixes et al). I've included a small demo transcript below. Note that all of of the display functionality/intelligence you see here, can be had merely by calling the new LIBPQ PQprint() routine with the appropriate arguments/options, including the HTML3 output guff. submitted by: Julian Assange <proff@suburbia.net>
Diffstat (limited to 'src/interfaces/libpq/fe-exec.c')
-rw-r--r--src/interfaces/libpq/fe-exec.c417
1 files changed, 292 insertions, 125 deletions
diff --git a/src/interfaces/libpq/fe-exec.c b/src/interfaces/libpq/fe-exec.c
index 1ca135151d0..99410cfcbc5 100644
--- a/src/interfaces/libpq/fe-exec.c
+++ b/src/interfaces/libpq/fe-exec.c
@@ -7,7 +7,7 @@
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
@@ -18,7 +18,6 @@
#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: */
@@ -39,7 +38,6 @@ static PGresult* makePGresult(PGconn *conn, char *pname);
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 -
@@ -624,133 +622,13 @@ PQendcopy(PGconn *conn)
}
}
-/* 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.
@@ -821,6 +699,295 @@ PQprintTuples(PGresult *res,
}
}
+/*
+ * 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.