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