1998-05-07 16:52:52 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
1999-02-14 00:22:53 +01:00
|
|
|
* fe-print.c
|
1998-05-07 16:52:52 +02:00
|
|
|
* functions for pretty-printing query results
|
|
|
|
*
|
2017-01-03 19:48:53 +01:00
|
|
|
* Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
|
2000-01-26 06:58:53 +01:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
1998-05-07 16:52:52 +02:00
|
|
|
*
|
|
|
|
* These functions were formerly part of fe-exec.c, but they
|
|
|
|
* didn't really belong there.
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
2010-09-20 22:08:53 +02:00
|
|
|
* src/interfaces/libpq/fe-print.c
|
1998-05-07 16:52:52 +02:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
2001-02-10 03:31:31 +01:00
|
|
|
#include "postgres_fe.h"
|
1999-07-19 04:27:16 +02:00
|
|
|
|
2000-01-29 17:58:54 +01:00
|
|
|
#include <signal.h>
|
1998-08-17 05:50:43 +02:00
|
|
|
|
1998-07-03 06:24:16 +02:00
|
|
|
#ifdef WIN32
|
|
|
|
#include "win32.h"
|
1998-08-17 05:50:43 +02:00
|
|
|
#else
|
1999-07-19 08:25:40 +02:00
|
|
|
#include <unistd.h>
|
1998-08-17 05:50:43 +02:00
|
|
|
#include <sys/ioctl.h>
|
1999-07-19 04:27:16 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAVE_TERMIOS_H
|
1998-05-07 16:52:52 +02:00
|
|
|
#include <termios.h>
|
1999-07-19 04:27:16 +02:00
|
|
|
#else
|
2000-01-18 20:05:31 +01:00
|
|
|
#ifndef WIN32
|
1999-07-19 04:27:16 +02:00
|
|
|
#include <sys/termios.h>
|
1998-05-07 16:52:52 +02:00
|
|
|
#endif
|
2000-01-18 20:05:31 +01:00
|
|
|
#endif
|
1998-05-07 16:52:52 +02:00
|
|
|
|
2001-01-06 18:43:01 +01:00
|
|
|
#include "libpq-fe.h"
|
|
|
|
#include "libpq-int.h"
|
1998-05-07 16:52:52 +02:00
|
|
|
|
|
|
|
|
In the spirit of TODO item
* Add use of 'const' for varibles in source tree
(which is misspelled, btw.)
I went through the front-end libpq code and did so. This affects in
particular the various accessor functions (such as PQdb() and
PQgetvalue()) as well as, by necessity, the internal helpers they use.
I have been really thorough in that regard, perhaps some people will find
it annoying that things like
char * foo = PQgetvalue(res, 0, 0)
will generate a warning. On the other hand it _should_ generate one. This
is no real compatibility break, although a few clients will have to be
fixed to suppress warnings. (Which again would be in the spirit of the
above TODO.)
In addition I replaced some int's by size_t's and removed some warnings
(and generated some new ones -- grmpf!). Also I rewrote PQoidStatus (so it
actually honors the const!) and supplied a new function PQoidValue that
returns a proper Oid type. This is only front-end stuff, none of the
communicaton stuff was touched.
The psql patch also adds some new consts to honor the new libpq situation,
as well as fixes a fatal condition that resulted when using the -V
(--version) option and there is no database listening.
So, to summarize, the psql you should definitely put in (with or without
the libpq). If you think I went too far with the const-mania in libpq, let
me know and I'll make adjustments. If you approve it, I will also update
the docs.
-Peter
--
Peter Eisentraut Sernanders vaeg 10:115
1999-11-11 01:10:14 +01:00
|
|
|
static void do_field(const PQprintOpt *po, const PGresult *res,
|
1999-08-31 03:37:37 +02:00
|
|
|
const int i, const int j, const int fs_len,
|
1998-09-01 05:29:17 +02:00
|
|
|
char **fields,
|
In the spirit of TODO item
* Add use of 'const' for varibles in source tree
(which is misspelled, btw.)
I went through the front-end libpq code and did so. This affects in
particular the various accessor functions (such as PQdb() and
PQgetvalue()) as well as, by necessity, the internal helpers they use.
I have been really thorough in that regard, perhaps some people will find
it annoying that things like
char * foo = PQgetvalue(res, 0, 0)
will generate a warning. On the other hand it _should_ generate one. This
is no real compatibility break, although a few clients will have to be
fixed to suppress warnings. (Which again would be in the spirit of the
above TODO.)
In addition I replaced some int's by size_t's and removed some warnings
(and generated some new ones -- grmpf!). Also I rewrote PQoidStatus (so it
actually honors the const!) and supplied a new function PQoidValue that
returns a proper Oid type. This is only front-end stuff, none of the
communicaton stuff was touched.
The psql patch also adds some new consts to honor the new libpq situation,
as well as fixes a fatal condition that resulted when using the -V
(--version) option and there is no database listening.
So, to summarize, the psql you should definitely put in (with or without
the libpq). If you think I went too far with the const-mania in libpq, let
me know and I'll make adjustments. If you approve it, I will also update
the docs.
-Peter
--
Peter Eisentraut Sernanders vaeg 10:115
1999-11-11 01:10:14 +01:00
|
|
|
const int nFields, const char **fieldNames,
|
1998-09-01 05:29:17 +02:00
|
|
|
unsigned char *fieldNotNum, int *fieldMax,
|
1998-05-07 16:52:52 +02:00
|
|
|
const int fieldMaxLen, FILE *fout);
|
In the spirit of TODO item
* Add use of 'const' for varibles in source tree
(which is misspelled, btw.)
I went through the front-end libpq code and did so. This affects in
particular the various accessor functions (such as PQdb() and
PQgetvalue()) as well as, by necessity, the internal helpers they use.
I have been really thorough in that regard, perhaps some people will find
it annoying that things like
char * foo = PQgetvalue(res, 0, 0)
will generate a warning. On the other hand it _should_ generate one. This
is no real compatibility break, although a few clients will have to be
fixed to suppress warnings. (Which again would be in the spirit of the
above TODO.)
In addition I replaced some int's by size_t's and removed some warnings
(and generated some new ones -- grmpf!). Also I rewrote PQoidStatus (so it
actually honors the const!) and supplied a new function PQoidValue that
returns a proper Oid type. This is only front-end stuff, none of the
communicaton stuff was touched.
The psql patch also adds some new consts to honor the new libpq situation,
as well as fixes a fatal condition that resulted when using the -V
(--version) option and there is no database listening.
So, to summarize, the psql you should definitely put in (with or without
the libpq). If you think I went too far with the const-mania in libpq, let
me know and I'll make adjustments. If you approve it, I will also update
the docs.
-Peter
--
Peter Eisentraut Sernanders vaeg 10:115
1999-11-11 01:10:14 +01:00
|
|
|
static char *do_header(FILE *fout, const PQprintOpt *po, const int nFields,
|
2005-10-15 04:49:52 +02:00
|
|
|
int *fieldMax, const char **fieldNames, unsigned char *fieldNotNum,
|
In the spirit of TODO item
* Add use of 'const' for varibles in source tree
(which is misspelled, btw.)
I went through the front-end libpq code and did so. This affects in
particular the various accessor functions (such as PQdb() and
PQgetvalue()) as well as, by necessity, the internal helpers they use.
I have been really thorough in that regard, perhaps some people will find
it annoying that things like
char * foo = PQgetvalue(res, 0, 0)
will generate a warning. On the other hand it _should_ generate one. This
is no real compatibility break, although a few clients will have to be
fixed to suppress warnings. (Which again would be in the spirit of the
above TODO.)
In addition I replaced some int's by size_t's and removed some warnings
(and generated some new ones -- grmpf!). Also I rewrote PQoidStatus (so it
actually honors the const!) and supplied a new function PQoidValue that
returns a proper Oid type. This is only front-end stuff, none of the
communicaton stuff was touched.
The psql patch also adds some new consts to honor the new libpq situation,
as well as fixes a fatal condition that resulted when using the -V
(--version) option and there is no database listening.
So, to summarize, the psql you should definitely put in (with or without
the libpq). If you think I went too far with the const-mania in libpq, let
me know and I'll make adjustments. If you approve it, I will also update
the docs.
-Peter
--
Peter Eisentraut Sernanders vaeg 10:115
1999-11-11 01:10:14 +01:00
|
|
|
const int fs_len, const PGresult *res);
|
|
|
|
static void output_row(FILE *fout, const PQprintOpt *po, const int nFields, char **fields,
|
1998-09-01 05:29:17 +02:00
|
|
|
unsigned char *fieldNotNum, int *fieldMax, char *border,
|
1998-05-07 16:52:52 +02:00
|
|
|
const int row_index);
|
2000-02-08 00:10:11 +01:00
|
|
|
static void fill(int length, int max, char filler, FILE *fp);
|
1998-05-07 16:52:52 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* PQprint()
|
|
|
|
*
|
|
|
|
* Format results of a query for printing.
|
|
|
|
*
|
2012-04-24 04:43:09 +02:00
|
|
|
* PQprintOpt is a typedef (structure) that contains
|
1998-05-07 16:52:52 +02:00
|
|
|
* various flags and options. consult libpq-fe.h for
|
|
|
|
* details
|
|
|
|
*
|
2000-01-29 17:58:54 +01:00
|
|
|
* This function should probably be removed sometime since psql
|
2005-06-12 02:00:21 +02:00
|
|
|
* doesn't use it anymore. It is unclear to what extent this is used
|
2000-01-29 17:58:54 +01:00
|
|
|
* by external clients, however.
|
1998-05-07 16:52:52 +02:00
|
|
|
*/
|
|
|
|
void
|
2005-06-12 02:00:21 +02:00
|
|
|
PQprint(FILE *fout, const PGresult *res, const PQprintOpt *po)
|
1998-05-07 16:52:52 +02:00
|
|
|
{
|
|
|
|
int nFields;
|
|
|
|
|
|
|
|
nFields = PQnfields(res);
|
|
|
|
|
|
|
|
if (nFields > 0)
|
|
|
|
{ /* only print rows with at least 1 field. */
|
|
|
|
int i,
|
|
|
|
j;
|
|
|
|
int nTups;
|
|
|
|
int *fieldMax = NULL; /* in case we don't use them */
|
|
|
|
unsigned char *fieldNotNum = NULL;
|
|
|
|
char *border = NULL;
|
|
|
|
char **fields = NULL;
|
2000-04-12 19:17:23 +02:00
|
|
|
const char **fieldNames;
|
1998-05-07 16:52:52 +02:00
|
|
|
int fieldMaxLen = 0;
|
|
|
|
int numFieldName;
|
|
|
|
int fs_len = strlen(po->fieldSep);
|
|
|
|
int total_line_length = 0;
|
|
|
|
int usePipe = 0;
|
|
|
|
char *pagerenv;
|
2005-10-15 04:49:52 +02:00
|
|
|
|
2005-08-23 23:02:05 +02:00
|
|
|
#if defined(ENABLE_THREAD_SAFETY) && !defined(WIN32)
|
2004-12-02 16:32:54 +01:00
|
|
|
sigset_t osigset;
|
|
|
|
bool sigpipe_masked = false;
|
|
|
|
bool sigpipe_pending;
|
|
|
|
#endif
|
2004-01-09 03:02:43 +01:00
|
|
|
#if !defined(ENABLE_THREAD_SAFETY) && !defined(WIN32)
|
|
|
|
pqsigfunc oldsigpipehandler = NULL;
|
|
|
|
#endif
|
2001-03-22 05:01:46 +01:00
|
|
|
|
2001-01-06 18:43:01 +01:00
|
|
|
#ifdef TIOCGWINSZ
|
|
|
|
struct winsize screen_size;
|
|
|
|
#else
|
|
|
|
struct winsize
|
|
|
|
{
|
|
|
|
int ws_row;
|
|
|
|
int ws_col;
|
|
|
|
} screen_size;
|
|
|
|
#endif
|
1998-05-07 16:52:52 +02:00
|
|
|
|
|
|
|
nTups = PQntuples(res);
|
In the spirit of TODO item
* Add use of 'const' for varibles in source tree
(which is misspelled, btw.)
I went through the front-end libpq code and did so. This affects in
particular the various accessor functions (such as PQdb() and
PQgetvalue()) as well as, by necessity, the internal helpers they use.
I have been really thorough in that regard, perhaps some people will find
it annoying that things like
char * foo = PQgetvalue(res, 0, 0)
will generate a warning. On the other hand it _should_ generate one. This
is no real compatibility break, although a few clients will have to be
fixed to suppress warnings. (Which again would be in the spirit of the
above TODO.)
In addition I replaced some int's by size_t's and removed some warnings
(and generated some new ones -- grmpf!). Also I rewrote PQoidStatus (so it
actually honors the const!) and supplied a new function PQoidValue that
returns a proper Oid type. This is only front-end stuff, none of the
communicaton stuff was touched.
The psql patch also adds some new consts to honor the new libpq situation,
as well as fixes a fatal condition that resulted when using the -V
(--version) option and there is no database listening.
So, to summarize, the psql you should definitely put in (with or without
the libpq). If you think I went too far with the const-mania in libpq, let
me know and I'll make adjustments. If you approve it, I will also update
the docs.
-Peter
--
Peter Eisentraut Sernanders vaeg 10:115
1999-11-11 01:10:14 +01:00
|
|
|
if (!(fieldNames = (const char **) calloc(nFields, sizeof(char *))))
|
1998-05-07 16:52:52 +02:00
|
|
|
{
|
2004-11-09 16:57:57 +01:00
|
|
|
fprintf(stderr, libpq_gettext("out of memory\n"));
|
2012-01-30 20:34:00 +01:00
|
|
|
abort();
|
1998-05-07 16:52:52 +02:00
|
|
|
}
|
|
|
|
if (!(fieldNotNum = (unsigned char *) calloc(nFields, 1)))
|
|
|
|
{
|
2004-11-09 16:57:57 +01:00
|
|
|
fprintf(stderr, libpq_gettext("out of memory\n"));
|
2012-01-30 20:34:00 +01:00
|
|
|
abort();
|
1998-05-07 16:52:52 +02:00
|
|
|
}
|
|
|
|
if (!(fieldMax = (int *) calloc(nFields, sizeof(int))))
|
|
|
|
{
|
2004-11-09 16:57:57 +01:00
|
|
|
fprintf(stderr, libpq_gettext("out of memory\n"));
|
2012-01-30 20:34:00 +01:00
|
|
|
abort();
|
1998-05-07 16:52:52 +02:00
|
|
|
}
|
|
|
|
for (numFieldName = 0;
|
|
|
|
po->fieldName && po->fieldName[numFieldName];
|
|
|
|
numFieldName++)
|
|
|
|
;
|
|
|
|
for (j = 0; j < nFields; j++)
|
|
|
|
{
|
|
|
|
int len;
|
2000-04-12 19:17:23 +02:00
|
|
|
const char *s = (j < numFieldName && po->fieldName[j][0]) ?
|
1998-05-07 16:52:52 +02:00
|
|
|
po->fieldName[j] : PQfname(res, j);
|
|
|
|
|
|
|
|
fieldNames[j] = s;
|
|
|
|
len = s ? strlen(s) : 0;
|
|
|
|
fieldMax[j] = len;
|
|
|
|
len += fs_len;
|
|
|
|
if (len > fieldMaxLen)
|
|
|
|
fieldMaxLen = len;
|
|
|
|
total_line_length += len;
|
|
|
|
}
|
|
|
|
|
|
|
|
total_line_length += nFields * strlen(po->fieldSep) + 1;
|
|
|
|
|
|
|
|
if (fout == NULL)
|
|
|
|
fout = stdout;
|
2008-05-18 01:34:44 +02:00
|
|
|
if (po->pager && fout == stdout && isatty(fileno(stdin)) &&
|
|
|
|
isatty(fileno(stdout)))
|
1998-05-07 16:52:52 +02:00
|
|
|
{
|
2001-01-06 18:43:01 +01:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* If we think there'll be more than one screen of output, try to
|
|
|
|
* pipe to the pager program.
|
2001-01-06 18:43:01 +01:00
|
|
|
*/
|
1998-05-07 16:52:52 +02:00
|
|
|
#ifdef TIOCGWINSZ
|
|
|
|
if (ioctl(fileno(stdout), TIOCGWINSZ, &screen_size) == -1 ||
|
|
|
|
screen_size.ws_col == 0 ||
|
|
|
|
screen_size.ws_row == 0)
|
|
|
|
{
|
|
|
|
screen_size.ws_row = 24;
|
|
|
|
screen_size.ws_col = 80;
|
|
|
|
}
|
2001-01-06 18:43:01 +01:00
|
|
|
#else
|
|
|
|
screen_size.ws_row = 24;
|
|
|
|
screen_size.ws_col = 80;
|
1998-05-07 16:52:52 +02:00
|
|
|
#endif
|
2017-09-05 18:02:06 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Since this function is no longer used by psql, we don't examine
|
|
|
|
* PSQL_PAGER. It's possible that the hypothetical external users
|
|
|
|
* of the function would like that to happen, but in the name of
|
|
|
|
* backwards compatibility, we'll stick to just examining PAGER.
|
|
|
|
*/
|
1998-05-07 16:52:52 +02:00
|
|
|
pagerenv = getenv("PAGER");
|
Handle empty or all-blank PAGER setting more sanely in psql.
If the PAGER environment variable is set but contains an empty string,
psql would pass it to "sh" which would silently exit, causing whatever
query output we were printing to vanish entirely. This is quite
mystifying; it took a long time for us to figure out that this was the
cause of Joseph Brenner's trouble report. Rather than allowing that
to happen, we should treat this as another way to specify "no pager".
(We could alternatively treat it as selecting the default pager, but
it seems more likely that the former is what the user meant to achieve
by setting PAGER this way.)
Nonempty, but all-white-space, PAGER values have the same behavior, and
it's pretty easy to test for that, so let's handle that case the same way.
Most other cases of faulty PAGER values will result in the shell printing
some kind of complaint to stderr, which should be enough to diagnose the
problem, so we don't need to work harder than this. (Note that there's
been an intentional decision not to be very chatty about apparent failure
returns from the pager process, since that may happen if, eg, the user
quits the pager with control-C or some such. I'd just as soon not start
splitting hairs about which exit codes might merit making our own report.)
libpq's old PQprint() function was already on board with ignoring empty
PAGER values, but for consistency, make it ignore all-white-space values
as well.
It's been like this a long time, so back-patch to all supported branches.
Discussion: https://postgr.es/m/CAFfgvXWLOE2novHzYjmQK8-J6TmHz42G8f3X0SORM44+stUGmw@mail.gmail.com
2016-12-07 18:19:56 +01:00
|
|
|
/* if PAGER is unset, empty or all-white-space, don't use pager */
|
1998-05-07 16:52:52 +02:00
|
|
|
if (pagerenv != NULL &&
|
Handle empty or all-blank PAGER setting more sanely in psql.
If the PAGER environment variable is set but contains an empty string,
psql would pass it to "sh" which would silently exit, causing whatever
query output we were printing to vanish entirely. This is quite
mystifying; it took a long time for us to figure out that this was the
cause of Joseph Brenner's trouble report. Rather than allowing that
to happen, we should treat this as another way to specify "no pager".
(We could alternatively treat it as selecting the default pager, but
it seems more likely that the former is what the user meant to achieve
by setting PAGER this way.)
Nonempty, but all-white-space, PAGER values have the same behavior, and
it's pretty easy to test for that, so let's handle that case the same way.
Most other cases of faulty PAGER values will result in the shell printing
some kind of complaint to stderr, which should be enough to diagnose the
problem, so we don't need to work harder than this. (Note that there's
been an intentional decision not to be very chatty about apparent failure
returns from the pager process, since that may happen if, eg, the user
quits the pager with control-C or some such. I'd just as soon not start
splitting hairs about which exit codes might merit making our own report.)
libpq's old PQprint() function was already on board with ignoring empty
PAGER values, but for consistency, make it ignore all-white-space values
as well.
It's been like this a long time, so back-patch to all supported branches.
Discussion: https://postgr.es/m/CAFfgvXWLOE2novHzYjmQK8-J6TmHz42G8f3X0SORM44+stUGmw@mail.gmail.com
2016-12-07 18:19:56 +01:00
|
|
|
strspn(pagerenv, " \t\r\n") != strlen(pagerenv) &&
|
1998-05-07 16:52:52 +02:00
|
|
|
!po->html3 &&
|
|
|
|
((po->expanded &&
|
|
|
|
nTups * (nFields + 1) >= screen_size.ws_row) ||
|
|
|
|
(!po->expanded &&
|
|
|
|
nTups * (total_line_length / screen_size.ws_col + 1) *
|
1999-02-03 22:18:02 +01:00
|
|
|
(1 + (po->standard != 0)) >= screen_size.ws_row -
|
1998-05-07 16:52:52 +02:00
|
|
|
(po->header != 0) *
|
|
|
|
(total_line_length / screen_size.ws_col + 1) * 2
|
Phase 2 of pgindent updates.
Change pg_bsd_indent to follow upstream rules for placement of comments
to the right of code, and remove pgindent hack that caused comments
following #endif to not obey the general rule.
Commit e3860ffa4dd0dad0dd9eea4be9cc1412373a8c89 wasn't actually using
the published version of pg_bsd_indent, but a hacked-up version that
tried to minimize the amount of movement of comments to the right of
code. The situation of interest is where such a comment has to be
moved to the right of its default placement at column 33 because there's
code there. BSD indent has always moved right in units of tab stops
in such cases --- but in the previous incarnation, indent was working
in 8-space tab stops, while now it knows we use 4-space tabs. So the
net result is that in about half the cases, such comments are placed
one tab stop left of before. This is better all around: it leaves
more room on the line for comment text, and it means that in such
cases the comment uniformly starts at the next 4-space tab stop after
the code, rather than sometimes one and sometimes two tabs after.
Also, ensure that comments following #endif are indented the same
as comments following other preprocessor commands such as #else.
That inconsistency turns out to have been self-inflicted damage
from a poorly-thought-through post-indent "fixup" in pgindent.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:18:54 +02:00
|
|
|
- (po->header != 0) * 2 /* row count and newline */
|
1998-05-07 16:52:52 +02:00
|
|
|
)))
|
|
|
|
{
|
|
|
|
fout = popen(pagerenv, "w");
|
|
|
|
if (fout)
|
|
|
|
{
|
|
|
|
usePipe = 1;
|
2005-08-23 23:02:05 +02:00
|
|
|
#ifndef WIN32
|
2004-01-09 03:02:43 +01:00
|
|
|
#ifdef ENABLE_THREAD_SAFETY
|
2004-12-03 00:20:21 +01:00
|
|
|
if (pq_block_sigpipe(&osigset, &sigpipe_pending) == 0)
|
|
|
|
sigpipe_masked = true;
|
2004-01-09 03:02:43 +01:00
|
|
|
#else
|
1998-08-09 04:59:33 +02:00
|
|
|
oldsigpipehandler = pqsignal(SIGPIPE, SIG_IGN);
|
Phase 2 of pgindent updates.
Change pg_bsd_indent to follow upstream rules for placement of comments
to the right of code, and remove pgindent hack that caused comments
following #endif to not obey the general rule.
Commit e3860ffa4dd0dad0dd9eea4be9cc1412373a8c89 wasn't actually using
the published version of pg_bsd_indent, but a hacked-up version that
tried to minimize the amount of movement of comments to the right of
code. The situation of interest is where such a comment has to be
moved to the right of its default placement at column 33 because there's
code there. BSD indent has always moved right in units of tab stops
in such cases --- but in the previous incarnation, indent was working
in 8-space tab stops, while now it knows we use 4-space tabs. So the
net result is that in about half the cases, such comments are placed
one tab stop left of before. This is better all around: it leaves
more room on the line for comment text, and it means that in such
cases the comment uniformly starts at the next 4-space tab stop after
the code, rather than sometimes one and sometimes two tabs after.
Also, ensure that comments following #endif are indented the same
as comments following other preprocessor commands such as #else.
That inconsistency turns out to have been self-inflicted damage
from a poorly-thought-through post-indent "fixup" in pgindent.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:18:54 +02:00
|
|
|
#endif /* ENABLE_THREAD_SAFETY */
|
|
|
|
#endif /* WIN32 */
|
1998-05-07 16:52:52 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
fout = stdout;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!po->expanded && (po->align || po->html3))
|
|
|
|
{
|
|
|
|
if (!(fields = (char **) calloc(nFields * (nTups + 1), sizeof(char *))))
|
|
|
|
{
|
2004-11-09 16:57:57 +01:00
|
|
|
fprintf(stderr, libpq_gettext("out of memory\n"));
|
2012-01-30 20:34:00 +01:00
|
|
|
abort();
|
1998-05-07 16:52:52 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (po->header && !po->html3)
|
|
|
|
{
|
|
|
|
if (po->expanded)
|
|
|
|
{
|
|
|
|
if (po->align)
|
2005-02-22 05:43:23 +01:00
|
|
|
fprintf(fout, libpq_gettext("%-*s%s Value\n"),
|
|
|
|
fieldMaxLen - fs_len, libpq_gettext("Field"), po->fieldSep);
|
1998-05-07 16:52:52 +02:00
|
|
|
else
|
2005-02-22 05:43:23 +01:00
|
|
|
fprintf(fout, libpq_gettext("%s%sValue\n"), libpq_gettext("Field"), po->fieldSep);
|
1998-05-07 16:52:52 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int len = 0;
|
|
|
|
|
|
|
|
for (j = 0; j < nFields; j++)
|
|
|
|
{
|
2000-04-12 19:17:23 +02:00
|
|
|
const char *s = fieldNames[j];
|
1998-05-07 16:52:52 +02:00
|
|
|
|
|
|
|
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)
|
2006-02-06 03:23:07 +01:00
|
|
|
fprintf(fout, "<center><h2>%s</h2></center>\n", po->caption);
|
1998-05-07 16:52:52 +02:00
|
|
|
else
|
|
|
|
fprintf(fout,
|
2006-02-06 03:23:07 +01:00
|
|
|
"<center><h2>"
|
1998-05-07 16:52:52 +02:00
|
|
|
"Query retrieved %d rows * %d fields"
|
2006-02-06 03:23:07 +01:00
|
|
|
"</h2></center>\n",
|
1998-05-07 16:52:52 +02:00
|
|
|
nTups, nFields);
|
|
|
|
}
|
|
|
|
for (i = 0; i < nTups; i++)
|
|
|
|
{
|
|
|
|
if (po->expanded)
|
|
|
|
{
|
|
|
|
if (po->html3)
|
|
|
|
fprintf(fout,
|
2006-02-07 01:26:15 +01:00
|
|
|
"<table %s><caption align=\"top\">%d</caption>\n",
|
1998-05-07 16:52:52 +02:00
|
|
|
po->tableOpt ? po->tableOpt : "", i);
|
|
|
|
else
|
2005-02-22 05:43:23 +01:00
|
|
|
fprintf(fout, libpq_gettext("-- RECORD %d --\n"), i);
|
1998-05-07 16:52:52 +02:00
|
|
|
}
|
|
|
|
for (j = 0; j < nFields; j++)
|
1999-08-31 03:37:37 +02:00
|
|
|
do_field(po, res, i, j, fs_len, fields, nFields,
|
1998-05-07 16:52:52 +02:00
|
|
|
fieldNames, fieldNotNum,
|
|
|
|
fieldMax, fieldMaxLen, 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,
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
"<table %s><caption align=\"top\">%s</caption>\n",
|
1998-05-07 16:52:52 +02:00
|
|
|
po->tableOpt ? po->tableOpt : "",
|
|
|
|
po->caption);
|
|
|
|
else
|
|
|
|
fprintf(fout,
|
2006-02-07 01:26:15 +01:00
|
|
|
"<table %s><caption align=\"top\">"
|
1998-05-07 16:52:52 +02:00
|
|
|
"Retrieved %d rows * %d fields"
|
|
|
|
"</caption>\n",
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
po->tableOpt ? po->tableOpt : "", nTups, nFields);
|
1998-05-07 16:52:52 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
fprintf(fout, "<table %s>", po->tableOpt ? po->tableOpt : "");
|
|
|
|
}
|
|
|
|
if (po->header)
|
|
|
|
border = do_header(fout, po, nFields, fieldMax, fieldNames,
|
|
|
|
fieldNotNum, fs_len, res);
|
|
|
|
for (i = 0; i < nTups; i++)
|
|
|
|
output_row(fout, po, nFields, fields,
|
|
|
|
fieldNotNum, fieldMax, border, i);
|
|
|
|
free(fields);
|
|
|
|
if (border)
|
|
|
|
free(border);
|
|
|
|
}
|
|
|
|
if (po->header && !po->html3)
|
|
|
|
fprintf(fout, "(%d row%s)\n\n", PQntuples(res),
|
|
|
|
(PQntuples(res) == 1) ? "" : "s");
|
|
|
|
free(fieldMax);
|
|
|
|
free(fieldNotNum);
|
2002-10-03 19:09:42 +02:00
|
|
|
free((void *) fieldNames);
|
1998-05-07 16:52:52 +02:00
|
|
|
if (usePipe)
|
|
|
|
{
|
1998-07-03 06:24:16 +02:00
|
|
|
#ifdef WIN32
|
|
|
|
_pclose(fout);
|
|
|
|
#else
|
1998-05-07 16:52:52 +02:00
|
|
|
pclose(fout);
|
2005-10-15 04:49:52 +02:00
|
|
|
|
2004-01-09 03:02:43 +01:00
|
|
|
#ifdef ENABLE_THREAD_SAFETY
|
2004-12-03 00:20:21 +01:00
|
|
|
/* we can't easily verify if EPIPE occurred, so say it did */
|
2004-12-02 16:32:54 +01:00
|
|
|
if (sigpipe_masked)
|
2004-12-03 00:20:21 +01:00
|
|
|
pq_reset_sigpipe(&osigset, sigpipe_pending, true);
|
2004-01-09 03:02:43 +01:00
|
|
|
#else
|
1998-08-09 04:59:33 +02:00
|
|
|
pqsignal(SIGPIPE, oldsigpipehandler);
|
Phase 2 of pgindent updates.
Change pg_bsd_indent to follow upstream rules for placement of comments
to the right of code, and remove pgindent hack that caused comments
following #endif to not obey the general rule.
Commit e3860ffa4dd0dad0dd9eea4be9cc1412373a8c89 wasn't actually using
the published version of pg_bsd_indent, but a hacked-up version that
tried to minimize the amount of movement of comments to the right of
code. The situation of interest is where such a comment has to be
moved to the right of its default placement at column 33 because there's
code there. BSD indent has always moved right in units of tab stops
in such cases --- but in the previous incarnation, indent was working
in 8-space tab stops, while now it knows we use 4-space tabs. So the
net result is that in about half the cases, such comments are placed
one tab stop left of before. This is better all around: it leaves
more room on the line for comment text, and it means that in such
cases the comment uniformly starts at the next 4-space tab stop after
the code, rather than sometimes one and sometimes two tabs after.
Also, ensure that comments following #endif are indented the same
as comments following other preprocessor commands such as #else.
That inconsistency turns out to have been self-inflicted damage
from a poorly-thought-through post-indent "fixup" in pgindent.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:18:54 +02:00
|
|
|
#endif /* ENABLE_THREAD_SAFETY */
|
|
|
|
#endif /* WIN32 */
|
1998-05-07 16:52:52 +02:00
|
|
|
}
|
|
|
|
if (po->html3 && !po->expanded)
|
|
|
|
fputs("</table>\n", fout);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
In the spirit of TODO item
* Add use of 'const' for varibles in source tree
(which is misspelled, btw.)
I went through the front-end libpq code and did so. This affects in
particular the various accessor functions (such as PQdb() and
PQgetvalue()) as well as, by necessity, the internal helpers they use.
I have been really thorough in that regard, perhaps some people will find
it annoying that things like
char * foo = PQgetvalue(res, 0, 0)
will generate a warning. On the other hand it _should_ generate one. This
is no real compatibility break, although a few clients will have to be
fixed to suppress warnings. (Which again would be in the spirit of the
above TODO.)
In addition I replaced some int's by size_t's and removed some warnings
(and generated some new ones -- grmpf!). Also I rewrote PQoidStatus (so it
actually honors the const!) and supplied a new function PQoidValue that
returns a proper Oid type. This is only front-end stuff, none of the
communicaton stuff was touched.
The psql patch also adds some new consts to honor the new libpq situation,
as well as fixes a fatal condition that resulted when using the -V
(--version) option and there is no database listening.
So, to summarize, the psql you should definitely put in (with or without
the libpq). If you think I went too far with the const-mania in libpq, let
me know and I'll make adjustments. If you approve it, I will also update
the docs.
-Peter
--
Peter Eisentraut Sernanders vaeg 10:115
1999-11-11 01:10:14 +01:00
|
|
|
do_field(const PQprintOpt *po, const PGresult *res,
|
1999-08-31 03:37:37 +02:00
|
|
|
const int i, const int j, const int fs_len,
|
1998-09-01 05:29:17 +02:00
|
|
|
char **fields,
|
2017-06-21 20:39:04 +02:00
|
|
|
const int nFields, char const **fieldNames,
|
1998-09-01 05:29:17 +02:00
|
|
|
unsigned char *fieldNotNum, int *fieldMax,
|
1998-05-07 16:52:52 +02:00
|
|
|
const int fieldMaxLen, FILE *fout)
|
|
|
|
{
|
2000-04-12 19:17:23 +02:00
|
|
|
const char *pval,
|
1999-08-31 03:37:37 +02:00
|
|
|
*p;
|
1998-05-07 16:52:52 +02:00
|
|
|
int plen;
|
|
|
|
bool skipit;
|
|
|
|
|
|
|
|
plen = PQgetlength(res, i, j);
|
|
|
|
pval = PQgetvalue(res, i, j);
|
|
|
|
|
|
|
|
if (plen < 1 || !pval || !*pval)
|
|
|
|
{
|
|
|
|
if (po->align || po->expanded)
|
|
|
|
skipit = true;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
skipit = false;
|
|
|
|
goto efield;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
skipit = false;
|
|
|
|
|
|
|
|
if (!skipit)
|
|
|
|
{
|
2000-04-12 19:17:23 +02:00
|
|
|
if (po->align && !fieldNotNum[j])
|
1999-08-31 03:37:37 +02:00
|
|
|
{
|
|
|
|
/* Detect whether field contains non-numeric data */
|
|
|
|
char ch = '0';
|
1999-05-25 18:15:34 +02:00
|
|
|
|
2000-03-15 00:59:23 +01:00
|
|
|
for (p = pval; *p; p += PQmblen(p, res->client_encoding))
|
1999-08-31 03:37:37 +02:00
|
|
|
{
|
|
|
|
ch = *p;
|
2000-04-12 19:17:23 +02:00
|
|
|
if (!((ch >= '0' && ch <= '9') ||
|
|
|
|
ch == '.' ||
|
|
|
|
ch == 'E' ||
|
|
|
|
ch == 'e' ||
|
|
|
|
ch == ' ' ||
|
|
|
|
ch == '-'))
|
1999-08-31 03:37:37 +02:00
|
|
|
{
|
|
|
|
fieldNotNum[j] = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2000-04-12 19:17:23 +02:00
|
|
|
|
1998-10-04 22:46:39 +02:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Above loop will believe E in first column is numeric; also, we
|
|
|
|
* insist on a digit in the last column for a numeric. This test
|
|
|
|
* is still not bulletproof but it handles most cases.
|
1998-10-04 22:46:39 +02:00
|
|
|
*/
|
1999-08-31 03:37:37 +02:00
|
|
|
if (*pval == 'E' || *pval == 'e' ||
|
|
|
|
!(ch >= '0' && ch <= '9'))
|
1998-05-07 16:52:52 +02:00
|
|
|
fieldNotNum[j] = 1;
|
|
|
|
}
|
1999-08-31 03:37:37 +02:00
|
|
|
|
1998-05-07 16:52:52 +02:00
|
|
|
if (!po->expanded && (po->align || po->html3))
|
|
|
|
{
|
1999-08-31 03:37:37 +02:00
|
|
|
if (plen > fieldMax[j])
|
|
|
|
fieldMax[j] = plen;
|
|
|
|
if (!(fields[i * nFields + j] = (char *) malloc(plen + 1)))
|
1998-05-07 16:52:52 +02:00
|
|
|
{
|
2004-11-09 16:57:57 +01:00
|
|
|
fprintf(stderr, libpq_gettext("out of memory\n"));
|
2012-01-30 20:34:00 +01:00
|
|
|
abort();
|
1998-05-07 16:52:52 +02:00
|
|
|
}
|
1999-08-31 03:37:37 +02:00
|
|
|
strcpy(fields[i * nFields + j], pval);
|
1998-05-07 16:52:52 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (po->expanded)
|
|
|
|
{
|
|
|
|
if (po->html3)
|
|
|
|
fprintf(fout,
|
2006-02-07 01:26:15 +01:00
|
|
|
"<tr><td align=\"left\"><b>%s</b></td>"
|
|
|
|
"<td align=\"%s\">%s</td></tr>\n",
|
1998-05-07 16:52:52 +02:00
|
|
|
fieldNames[j],
|
|
|
|
fieldNotNum[j] ? "left" : "right",
|
1999-08-31 03:37:37 +02:00
|
|
|
pval);
|
1998-05-07 16:52:52 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
if (po->align)
|
|
|
|
fprintf(fout,
|
|
|
|
"%-*s%s %s\n",
|
1999-08-31 03:37:37 +02:00
|
|
|
fieldMaxLen - fs_len, fieldNames[j],
|
|
|
|
po->fieldSep,
|
|
|
|
pval);
|
1998-05-07 16:52:52 +02:00
|
|
|
else
|
1999-08-31 03:37:37 +02:00
|
|
|
fprintf(fout,
|
|
|
|
"%s%s%s\n",
|
|
|
|
fieldNames[j], po->fieldSep, pval);
|
1998-05-07 16:52:52 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (!po->html3)
|
|
|
|
{
|
1999-08-31 03:37:37 +02:00
|
|
|
fputs(pval, fout);
|
1998-05-07 16:52:52 +02:00
|
|
|
efield:
|
|
|
|
if ((j + 1) < nFields)
|
|
|
|
fputs(po->fieldSep, fout);
|
|
|
|
else
|
|
|
|
fputc('\n', fout);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static char *
|
In the spirit of TODO item
* Add use of 'const' for varibles in source tree
(which is misspelled, btw.)
I went through the front-end libpq code and did so. This affects in
particular the various accessor functions (such as PQdb() and
PQgetvalue()) as well as, by necessity, the internal helpers they use.
I have been really thorough in that regard, perhaps some people will find
it annoying that things like
char * foo = PQgetvalue(res, 0, 0)
will generate a warning. On the other hand it _should_ generate one. This
is no real compatibility break, although a few clients will have to be
fixed to suppress warnings. (Which again would be in the spirit of the
above TODO.)
In addition I replaced some int's by size_t's and removed some warnings
(and generated some new ones -- grmpf!). Also I rewrote PQoidStatus (so it
actually honors the const!) and supplied a new function PQoidValue that
returns a proper Oid type. This is only front-end stuff, none of the
communicaton stuff was touched.
The psql patch also adds some new consts to honor the new libpq situation,
as well as fixes a fatal condition that resulted when using the -V
(--version) option and there is no database listening.
So, to summarize, the psql you should definitely put in (with or without
the libpq). If you think I went too far with the const-mania in libpq, let
me know and I'll make adjustments. If you approve it, I will also update
the docs.
-Peter
--
Peter Eisentraut Sernanders vaeg 10:115
1999-11-11 01:10:14 +01:00
|
|
|
do_header(FILE *fout, const PQprintOpt *po, const int nFields, int *fieldMax,
|
|
|
|
const char **fieldNames, unsigned char *fieldNotNum,
|
|
|
|
const int fs_len, const PGresult *res)
|
1998-05-07 16:52:52 +02:00
|
|
|
{
|
|
|
|
int j; /* for loop index */
|
|
|
|
char *border = NULL;
|
|
|
|
|
|
|
|
if (po->html3)
|
|
|
|
fputs("<tr>", fout);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int tot = 0;
|
|
|
|
int n = 0;
|
|
|
|
char *p = NULL;
|
|
|
|
|
|
|
|
for (; n < nFields; n++)
|
|
|
|
tot += fieldMax[n] + fs_len + (po->standard ? 2 : 0);
|
|
|
|
if (po->standard)
|
|
|
|
tot += fs_len * 2 + 2;
|
|
|
|
border = malloc(tot + 1);
|
|
|
|
if (!border)
|
|
|
|
{
|
2004-11-09 16:57:57 +01:00
|
|
|
fprintf(stderr, libpq_gettext("out of memory\n"));
|
2012-01-30 20:34:00 +01:00
|
|
|
abort();
|
1998-05-07 16:52:52 +02:00
|
|
|
}
|
|
|
|
p = border;
|
|
|
|
if (po->standard)
|
|
|
|
{
|
1999-02-05 05:25:55 +01:00
|
|
|
char *fs = po->fieldSep;
|
1998-05-07 16:52:52 +02:00
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
1999-02-05 05:25:55 +01:00
|
|
|
char *fs = po->fieldSep;
|
1998-05-07 16:52:52 +02:00
|
|
|
|
|
|
|
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++)
|
|
|
|
{
|
2000-04-12 19:17:23 +02:00
|
|
|
const char *s = PQfname(res, j);
|
1998-05-07 16:52:52 +02:00
|
|
|
|
|
|
|
if (po->html3)
|
|
|
|
{
|
2006-02-07 01:26:15 +01:00
|
|
|
fprintf(fout, "<th align=\"%s\">%s</th>",
|
1998-05-07 16:52:52 +02:00
|
|
|
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);
|
|
|
|
return border;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
In the spirit of TODO item
* Add use of 'const' for varibles in source tree
(which is misspelled, btw.)
I went through the front-end libpq code and did so. This affects in
particular the various accessor functions (such as PQdb() and
PQgetvalue()) as well as, by necessity, the internal helpers they use.
I have been really thorough in that regard, perhaps some people will find
it annoying that things like
char * foo = PQgetvalue(res, 0, 0)
will generate a warning. On the other hand it _should_ generate one. This
is no real compatibility break, although a few clients will have to be
fixed to suppress warnings. (Which again would be in the spirit of the
above TODO.)
In addition I replaced some int's by size_t's and removed some warnings
(and generated some new ones -- grmpf!). Also I rewrote PQoidStatus (so it
actually honors the const!) and supplied a new function PQoidValue that
returns a proper Oid type. This is only front-end stuff, none of the
communicaton stuff was touched.
The psql patch also adds some new consts to honor the new libpq situation,
as well as fixes a fatal condition that resulted when using the -V
(--version) option and there is no database listening.
So, to summarize, the psql you should definitely put in (with or without
the libpq). If you think I went too far with the const-mania in libpq, let
me know and I'll make adjustments. If you approve it, I will also update
the docs.
-Peter
--
Peter Eisentraut Sernanders vaeg 10:115
1999-11-11 01:10:14 +01:00
|
|
|
output_row(FILE *fout, const PQprintOpt *po, const int nFields, char **fields,
|
1998-09-01 05:29:17 +02:00
|
|
|
unsigned char *fieldNotNum, int *fieldMax, char *border,
|
1998-05-07 16:52:52 +02:00
|
|
|
const int row_index)
|
|
|
|
{
|
|
|
|
int field_index; /* for loop index */
|
|
|
|
|
|
|
|
if (po->html3)
|
|
|
|
fputs("<tr>", fout);
|
|
|
|
else if (po->standard)
|
|
|
|
fputs(po->fieldSep, fout);
|
|
|
|
for (field_index = 0; field_index < nFields; field_index++)
|
|
|
|
{
|
|
|
|
char *p = fields[row_index * nFields + field_index];
|
|
|
|
|
|
|
|
if (po->html3)
|
2006-02-07 01:26:15 +01:00
|
|
|
fprintf(fout, "<td align=\"%s\">%s</td>",
|
2005-10-15 04:49:52 +02:00
|
|
|
fieldNotNum[field_index] ? "left" : "right", p ? p : "");
|
1998-05-07 16:52:52 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
fprintf(fout,
|
|
|
|
fieldNotNum[field_index] ?
|
|
|
|
(po->standard ? " %-*s " : "%-*s") :
|
|
|
|
(po->standard ? " %*s " : "%*s"),
|
|
|
|
fieldMax[field_index],
|
|
|
|
p ? p : "");
|
|
|
|
if (po->standard || field_index + 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);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2000-01-29 17:58:54 +01:00
|
|
|
/*
|
|
|
|
* really old printing routines
|
|
|
|
*/
|
|
|
|
|
|
|
|
void
|
|
|
|
PQdisplayTuples(const PGresult *res,
|
2000-04-12 19:17:23 +02:00
|
|
|
FILE *fp, /* where to send the output */
|
|
|
|
int fillAlign, /* pad the fields with spaces */
|
|
|
|
const char *fieldSep, /* field separator */
|
2001-10-28 07:26:15 +01:00
|
|
|
int printHeader, /* display headers? */
|
2000-04-12 19:17:23 +02:00
|
|
|
int quiet
|
2000-01-29 17:58:54 +01:00
|
|
|
)
|
|
|
|
{
|
|
|
|
#define DEFAULT_FIELD_SEP " "
|
|
|
|
|
|
|
|
int i,
|
|
|
|
j;
|
|
|
|
int nFields;
|
|
|
|
int nTuples;
|
|
|
|
int *fLength = NULL;
|
|
|
|
|
|
|
|
if (fieldSep == NULL)
|
|
|
|
fieldSep = DEFAULT_FIELD_SEP;
|
|
|
|
|
|
|
|
/* Get some useful info about the results */
|
|
|
|
nFields = PQnfields(res);
|
|
|
|
nTuples = PQntuples(res);
|
|
|
|
|
|
|
|
if (fp == NULL)
|
|
|
|
fp = stdout;
|
|
|
|
|
|
|
|
/* Figure the field lengths to align to */
|
|
|
|
/* will be somewhat time consuming for very large results */
|
|
|
|
if (fillAlign)
|
|
|
|
{
|
|
|
|
fLength = (int *) malloc(nFields * sizeof(int));
|
2005-06-12 02:00:21 +02:00
|
|
|
if (!fLength)
|
|
|
|
{
|
|
|
|
fprintf(stderr, libpq_gettext("out of memory\n"));
|
2012-01-30 20:34:00 +01:00
|
|
|
abort();
|
2005-06-12 02:00:21 +02:00
|
|
|
}
|
|
|
|
|
2000-01-29 17:58:54 +01:00
|
|
|
for (j = 0; j < nFields; j++)
|
|
|
|
{
|
|
|
|
fLength[j] = strlen(PQfname(res, j));
|
|
|
|
for (i = 0; i < nTuples; i++)
|
|
|
|
{
|
2000-04-12 19:17:23 +02:00
|
|
|
int flen = PQgetlength(res, i, j);
|
|
|
|
|
2000-01-29 17:58:54 +01:00
|
|
|
if (flen > fLength[j])
|
|
|
|
fLength[j] = flen;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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 (fLength)
|
|
|
|
free(fLength);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
PQprintTuples(const PGresult *res,
|
2000-04-12 19:17:23 +02:00
|
|
|
FILE *fout, /* output stream */
|
2001-10-28 07:26:15 +01:00
|
|
|
int PrintAttNames, /* print attribute names or not */
|
2000-04-12 19:17:23 +02:00
|
|
|
int TerseOutput, /* delimiter bars or not? */
|
2005-10-15 04:49:52 +02:00
|
|
|
int colWidth /* width of column, if 0, use variable width */
|
2000-01-29 17:58:54 +01:00
|
|
|
)
|
1998-05-07 16:52:52 +02:00
|
|
|
{
|
2000-01-29 17:58:54 +01:00
|
|
|
int nFields;
|
|
|
|
int nTups;
|
|
|
|
int i,
|
|
|
|
j;
|
|
|
|
char formatString[80];
|
|
|
|
char *tborder = NULL;
|
|
|
|
|
|
|
|
nFields = PQnfields(res);
|
|
|
|
nTups = PQntuples(res);
|
|
|
|
|
|
|
|
if (colWidth > 0)
|
|
|
|
sprintf(formatString, "%%s %%-%ds", colWidth);
|
|
|
|
else
|
|
|
|
sprintf(formatString, "%%s %%s");
|
|
|
|
|
|
|
|
if (nFields > 0)
|
|
|
|
{ /* only print rows with at least 1 field. */
|
|
|
|
|
|
|
|
if (!TerseOutput)
|
|
|
|
{
|
|
|
|
int width;
|
|
|
|
|
|
|
|
width = nFields * 14;
|
2013-01-21 05:43:46 +01:00
|
|
|
tborder = (char *) malloc(width + 1);
|
2005-06-12 02:00:21 +02:00
|
|
|
if (!tborder)
|
|
|
|
{
|
|
|
|
fprintf(stderr, libpq_gettext("out of memory\n"));
|
2012-01-30 20:34:00 +01:00
|
|
|
abort();
|
2005-06-12 02:00:21 +02:00
|
|
|
}
|
2013-01-21 05:43:46 +01:00
|
|
|
for (i = 0; i < width; i++)
|
2000-01-29 17:58:54 +01:00
|
|
|
tborder[i] = '-';
|
2013-01-21 05:43:46 +01:00
|
|
|
tborder[width] = '\0';
|
2000-01-29 17:58:54 +01:00
|
|
|
fprintf(fout, "%s\n", tborder);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < nFields; i++)
|
|
|
|
{
|
|
|
|
if (PrintAttNames)
|
|
|
|
{
|
|
|
|
fprintf(fout, formatString,
|
|
|
|
TerseOutput ? "" : "|",
|
|
|
|
PQfname(res, i));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (PrintAttNames)
|
|
|
|
{
|
|
|
|
if (TerseOutput)
|
|
|
|
fprintf(fout, "\n");
|
|
|
|
else
|
|
|
|
fprintf(fout, "|\n%s\n", tborder);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < nTups; i++)
|
|
|
|
{
|
|
|
|
for (j = 0; j < nFields; j++)
|
|
|
|
{
|
2000-04-12 19:17:23 +02:00
|
|
|
const char *pval = PQgetvalue(res, i, j);
|
1998-05-07 16:52:52 +02:00
|
|
|
|
2000-01-29 17:58:54 +01:00
|
|
|
fprintf(fout, formatString,
|
|
|
|
TerseOutput ? "" : "|",
|
|
|
|
pval ? pval : "");
|
|
|
|
}
|
|
|
|
if (TerseOutput)
|
|
|
|
fprintf(fout, "\n");
|
|
|
|
else
|
|
|
|
fprintf(fout, "|\n%s\n", tborder);
|
|
|
|
}
|
|
|
|
}
|
2000-02-08 00:10:11 +01:00
|
|
|
|
2006-04-19 18:15:29 +02:00
|
|
|
if (tborder)
|
|
|
|
free(tborder);
|
|
|
|
}
|
2000-02-08 00:10:11 +01:00
|
|
|
|
|
|
|
|
|
|
|
/* simply send out max-length number of filler characters to fp */
|
2000-04-12 19:17:23 +02:00
|
|
|
|
2000-02-08 00:10:11 +01:00
|
|
|
static void
|
|
|
|
fill(int length, int max, char filler, FILE *fp)
|
|
|
|
{
|
2000-04-12 19:17:23 +02:00
|
|
|
int count;
|
|
|
|
|
|
|
|
count = max - length;
|
|
|
|
while (count-- >= 0)
|
|
|
|
putc(filler, fp);
|
2000-02-08 00:10:11 +01:00
|
|
|
}
|