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