00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include "postgres_fe.h"
00018
00019 #include <signal.h>
00020
00021 #ifdef WIN32
00022 #include "win32.h"
00023 #else
00024 #include <unistd.h>
00025 #include <sys/ioctl.h>
00026 #endif
00027
00028 #ifdef HAVE_TERMIOS_H
00029 #include <termios.h>
00030 #else
00031 #ifndef WIN32
00032 #include <sys/termios.h>
00033 #endif
00034 #endif
00035
00036 #include "libpq-fe.h"
00037 #include "libpq-int.h"
00038
00039
00040 static void do_field(const PQprintOpt *po, const PGresult *res,
00041 const int i, const int j, const int fs_len,
00042 char **fields,
00043 const int nFields, const char **fieldNames,
00044 unsigned char *fieldNotNum, int *fieldMax,
00045 const int fieldMaxLen, FILE *fout);
00046 static char *do_header(FILE *fout, const PQprintOpt *po, const int nFields,
00047 int *fieldMax, const char **fieldNames, unsigned char *fieldNotNum,
00048 const int fs_len, const PGresult *res);
00049 static void output_row(FILE *fout, const PQprintOpt *po, const int nFields, char **fields,
00050 unsigned char *fieldNotNum, int *fieldMax, char *border,
00051 const int row_index);
00052 static void fill(int length, int max, char filler, FILE *fp);
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067 void
00068 PQprint(FILE *fout, const PGresult *res, const PQprintOpt *po)
00069 {
00070 int nFields;
00071
00072 nFields = PQnfields(res);
00073
00074 if (nFields > 0)
00075 {
00076 int i,
00077 j;
00078 int nTups;
00079 int *fieldMax = NULL;
00080 unsigned char *fieldNotNum = NULL;
00081 char *border = NULL;
00082 char **fields = NULL;
00083 const char **fieldNames;
00084 int fieldMaxLen = 0;
00085 int numFieldName;
00086 int fs_len = strlen(po->fieldSep);
00087 int total_line_length = 0;
00088 int usePipe = 0;
00089 char *pagerenv;
00090
00091 #if defined(ENABLE_THREAD_SAFETY) && !defined(WIN32)
00092 sigset_t osigset;
00093 bool sigpipe_masked = false;
00094 bool sigpipe_pending;
00095 #endif
00096 #if !defined(ENABLE_THREAD_SAFETY) && !defined(WIN32)
00097 pqsigfunc oldsigpipehandler = NULL;
00098 #endif
00099
00100 #ifdef TIOCGWINSZ
00101 struct winsize screen_size;
00102 #else
00103 struct winsize
00104 {
00105 int ws_row;
00106 int ws_col;
00107 } screen_size;
00108 #endif
00109
00110 nTups = PQntuples(res);
00111 if (!(fieldNames = (const char **) calloc(nFields, sizeof(char *))))
00112 {
00113 fprintf(stderr, libpq_gettext("out of memory\n"));
00114 abort();
00115 }
00116 if (!(fieldNotNum = (unsigned char *) calloc(nFields, 1)))
00117 {
00118 fprintf(stderr, libpq_gettext("out of memory\n"));
00119 abort();
00120 }
00121 if (!(fieldMax = (int *) calloc(nFields, sizeof(int))))
00122 {
00123 fprintf(stderr, libpq_gettext("out of memory\n"));
00124 abort();
00125 }
00126 for (numFieldName = 0;
00127 po->fieldName && po->fieldName[numFieldName];
00128 numFieldName++)
00129 ;
00130 for (j = 0; j < nFields; j++)
00131 {
00132 int len;
00133 const char *s = (j < numFieldName && po->fieldName[j][0]) ?
00134 po->fieldName[j] : PQfname(res, j);
00135
00136 fieldNames[j] = s;
00137 len = s ? strlen(s) : 0;
00138 fieldMax[j] = len;
00139 len += fs_len;
00140 if (len > fieldMaxLen)
00141 fieldMaxLen = len;
00142 total_line_length += len;
00143 }
00144
00145 total_line_length += nFields * strlen(po->fieldSep) + 1;
00146
00147 if (fout == NULL)
00148 fout = stdout;
00149 if (po->pager && fout == stdout && isatty(fileno(stdin)) &&
00150 isatty(fileno(stdout)))
00151 {
00152
00153
00154
00155
00156 #ifdef TIOCGWINSZ
00157 if (ioctl(fileno(stdout), TIOCGWINSZ, &screen_size) == -1 ||
00158 screen_size.ws_col == 0 ||
00159 screen_size.ws_row == 0)
00160 {
00161 screen_size.ws_row = 24;
00162 screen_size.ws_col = 80;
00163 }
00164 #else
00165 screen_size.ws_row = 24;
00166 screen_size.ws_col = 80;
00167 #endif
00168 pagerenv = getenv("PAGER");
00169 if (pagerenv != NULL &&
00170 pagerenv[0] != '\0' &&
00171 !po->html3 &&
00172 ((po->expanded &&
00173 nTups * (nFields + 1) >= screen_size.ws_row) ||
00174 (!po->expanded &&
00175 nTups * (total_line_length / screen_size.ws_col + 1) *
00176 (1 + (po->standard != 0)) >= screen_size.ws_row -
00177 (po->header != 0) *
00178 (total_line_length / screen_size.ws_col + 1) * 2
00179 - (po->header != 0) * 2
00180 )))
00181 {
00182 fout = popen(pagerenv, "w");
00183 if (fout)
00184 {
00185 usePipe = 1;
00186 #ifndef WIN32
00187 #ifdef ENABLE_THREAD_SAFETY
00188 if (pq_block_sigpipe(&osigset, &sigpipe_pending) == 0)
00189 sigpipe_masked = true;
00190 #else
00191 oldsigpipehandler = pqsignal(SIGPIPE, SIG_IGN);
00192 #endif
00193 #endif
00194 }
00195 else
00196 fout = stdout;
00197 }
00198 }
00199
00200 if (!po->expanded && (po->align || po->html3))
00201 {
00202 if (!(fields = (char **) calloc(nFields * (nTups + 1), sizeof(char *))))
00203 {
00204 fprintf(stderr, libpq_gettext("out of memory\n"));
00205 abort();
00206 }
00207 }
00208 else if (po->header && !po->html3)
00209 {
00210 if (po->expanded)
00211 {
00212 if (po->align)
00213 fprintf(fout, libpq_gettext("%-*s%s Value\n"),
00214 fieldMaxLen - fs_len, libpq_gettext("Field"), po->fieldSep);
00215 else
00216 fprintf(fout, libpq_gettext("%s%sValue\n"), libpq_gettext("Field"), po->fieldSep);
00217 }
00218 else
00219 {
00220 int len = 0;
00221
00222 for (j = 0; j < nFields; j++)
00223 {
00224 const char *s = fieldNames[j];
00225
00226 fputs(s, fout);
00227 len += strlen(s) + fs_len;
00228 if ((j + 1) < nFields)
00229 fputs(po->fieldSep, fout);
00230 }
00231 fputc('\n', fout);
00232 for (len -= fs_len; len--; fputc('-', fout));
00233 fputc('\n', fout);
00234 }
00235 }
00236 if (po->expanded && po->html3)
00237 {
00238 if (po->caption)
00239 fprintf(fout, "<center><h2>%s</h2></center>\n", po->caption);
00240 else
00241 fprintf(fout,
00242 "<center><h2>"
00243 "Query retrieved %d rows * %d fields"
00244 "</h2></center>\n",
00245 nTups, nFields);
00246 }
00247 for (i = 0; i < nTups; i++)
00248 {
00249 if (po->expanded)
00250 {
00251 if (po->html3)
00252 fprintf(fout,
00253 "<table %s><caption align=\"top\">%d</caption>\n",
00254 po->tableOpt ? po->tableOpt : "", i);
00255 else
00256 fprintf(fout, libpq_gettext("-- RECORD %d --\n"), i);
00257 }
00258 for (j = 0; j < nFields; j++)
00259 do_field(po, res, i, j, fs_len, fields, nFields,
00260 fieldNames, fieldNotNum,
00261 fieldMax, fieldMaxLen, fout);
00262 if (po->html3 && po->expanded)
00263 fputs("</table>\n", fout);
00264 }
00265 if (!po->expanded && (po->align || po->html3))
00266 {
00267 if (po->html3)
00268 {
00269 if (po->header)
00270 {
00271 if (po->caption)
00272 fprintf(fout,
00273 "<table %s><caption align=\"top\">%s</caption>\n",
00274 po->tableOpt ? po->tableOpt : "",
00275 po->caption);
00276 else
00277 fprintf(fout,
00278 "<table %s><caption align=\"top\">"
00279 "Retrieved %d rows * %d fields"
00280 "</caption>\n",
00281 po->tableOpt ? po->tableOpt : "", nTups, nFields);
00282 }
00283 else
00284 fprintf(fout, "<table %s>", po->tableOpt ? po->tableOpt : "");
00285 }
00286 if (po->header)
00287 border = do_header(fout, po, nFields, fieldMax, fieldNames,
00288 fieldNotNum, fs_len, res);
00289 for (i = 0; i < nTups; i++)
00290 output_row(fout, po, nFields, fields,
00291 fieldNotNum, fieldMax, border, i);
00292 free(fields);
00293 if (border)
00294 free(border);
00295 }
00296 if (po->header && !po->html3)
00297 fprintf(fout, "(%d row%s)\n\n", PQntuples(res),
00298 (PQntuples(res) == 1) ? "" : "s");
00299 free(fieldMax);
00300 free(fieldNotNum);
00301 free((void *) fieldNames);
00302 if (usePipe)
00303 {
00304 #ifdef WIN32
00305 _pclose(fout);
00306 #else
00307 pclose(fout);
00308
00309 #ifdef ENABLE_THREAD_SAFETY
00310
00311 if (sigpipe_masked)
00312 pq_reset_sigpipe(&osigset, sigpipe_pending, true);
00313 #else
00314 pqsignal(SIGPIPE, oldsigpipehandler);
00315 #endif
00316 #endif
00317 }
00318 if (po->html3 && !po->expanded)
00319 fputs("</table>\n", fout);
00320 }
00321 }
00322
00323
00324 static void
00325 do_field(const PQprintOpt *po, const PGresult *res,
00326 const int i, const int j, const int fs_len,
00327 char **fields,
00328 const int nFields, char const ** fieldNames,
00329 unsigned char *fieldNotNum, int *fieldMax,
00330 const int fieldMaxLen, FILE *fout)
00331 {
00332
00333 const char *pval,
00334 *p;
00335 int plen;
00336 bool skipit;
00337
00338 plen = PQgetlength(res, i, j);
00339 pval = PQgetvalue(res, i, j);
00340
00341 if (plen < 1 || !pval || !*pval)
00342 {
00343 if (po->align || po->expanded)
00344 skipit = true;
00345 else
00346 {
00347 skipit = false;
00348 goto efield;
00349 }
00350 }
00351 else
00352 skipit = false;
00353
00354 if (!skipit)
00355 {
00356 if (po->align && !fieldNotNum[j])
00357 {
00358
00359 char ch = '0';
00360
00361 for (p = pval; *p; p += PQmblen(p, res->client_encoding))
00362 {
00363 ch = *p;
00364 if (!((ch >= '0' && ch <= '9') ||
00365 ch == '.' ||
00366 ch == 'E' ||
00367 ch == 'e' ||
00368 ch == ' ' ||
00369 ch == '-'))
00370 {
00371 fieldNotNum[j] = 1;
00372 break;
00373 }
00374 }
00375
00376
00377
00378
00379
00380
00381 if (*pval == 'E' || *pval == 'e' ||
00382 !(ch >= '0' && ch <= '9'))
00383 fieldNotNum[j] = 1;
00384 }
00385
00386 if (!po->expanded && (po->align || po->html3))
00387 {
00388 if (plen > fieldMax[j])
00389 fieldMax[j] = plen;
00390 if (!(fields[i * nFields + j] = (char *) malloc(plen + 1)))
00391 {
00392 fprintf(stderr, libpq_gettext("out of memory\n"));
00393 abort();
00394 }
00395 strcpy(fields[i * nFields + j], pval);
00396 }
00397 else
00398 {
00399 if (po->expanded)
00400 {
00401 if (po->html3)
00402 fprintf(fout,
00403 "<tr><td align=\"left\"><b>%s</b></td>"
00404 "<td align=\"%s\">%s</td></tr>\n",
00405 fieldNames[j],
00406 fieldNotNum[j] ? "left" : "right",
00407 pval);
00408 else
00409 {
00410 if (po->align)
00411 fprintf(fout,
00412 "%-*s%s %s\n",
00413 fieldMaxLen - fs_len, fieldNames[j],
00414 po->fieldSep,
00415 pval);
00416 else
00417 fprintf(fout,
00418 "%s%s%s\n",
00419 fieldNames[j], po->fieldSep, pval);
00420 }
00421 }
00422 else
00423 {
00424 if (!po->html3)
00425 {
00426 fputs(pval, fout);
00427 efield:
00428 if ((j + 1) < nFields)
00429 fputs(po->fieldSep, fout);
00430 else
00431 fputc('\n', fout);
00432 }
00433 }
00434 }
00435 }
00436 }
00437
00438
00439 static char *
00440 do_header(FILE *fout, const PQprintOpt *po, const int nFields, int *fieldMax,
00441 const char **fieldNames, unsigned char *fieldNotNum,
00442 const int fs_len, const PGresult *res)
00443 {
00444
00445 int j;
00446 char *border = NULL;
00447
00448 if (po->html3)
00449 fputs("<tr>", fout);
00450 else
00451 {
00452 int tot = 0;
00453 int n = 0;
00454 char *p = NULL;
00455
00456 for (; n < nFields; n++)
00457 tot += fieldMax[n] + fs_len + (po->standard ? 2 : 0);
00458 if (po->standard)
00459 tot += fs_len * 2 + 2;
00460 border = malloc(tot + 1);
00461 if (!border)
00462 {
00463 fprintf(stderr, libpq_gettext("out of memory\n"));
00464 abort();
00465 }
00466 p = border;
00467 if (po->standard)
00468 {
00469 char *fs = po->fieldSep;
00470
00471 while (*fs++)
00472 *p++ = '+';
00473 }
00474 for (j = 0; j < nFields; j++)
00475 {
00476 int len;
00477
00478 for (len = fieldMax[j] + (po->standard ? 2 : 0); len--; *p++ = '-');
00479 if (po->standard || (j + 1) < nFields)
00480 {
00481 char *fs = po->fieldSep;
00482
00483 while (*fs++)
00484 *p++ = '+';
00485 }
00486 }
00487 *p = '\0';
00488 if (po->standard)
00489 fprintf(fout, "%s\n", border);
00490 }
00491 if (po->standard)
00492 fputs(po->fieldSep, fout);
00493 for (j = 0; j < nFields; j++)
00494 {
00495 const char *s = PQfname(res, j);
00496
00497 if (po->html3)
00498 {
00499 fprintf(fout, "<th align=\"%s\">%s</th>",
00500 fieldNotNum[j] ? "left" : "right", fieldNames[j]);
00501 }
00502 else
00503 {
00504 int n = strlen(s);
00505
00506 if (n > fieldMax[j])
00507 fieldMax[j] = n;
00508 if (po->standard)
00509 fprintf(fout,
00510 fieldNotNum[j] ? " %-*s " : " %*s ",
00511 fieldMax[j], s);
00512 else
00513 fprintf(fout, fieldNotNum[j] ? "%-*s" : "%*s", fieldMax[j], s);
00514 if (po->standard || (j + 1) < nFields)
00515 fputs(po->fieldSep, fout);
00516 }
00517 }
00518 if (po->html3)
00519 fputs("</tr>\n", fout);
00520 else
00521 fprintf(fout, "\n%s\n", border);
00522 return border;
00523 }
00524
00525
00526 static void
00527 output_row(FILE *fout, const PQprintOpt *po, const int nFields, char **fields,
00528 unsigned char *fieldNotNum, int *fieldMax, char *border,
00529 const int row_index)
00530 {
00531
00532 int field_index;
00533
00534 if (po->html3)
00535 fputs("<tr>", fout);
00536 else if (po->standard)
00537 fputs(po->fieldSep, fout);
00538 for (field_index = 0; field_index < nFields; field_index++)
00539 {
00540 char *p = fields[row_index * nFields + field_index];
00541
00542 if (po->html3)
00543 fprintf(fout, "<td align=\"%s\">%s</td>",
00544 fieldNotNum[field_index] ? "left" : "right", p ? p : "");
00545 else
00546 {
00547 fprintf(fout,
00548 fieldNotNum[field_index] ?
00549 (po->standard ? " %-*s " : "%-*s") :
00550 (po->standard ? " %*s " : "%*s"),
00551 fieldMax[field_index],
00552 p ? p : "");
00553 if (po->standard || field_index + 1 < nFields)
00554 fputs(po->fieldSep, fout);
00555 }
00556 if (p)
00557 free(p);
00558 }
00559 if (po->html3)
00560 fputs("</tr>", fout);
00561 else if (po->standard)
00562 fprintf(fout, "\n%s", border);
00563 fputc('\n', fout);
00564 }
00565
00566
00567
00568
00569
00570
00571
00572 void
00573 PQdisplayTuples(const PGresult *res,
00574 FILE *fp,
00575 int fillAlign,
00576 const char *fieldSep,
00577 int printHeader,
00578 int quiet
00579 )
00580 {
00581 #define DEFAULT_FIELD_SEP " "
00582
00583 int i,
00584 j;
00585 int nFields;
00586 int nTuples;
00587 int *fLength = NULL;
00588
00589 if (fieldSep == NULL)
00590 fieldSep = DEFAULT_FIELD_SEP;
00591
00592
00593 nFields = PQnfields(res);
00594 nTuples = PQntuples(res);
00595
00596 if (fp == NULL)
00597 fp = stdout;
00598
00599
00600
00601 if (fillAlign)
00602 {
00603 fLength = (int *) malloc(nFields * sizeof(int));
00604 if (!fLength)
00605 {
00606 fprintf(stderr, libpq_gettext("out of memory\n"));
00607 abort();
00608 }
00609
00610 for (j = 0; j < nFields; j++)
00611 {
00612 fLength[j] = strlen(PQfname(res, j));
00613 for (i = 0; i < nTuples; i++)
00614 {
00615 int flen = PQgetlength(res, i, j);
00616
00617 if (flen > fLength[j])
00618 fLength[j] = flen;
00619 }
00620 }
00621 }
00622
00623 if (printHeader)
00624 {
00625
00626 for (i = 0; i < nFields; i++)
00627 {
00628 fputs(PQfname(res, i), fp);
00629 if (fillAlign)
00630 fill(strlen(PQfname(res, i)), fLength[i], ' ', fp);
00631 fputs(fieldSep, fp);
00632 }
00633 fprintf(fp, "\n");
00634
00635
00636 for (i = 0; i < nFields; i++)
00637 {
00638 if (fillAlign)
00639 fill(0, fLength[i], '-', fp);
00640 fputs(fieldSep, fp);
00641 }
00642 fprintf(fp, "\n");
00643 }
00644
00645
00646 for (i = 0; i < nTuples; i++)
00647 {
00648 for (j = 0; j < nFields; j++)
00649 {
00650 fprintf(fp, "%s", PQgetvalue(res, i, j));
00651 if (fillAlign)
00652 fill(strlen(PQgetvalue(res, i, j)), fLength[j], ' ', fp);
00653 fputs(fieldSep, fp);
00654 }
00655 fprintf(fp, "\n");
00656 }
00657
00658 if (!quiet)
00659 fprintf(fp, "\nQuery returned %d row%s.\n", PQntuples(res),
00660 (PQntuples(res) == 1) ? "" : "s");
00661
00662 fflush(fp);
00663
00664 if (fLength)
00665 free(fLength);
00666 }
00667
00668
00669
00670 void
00671 PQprintTuples(const PGresult *res,
00672 FILE *fout,
00673 int PrintAttNames,
00674 int TerseOutput,
00675 int colWidth
00676 )
00677 {
00678 int nFields;
00679 int nTups;
00680 int i,
00681 j;
00682 char formatString[80];
00683 char *tborder = NULL;
00684
00685 nFields = PQnfields(res);
00686 nTups = PQntuples(res);
00687
00688 if (colWidth > 0)
00689 sprintf(formatString, "%%s %%-%ds", colWidth);
00690 else
00691 sprintf(formatString, "%%s %%s");
00692
00693 if (nFields > 0)
00694 {
00695
00696 if (!TerseOutput)
00697 {
00698 int width;
00699
00700 width = nFields * 14;
00701 tborder = (char *) malloc(width + 1);
00702 if (!tborder)
00703 {
00704 fprintf(stderr, libpq_gettext("out of memory\n"));
00705 abort();
00706 }
00707 for (i = 0; i < width; i++)
00708 tborder[i] = '-';
00709 tborder[width] = '\0';
00710 fprintf(fout, "%s\n", tborder);
00711 }
00712
00713 for (i = 0; i < nFields; i++)
00714 {
00715 if (PrintAttNames)
00716 {
00717 fprintf(fout, formatString,
00718 TerseOutput ? "" : "|",
00719 PQfname(res, i));
00720 }
00721 }
00722
00723 if (PrintAttNames)
00724 {
00725 if (TerseOutput)
00726 fprintf(fout, "\n");
00727 else
00728 fprintf(fout, "|\n%s\n", tborder);
00729 }
00730
00731 for (i = 0; i < nTups; i++)
00732 {
00733 for (j = 0; j < nFields; j++)
00734 {
00735 const char *pval = PQgetvalue(res, i, j);
00736
00737 fprintf(fout, formatString,
00738 TerseOutput ? "" : "|",
00739 pval ? pval : "");
00740 }
00741 if (TerseOutput)
00742 fprintf(fout, "\n");
00743 else
00744 fprintf(fout, "|\n%s\n", tborder);
00745 }
00746 }
00747
00748 if (tborder)
00749 free(tborder);
00750 }
00751
00752
00753
00754
00755 static void
00756 fill(int length, int max, char filler, FILE *fp)
00757 {
00758 int count;
00759
00760 count = max - length;
00761 while (count-- >= 0)
00762 putc(filler, fp);
00763 }