00001
00002
00003
00004
00005
00006
00007
00008 #include "postgres_fe.h"
00009 #include "command.h"
00010
00011 #ifdef __BORLANDC__
00012 #undef mkdir
00013 #endif
00014
00015 #include <ctype.h>
00016 #include <time.h>
00017 #ifdef HAVE_PWD_H
00018 #include <pwd.h>
00019 #endif
00020 #ifndef WIN32
00021 #include <sys/types.h>
00022 #include <sys/stat.h>
00023 #include <fcntl.h>
00024 #include <unistd.h>
00025 #else
00026 #include <win32.h>
00027 #include <io.h>
00028 #include <fcntl.h>
00029 #include <direct.h>
00030 #include <sys/types.h>
00031 #include <sys/stat.h>
00032 #endif
00033 #ifdef USE_SSL
00034 #include <openssl/ssl.h>
00035 #endif
00036
00037 #include "portability/instr_time.h"
00038
00039 #include "libpq-fe.h"
00040 #include "pqexpbuffer.h"
00041 #include "dumputils.h"
00042
00043 #include "common.h"
00044 #include "copy.h"
00045 #include "describe.h"
00046 #include "help.h"
00047 #include "input.h"
00048 #include "large_obj.h"
00049 #include "mainloop.h"
00050 #include "print.h"
00051 #include "psqlscan.h"
00052 #include "settings.h"
00053 #include "variables.h"
00054
00055
00056
00057 static backslashResult exec_command(const char *cmd,
00058 PsqlScanState scan_state,
00059 PQExpBuffer query_buf);
00060 static bool do_edit(const char *filename_arg, PQExpBuffer query_buf,
00061 int lineno, bool *edited);
00062 static bool do_connect(char *dbname, char *user, char *host, char *port);
00063 static bool do_shell(const char *command);
00064 static bool do_watch(PQExpBuffer query_buf, long sleep);
00065 static bool lookup_function_oid(PGconn *conn, const char *desc, Oid *foid);
00066 static bool get_create_function_cmd(PGconn *conn, Oid oid, PQExpBuffer buf);
00067 static int strip_lineno_from_funcdesc(char *func);
00068 static void minimal_error_message(PGresult *res);
00069
00070 static void printSSLInfo(void);
00071
00072 #ifdef WIN32
00073 static void checkWin32Codepage(void);
00074 #endif
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096 backslashResult
00097 HandleSlashCmds(PsqlScanState scan_state,
00098 PQExpBuffer query_buf)
00099 {
00100 backslashResult status = PSQL_CMD_SKIP_LINE;
00101 char *cmd;
00102 char *arg;
00103
00104 Assert(scan_state != NULL);
00105
00106
00107 cmd = psql_scan_slash_command(scan_state);
00108
00109
00110 status = exec_command(cmd, scan_state, query_buf);
00111
00112 if (status == PSQL_CMD_UNKNOWN)
00113 {
00114 if (pset.cur_cmd_interactive)
00115 psql_error("Invalid command \\%s. Try \\? for help.\n", cmd);
00116 else
00117 psql_error("invalid command \\%s\n", cmd);
00118 status = PSQL_CMD_ERROR;
00119 }
00120
00121 if (status != PSQL_CMD_ERROR)
00122 {
00123
00124
00125 while ((arg = psql_scan_slash_option(scan_state,
00126 OT_NO_EVAL, NULL, false)))
00127 {
00128 psql_error("\\%s: extra argument \"%s\" ignored\n", cmd, arg);
00129 free(arg);
00130 }
00131 }
00132 else
00133 {
00134
00135 while ((arg = psql_scan_slash_option(scan_state,
00136 OT_WHOLE_LINE, NULL, false)))
00137 free(arg);
00138 }
00139
00140
00141 psql_scan_slash_command_end(scan_state);
00142
00143 free(cmd);
00144
00145
00146 fflush(pset.queryFout);
00147
00148 return status;
00149 }
00150
00151
00152
00153
00154 static char *
00155 read_connect_arg(PsqlScanState scan_state)
00156 {
00157 char *result;
00158 char quote;
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169 result = psql_scan_slash_option(scan_state, OT_SQLIDHACK, "e, true);
00170
00171 if (!result)
00172 return NULL;
00173
00174 if (quote)
00175 return result;
00176
00177 if (*result == '\0' || strcmp(result, "-") == 0)
00178 return NULL;
00179
00180 return result;
00181 }
00182
00183
00184
00185
00186
00187 static backslashResult
00188 exec_command(const char *cmd,
00189 PsqlScanState scan_state,
00190 PQExpBuffer query_buf)
00191 {
00192 bool success = true;
00193
00194 backslashResult status = PSQL_CMD_SKIP_LINE;
00195
00196
00197
00198
00199
00200 if (strcmp(cmd, "a") == 0)
00201 {
00202 if (pset.popt.topt.format != PRINT_ALIGNED)
00203 success = do_pset("format", "aligned", &pset.popt, pset.quiet);
00204 else
00205 success = do_pset("format", "unaligned", &pset.popt, pset.quiet);
00206 }
00207
00208
00209 else if (strcmp(cmd, "C") == 0)
00210 {
00211 char *opt = psql_scan_slash_option(scan_state,
00212 OT_NORMAL, NULL, true);
00213
00214 success = do_pset("title", opt, &pset.popt, pset.quiet);
00215 free(opt);
00216 }
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233 else if (strcmp(cmd, "c") == 0 || strcmp(cmd, "connect") == 0)
00234 {
00235 char *opt1,
00236 *opt2,
00237 *opt3,
00238 *opt4;
00239
00240 opt1 = read_connect_arg(scan_state);
00241 opt2 = read_connect_arg(scan_state);
00242 opt3 = read_connect_arg(scan_state);
00243 opt4 = read_connect_arg(scan_state);
00244
00245 success = do_connect(opt1, opt2, opt3, opt4);
00246
00247 free(opt1);
00248 free(opt2);
00249 free(opt3);
00250 free(opt4);
00251 }
00252
00253
00254 else if (strcmp(cmd, "cd") == 0)
00255 {
00256 char *opt = psql_scan_slash_option(scan_state,
00257 OT_NORMAL, NULL, true);
00258 char *dir;
00259
00260 if (opt)
00261 dir = opt;
00262 else
00263 {
00264 #ifndef WIN32
00265 struct passwd *pw;
00266
00267 pw = getpwuid(geteuid());
00268 if (!pw)
00269 {
00270 psql_error("could not get home directory: %s\n", strerror(errno));
00271 exit(EXIT_FAILURE);
00272 }
00273 dir = pw->pw_dir;
00274 #else
00275
00276
00277
00278
00279
00280 dir = "/";
00281 #endif
00282 }
00283
00284 if (chdir(dir) == -1)
00285 {
00286 psql_error("\\%s: could not change directory to \"%s\": %s\n",
00287 cmd, dir, strerror(errno));
00288 success = false;
00289 }
00290
00291 if (pset.dirname)
00292 free(pset.dirname);
00293 pset.dirname = pg_strdup(dir);
00294 canonicalize_path(pset.dirname);
00295
00296 if (opt)
00297 free(opt);
00298 }
00299
00300
00301 else if (strcmp(cmd, "conninfo") == 0)
00302 {
00303 char *db = PQdb(pset.db);
00304 char *host = PQhost(pset.db);
00305
00306 if (db == NULL)
00307 printf(_("You are currently not connected to a database.\n"));
00308 else
00309 {
00310 if (host == NULL)
00311 host = DEFAULT_PGSOCKET_DIR;
00312
00313 if (is_absolute_path(host))
00314 printf(_("You are connected to database \"%s\" as user \"%s\" via socket in \"%s\" at port \"%s\".\n"),
00315 db, PQuser(pset.db), host, PQport(pset.db));
00316 else
00317 printf(_("You are connected to database \"%s\" as user \"%s\" on host \"%s\" at port \"%s\".\n"),
00318 db, PQuser(pset.db), host, PQport(pset.db));
00319 printSSLInfo();
00320 }
00321 }
00322
00323
00324 else if (pg_strcasecmp(cmd, "copy") == 0)
00325 {
00326 char *opt = psql_scan_slash_option(scan_state,
00327 OT_WHOLE_LINE, NULL, false);
00328
00329 success = do_copy(opt);
00330 free(opt);
00331 }
00332
00333
00334 else if (strcmp(cmd, "copyright") == 0)
00335 print_copyright();
00336
00337
00338 else if (cmd[0] == 'd')
00339 {
00340 char *pattern;
00341 bool show_verbose,
00342 show_system;
00343
00344
00345 pattern = psql_scan_slash_option(scan_state,
00346 OT_NORMAL, NULL, true);
00347
00348 show_verbose = strchr(cmd, '+') ? true : false;
00349 show_system = strchr(cmd, 'S') ? true : false;
00350
00351 switch (cmd[1])
00352 {
00353 case '\0':
00354 case '+':
00355 case 'S':
00356 if (pattern)
00357 success = describeTableDetails(pattern, show_verbose, show_system);
00358 else
00359
00360 success = listTables("tvmsE", NULL, show_verbose, show_system);
00361 break;
00362 case 'a':
00363 success = describeAggregates(pattern, show_verbose, show_system);
00364 break;
00365 case 'b':
00366 success = describeTablespaces(pattern, show_verbose);
00367 break;
00368 case 'c':
00369 success = listConversions(pattern, show_verbose, show_system);
00370 break;
00371 case 'C':
00372 success = listCasts(pattern, show_verbose);
00373 break;
00374 case 'd':
00375 if (strncmp(cmd, "ddp", 3) == 0)
00376 success = listDefaultACLs(pattern);
00377 else
00378 success = objectDescription(pattern, show_system);
00379 break;
00380 case 'D':
00381 success = listDomains(pattern, show_verbose, show_system);
00382 break;
00383 case 'f':
00384 switch (cmd[2])
00385 {
00386 case '\0':
00387 case '+':
00388 case 'S':
00389 case 'a':
00390 case 'n':
00391 case 't':
00392 case 'w':
00393 success = describeFunctions(&cmd[2], pattern, show_verbose, show_system);
00394 break;
00395 default:
00396 status = PSQL_CMD_UNKNOWN;
00397 break;
00398 }
00399 break;
00400 case 'g':
00401
00402 success = describeRoles(pattern, show_verbose);
00403 break;
00404 case 'l':
00405 success = do_lo_list();
00406 break;
00407 case 'L':
00408 success = listLanguages(pattern, show_verbose, show_system);
00409 break;
00410 case 'n':
00411 success = listSchemas(pattern, show_verbose, show_system);
00412 break;
00413 case 'o':
00414 success = describeOperators(pattern, show_system);
00415 break;
00416 case 'O':
00417 success = listCollations(pattern, show_verbose, show_system);
00418 break;
00419 case 'p':
00420 success = permissionsList(pattern);
00421 break;
00422 case 'T':
00423 success = describeTypes(pattern, show_verbose, show_system);
00424 break;
00425 case 't':
00426 case 'v':
00427 case 'm':
00428 case 'i':
00429 case 's':
00430 case 'E':
00431 success = listTables(&cmd[1], pattern, show_verbose, show_system);
00432 break;
00433 case 'r':
00434 if (cmd[2] == 'd' && cmd[3] == 's')
00435 {
00436 char *pattern2 = NULL;
00437
00438 if (pattern)
00439 pattern2 = psql_scan_slash_option(scan_state,
00440 OT_NORMAL, NULL, true);
00441 success = listDbRoleSettings(pattern, pattern2);
00442 }
00443 else
00444 success = PSQL_CMD_UNKNOWN;
00445 break;
00446 case 'u':
00447 success = describeRoles(pattern, show_verbose);
00448 break;
00449 case 'F':
00450 switch (cmd[2])
00451 {
00452 case '\0':
00453 case '+':
00454 success = listTSConfigs(pattern, show_verbose);
00455 break;
00456 case 'p':
00457 success = listTSParsers(pattern, show_verbose);
00458 break;
00459 case 'd':
00460 success = listTSDictionaries(pattern, show_verbose);
00461 break;
00462 case 't':
00463 success = listTSTemplates(pattern, show_verbose);
00464 break;
00465 default:
00466 status = PSQL_CMD_UNKNOWN;
00467 break;
00468 }
00469 break;
00470 case 'e':
00471 switch (cmd[2])
00472 {
00473 case 's':
00474 success = listForeignServers(pattern, show_verbose);
00475 break;
00476 case 'u':
00477 success = listUserMappings(pattern, show_verbose);
00478 break;
00479 case 'w':
00480 success = listForeignDataWrappers(pattern, show_verbose);
00481 break;
00482 case 't':
00483 success = listForeignTables(pattern, show_verbose);
00484 break;
00485 default:
00486 status = PSQL_CMD_UNKNOWN;
00487 break;
00488 }
00489 break;
00490 case 'x':
00491 if (show_verbose)
00492 success = listExtensionContents(pattern);
00493 else
00494 success = listExtensions(pattern);
00495 break;
00496 case 'y':
00497 success = listEventTriggers(pattern, show_verbose);
00498 break;
00499 default:
00500 status = PSQL_CMD_UNKNOWN;
00501 }
00502
00503 if (pattern)
00504 free(pattern);
00505 }
00506
00507
00508
00509
00510
00511
00512 else if (strcmp(cmd, "e") == 0 || strcmp(cmd, "edit") == 0)
00513 {
00514 if (!query_buf)
00515 {
00516 psql_error("no query buffer\n");
00517 status = PSQL_CMD_ERROR;
00518 }
00519 else
00520 {
00521 char *fname;
00522 char *ln = NULL;
00523 int lineno = -1;
00524
00525 fname = psql_scan_slash_option(scan_state,
00526 OT_NORMAL, NULL, true);
00527 if (fname)
00528 {
00529
00530 ln = psql_scan_slash_option(scan_state,
00531 OT_NORMAL, NULL, true);
00532 if (ln == NULL)
00533 {
00534
00535 if (fname[0] &&
00536 strspn(fname, "0123456789") == strlen(fname))
00537 {
00538
00539 ln = fname;
00540 fname = NULL;
00541 }
00542 }
00543 }
00544 if (ln)
00545 {
00546 lineno = atoi(ln);
00547 if (lineno < 1)
00548 {
00549 psql_error("invalid line number: %s\n", ln);
00550 status = PSQL_CMD_ERROR;
00551 }
00552 }
00553 if (status != PSQL_CMD_ERROR)
00554 {
00555 expand_tilde(&fname);
00556 if (fname)
00557 canonicalize_path(fname);
00558 if (do_edit(fname, query_buf, lineno, NULL))
00559 status = PSQL_CMD_NEWEDIT;
00560 else
00561 status = PSQL_CMD_ERROR;
00562 }
00563 if (fname)
00564 free(fname);
00565 if (ln)
00566 free(ln);
00567 }
00568 }
00569
00570
00571
00572
00573
00574 else if (strcmp(cmd, "ef") == 0)
00575 {
00576 int lineno = -1;
00577
00578 if (pset.sversion < 80400)
00579 {
00580 psql_error("The server (version %d.%d) does not support editing function source.\n",
00581 pset.sversion / 10000, (pset.sversion / 100) % 100);
00582 status = PSQL_CMD_ERROR;
00583 }
00584 else if (!query_buf)
00585 {
00586 psql_error("no query buffer\n");
00587 status = PSQL_CMD_ERROR;
00588 }
00589 else
00590 {
00591 char *func;
00592 Oid foid = InvalidOid;
00593
00594 func = psql_scan_slash_option(scan_state,
00595 OT_WHOLE_LINE, NULL, true);
00596 lineno = strip_lineno_from_funcdesc(func);
00597 if (lineno == 0)
00598 {
00599
00600 status = PSQL_CMD_ERROR;
00601 }
00602 else if (!func)
00603 {
00604
00605 printfPQExpBuffer(query_buf,
00606 "CREATE FUNCTION ( )\n"
00607 " RETURNS \n"
00608 " LANGUAGE \n"
00609 " -- common options: IMMUTABLE STABLE STRICT SECURITY DEFINER\n"
00610 "AS $function$\n"
00611 "\n$function$\n");
00612 }
00613 else if (!lookup_function_oid(pset.db, func, &foid))
00614 {
00615
00616 status = PSQL_CMD_ERROR;
00617 }
00618 else if (!get_create_function_cmd(pset.db, foid, query_buf))
00619 {
00620
00621 status = PSQL_CMD_ERROR;
00622 }
00623 else if (lineno > 0)
00624 {
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634 const char *lines = query_buf->data;
00635
00636 while (*lines != '\0')
00637 {
00638 if (strncmp(lines, "AS ", 3) == 0)
00639 break;
00640 lineno++;
00641
00642 lines = strchr(lines, '\n');
00643 if (!lines)
00644 break;
00645 lines++;
00646 }
00647 }
00648
00649 if (func)
00650 free(func);
00651 }
00652
00653 if (status != PSQL_CMD_ERROR)
00654 {
00655 bool edited = false;
00656
00657 if (!do_edit(NULL, query_buf, lineno, &edited))
00658 status = PSQL_CMD_ERROR;
00659 else if (!edited)
00660 puts(_("No changes"));
00661 else
00662 status = PSQL_CMD_NEWEDIT;
00663 }
00664 }
00665
00666
00667 else if (strcmp(cmd, "echo") == 0 || strcmp(cmd, "qecho") == 0)
00668 {
00669 char *value;
00670 char quoted;
00671 bool no_newline = false;
00672 bool first = true;
00673 FILE *fout;
00674
00675 if (strcmp(cmd, "qecho") == 0)
00676 fout = pset.queryFout;
00677 else
00678 fout = stdout;
00679
00680 while ((value = psql_scan_slash_option(scan_state,
00681 OT_NORMAL, "ed, false)))
00682 {
00683 if (!quoted && strcmp(value, "-n") == 0)
00684 no_newline = true;
00685 else
00686 {
00687 if (first)
00688 first = false;
00689 else
00690 fputc(' ', fout);
00691 fputs(value, fout);
00692 }
00693 free(value);
00694 }
00695 if (!no_newline)
00696 fputs("\n", fout);
00697 }
00698
00699
00700 else if (strcmp(cmd, "encoding") == 0)
00701 {
00702 char *encoding = psql_scan_slash_option(scan_state,
00703 OT_NORMAL, NULL, false);
00704
00705 if (!encoding)
00706 {
00707
00708 puts(pg_encoding_to_char(pset.encoding));
00709 }
00710 else
00711 {
00712
00713 if (PQsetClientEncoding(pset.db, encoding) == -1)
00714 psql_error("%s: invalid encoding name or conversion procedure not found\n", encoding);
00715 else
00716 {
00717
00718 pset.encoding = PQclientEncoding(pset.db);
00719 pset.popt.topt.encoding = pset.encoding;
00720 SetVariable(pset.vars, "ENCODING",
00721 pg_encoding_to_char(pset.encoding));
00722 }
00723 free(encoding);
00724 }
00725 }
00726
00727
00728 else if (strcmp(cmd, "f") == 0)
00729 {
00730 char *fname = psql_scan_slash_option(scan_state,
00731 OT_NORMAL, NULL, false);
00732
00733 success = do_pset("fieldsep", fname, &pset.popt, pset.quiet);
00734 free(fname);
00735 }
00736
00737
00738 else if (strcmp(cmd, "g") == 0)
00739 {
00740 char *fname = psql_scan_slash_option(scan_state,
00741 OT_FILEPIPE, NULL, false);
00742
00743 if (!fname)
00744 pset.gfname = NULL;
00745 else
00746 {
00747 expand_tilde(&fname);
00748 pset.gfname = pg_strdup(fname);
00749 }
00750 free(fname);
00751 status = PSQL_CMD_SEND;
00752 }
00753
00754
00755 else if (strcmp(cmd, "gset") == 0)
00756 {
00757 char *prefix = psql_scan_slash_option(scan_state,
00758 OT_NORMAL, NULL, false);
00759
00760 if (prefix)
00761 pset.gset_prefix = prefix;
00762 else
00763 {
00764
00765 pset.gset_prefix = pg_strdup("");
00766 }
00767 status = PSQL_CMD_SEND;
00768 }
00769
00770
00771 else if (strcmp(cmd, "h") == 0 || strcmp(cmd, "help") == 0)
00772 {
00773 char *opt = psql_scan_slash_option(scan_state,
00774 OT_WHOLE_LINE, NULL, false);
00775 size_t len;
00776
00777
00778 if (opt)
00779 {
00780 len = strlen(opt);
00781 while (len > 0 &&
00782 (isspace((unsigned char) opt[len - 1])
00783 || opt[len - 1] == ';'))
00784 opt[--len] = '\0';
00785 }
00786
00787 helpSQL(opt, pset.popt.topt.pager);
00788 free(opt);
00789 }
00790
00791
00792 else if (strcmp(cmd, "H") == 0 || strcmp(cmd, "html") == 0)
00793 {
00794 if (pset.popt.topt.format != PRINT_HTML)
00795 success = do_pset("format", "html", &pset.popt, pset.quiet);
00796 else
00797 success = do_pset("format", "aligned", &pset.popt, pset.quiet);
00798 }
00799
00800
00801
00802 else if (strcmp(cmd, "i") == 0 || strcmp(cmd, "include") == 0
00803 || strcmp(cmd, "ir") == 0 || strcmp(cmd, "include_relative") == 0)
00804 {
00805 char *fname = psql_scan_slash_option(scan_state,
00806 OT_NORMAL, NULL, true);
00807
00808 if (!fname)
00809 {
00810 psql_error("\\%s: missing required argument\n", cmd);
00811 success = false;
00812 }
00813 else
00814 {
00815 bool include_relative;
00816
00817 include_relative = (strcmp(cmd, "ir") == 0
00818 || strcmp(cmd, "include_relative") == 0);
00819 expand_tilde(&fname);
00820 success = (process_file(fname, false, include_relative) == EXIT_SUCCESS);
00821 free(fname);
00822 }
00823 }
00824
00825
00826 else if (strcmp(cmd, "l") == 0 || strcmp(cmd, "list") == 0 ||
00827 strcmp(cmd, "l+") == 0 || strcmp(cmd, "list+") == 0)
00828 {
00829 char *pattern;
00830 bool show_verbose;
00831
00832 pattern = psql_scan_slash_option(scan_state,
00833 OT_NORMAL, NULL, true);
00834
00835 show_verbose = strchr(cmd, '+') ? true : false;
00836
00837 success = listAllDbs(pattern, show_verbose);
00838
00839 if (pattern)
00840 free(pattern);
00841 }
00842
00843
00844
00845
00846 else if (strncmp(cmd, "lo_", 3) == 0)
00847 {
00848 char *opt1,
00849 *opt2;
00850
00851 opt1 = psql_scan_slash_option(scan_state,
00852 OT_NORMAL, NULL, true);
00853 opt2 = psql_scan_slash_option(scan_state,
00854 OT_NORMAL, NULL, true);
00855
00856 if (strcmp(cmd + 3, "export") == 0)
00857 {
00858 if (!opt2)
00859 {
00860 psql_error("\\%s: missing required argument\n", cmd);
00861 success = false;
00862 }
00863 else
00864 {
00865 expand_tilde(&opt2);
00866 success = do_lo_export(opt1, opt2);
00867 }
00868 }
00869
00870 else if (strcmp(cmd + 3, "import") == 0)
00871 {
00872 if (!opt1)
00873 {
00874 psql_error("\\%s: missing required argument\n", cmd);
00875 success = false;
00876 }
00877 else
00878 {
00879 expand_tilde(&opt1);
00880 success = do_lo_import(opt1, opt2);
00881 }
00882 }
00883
00884 else if (strcmp(cmd + 3, "list") == 0)
00885 success = do_lo_list();
00886
00887 else if (strcmp(cmd + 3, "unlink") == 0)
00888 {
00889 if (!opt1)
00890 {
00891 psql_error("\\%s: missing required argument\n", cmd);
00892 success = false;
00893 }
00894 else
00895 success = do_lo_unlink(opt1);
00896 }
00897
00898 else
00899 status = PSQL_CMD_UNKNOWN;
00900
00901 free(opt1);
00902 free(opt2);
00903 }
00904
00905
00906
00907 else if (strcmp(cmd, "o") == 0 || strcmp(cmd, "out") == 0)
00908 {
00909 char *fname = psql_scan_slash_option(scan_state,
00910 OT_FILEPIPE, NULL, true);
00911
00912 expand_tilde(&fname);
00913 success = setQFout(fname);
00914 free(fname);
00915 }
00916
00917
00918 else if (strcmp(cmd, "p") == 0 || strcmp(cmd, "print") == 0)
00919 {
00920 if (query_buf && query_buf->len > 0)
00921 puts(query_buf->data);
00922 else if (!pset.quiet)
00923 puts(_("Query buffer is empty."));
00924 fflush(stdout);
00925 }
00926
00927
00928 else if (strcmp(cmd, "password") == 0)
00929 {
00930 char *pw1;
00931 char *pw2;
00932
00933 pw1 = simple_prompt("Enter new password: ", 100, false);
00934 pw2 = simple_prompt("Enter it again: ", 100, false);
00935
00936 if (strcmp(pw1, pw2) != 0)
00937 {
00938 psql_error("Passwords didn't match.\n");
00939 success = false;
00940 }
00941 else
00942 {
00943 char *opt0 = psql_scan_slash_option(scan_state, OT_SQLID, NULL, true);
00944 char *user;
00945 char *encrypted_password;
00946
00947 if (opt0)
00948 user = opt0;
00949 else
00950 user = PQuser(pset.db);
00951
00952 encrypted_password = PQencryptPassword(pw1, user);
00953
00954 if (!encrypted_password)
00955 {
00956 psql_error("Password encryption failed.\n");
00957 success = false;
00958 }
00959 else
00960 {
00961 PQExpBufferData buf;
00962 PGresult *res;
00963
00964 initPQExpBuffer(&buf);
00965 printfPQExpBuffer(&buf, "ALTER USER %s PASSWORD ",
00966 fmtId(user));
00967 appendStringLiteralConn(&buf, encrypted_password, pset.db);
00968 res = PSQLexec(buf.data, false);
00969 termPQExpBuffer(&buf);
00970 if (!res)
00971 success = false;
00972 else
00973 PQclear(res);
00974 PQfreemem(encrypted_password);
00975 }
00976
00977 if (opt0)
00978 free(opt0);
00979 }
00980
00981 free(pw1);
00982 free(pw2);
00983 }
00984
00985
00986 else if (strcmp(cmd, "prompt") == 0)
00987 {
00988 char *opt,
00989 *prompt_text = NULL;
00990 char *arg1,
00991 *arg2;
00992
00993 arg1 = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, false);
00994 arg2 = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, false);
00995
00996 if (!arg1)
00997 {
00998 psql_error("\\%s: missing required argument\n", cmd);
00999 success = false;
01000 }
01001 else
01002 {
01003 char *result;
01004
01005 if (arg2)
01006 {
01007 prompt_text = arg1;
01008 opt = arg2;
01009 }
01010 else
01011 opt = arg1;
01012
01013 if (!pset.inputfile)
01014 result = simple_prompt(prompt_text, 4096, true);
01015 else
01016 {
01017 if (prompt_text)
01018 {
01019 fputs(prompt_text, stdout);
01020 fflush(stdout);
01021 }
01022 result = gets_fromFile(stdin);
01023 }
01024
01025 if (!SetVariable(pset.vars, opt, result))
01026 {
01027 psql_error("\\%s: error while setting variable\n", cmd);
01028 success = false;
01029 }
01030
01031 free(result);
01032 if (prompt_text)
01033 free(prompt_text);
01034 free(opt);
01035 }
01036 }
01037
01038
01039 else if (strcmp(cmd, "pset") == 0)
01040 {
01041 char *opt0 = psql_scan_slash_option(scan_state,
01042 OT_NORMAL, NULL, false);
01043 char *opt1 = psql_scan_slash_option(scan_state,
01044 OT_NORMAL, NULL, false);
01045
01046 if (!opt0)
01047 {
01048 psql_error("\\%s: missing required argument\n", cmd);
01049 success = false;
01050 }
01051 else
01052 success = do_pset(opt0, opt1, &pset.popt, pset.quiet);
01053
01054 free(opt0);
01055 free(opt1);
01056 }
01057
01058
01059 else if (strcmp(cmd, "q") == 0 || strcmp(cmd, "quit") == 0)
01060 status = PSQL_CMD_TERMINATE;
01061
01062
01063 else if (strcmp(cmd, "r") == 0 || strcmp(cmd, "reset") == 0)
01064 {
01065 resetPQExpBuffer(query_buf);
01066 psql_scan_reset(scan_state);
01067 if (!pset.quiet)
01068 puts(_("Query buffer reset (cleared)."));
01069 }
01070
01071
01072 else if (strcmp(cmd, "s") == 0)
01073 {
01074 char *fname = psql_scan_slash_option(scan_state,
01075 OT_NORMAL, NULL, true);
01076
01077 #if defined(WIN32) && !defined(__CYGWIN__)
01078
01079
01080
01081
01082
01083 #define DEVTTY "con"
01084 #else
01085 #define DEVTTY "/dev/tty"
01086 #endif
01087
01088 expand_tilde(&fname);
01089
01090 success = saveHistory(fname ? fname : DEVTTY, -1, false, false);
01091 if (success && !pset.quiet && fname)
01092 printf(gettext("Wrote history to file \"%s/%s\".\n"),
01093 pset.dirname ? pset.dirname : ".", fname);
01094 if (!fname)
01095 putchar('\n');
01096 free(fname);
01097 }
01098
01099
01100 else if (strcmp(cmd, "set") == 0)
01101 {
01102 char *opt0 = psql_scan_slash_option(scan_state,
01103 OT_NORMAL, NULL, false);
01104
01105 if (!opt0)
01106 {
01107
01108 PrintVariables(pset.vars);
01109 success = true;
01110 }
01111 else
01112 {
01113
01114
01115
01116 char *newval;
01117 char *opt;
01118
01119 opt = psql_scan_slash_option(scan_state,
01120 OT_NORMAL, NULL, false);
01121 newval = pg_strdup(opt ? opt : "");
01122 free(opt);
01123
01124 while ((opt = psql_scan_slash_option(scan_state,
01125 OT_NORMAL, NULL, false)))
01126 {
01127 newval = realloc(newval, strlen(newval) + strlen(opt) + 1);
01128 if (!newval)
01129 {
01130 psql_error("out of memory\n");
01131 exit(EXIT_FAILURE);
01132 }
01133 strcat(newval, opt);
01134 free(opt);
01135 }
01136
01137 if (!SetVariable(pset.vars, opt0, newval))
01138 {
01139 psql_error("\\%s: error while setting variable\n", cmd);
01140 success = false;
01141 }
01142 free(newval);
01143 }
01144 free(opt0);
01145 }
01146
01147
01148
01149 else if (strcmp(cmd, "setenv") == 0)
01150 {
01151 char *envvar = psql_scan_slash_option(scan_state,
01152 OT_NORMAL, NULL, false);
01153 char *envval = psql_scan_slash_option(scan_state,
01154 OT_NORMAL, NULL, false);
01155
01156 if (!envvar)
01157 {
01158 psql_error("\\%s: missing required argument\n", cmd);
01159 success = false;
01160 }
01161 else if (strchr(envvar, '=') != NULL)
01162 {
01163 psql_error("\\%s: environment variable name must not contain \"=\"\n",
01164 cmd);
01165 success = false;
01166 }
01167 else if (!envval)
01168 {
01169
01170 unsetenv(envvar);
01171 success = true;
01172 }
01173 else
01174 {
01175
01176 int len = strlen(envvar) + strlen(envval) + 1;
01177 char *newval = pg_malloc(len + 1);
01178
01179 snprintf(newval, len + 1, "%s=%s", envvar, envval);
01180 putenv(newval);
01181 success = true;
01182
01183
01184
01185
01186
01187
01188 }
01189 free(envvar);
01190 free(envval);
01191 }
01192
01193
01194 else if (strcmp(cmd, "sf") == 0 || strcmp(cmd, "sf+") == 0)
01195 {
01196 bool show_linenumbers = (strcmp(cmd, "sf+") == 0);
01197 PQExpBuffer func_buf;
01198 char *func;
01199 Oid foid = InvalidOid;
01200
01201 func_buf = createPQExpBuffer();
01202 func = psql_scan_slash_option(scan_state,
01203 OT_WHOLE_LINE, NULL, true);
01204 if (pset.sversion < 80400)
01205 {
01206 psql_error("The server (version %d.%d) does not support showing function source.\n",
01207 pset.sversion / 10000, (pset.sversion / 100) % 100);
01208 status = PSQL_CMD_ERROR;
01209 }
01210 else if (!func)
01211 {
01212 psql_error("function name is required\n");
01213 status = PSQL_CMD_ERROR;
01214 }
01215 else if (!lookup_function_oid(pset.db, func, &foid))
01216 {
01217
01218 status = PSQL_CMD_ERROR;
01219 }
01220 else if (!get_create_function_cmd(pset.db, foid, func_buf))
01221 {
01222
01223 status = PSQL_CMD_ERROR;
01224 }
01225 else
01226 {
01227 FILE *output;
01228 bool is_pager;
01229
01230
01231 if (pset.queryFout == stdout)
01232 {
01233
01234 int lineno = 0;
01235 const char *lines = func_buf->data;
01236
01237 while (*lines != '\0')
01238 {
01239 lineno++;
01240
01241 lines = strchr(lines, '\n');
01242 if (!lines)
01243 break;
01244 lines++;
01245 }
01246
01247 output = PageOutput(lineno, pset.popt.topt.pager);
01248 is_pager = true;
01249 }
01250 else
01251 {
01252
01253 output = pset.queryFout;
01254 is_pager = false;
01255 }
01256
01257 if (show_linenumbers)
01258 {
01259 bool in_header = true;
01260 int lineno = 0;
01261 char *lines = func_buf->data;
01262
01263
01264
01265
01266
01267
01268
01269
01270
01271
01272 while (*lines != '\0')
01273 {
01274 char *eol;
01275
01276 if (in_header && strncmp(lines, "AS ", 3) == 0)
01277 in_header = false;
01278
01279 if (!in_header)
01280 lineno++;
01281
01282
01283 eol = strchr(lines, '\n');
01284 if (eol != NULL)
01285 *eol = '\0';
01286
01287
01288 if (in_header)
01289 fprintf(output, " %s\n", lines);
01290 else
01291 fprintf(output, "%-7d %s\n", lineno, lines);
01292
01293
01294 if (eol == NULL)
01295 break;
01296 lines = ++eol;
01297 }
01298 }
01299 else
01300 {
01301
01302 fputs(func_buf->data, output);
01303 }
01304
01305 if (is_pager)
01306 ClosePager(output);
01307 }
01308
01309 if (func)
01310 free(func);
01311 destroyPQExpBuffer(func_buf);
01312 }
01313
01314
01315 else if (strcmp(cmd, "t") == 0)
01316 {
01317 char *opt = psql_scan_slash_option(scan_state,
01318 OT_NORMAL, NULL, true);
01319
01320 success = do_pset("tuples_only", opt, &pset.popt, pset.quiet);
01321 free(opt);
01322 }
01323
01324
01325 else if (strcmp(cmd, "T") == 0)
01326 {
01327 char *value = psql_scan_slash_option(scan_state,
01328 OT_NORMAL, NULL, false);
01329
01330 success = do_pset("tableattr", value, &pset.popt, pset.quiet);
01331 free(value);
01332 }
01333
01334
01335 else if (strcmp(cmd, "timing") == 0)
01336 {
01337 char *opt = psql_scan_slash_option(scan_state,
01338 OT_NORMAL, NULL, false);
01339
01340 if (opt)
01341 pset.timing = ParseVariableBool(opt);
01342 else
01343 pset.timing = !pset.timing;
01344 if (!pset.quiet)
01345 {
01346 if (pset.timing)
01347 puts(_("Timing is on."));
01348 else
01349 puts(_("Timing is off."));
01350 }
01351 free(opt);
01352 }
01353
01354
01355 else if (strcmp(cmd, "unset") == 0)
01356 {
01357 char *opt = psql_scan_slash_option(scan_state,
01358 OT_NORMAL, NULL, false);
01359
01360 if (!opt)
01361 {
01362 psql_error("\\%s: missing required argument\n", cmd);
01363 success = false;
01364 }
01365 else if (!SetVariable(pset.vars, opt, NULL))
01366 {
01367 psql_error("\\%s: error while setting variable\n", cmd);
01368 success = false;
01369 }
01370 free(opt);
01371 }
01372
01373
01374 else if (strcmp(cmd, "w") == 0 || strcmp(cmd, "write") == 0)
01375 {
01376 FILE *fd = NULL;
01377 bool is_pipe = false;
01378 char *fname = NULL;
01379
01380 if (!query_buf)
01381 {
01382 psql_error("no query buffer\n");
01383 status = PSQL_CMD_ERROR;
01384 }
01385 else
01386 {
01387 fname = psql_scan_slash_option(scan_state,
01388 OT_FILEPIPE, NULL, true);
01389 expand_tilde(&fname);
01390
01391 if (!fname)
01392 {
01393 psql_error("\\%s: missing required argument\n", cmd);
01394 success = false;
01395 }
01396 else
01397 {
01398 if (fname[0] == '|')
01399 {
01400 is_pipe = true;
01401 fd = popen(&fname[1], "w");
01402 }
01403 else
01404 {
01405 canonicalize_path(fname);
01406 fd = fopen(fname, "w");
01407 }
01408 if (!fd)
01409 {
01410 psql_error("%s: %s\n", fname, strerror(errno));
01411 success = false;
01412 }
01413 }
01414 }
01415
01416 if (fd)
01417 {
01418 int result;
01419
01420 if (query_buf && query_buf->len > 0)
01421 fprintf(fd, "%s\n", query_buf->data);
01422
01423 if (is_pipe)
01424 result = pclose(fd);
01425 else
01426 result = fclose(fd);
01427
01428 if (result == EOF)
01429 {
01430 psql_error("%s: %s\n", fname, strerror(errno));
01431 success = false;
01432 }
01433 }
01434
01435 free(fname);
01436 }
01437
01438
01439 else if (strcmp(cmd, "watch") == 0)
01440 {
01441 char *opt = psql_scan_slash_option(scan_state,
01442 OT_NORMAL, NULL, true);
01443 long sleep = 2;
01444
01445
01446 if (opt)
01447 {
01448 sleep = strtol(opt, NULL, 10);
01449 if (sleep <= 0)
01450 sleep = 1;
01451 free(opt);
01452 }
01453
01454 success = do_watch(query_buf, sleep);
01455
01456
01457 resetPQExpBuffer(query_buf);
01458 psql_scan_reset(scan_state);
01459 }
01460
01461
01462 else if (strcmp(cmd, "x") == 0)
01463 {
01464 char *opt = psql_scan_slash_option(scan_state,
01465 OT_NORMAL, NULL, true);
01466
01467 success = do_pset("expanded", opt, &pset.popt, pset.quiet);
01468 free(opt);
01469 }
01470
01471
01472 else if (strcmp(cmd, "z") == 0)
01473 {
01474 char *pattern = psql_scan_slash_option(scan_state,
01475 OT_NORMAL, NULL, true);
01476
01477 success = permissionsList(pattern);
01478 if (pattern)
01479 free(pattern);
01480 }
01481
01482
01483 else if (strcmp(cmd, "!") == 0)
01484 {
01485 char *opt = psql_scan_slash_option(scan_state,
01486 OT_WHOLE_LINE, NULL, false);
01487
01488 success = do_shell(opt);
01489 free(opt);
01490 }
01491
01492
01493 else if (strcmp(cmd, "?") == 0)
01494 slashUsage(pset.popt.topt.pager);
01495
01496 #if 0
01497
01498
01499
01500
01501 else if (strcmp(cmd, "void") == 0 || strcmp(cmd, "#") == 0)
01502 {
01503 int i = 0;
01504 char *value;
01505
01506 while ((value = psql_scan_slash_option(scan_state,
01507 OT_NORMAL, NULL, true)))
01508 {
01509 psql_error("+ opt(%d) = |%s|\n", i++, value);
01510 free(value);
01511 }
01512 }
01513 #endif
01514
01515 else
01516 status = PSQL_CMD_UNKNOWN;
01517
01518 if (!success)
01519 status = PSQL_CMD_ERROR;
01520
01521 return status;
01522 }
01523
01524
01525
01526
01527
01528
01529 static char *
01530 prompt_for_password(const char *username)
01531 {
01532 char *result;
01533
01534 if (username == NULL)
01535 result = simple_prompt("Password: ", 100, false);
01536 else
01537 {
01538 char *prompt_text;
01539
01540 prompt_text = pg_malloc(strlen(username) + 100);
01541 snprintf(prompt_text, strlen(username) + 100,
01542 _("Password for user %s: "), username);
01543 result = simple_prompt(prompt_text, 100, false);
01544 free(prompt_text);
01545 }
01546
01547 return result;
01548 }
01549
01550 static bool
01551 param_is_newly_set(const char *old_val, const char *new_val)
01552 {
01553 if (new_val == NULL)
01554 return false;
01555
01556 if (old_val == NULL || strcmp(old_val, new_val) != 0)
01557 return true;
01558
01559 return false;
01560 }
01561
01562
01563
01564
01565
01566
01567
01568
01569
01570
01571
01572
01573 static bool
01574 do_connect(char *dbname, char *user, char *host, char *port)
01575 {
01576 PGconn *o_conn = pset.db,
01577 *n_conn;
01578 char *password = NULL;
01579
01580 if (!o_conn && (!dbname || !user || !host || !port))
01581 {
01582
01583
01584
01585
01586
01587 psql_error("All connection parameters must be supplied because no "
01588 "database connection exists\n");
01589 return false;
01590 }
01591
01592 if (!dbname)
01593 dbname = PQdb(o_conn);
01594 if (!user)
01595 user = PQuser(o_conn);
01596 if (!host)
01597 host = PQhost(o_conn);
01598 if (!port)
01599 port = PQport(o_conn);
01600
01601
01602
01603
01604
01605
01606
01607
01608
01609
01610
01611 if (pset.getPassword == TRI_YES)
01612 {
01613 password = prompt_for_password(user);
01614 }
01615 else if (o_conn && user && strcmp(PQuser(o_conn), user) == 0)
01616 {
01617 password = pg_strdup(PQpass(o_conn));
01618 }
01619
01620 while (true)
01621 {
01622 #define PARAMS_ARRAY_SIZE 8
01623 const char **keywords = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*keywords));
01624 const char **values = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*values));
01625
01626 keywords[0] = "host";
01627 values[0] = host;
01628 keywords[1] = "port";
01629 values[1] = port;
01630 keywords[2] = "user";
01631 values[2] = user;
01632 keywords[3] = "password";
01633 values[3] = password;
01634 keywords[4] = "dbname";
01635 values[4] = dbname;
01636 keywords[5] = "fallback_application_name";
01637 values[5] = pset.progname;
01638 keywords[6] = "client_encoding";
01639 values[6] = (pset.notty || getenv("PGCLIENTENCODING")) ? NULL : "auto";
01640 keywords[7] = NULL;
01641 values[7] = NULL;
01642
01643 n_conn = PQconnectdbParams(keywords, values, true);
01644
01645 free(keywords);
01646 free(values);
01647
01648
01649 if (password)
01650 free(password);
01651
01652 if (PQstatus(n_conn) == CONNECTION_OK)
01653 break;
01654
01655
01656
01657
01658
01659 if (!password && PQconnectionNeedsPassword(n_conn) && pset.getPassword != TRI_NO)
01660 {
01661 PQfinish(n_conn);
01662 password = prompt_for_password(user);
01663 continue;
01664 }
01665
01666
01667
01668
01669
01670
01671 if (pset.cur_cmd_interactive)
01672 {
01673 psql_error("%s", PQerrorMessage(n_conn));
01674
01675
01676 if (o_conn)
01677 psql_error("Previous connection kept\n");
01678 }
01679 else
01680 {
01681 psql_error("\\connect: %s", PQerrorMessage(n_conn));
01682 if (o_conn)
01683 {
01684 PQfinish(o_conn);
01685 pset.db = NULL;
01686 }
01687 }
01688
01689 PQfinish(n_conn);
01690 return false;
01691 }
01692
01693
01694
01695
01696
01697 PQsetNoticeProcessor(n_conn, NoticeProcessor, NULL);
01698 pset.db = n_conn;
01699 SyncVariables();
01700 connection_warnings(false);
01701
01702
01703 if (!pset.quiet)
01704 {
01705 if (param_is_newly_set(PQhost(o_conn), PQhost(pset.db)) ||
01706 param_is_newly_set(PQport(o_conn), PQport(pset.db)))
01707 {
01708 char *host = PQhost(pset.db);
01709
01710 if (host == NULL)
01711 host = DEFAULT_PGSOCKET_DIR;
01712
01713 if (is_absolute_path(host))
01714 printf(_("You are now connected to database \"%s\" as user \"%s\" via socket in \"%s\" at port \"%s\".\n"),
01715 PQdb(pset.db), PQuser(pset.db), host, PQport(pset.db));
01716 else
01717 printf(_("You are now connected to database \"%s\" as user \"%s\" on host \"%s\" at port \"%s\".\n"),
01718 PQdb(pset.db), PQuser(pset.db), host, PQport(pset.db));
01719 }
01720 else
01721 printf(_("You are now connected to database \"%s\" as user \"%s\".\n"),
01722 PQdb(pset.db), PQuser(pset.db));
01723 }
01724
01725 if (o_conn)
01726 PQfinish(o_conn);
01727 return true;
01728 }
01729
01730
01731 void
01732 connection_warnings(bool in_startup)
01733 {
01734 if (!pset.quiet && !pset.notty)
01735 {
01736 int client_ver = PG_VERSION_NUM;
01737
01738 if (pset.sversion != client_ver)
01739 {
01740 const char *server_version;
01741 char server_ver_str[16];
01742
01743
01744 server_version = PQparameterStatus(pset.db, "server_version");
01745 if (!server_version)
01746 {
01747 snprintf(server_ver_str, sizeof(server_ver_str),
01748 "%d.%d.%d",
01749 pset.sversion / 10000,
01750 (pset.sversion / 100) % 100,
01751 pset.sversion % 100);
01752 server_version = server_ver_str;
01753 }
01754
01755 printf(_("%s (%s, server %s)\n"),
01756 pset.progname, PG_VERSION, server_version);
01757 }
01758
01759 else if (in_startup)
01760 printf("%s (%s)\n", pset.progname, PG_VERSION);
01761
01762 if (pset.sversion / 100 > client_ver / 100)
01763 printf(_("WARNING: %s major version %d.%d, server major version %d.%d.\n"
01764 " Some psql features might not work.\n"),
01765 pset.progname, client_ver / 10000, (client_ver / 100) % 100,
01766 pset.sversion / 10000, (pset.sversion / 100) % 100);
01767
01768 #ifdef WIN32
01769 checkWin32Codepage();
01770 #endif
01771 printSSLInfo();
01772 }
01773 }
01774
01775
01776
01777
01778
01779
01780
01781 static void
01782 printSSLInfo(void)
01783 {
01784 #ifdef USE_SSL
01785 int sslbits = -1;
01786 SSL *ssl;
01787
01788 ssl = PQgetssl(pset.db);
01789 if (!ssl)
01790 return;
01791
01792 SSL_get_cipher_bits(ssl, &sslbits);
01793 printf(_("SSL connection (cipher: %s, bits: %d)\n"),
01794 SSL_get_cipher(ssl), sslbits);
01795 #else
01796
01797
01798
01799
01800
01801
01802 if (PQgetssl(pset.db))
01803 printf(_("SSL connection (unknown cipher)\n"));
01804 #endif
01805 }
01806
01807
01808
01809
01810
01811
01812
01813 #ifdef WIN32
01814 static void
01815 checkWin32Codepage(void)
01816 {
01817 unsigned int wincp,
01818 concp;
01819
01820 wincp = GetACP();
01821 concp = GetConsoleCP();
01822 if (wincp != concp)
01823 {
01824 printf(_("WARNING: Console code page (%u) differs from Windows code page (%u)\n"
01825 " 8-bit characters might not work correctly. See psql reference\n"
01826 " page \"Notes for Windows users\" for details.\n"),
01827 concp, wincp);
01828 }
01829 }
01830 #endif
01831
01832
01833
01834
01835
01836
01837
01838
01839 void
01840 SyncVariables(void)
01841 {
01842
01843 pset.encoding = PQclientEncoding(pset.db);
01844 pset.popt.topt.encoding = pset.encoding;
01845 pset.sversion = PQserverVersion(pset.db);
01846
01847 SetVariable(pset.vars, "DBNAME", PQdb(pset.db));
01848 SetVariable(pset.vars, "USER", PQuser(pset.db));
01849 SetVariable(pset.vars, "HOST", PQhost(pset.db));
01850 SetVariable(pset.vars, "PORT", PQport(pset.db));
01851 SetVariable(pset.vars, "ENCODING", pg_encoding_to_char(pset.encoding));
01852
01853
01854 PQsetErrorVerbosity(pset.db, pset.verbosity);
01855 }
01856
01857
01858
01859
01860
01861
01862 void
01863 UnsyncVariables(void)
01864 {
01865 SetVariable(pset.vars, "DBNAME", NULL);
01866 SetVariable(pset.vars, "USER", NULL);
01867 SetVariable(pset.vars, "HOST", NULL);
01868 SetVariable(pset.vars, "PORT", NULL);
01869 SetVariable(pset.vars, "ENCODING", NULL);
01870 }
01871
01872
01873
01874
01875
01876
01877
01878
01879 static bool
01880 editFile(const char *fname, int lineno)
01881 {
01882 const char *editorName;
01883 const char *editor_lineno_arg = NULL;
01884 char *sys;
01885 int result;
01886
01887 Assert(fname != NULL);
01888
01889
01890 editorName = getenv("PSQL_EDITOR");
01891 if (!editorName)
01892 editorName = getenv("EDITOR");
01893 if (!editorName)
01894 editorName = getenv("VISUAL");
01895 if (!editorName)
01896 editorName = DEFAULT_EDITOR;
01897
01898
01899 if (lineno > 0)
01900 {
01901 editor_lineno_arg = getenv("PSQL_EDITOR_LINENUMBER_ARG");
01902 #ifdef DEFAULT_EDITOR_LINENUMBER_ARG
01903 if (!editor_lineno_arg)
01904 editor_lineno_arg = DEFAULT_EDITOR_LINENUMBER_ARG;
01905 #endif
01906 if (!editor_lineno_arg)
01907 {
01908 psql_error("environment variable PSQL_EDITOR_LINENUMBER_ARG must be set to specify a line number\n");
01909 return false;
01910 }
01911 }
01912
01913
01914 if (lineno > 0)
01915 sys = pg_malloc(strlen(editorName)
01916 + strlen(editor_lineno_arg) + 10
01917 + 1 + strlen(fname) + 10 + 1);
01918 else
01919 sys = pg_malloc(strlen(editorName) + strlen(fname) + 10 + 1);
01920
01921
01922
01923
01924
01925
01926
01927
01928 #ifndef WIN32
01929 if (lineno > 0)
01930 sprintf(sys, "exec %s %s%d '%s'",
01931 editorName, editor_lineno_arg, lineno, fname);
01932 else
01933 sprintf(sys, "exec %s '%s'",
01934 editorName, fname);
01935 #else
01936 if (lineno > 0)
01937 sprintf(sys, SYSTEMQUOTE "\"%s\" %s%d \"%s\"" SYSTEMQUOTE,
01938 editorName, editor_lineno_arg, lineno, fname);
01939 else
01940 sprintf(sys, SYSTEMQUOTE "\"%s\" \"%s\"" SYSTEMQUOTE,
01941 editorName, fname);
01942 #endif
01943 result = system(sys);
01944 if (result == -1)
01945 psql_error("could not start editor \"%s\"\n", editorName);
01946 else if (result == 127)
01947 psql_error("could not start /bin/sh\n");
01948 free(sys);
01949
01950 return result == 0;
01951 }
01952
01953
01954
01955 static bool
01956 do_edit(const char *filename_arg, PQExpBuffer query_buf,
01957 int lineno, bool *edited)
01958 {
01959 char fnametmp[MAXPGPATH];
01960 FILE *stream = NULL;
01961 const char *fname;
01962 bool error = false;
01963 int fd;
01964
01965 struct stat before,
01966 after;
01967
01968 if (filename_arg)
01969 fname = filename_arg;
01970 else
01971 {
01972
01973 #ifndef WIN32
01974 const char *tmpdir = getenv("TMPDIR");
01975
01976 if (!tmpdir)
01977 tmpdir = "/tmp";
01978 #else
01979 char tmpdir[MAXPGPATH];
01980 int ret;
01981
01982 ret = GetTempPath(MAXPGPATH, tmpdir);
01983 if (ret == 0 || ret > MAXPGPATH)
01984 {
01985 psql_error("could not locate temporary directory: %s\n",
01986 !ret ? strerror(errno) : "");
01987 return false;
01988 }
01989
01990
01991
01992
01993
01994
01995 #endif
01996 #ifndef WIN32
01997 snprintf(fnametmp, sizeof(fnametmp), "%s%spsql.edit.%d.sql", tmpdir,
01998 "/", (int) getpid());
01999 #else
02000 snprintf(fnametmp, sizeof(fnametmp), "%s%spsql.edit.%d.sql", tmpdir,
02001 "" , (int) getpid());
02002 #endif
02003
02004 fname = (const char *) fnametmp;
02005
02006 fd = open(fname, O_WRONLY | O_CREAT | O_EXCL, 0600);
02007 if (fd != -1)
02008 stream = fdopen(fd, "w");
02009
02010 if (fd == -1 || !stream)
02011 {
02012 psql_error("could not open temporary file \"%s\": %s\n", fname, strerror(errno));
02013 error = true;
02014 }
02015 else
02016 {
02017 unsigned int ql = query_buf->len;
02018
02019 if (ql == 0 || query_buf->data[ql - 1] != '\n')
02020 {
02021 appendPQExpBufferChar(query_buf, '\n');
02022 ql++;
02023 }
02024
02025 if (fwrite(query_buf->data, 1, ql, stream) != ql)
02026 {
02027 psql_error("%s: %s\n", fname, strerror(errno));
02028 fclose(stream);
02029 remove(fname);
02030 error = true;
02031 }
02032 else if (fclose(stream) != 0)
02033 {
02034 psql_error("%s: %s\n", fname, strerror(errno));
02035 remove(fname);
02036 error = true;
02037 }
02038 }
02039 }
02040
02041 if (!error && stat(fname, &before) != 0)
02042 {
02043 psql_error("%s: %s\n", fname, strerror(errno));
02044 error = true;
02045 }
02046
02047
02048 if (!error)
02049 error = !editFile(fname, lineno);
02050
02051 if (!error && stat(fname, &after) != 0)
02052 {
02053 psql_error("%s: %s\n", fname, strerror(errno));
02054 error = true;
02055 }
02056
02057 if (!error && before.st_mtime != after.st_mtime)
02058 {
02059 stream = fopen(fname, PG_BINARY_R);
02060 if (!stream)
02061 {
02062 psql_error("%s: %s\n", fname, strerror(errno));
02063 error = true;
02064 }
02065 else
02066 {
02067
02068 char line[1024];
02069
02070 resetPQExpBuffer(query_buf);
02071 while (fgets(line, sizeof(line), stream) != NULL)
02072 appendPQExpBufferStr(query_buf, line);
02073
02074 if (ferror(stream))
02075 {
02076 psql_error("%s: %s\n", fname, strerror(errno));
02077 error = true;
02078 }
02079 else if (edited)
02080 {
02081 *edited = true;
02082 }
02083
02084 fclose(stream);
02085 }
02086 }
02087
02088
02089 if (!filename_arg)
02090 {
02091 if (remove(fname) == -1)
02092 {
02093 psql_error("%s: %s\n", fname, strerror(errno));
02094 error = true;
02095 }
02096 }
02097
02098 return !error;
02099 }
02100
02101
02102
02103
02104
02105
02106
02107
02108
02109
02110
02111
02112
02113 int
02114 process_file(char *filename, bool single_txn, bool use_relative_path)
02115 {
02116 FILE *fd;
02117 int result;
02118 char *oldfilename;
02119 char relpath[MAXPGPATH];
02120 PGresult *res;
02121
02122 if (!filename)
02123 {
02124 fd = stdin;
02125 filename = NULL;
02126 }
02127 else if (strcmp(filename, "-") != 0)
02128 {
02129 canonicalize_path(filename);
02130
02131
02132
02133
02134
02135
02136
02137 if (use_relative_path && pset.inputfile &&
02138 !is_absolute_path(filename) && !has_drive_prefix(filename))
02139 {
02140 strlcpy(relpath, pset.inputfile, sizeof(relpath));
02141 get_parent_directory(relpath);
02142 join_path_components(relpath, relpath, filename);
02143 canonicalize_path(relpath);
02144
02145 filename = relpath;
02146 }
02147
02148 fd = fopen(filename, PG_BINARY_R);
02149
02150 if (!fd)
02151 {
02152 psql_error("%s: %s\n", filename, strerror(errno));
02153 return EXIT_FAILURE;
02154 }
02155 }
02156 else
02157 {
02158 fd = stdin;
02159 filename = "<stdin>";
02160 }
02161
02162 oldfilename = pset.inputfile;
02163 pset.inputfile = filename;
02164
02165 if (single_txn)
02166 {
02167 if ((res = PSQLexec("BEGIN", false)) == NULL)
02168 {
02169 if (pset.on_error_stop)
02170 {
02171 result = EXIT_USER;
02172 goto error;
02173 }
02174 }
02175 else
02176 PQclear(res);
02177 }
02178
02179 result = MainLoop(fd);
02180
02181 if (single_txn)
02182 {
02183 if ((res = PSQLexec("COMMIT", false)) == NULL)
02184 {
02185 if (pset.on_error_stop)
02186 {
02187 result = EXIT_USER;
02188 goto error;
02189 }
02190 }
02191 else
02192 PQclear(res);
02193 }
02194
02195 error:
02196 if (fd != stdin)
02197 fclose(fd);
02198
02199 pset.inputfile = oldfilename;
02200 return result;
02201 }
02202
02203
02204
02205
02206
02207
02208
02209 static const char *
02210 _align2string(enum printFormat in)
02211 {
02212 switch (in)
02213 {
02214 case PRINT_NOTHING:
02215 return "nothing";
02216 break;
02217 case PRINT_UNALIGNED:
02218 return "unaligned";
02219 break;
02220 case PRINT_ALIGNED:
02221 return "aligned";
02222 break;
02223 case PRINT_WRAPPED:
02224 return "wrapped";
02225 break;
02226 case PRINT_HTML:
02227 return "html";
02228 break;
02229 case PRINT_LATEX:
02230 return "latex";
02231 break;
02232 case PRINT_LATEX_LONGTABLE:
02233 return "latex-longtable";
02234 break;
02235 case PRINT_TROFF_MS:
02236 return "troff-ms";
02237 break;
02238 }
02239 return "unknown";
02240 }
02241
02242
02243 bool
02244 do_pset(const char *param, const char *value, printQueryOpt *popt, bool quiet)
02245 {
02246 size_t vallen = 0;
02247
02248 Assert(param != NULL);
02249
02250 if (value)
02251 vallen = strlen(value);
02252
02253
02254 if (strcmp(param, "format") == 0)
02255 {
02256 if (!value)
02257 ;
02258 else if (pg_strncasecmp("unaligned", value, vallen) == 0)
02259 popt->topt.format = PRINT_UNALIGNED;
02260 else if (pg_strncasecmp("aligned", value, vallen) == 0)
02261 popt->topt.format = PRINT_ALIGNED;
02262 else if (pg_strncasecmp("wrapped", value, vallen) == 0)
02263 popt->topt.format = PRINT_WRAPPED;
02264 else if (pg_strncasecmp("html", value, vallen) == 0)
02265 popt->topt.format = PRINT_HTML;
02266 else if (pg_strncasecmp("latex", value, vallen) == 0)
02267 popt->topt.format = PRINT_LATEX;
02268 else if (pg_strncasecmp("latex-longtable", value, vallen) == 0)
02269 popt->topt.format = PRINT_LATEX_LONGTABLE;
02270 else if (pg_strncasecmp("troff-ms", value, vallen) == 0)
02271 popt->topt.format = PRINT_TROFF_MS;
02272 else
02273 {
02274 psql_error("\\pset: allowed formats are unaligned, aligned, wrapped, html, latex, troff-ms\n");
02275 return false;
02276 }
02277
02278 if (!quiet)
02279 printf(_("Output format is %s.\n"), _align2string(popt->topt.format));
02280 }
02281
02282
02283 else if (strcmp(param, "linestyle") == 0)
02284 {
02285 if (!value)
02286 ;
02287 else if (pg_strncasecmp("ascii", value, vallen) == 0)
02288 popt->topt.line_style = &pg_asciiformat;
02289 else if (pg_strncasecmp("old-ascii", value, vallen) == 0)
02290 popt->topt.line_style = &pg_asciiformat_old;
02291 else if (pg_strncasecmp("unicode", value, vallen) == 0)
02292 popt->topt.line_style = &pg_utf8format;
02293 else
02294 {
02295 psql_error("\\pset: allowed line styles are ascii, old-ascii, unicode\n");
02296 return false;
02297 }
02298
02299 if (!quiet)
02300 printf(_("Line style is %s.\n"),
02301 get_line_style(&popt->topt)->name);
02302 }
02303
02304
02305 else if (strcmp(param, "border") == 0)
02306 {
02307 if (value)
02308 popt->topt.border = atoi(value);
02309
02310 if (!quiet)
02311 printf(_("Border style is %d.\n"), popt->topt.border);
02312 }
02313
02314
02315 else if (strcmp(param, "x") == 0 || strcmp(param, "expanded") == 0 || strcmp(param, "vertical") == 0)
02316 {
02317 if (value && pg_strcasecmp(value, "auto") == 0)
02318 popt->topt.expanded = 2;
02319 else if (value)
02320 popt->topt.expanded = ParseVariableBool(value);
02321 else
02322 popt->topt.expanded = !popt->topt.expanded;
02323 if (!quiet)
02324 {
02325 if (popt->topt.expanded == 1)
02326 printf(_("Expanded display is on.\n"));
02327 else if (popt->topt.expanded == 2)
02328 printf(_("Expanded display is used automatically.\n"));
02329 else
02330 printf(_("Expanded display is off.\n"));
02331 }
02332 }
02333
02334
02335 else if (strcmp(param, "numericlocale") == 0)
02336 {
02337 if (value)
02338 popt->topt.numericLocale = ParseVariableBool(value);
02339 else
02340 popt->topt.numericLocale = !popt->topt.numericLocale;
02341 if (!quiet)
02342 {
02343 if (popt->topt.numericLocale)
02344 puts(_("Showing locale-adjusted numeric output."));
02345 else
02346 puts(_("Locale-adjusted numeric output is off."));
02347 }
02348 }
02349
02350
02351 else if (strcmp(param, "null") == 0)
02352 {
02353 if (value)
02354 {
02355 free(popt->nullPrint);
02356 popt->nullPrint = pg_strdup(value);
02357 }
02358 if (!quiet)
02359 printf(_("Null display is \"%s\".\n"), popt->nullPrint ? popt->nullPrint : "");
02360 }
02361
02362
02363 else if (strcmp(param, "fieldsep") == 0)
02364 {
02365 if (value)
02366 {
02367 free(popt->topt.fieldSep.separator);
02368 popt->topt.fieldSep.separator = pg_strdup(value);
02369 popt->topt.fieldSep.separator_zero = false;
02370 }
02371 if (!quiet)
02372 {
02373 if (popt->topt.fieldSep.separator_zero)
02374 printf(_("Field separator is zero byte.\n"));
02375 else
02376 printf(_("Field separator is \"%s\".\n"), popt->topt.fieldSep.separator);
02377 }
02378 }
02379
02380 else if (strcmp(param, "fieldsep_zero") == 0)
02381 {
02382 free(popt->topt.fieldSep.separator);
02383 popt->topt.fieldSep.separator = NULL;
02384 popt->topt.fieldSep.separator_zero = true;
02385 if (!quiet)
02386 printf(_("Field separator is zero byte.\n"));
02387 }
02388
02389
02390 else if (strcmp(param, "recordsep") == 0)
02391 {
02392 if (value)
02393 {
02394 free(popt->topt.recordSep.separator);
02395 popt->topt.recordSep.separator = pg_strdup(value);
02396 popt->topt.recordSep.separator_zero = false;
02397 }
02398 if (!quiet)
02399 {
02400 if (popt->topt.recordSep.separator_zero)
02401 printf(_("Record separator is zero byte.\n"));
02402 else if (strcmp(popt->topt.recordSep.separator, "\n") == 0)
02403 printf(_("Record separator is <newline>."));
02404 else
02405 printf(_("Record separator is \"%s\".\n"), popt->topt.recordSep.separator);
02406 }
02407 }
02408
02409 else if (strcmp(param, "recordsep_zero") == 0)
02410 {
02411 free(popt->topt.recordSep.separator);
02412 popt->topt.recordSep.separator = NULL;
02413 popt->topt.recordSep.separator_zero = true;
02414 if (!quiet)
02415 printf(_("Record separator is zero byte.\n"));
02416 }
02417
02418
02419 else if (strcmp(param, "t") == 0 || strcmp(param, "tuples_only") == 0)
02420 {
02421 if (value)
02422 popt->topt.tuples_only = ParseVariableBool(value);
02423 else
02424 popt->topt.tuples_only = !popt->topt.tuples_only;
02425 if (!quiet)
02426 {
02427 if (popt->topt.tuples_only)
02428 puts(_("Showing only tuples."));
02429 else
02430 puts(_("Tuples only is off."));
02431 }
02432 }
02433
02434
02435 else if (strcmp(param, "title") == 0)
02436 {
02437 free(popt->title);
02438 if (!value)
02439 popt->title = NULL;
02440 else
02441 popt->title = pg_strdup(value);
02442
02443 if (!quiet)
02444 {
02445 if (popt->title)
02446 printf(_("Title is \"%s\".\n"), popt->title);
02447 else
02448 printf(_("Title is unset.\n"));
02449 }
02450 }
02451
02452
02453 else if (strcmp(param, "T") == 0 || strcmp(param, "tableattr") == 0)
02454 {
02455 free(popt->topt.tableAttr);
02456 if (!value)
02457 popt->topt.tableAttr = NULL;
02458 else
02459 popt->topt.tableAttr = pg_strdup(value);
02460
02461 if (!quiet)
02462 {
02463 if (popt->topt.tableAttr)
02464 printf(_("Table attribute is \"%s\".\n"), popt->topt.tableAttr);
02465 else
02466 printf(_("Table attributes unset.\n"));
02467 }
02468 }
02469
02470
02471 else if (strcmp(param, "pager") == 0)
02472 {
02473 if (value && pg_strcasecmp(value, "always") == 0)
02474 popt->topt.pager = 2;
02475 else if (value)
02476 if (ParseVariableBool(value))
02477 popt->topt.pager = 1;
02478 else
02479 popt->topt.pager = 0;
02480 else if (popt->topt.pager == 1)
02481 popt->topt.pager = 0;
02482 else
02483 popt->topt.pager = 1;
02484 if (!quiet)
02485 {
02486 if (popt->topt.pager == 1)
02487 puts(_("Pager is used for long output."));
02488 else if (popt->topt.pager == 2)
02489 puts(_("Pager is always used."));
02490 else
02491 puts(_("Pager usage is off."));
02492 }
02493 }
02494
02495
02496 else if (strcmp(param, "footer") == 0)
02497 {
02498 if (value)
02499 popt->topt.default_footer = ParseVariableBool(value);
02500 else
02501 popt->topt.default_footer = !popt->topt.default_footer;
02502 if (!quiet)
02503 {
02504 if (popt->topt.default_footer)
02505 puts(_("Default footer is on."));
02506 else
02507 puts(_("Default footer is off."));
02508 }
02509 }
02510
02511
02512 else if (strcmp(param, "columns") == 0)
02513 {
02514 if (value)
02515 popt->topt.columns = atoi(value);
02516
02517 if (!quiet)
02518 printf(_("Target width is %d.\n"), popt->topt.columns);
02519 }
02520
02521 else
02522 {
02523 psql_error("\\pset: unknown option: %s\n", param);
02524 return false;
02525 }
02526
02527 return true;
02528 }
02529
02530
02531
02532 #ifndef WIN32
02533 #define DEFAULT_SHELL "/bin/sh"
02534 #else
02535
02536
02537
02538
02539 #define DEFAULT_SHELL "cmd.exe"
02540 #endif
02541
02542 static bool
02543 do_shell(const char *command)
02544 {
02545 int result;
02546
02547 if (!command)
02548 {
02549 char *sys;
02550 const char *shellName;
02551
02552 shellName = getenv("SHELL");
02553 #ifdef WIN32
02554 if (shellName == NULL)
02555 shellName = getenv("COMSPEC");
02556 #endif
02557 if (shellName == NULL)
02558 shellName = DEFAULT_SHELL;
02559
02560 sys = pg_malloc(strlen(shellName) + 16);
02561 #ifndef WIN32
02562 sprintf(sys,
02563
02564 "exec %s", shellName);
02565 #else
02566
02567 sprintf(sys, SYSTEMQUOTE "\"%s\"" SYSTEMQUOTE, shellName);
02568 #endif
02569 result = system(sys);
02570 free(sys);
02571 }
02572 else
02573 result = system(command);
02574
02575 if (result == 127 || result == -1)
02576 {
02577 psql_error("\\!: failed\n");
02578 return false;
02579 }
02580 return true;
02581 }
02582
02583
02584
02585
02586
02587
02588
02589 static bool
02590 do_watch(PQExpBuffer query_buf, long sleep)
02591 {
02592 printQueryOpt myopt = pset.popt;
02593 char title[50];
02594
02595 if (!query_buf || query_buf->len <= 0)
02596 {
02597 psql_error(_("\\watch cannot be used with an empty query\n"));
02598 return false;
02599 }
02600
02601
02602
02603
02604
02605 myopt.nullPrint = NULL;
02606 myopt.topt.pager = 0;
02607
02608 for (;;)
02609 {
02610 PGresult *res;
02611 time_t timer;
02612 long i;
02613
02614
02615
02616
02617
02618 timer = time(NULL);
02619 snprintf(title, sizeof(title), _("Watch every %lds\t%s"),
02620 sleep, asctime(localtime(&timer)));
02621 myopt.title = title;
02622
02623
02624
02625
02626
02627 res = PSQLexec(query_buf->data, false);
02628
02629
02630 if (res == NULL)
02631 break;
02632
02633
02634
02635
02636
02637
02638
02639 if (cancel_pressed)
02640 {
02641 PQclear(res);
02642 break;
02643 }
02644
02645 switch (PQresultStatus(res))
02646 {
02647 case PGRES_TUPLES_OK:
02648 printQuery(res, &myopt, pset.queryFout, pset.logfile);
02649 break;
02650
02651 case PGRES_EMPTY_QUERY:
02652 psql_error(_("\\watch cannot be used with an empty query\n"));
02653 PQclear(res);
02654 return false;
02655
02656 default:
02657
02658 break;
02659 }
02660
02661 PQclear(res);
02662
02663
02664
02665
02666
02667
02668 if (sigsetjmp(sigint_interrupt_jmp, 1) != 0)
02669 break;
02670
02671
02672
02673
02674
02675
02676 sigint_interrupt_enabled = true;
02677 for (i = 0; i < sleep; i++)
02678 {
02679 pg_usleep(1000000L);
02680 if (cancel_pressed)
02681 break;
02682 }
02683 sigint_interrupt_enabled = false;
02684 }
02685
02686 return true;
02687 }
02688
02689
02690
02691
02692
02693
02694
02695
02696
02697
02698 static bool
02699 lookup_function_oid(PGconn *conn, const char *desc, Oid *foid)
02700 {
02701 bool result = true;
02702 PQExpBuffer query;
02703 PGresult *res;
02704
02705 query = createPQExpBuffer();
02706 printfPQExpBuffer(query, "SELECT ");
02707 appendStringLiteralConn(query, desc, conn);
02708 appendPQExpBuffer(query, "::pg_catalog.%s::pg_catalog.oid",
02709 strchr(desc, '(') ? "regprocedure" : "regproc");
02710
02711 res = PQexec(conn, query->data);
02712 if (PQresultStatus(res) == PGRES_TUPLES_OK && PQntuples(res) == 1)
02713 *foid = atooid(PQgetvalue(res, 0, 0));
02714 else
02715 {
02716 minimal_error_message(res);
02717 result = false;
02718 }
02719
02720 PQclear(res);
02721 destroyPQExpBuffer(query);
02722
02723 return result;
02724 }
02725
02726
02727
02728
02729
02730 static bool
02731 get_create_function_cmd(PGconn *conn, Oid oid, PQExpBuffer buf)
02732 {
02733 bool result = true;
02734 PQExpBuffer query;
02735 PGresult *res;
02736
02737 query = createPQExpBuffer();
02738 printfPQExpBuffer(query, "SELECT pg_catalog.pg_get_functiondef(%u)", oid);
02739
02740 res = PQexec(conn, query->data);
02741 if (PQresultStatus(res) == PGRES_TUPLES_OK && PQntuples(res) == 1)
02742 {
02743 resetPQExpBuffer(buf);
02744 appendPQExpBufferStr(buf, PQgetvalue(res, 0, 0));
02745 }
02746 else
02747 {
02748 minimal_error_message(res);
02749 result = false;
02750 }
02751
02752 PQclear(res);
02753 destroyPQExpBuffer(query);
02754
02755 return result;
02756 }
02757
02758
02759
02760
02761
02762
02763
02764
02765
02766
02767 static int
02768 strip_lineno_from_funcdesc(char *func)
02769 {
02770 char *c;
02771 int lineno;
02772
02773 if (!func || func[0] == '\0')
02774 return -1;
02775
02776 c = func + strlen(func) - 1;
02777
02778
02779
02780
02781
02782
02783
02784
02785
02786
02787
02788
02789 while (c > func && isascii((unsigned char) *c) && isspace((unsigned char) *c))
02790 c--;
02791
02792
02793 if (c == func || !isascii((unsigned char) *c) || !isdigit((unsigned char) *c))
02794 return -1;
02795
02796
02797 while (c > func && isascii((unsigned char) *c) && isdigit((unsigned char) *c))
02798 c--;
02799
02800
02801
02802 if (c == func || !isascii((unsigned char) *c) ||
02803 !(isspace((unsigned char) *c) || *c == ')'))
02804 return -1;
02805
02806
02807 c++;
02808 lineno = atoi(c);
02809 if (lineno < 1)
02810 {
02811 psql_error("invalid line number: %s\n", c);
02812 return 0;
02813 }
02814
02815
02816 *c = '\0';
02817
02818 return lineno;
02819 }
02820
02821
02822
02823
02824
02825 static void
02826 minimal_error_message(PGresult *res)
02827 {
02828 PQExpBuffer msg;
02829 const char *fld;
02830
02831 msg = createPQExpBuffer();
02832
02833 fld = PQresultErrorField(res, PG_DIAG_SEVERITY);
02834 if (fld)
02835 printfPQExpBuffer(msg, "%s: ", fld);
02836 else
02837 printfPQExpBuffer(msg, "ERROR: ");
02838 fld = PQresultErrorField(res, PG_DIAG_MESSAGE_PRIMARY);
02839 if (fld)
02840 appendPQExpBufferStr(msg, fld);
02841 else
02842 appendPQExpBufferStr(msg, "(not available)");
02843 appendPQExpBufferStr(msg, "\n");
02844
02845 psql_error("%s", msg->data);
02846
02847 destroyPQExpBuffer(msg);
02848 }