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