Age Owner TLA Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * fe-print.c
4 : * functions for pretty-printing query results
5 : *
6 : * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
7 : * Portions Copyright (c) 1994, Regents of the University of California
8 : *
9 : * These functions were formerly part of fe-exec.c, but they
10 : * didn't really belong there.
11 : *
12 : * IDENTIFICATION
13 : * src/interfaces/libpq/fe-print.c
14 : *
15 : *-------------------------------------------------------------------------
16 : */
17 : #include "postgres_fe.h"
18 :
19 : #include <signal.h>
20 :
21 : #ifdef WIN32
22 : #include "win32.h"
23 : #else
24 : #include <unistd.h>
25 : #include <sys/ioctl.h>
26 : #endif
27 :
28 : #ifdef HAVE_TERMIOS_H
29 : #include <termios.h>
30 : #else
31 : #ifndef WIN32
32 : #include <sys/termios.h>
33 : #endif
34 : #endif
35 :
36 : #include "libpq-fe.h"
37 : #include "libpq-int.h"
38 :
39 :
40 : static bool do_field(const PQprintOpt *po, const PGresult *res,
41 : const int i, const int j, const int fs_len,
42 : char **fields,
43 : const int nFields, const char **fieldNames,
44 : unsigned char *fieldNotNum, int *fieldMax,
45 : const int fieldMaxLen, FILE *fout);
46 : static char *do_header(FILE *fout, const PQprintOpt *po, const int nFields,
47 : int *fieldMax, const char **fieldNames, unsigned char *fieldNotNum,
48 : const int fs_len, const PGresult *res);
49 : static void output_row(FILE *fout, const PQprintOpt *po, const int nFields, char **fields,
50 : unsigned char *fieldNotNum, int *fieldMax, char *border,
51 : const int row_index);
52 : static void fill(int length, int max, char filler, FILE *fp);
53 :
54 : /*
55 : * PQprint()
56 : *
57 : * Format results of a query for printing.
58 : *
59 : * PQprintOpt is a typedef (structure) that contains
60 : * various flags and options. consult libpq-fe.h for
61 : * details
62 : *
63 : * This function should probably be removed sometime since psql
64 : * doesn't use it anymore. It is unclear to what extent this is used
65 : * by external clients, however.
66 : */
67 : void
6510 neilc 68 CBC 3592 : PQprint(FILE *fout, const PGresult *res, const PQprintOpt *po)
69 : {
70 : int nFields;
71 :
9103 bruce 72 3592 : nFields = PQnfields(res);
73 :
74 3592 : if (nFields > 0)
75 : { /* only print rows with at least 1 field. */
76 : int i,
77 : j;
78 : int nTups;
79 3592 : int *fieldMax = NULL; /* in case we don't use them */
80 3592 : unsigned char *fieldNotNum = NULL;
81 3592 : char *border = NULL;
82 3592 : char **fields = NULL;
650 tgl 83 3592 : const char **fieldNames = NULL;
9103 bruce 84 3592 : int fieldMaxLen = 0;
85 : int numFieldName;
86 3592 : int fs_len = strlen(po->fieldSep);
87 3592 : int total_line_length = 0;
650 tgl 88 3592 : bool usePipe = false;
89 : char *pagerenv;
90 :
91 : #if defined(ENABLE_THREAD_SAFETY) && !defined(WIN32)
92 : sigset_t osigset;
6702 bruce 93 3592 : bool sigpipe_masked = false;
94 : bool sigpipe_pending;
95 : #endif
96 : #if !defined(ENABLE_THREAD_SAFETY) && !defined(WIN32)
97 : pqsigfunc oldsigpipehandler = NULL;
98 : #endif
99 :
100 : #ifdef TIOCGWINSZ
101 : struct winsize screen_size;
102 : #else
103 : struct winsize
104 : {
105 : int ws_row;
106 : int ws_col;
107 : } screen_size;
108 : #endif
109 :
9103 110 3592 : nTups = PQntuples(res);
650 tgl 111 3592 : fieldNames = (const char **) calloc(nFields, sizeof(char *));
112 3592 : fieldNotNum = (unsigned char *) calloc(nFields, 1);
113 3592 : fieldMax = (int *) calloc(nFields, sizeof(int));
114 3592 : if (!fieldNames || !fieldNotNum || !fieldMax)
115 : {
6725 peter_e 116 UBC 0 : fprintf(stderr, libpq_gettext("out of memory\n"));
650 tgl 117 0 : goto exit;
118 : }
9103 bruce 119 CBC 3592 : for (numFieldName = 0;
120 3592 : po->fieldName && po->fieldName[numFieldName];
9103 bruce 121 UBC 0 : numFieldName++)
122 : ;
9103 bruce 123 CBC 9282 : for (j = 0; j < nFields; j++)
124 : {
125 : int len;
8397 126 5690 : const char *s = (j < numFieldName && po->fieldName[j][0]) ?
9103 127 5690 : po->fieldName[j] : PQfname(res, j);
128 :
129 5690 : fieldNames[j] = s;
130 5690 : len = s ? strlen(s) : 0;
131 5690 : fieldMax[j] = len;
132 5690 : len += fs_len;
133 5690 : if (len > fieldMaxLen)
134 4815 : fieldMaxLen = len;
135 5690 : total_line_length += len;
136 : }
137 :
138 3592 : total_line_length += nFields * strlen(po->fieldSep) + 1;
139 :
140 3592 : if (fout == NULL)
9103 bruce 141 UBC 0 : fout = stdout;
5440 bruce 142 CBC 3592 : if (po->pager && fout == stdout && isatty(fileno(stdin)) &&
5440 bruce 143 UBC 0 : isatty(fileno(stdout)))
144 : {
145 : /*
146 : * If we think there'll be more than one screen of output, try to
147 : * pipe to the pager program.
148 : */
149 : #ifdef TIOCGWINSZ
9103 150 0 : if (ioctl(fileno(stdout), TIOCGWINSZ, &screen_size) == -1 ||
151 0 : screen_size.ws_col == 0 ||
152 0 : screen_size.ws_row == 0)
153 : {
154 0 : screen_size.ws_row = 24;
155 0 : screen_size.ws_col = 80;
156 : }
157 : #else
158 : screen_size.ws_row = 24;
159 : screen_size.ws_col = 80;
160 : #endif
161 :
162 : /*
163 : * Since this function is no longer used by psql, we don't examine
164 : * PSQL_PAGER. It's possible that the hypothetical external users
165 : * of the function would like that to happen, but in the name of
166 : * backwards compatibility, we'll stick to just examining PAGER.
167 : */
168 0 : pagerenv = getenv("PAGER");
169 : /* if PAGER is unset, empty or all-white-space, don't use pager */
170 0 : if (pagerenv != NULL &&
2314 tgl 171 0 : strspn(pagerenv, " \t\r\n") != strlen(pagerenv) &&
9103 bruce 172 0 : !po->html3 &&
173 0 : ((po->expanded &&
174 0 : nTups * (nFields + 1) >= screen_size.ws_row) ||
175 0 : (!po->expanded &&
176 0 : nTups * (total_line_length / screen_size.ws_col + 1) *
8831 177 0 : (1 + (po->standard != 0)) >= screen_size.ws_row -
9103 178 0 : (po->header != 0) *
179 0 : (total_line_length / screen_size.ws_col + 1) * 2
2118 tgl 180 0 : - (po->header != 0) * 2 /* row count and newline */
181 : )))
182 : {
223 tgl 183 UNC 0 : fflush(NULL);
9103 bruce 184 UBC 0 : fout = popen(pagerenv, "w");
185 0 : if (fout)
9103 bruce 186 EUB : {
650 tgl 187 UIC 0 : usePipe = true;
6438 bruce 188 EUB : #ifndef WIN32
189 : #ifdef ENABLE_THREAD_SAFETY
6702 tgl 190 UIC 0 : if (pq_block_sigpipe(&osigset, &sigpipe_pending) == 0)
6702 tgl 191 UBC 0 : sigpipe_masked = true;
7030 bruce 192 EUB : #else
193 : oldsigpipehandler = pqsignal(SIGPIPE, SIG_IGN);
194 : #endif /* ENABLE_THREAD_SAFETY */
195 : #endif /* WIN32 */
196 : }
197 : else
9103 bruce 198 UIC 0 : fout = stdout;
9103 bruce 199 EUB : }
200 : }
201 :
9103 bruce 202 GIC 3592 : if (!po->expanded && (po->align || po->html3))
9103 bruce 203 ECB : {
650 tgl 204 GIC 3592 : fields = (char **) calloc((size_t) nTups + 1,
650 tgl 205 ECB : nFields * sizeof(char *));
650 tgl 206 GIC 3592 : if (!fields)
9103 bruce 207 ECB : {
6725 peter_e 208 UIC 0 : fprintf(stderr, libpq_gettext("out of memory\n"));
650 tgl 209 UBC 0 : goto exit;
9103 bruce 210 EUB : }
211 : }
9103 bruce 212 UIC 0 : else if (po->header && !po->html3)
9103 bruce 213 EUB : {
9103 bruce 214 UIC 0 : if (po->expanded)
9103 bruce 215 EUB : {
9103 bruce 216 UIC 0 : if (po->align)
6620 bruce 217 UBC 0 : fprintf(fout, libpq_gettext("%-*s%s Value\n"),
218 0 : fieldMaxLen - fs_len, libpq_gettext("Field"), po->fieldSep);
9103 bruce 219 EUB : else
6620 bruce 220 UIC 0 : fprintf(fout, libpq_gettext("%s%sValue\n"), libpq_gettext("Field"), po->fieldSep);
9103 bruce 221 EUB : }
222 : else
223 : {
9103 bruce 224 UIC 0 : int len = 0;
9103 bruce 225 EUB :
9103 bruce 226 UIC 0 : for (j = 0; j < nFields; j++)
9103 bruce 227 EUB : {
8397 bruce 228 UIC 0 : const char *s = fieldNames[j];
9103 bruce 229 EUB :
9103 bruce 230 UIC 0 : fputs(s, fout);
9103 bruce 231 UBC 0 : len += strlen(s) + fs_len;
232 0 : if ((j + 1) < nFields)
233 0 : fputs(po->fieldSep, fout);
9103 bruce 234 EUB : }
9103 bruce 235 UIC 0 : fputc('\n', fout);
9103 bruce 236 UBC 0 : for (len -= fs_len; len--; fputc('-', fout));
237 0 : fputc('\n', fout);
9103 bruce 238 EUB : }
239 : }
9103 bruce 240 GIC 3592 : if (po->expanded && po->html3)
9103 bruce 241 ECB : {
9103 bruce 242 UIC 0 : if (po->caption)
6271 bruce 243 UBC 0 : fprintf(fout, "<center><h2>%s</h2></center>\n", po->caption);
9103 bruce 244 EUB : else
9103 bruce 245 UIC 0 : fprintf(fout,
6271 bruce 246 EUB : "<center><h2>"
247 : "Query retrieved %d rows * %d fields"
248 : "</h2></center>\n",
249 : nTups, nFields);
250 : }
9103 bruce 251 GIC 8585 : for (i = 0; i < nTups; i++)
9103 bruce 252 ECB : {
9103 bruce 253 GIC 4993 : if (po->expanded)
9103 bruce 254 ECB : {
9103 bruce 255 UIC 0 : if (po->html3)
9103 bruce 256 UBC 0 : fprintf(fout,
6270 bruce 257 EUB : "<table %s><caption align=\"top\">%d</caption>\n",
9103 bruce 258 UIC 0 : po->tableOpt ? po->tableOpt : "", i);
9103 bruce 259 EUB : else
6620 bruce 260 UIC 0 : fprintf(fout, libpq_gettext("-- RECORD %d --\n"), i);
9103 bruce 261 EUB : }
9103 bruce 262 GIC 13683 : for (j = 0; j < nFields; j++)
650 tgl 263 ECB : {
650 tgl 264 GIC 8690 : if (!do_field(po, res, i, j, fs_len, fields, nFields,
650 tgl 265 ECB : fieldNames, fieldNotNum,
266 : fieldMax, fieldMaxLen, fout))
650 tgl 267 UIC 0 : goto exit;
650 tgl 268 EUB : }
9103 bruce 269 GIC 4993 : if (po->html3 && po->expanded)
9103 bruce 270 LBC 0 : fputs("</table>\n", fout);
9103 bruce 271 EUB : }
9103 bruce 272 GIC 3592 : if (!po->expanded && (po->align || po->html3))
9103 bruce 273 ECB : {
9103 bruce 274 GIC 3592 : if (po->html3)
9103 bruce 275 ECB : {
9103 bruce 276 UIC 0 : if (po->header)
9103 bruce 277 EUB : {
9103 bruce 278 UIC 0 : if (po->caption)
9103 bruce 279 UBC 0 : fprintf(fout,
2118 tgl 280 EUB : "<table %s><caption align=\"top\">%s</caption>\n",
9103 bruce 281 UIC 0 : po->tableOpt ? po->tableOpt : "",
9103 bruce 282 UBC 0 : po->caption);
9103 bruce 283 EUB : else
9103 bruce 284 UIC 0 : fprintf(fout,
6270 bruce 285 EUB : "<table %s><caption align=\"top\">"
286 : "Retrieved %d rows * %d fields"
287 : "</caption>\n",
2118 tgl 288 UIC 0 : po->tableOpt ? po->tableOpt : "", nTups, nFields);
9103 bruce 289 EUB : }
290 : else
9103 bruce 291 UIC 0 : fprintf(fout, "<table %s>", po->tableOpt ? po->tableOpt : "");
9103 bruce 292 EUB : }
9103 bruce 293 GIC 3592 : if (po->header)
9103 bruce 294 CBC 3592 : border = do_header(fout, po, nFields, fieldMax, fieldNames,
9103 bruce 295 ECB : fieldNotNum, fs_len, res);
9103 bruce 296 GIC 8585 : for (i = 0; i < nTups; i++)
9103 bruce 297 CBC 4993 : output_row(fout, po, nFields, fields,
9103 bruce 298 ECB : fieldNotNum, fieldMax, border, i);
299 : }
9103 bruce 300 GIC 3592 : if (po->header && !po->html3)
9103 bruce 301 CBC 3592 : fprintf(fout, "(%d row%s)\n\n", PQntuples(res),
708 302 3592 : (PQntuples(res) == 1) ? "" : "s");
1584 tgl 303 3592 : if (po->html3 && !po->expanded)
1584 tgl 304 LBC 0 : fputs("</table>\n", fout);
650 tgl 305 EUB :
650 tgl 306 GIC 3592 : exit:
297 peter 307 GNC 3592 : free(fieldMax);
308 3592 : free(fieldNotNum);
309 3592 : free(border);
650 tgl 310 GIC 3592 : if (fields)
650 tgl 311 ECB : {
312 : /* if calloc succeeded, this shouldn't overflow size_t */
650 tgl 313 CBC 3592 : size_t numfields = ((size_t) nTups + 1) * (size_t) nFields;
650 tgl 314 ECB :
650 tgl 315 CBC 17972 : while (numfields-- > 0)
297 peter 316 GNC 14380 : free(fields[numfields]);
650 tgl 317 GIC 3592 : free(fields);
318 : }
297 peter 319 GNC 3592 : free(fieldNames);
9103 bruce 320 GIC 3592 : if (usePipe)
321 : {
322 : #ifdef WIN32
9046 bruce 323 EUB : _pclose(fout);
324 : #else
9103 bruce 325 UIC 0 : pclose(fout);
326 :
327 : #ifdef ENABLE_THREAD_SAFETY
328 : /* we can't easily verify if EPIPE occurred, so say it did */
6702 329 0 : if (sigpipe_masked)
tgl 330 0 : pq_reset_sigpipe(&osigset, sigpipe_pending, true);
7030 bruce 331 ECB : #else
332 : pqsignal(SIGPIPE, oldsigpipehandler);
333 : #endif /* ENABLE_THREAD_SAFETY */
334 : #endif /* WIN32 */
9103 335 : }
336 : }
9103 bruce 337 GIC 3592 : }
338 :
339 :
340 : static bool
8550 341 8690 : do_field(const PQprintOpt *po, const PGresult *res,
342 : const int i, const int j, const int fs_len,
343 : char **fields,
344 : const int nFields, char const **fieldNames,
345 : unsigned char *fieldNotNum, int *fieldMax,
346 : const int fieldMaxLen, FILE *fout)
9103 bruce 347 ECB : {
8397 348 : const char *pval,
349 : *p;
9103 350 : int plen;
351 : bool skipit;
352 :
9103 bruce 353 CBC 8690 : plen = PQgetlength(res, i, j);
9103 bruce 354 GIC 8690 : pval = PQgetvalue(res, i, j);
355 :
9103 bruce 356 GBC 8690 : if (plen < 1 || !pval || !*pval)
9103 bruce 357 EUB : {
9103 bruce 358 GIC 595 : if (po->align || po->expanded)
359 595 : skipit = true;
360 : else
9103 bruce 361 ECB : {
9103 bruce 362 UIC 0 : skipit = false;
9103 bruce 363 LBC 0 : goto efield;
364 : }
9103 bruce 365 ECB : }
366 : else
9103 bruce 367 GIC 8095 : skipit = false;
9103 bruce 368 ECB :
9103 bruce 369 GIC 8690 : if (!skipit)
9103 bruce 370 ECB : {
8397 bruce 371 GIC 8095 : if (po->align && !fieldNotNum[j])
8622 tgl 372 ECB : {
373 : /* Detect whether field contains non-numeric data */
8622 tgl 374 CBC 7247 : char ch = '0';
8720 bruce 375 ECB :
671 tgl 376 CBC 22242 : for (p = pval; *p; p += PQmblenBounded(p, res->client_encoding))
377 : {
8622 tgl 378 GIC 16656 : ch = *p;
8397 bruce 379 19633 : if (!((ch >= '0' && ch <= '9') ||
8397 bruce 380 CBC 2980 : ch == '.' ||
381 2977 : ch == 'E' ||
8397 bruce 382 GIC 2977 : ch == 'e' ||
383 : ch == ' ' ||
384 : ch == '-'))
385 : {
8622 tgl 386 1661 : fieldNotNum[j] = 1;
387 1661 : break;
388 : }
389 : }
8397 bruce 390 ECB :
8953 tgl 391 : /*
6385 bruce 392 : * Above loop will believe E in first column is numeric; also, we
393 : * insist on a digit in the last column for a numeric. This test
394 : * is still not bulletproof but it handles most cases.
8953 tgl 395 : */
8622 tgl 396 GIC 7247 : if (*pval == 'E' || *pval == 'e' ||
8622 tgl 397 CBC 7229 : !(ch >= '0' && ch <= '9'))
9103 bruce 398 1661 : fieldNotNum[j] = 1;
9103 bruce 399 ECB : }
400 :
9103 bruce 401 GBC 8095 : if (!po->expanded && (po->align || po->html3))
9103 bruce 402 EUB : {
8622 tgl 403 GIC 8095 : if (plen > fieldMax[j])
8622 tgl 404 CBC 1153 : fieldMax[j] = plen;
8622 tgl 405 GIC 8095 : if (!(fields[i * nFields + j] = (char *) malloc(plen + 1)))
406 : {
6725 peter_e 407 UIC 0 : fprintf(stderr, libpq_gettext("out of memory\n"));
650 tgl 408 UBC 0 : return false;
409 : }
8622 tgl 410 GBC 8095 : strcpy(fields[i * nFields + j], pval);
9103 bruce 411 EUB : }
412 : else
413 : {
9103 bruce 414 UBC 0 : if (po->expanded)
9103 bruce 415 EUB : {
9103 bruce 416 UIC 0 : if (po->html3)
417 0 : fprintf(fout,
418 : "<tr><td align=\"left\"><b>%s</b></td>"
6270 bruce 419 EUB : "<td align=\"%s\">%s</td></tr>\n",
9103 bruce 420 UBC 0 : fieldNames[j],
9103 bruce 421 UIC 0 : fieldNotNum[j] ? "left" : "right",
8622 tgl 422 EUB : pval);
9103 bruce 423 : else
424 : {
9103 bruce 425 UIC 0 : if (po->align)
9103 bruce 426 UBC 0 : fprintf(fout,
427 : "%-*s%s %s\n",
8622 tgl 428 0 : fieldMaxLen - fs_len, fieldNames[j],
8622 tgl 429 UIC 0 : po->fieldSep,
430 : pval);
431 : else
432 0 : fprintf(fout,
8622 tgl 433 EUB : "%s%s%s\n",
8622 tgl 434 UIC 0 : fieldNames[j], po->fieldSep, pval);
9103 bruce 435 EUB : }
436 : }
437 : else
438 : {
9103 bruce 439 UIC 0 : if (!po->html3)
9103 bruce 440 EUB : {
8622 tgl 441 UIC 0 : fputs(pval, fout);
9103 bruce 442 0 : efield:
443 0 : if ((j + 1) < nFields)
444 0 : fputs(po->fieldSep, fout);
9103 bruce 445 ECB : else
9103 bruce 446 UIC 0 : fputc('\n', fout);
447 : }
448 : }
449 : }
9103 bruce 450 ECB : }
650 tgl 451 GIC 8690 : return true;
452 : }
453 :
454 :
9103 bruce 455 ECB : static char *
8550 bruce 456 GIC 3592 : do_header(FILE *fout, const PQprintOpt *po, const int nFields, int *fieldMax,
8550 bruce 457 ECB : const char **fieldNames, unsigned char *fieldNotNum,
8550 bruce 458 EUB : const int fs_len, const PGresult *res)
459 : {
460 : int j; /* for loop index */
9103 bruce 461 CBC 3592 : char *border = NULL;
9103 bruce 462 ECB :
9103 bruce 463 CBC 3592 : if (po->html3)
9103 bruce 464 UIC 0 : fputs("<tr>", fout);
9103 bruce 465 ECB : else
466 : {
9103 bruce 467 CBC 3592 : int tot = 0;
9103 bruce 468 GBC 3592 : int n = 0;
9103 bruce 469 CBC 3592 : char *p = NULL;
9103 bruce 470 ECB :
9103 bruce 471 GIC 9282 : for (; n < nFields; n++)
9103 bruce 472 GBC 5690 : tot += fieldMax[n] + fs_len + (po->standard ? 2 : 0);
473 3592 : if (po->standard)
9103 bruce 474 UIC 0 : tot += fs_len * 2 + 2;
9103 bruce 475 CBC 3592 : border = malloc(tot + 1);
476 3592 : if (!border)
477 : {
6725 peter_e 478 UBC 0 : fprintf(stderr, libpq_gettext("out of memory\n"));
650 tgl 479 UIC 0 : return NULL;
9103 bruce 480 EUB : }
9103 bruce 481 GBC 3592 : p = border;
9103 bruce 482 GIC 3592 : if (po->standard)
9103 bruce 483 ECB : {
8829 bruce 484 UIC 0 : char *fs = po->fieldSep;
485 :
9103 486 0 : while (*fs++)
9103 bruce 487 LBC 0 : *p++ = '+';
9103 bruce 488 ECB : }
9103 bruce 489 GIC 9282 : for (j = 0; j < nFields; j++)
9103 bruce 490 ECB : {
491 : int len;
492 :
9103 bruce 493 CBC 55281 : for (len = fieldMax[j] + (po->standard ? 2 : 0); len--; *p++ = '-');
9103 bruce 494 GIC 5690 : if (po->standard || (j + 1) < nFields)
495 : {
8829 bruce 496 CBC 2098 : char *fs = po->fieldSep;
9103 bruce 497 ECB :
9103 bruce 498 GBC 4196 : while (*fs++)
9103 bruce 499 GIC 2098 : *p++ = '+';
9103 bruce 500 ECB : }
9103 bruce 501 EUB : }
9103 bruce 502 CBC 3592 : *p = '\0';
9103 bruce 503 GIC 3592 : if (po->standard)
9103 bruce 504 LBC 0 : fprintf(fout, "%s\n", border);
505 : }
9103 bruce 506 CBC 3592 : if (po->standard)
9103 bruce 507 UIC 0 : fputs(po->fieldSep, fout);
9103 bruce 508 GBC 9282 : for (j = 0; j < nFields; j++)
9103 bruce 509 EUB : {
8397 bruce 510 GIC 5690 : const char *s = PQfname(res, j);
511 :
9103 512 5690 : if (po->html3)
9103 bruce 513 ECB : {
6270 bruce 514 UIC 0 : fprintf(fout, "<th align=\"%s\">%s</th>",
9103 bruce 515 LBC 0 : fieldNotNum[j] ? "left" : "right", fieldNames[j]);
9103 bruce 516 EUB : }
9103 bruce 517 ECB : else
9103 bruce 518 EUB : {
9103 bruce 519 GBC 5690 : int n = strlen(s);
9103 bruce 520 EUB :
9103 bruce 521 GIC 5690 : if (n > fieldMax[j])
9103 bruce 522 LBC 0 : fieldMax[j] = n;
9103 bruce 523 CBC 5690 : if (po->standard)
9103 bruce 524 LBC 0 : fprintf(fout,
9103 bruce 525 UIC 0 : fieldNotNum[j] ? " %-*s " : " %*s ",
526 0 : fieldMax[j], s);
9103 bruce 527 ECB : else
9103 bruce 528 GBC 5690 : fprintf(fout, fieldNotNum[j] ? "%-*s" : "%*s", fieldMax[j], s);
9103 bruce 529 GIC 5690 : if (po->standard || (j + 1) < nFields)
9103 bruce 530 CBC 2098 : fputs(po->fieldSep, fout);
9103 bruce 531 ECB : }
532 : }
9103 bruce 533 GIC 3592 : if (po->html3)
9103 bruce 534 UIC 0 : fputs("</tr>\n", fout);
535 : else
9103 bruce 536 CBC 3592 : fprintf(fout, "\n%s\n", border);
9103 bruce 537 GIC 3592 : return border;
538 : }
539 :
540 :
541 : static void
8550 bruce 542 CBC 4993 : output_row(FILE *fout, const PQprintOpt *po, const int nFields, char **fields,
8986 bruce 543 EUB : unsigned char *fieldNotNum, int *fieldMax, char *border,
9103 bruce 544 ECB : const int row_index)
9103 bruce 545 EUB : {
9103 bruce 546 ECB : int field_index; /* for loop index */
547 :
9103 bruce 548 CBC 4993 : if (po->html3)
9103 bruce 549 UIC 0 : fputs("<tr>", fout);
9103 bruce 550 CBC 4993 : else if (po->standard)
9103 bruce 551 UBC 0 : fputs(po->fieldSep, fout);
9103 bruce 552 GBC 13683 : for (field_index = 0; field_index < nFields; field_index++)
553 : {
9103 bruce 554 GIC 8690 : char *p = fields[row_index * nFields + field_index];
9103 bruce 555 ECB :
9103 bruce 556 CBC 8690 : if (po->html3)
6270 bruce 557 LBC 0 : fprintf(fout, "<td align=\"%s\">%s</td>",
6385 558 0 : fieldNotNum[field_index] ? "left" : "right", p ? p : "");
9103 bruce 559 ECB : else
560 : {
9103 bruce 561 CBC 17380 : fprintf(fout,
562 8690 : fieldNotNum[field_index] ?
9103 bruce 563 GIC 8690 : (po->standard ? " %-*s " : "%-*s") :
564 6176 : (po->standard ? " %*s " : "%*s"),
9103 bruce 565 CBC 8690 : fieldMax[field_index],
9103 bruce 566 EUB : p ? p : "");
9103 bruce 567 CBC 8690 : if (po->standard || field_index + 1 < nFields)
9103 bruce 568 GBC 3697 : fputs(po->fieldSep, fout);
9103 bruce 569 ECB : }
570 : }
9103 bruce 571 GIC 4993 : if (po->html3)
9103 bruce 572 UIC 0 : fputs("</tr>", fout);
9103 bruce 573 GIC 4993 : else if (po->standard)
9103 bruce 574 UIC 0 : fprintf(fout, "\n%s", border);
9103 bruce 575 GIC 4993 : fputc('\n', fout);
576 4993 : }
577 :
578 :
9103 bruce 579 EUB :
580 : /*
581 : * really old printing routines
582 : */
583 :
584 : void
8471 peter_e 585 UIC 0 : PQdisplayTuples(const PGresult *res,
586 : FILE *fp, /* where to send the output */
587 : int fillAlign, /* pad the fields with spaces */
588 : const char *fieldSep, /* field separator */
589 : int printHeader, /* display headers? */
590 : int quiet
591 : )
592 : {
8471 peter_e 593 EUB : #define DEFAULT_FIELD_SEP " "
594 :
595 : int i,
596 : j;
597 : int nFields;
598 : int nTuples;
8471 peter_e 599 UBC 0 : int *fLength = NULL;
8471 peter_e 600 EUB :
8471 peter_e 601 UIC 0 : if (fieldSep == NULL)
8471 peter_e 602 UBC 0 : fieldSep = DEFAULT_FIELD_SEP;
8471 peter_e 603 EUB :
604 : /* Get some useful info about the results */
8471 peter_e 605 UIC 0 : nFields = PQnfields(res);
606 0 : nTuples = PQntuples(res);
8471 peter_e 607 EUB :
8471 peter_e 608 UIC 0 : if (fp == NULL)
8471 peter_e 609 UBC 0 : fp = stdout;
8471 peter_e 610 EUB :
611 : /* Figure the field lengths to align to */
612 : /* will be somewhat time consuming for very large results */
8471 peter_e 613 UBC 0 : if (fillAlign)
614 : {
8471 peter_e 615 UIC 0 : fLength = (int *) malloc(nFields * sizeof(int));
6510 neilc 616 UBC 0 : if (!fLength)
617 : {
618 0 : fprintf(stderr, libpq_gettext("out of memory\n"));
650 tgl 619 0 : return;
620 : }
6510 neilc 621 EUB :
8471 peter_e 622 UIC 0 : for (j = 0; j < nFields; j++)
8471 peter_e 623 EUB : {
8471 peter_e 624 UBC 0 : fLength[j] = strlen(PQfname(res, j));
8471 peter_e 625 UIC 0 : for (i = 0; i < nTuples; i++)
626 : {
8397 bruce 627 0 : int flen = PQgetlength(res, i, j);
628 :
8471 peter_e 629 UBC 0 : if (flen > fLength[j])
8471 peter_e 630 UIC 0 : fLength[j] = flen;
631 : }
8471 peter_e 632 EUB : }
633 : }
634 :
8471 peter_e 635 UBC 0 : if (printHeader)
8471 peter_e 636 EUB : {
637 : /* first, print out the attribute names */
8471 peter_e 638 UIC 0 : for (i = 0; i < nFields; i++)
8471 peter_e 639 EUB : {
8471 peter_e 640 UIC 0 : fputs(PQfname(res, i), fp);
641 0 : if (fillAlign)
8471 peter_e 642 UBC 0 : fill(strlen(PQfname(res, i)), fLength[i], ' ', fp);
8471 peter_e 643 UIC 0 : fputs(fieldSep, fp);
8471 peter_e 644 EUB : }
8471 peter_e 645 UBC 0 : fprintf(fp, "\n");
8471 peter_e 646 EUB :
647 : /* Underline the attribute names */
8471 peter_e 648 UBC 0 : for (i = 0; i < nFields; i++)
649 : {
8471 peter_e 650 UIC 0 : if (fillAlign)
651 0 : fill(0, fLength[i], '-', fp);
8471 peter_e 652 UBC 0 : fputs(fieldSep, fp);
653 : }
654 0 : fprintf(fp, "\n");
655 : }
8471 peter_e 656 EUB :
657 : /* next, print out the instances */
8471 peter_e 658 UBC 0 : for (i = 0; i < nTuples; i++)
8471 peter_e 659 EUB : {
8471 peter_e 660 UIC 0 : for (j = 0; j < nFields; j++)
8471 peter_e 661 EUB : {
8471 peter_e 662 UIC 0 : fprintf(fp, "%s", PQgetvalue(res, i, j));
663 0 : if (fillAlign)
8471 peter_e 664 UBC 0 : fill(strlen(PQgetvalue(res, i, j)), fLength[j], ' ', fp);
665 0 : fputs(fieldSep, fp);
8471 peter_e 666 EUB : }
8471 peter_e 667 UIC 0 : fprintf(fp, "\n");
8471 peter_e 668 EUB : }
669 :
8471 peter_e 670 UBC 0 : if (!quiet)
8471 peter_e 671 UIC 0 : fprintf(fp, "\nQuery returned %d row%s.\n", PQntuples(res),
708 bruce 672 0 : (PQntuples(res) == 1) ? "" : "s");
673 :
8471 peter_e 674 0 : fflush(fp);
675 :
297 peter 676 UNC 0 : free(fLength);
677 : }
678 :
679 :
680 :
681 : void
8471 peter_e 682 UIC 0 : PQprintTuples(const PGresult *res,
683 : FILE *fout, /* output stream */
684 : int PrintAttNames, /* print attribute names or not */
685 : int TerseOutput, /* delimiter bars or not? */
686 : int colWidth /* width of column, if 0, use variable width */
8471 peter_e 687 EUB : )
688 : {
689 : int nFields;
690 : int nTups;
691 : int i,
692 : j;
693 : char formatString[80];
8471 peter_e 694 UIC 0 : char *tborder = NULL;
8471 peter_e 695 EUB :
8471 peter_e 696 UIC 0 : nFields = PQnfields(res);
8471 peter_e 697 UBC 0 : nTups = PQntuples(res);
698 :
8471 peter_e 699 UIC 0 : if (colWidth > 0)
8471 peter_e 700 UBC 0 : sprintf(formatString, "%%s %%-%ds", colWidth);
701 : else
8471 peter_e 702 UIC 0 : sprintf(formatString, "%%s %%s");
703 :
8471 peter_e 704 UBC 0 : if (nFields > 0)
8471 peter_e 705 EUB : { /* only print rows with at least 1 field. */
706 :
8471 peter_e 707 UIC 0 : if (!TerseOutput)
8471 peter_e 708 EUB : {
709 : int width;
710 :
8471 peter_e 711 UBC 0 : width = nFields * 14;
3731 tgl 712 0 : tborder = (char *) malloc(width + 1);
6510 neilc 713 0 : if (!tborder)
6510 neilc 714 EUB : {
6510 neilc 715 UIC 0 : fprintf(stderr, libpq_gettext("out of memory\n"));
650 tgl 716 0 : return;
6510 neilc 717 EUB : }
3731 tgl 718 UIC 0 : for (i = 0; i < width; i++)
8471 peter_e 719 UBC 0 : tborder[i] = '-';
3731 tgl 720 UIC 0 : tborder[width] = '\0';
8471 peter_e 721 UBC 0 : fprintf(fout, "%s\n", tborder);
722 : }
723 :
8471 peter_e 724 UIC 0 : for (i = 0; i < nFields; i++)
725 : {
726 0 : if (PrintAttNames)
8471 peter_e 727 EUB : {
8471 peter_e 728 UIC 0 : fprintf(fout, formatString,
8471 peter_e 729 EUB : TerseOutput ? "" : "|",
730 : PQfname(res, i));
731 : }
732 : }
733 :
8471 peter_e 734 UIC 0 : if (PrintAttNames)
8471 peter_e 735 EUB : {
8471 peter_e 736 UIC 0 : if (TerseOutput)
8471 peter_e 737 UBC 0 : fprintf(fout, "\n");
738 : else
739 0 : fprintf(fout, "|\n%s\n", tborder);
740 : }
8471 peter_e 741 EUB :
8471 peter_e 742 UIC 0 : for (i = 0; i < nTups; i++)
743 : {
744 0 : for (j = 0; j < nFields; j++)
8471 peter_e 745 EUB : {
8397 bruce 746 UBC 0 : const char *pval = PQgetvalue(res, i, j);
747 :
8471 peter_e 748 0 : fprintf(fout, formatString,
749 : TerseOutput ? "" : "|",
750 : pval ? pval : "");
751 : }
752 0 : if (TerseOutput)
8471 peter_e 753 UIC 0 : fprintf(fout, "\n");
754 : else
755 0 : fprintf(fout, "|\n%s\n", tborder);
756 : }
757 : }
758 :
297 peter 759 UNC 0 : free(tborder);
760 : }
761 :
8462 peter_e 762 EUB :
763 : /* simply send out max-length number of filler characters to fp */
8397 bruce 764 :
8462 peter_e 765 : static void
8462 peter_e 766 UIC 0 : fill(int length, int max, char filler, FILE *fp)
767 : {
768 : int count;
769 :
8397 bruce 770 0 : count = max - length;
771 0 : while (count-- >= 0)
772 0 : putc(filler, fp);
8462 peter_e 773 0 : }
|