1 /* 2 * psql - the PostgreSQL interactive terminal 3 * 4 * Copyright (c) 2000-2019, PostgreSQL Global Development Group 5 * 6 * src/bin/psql/startup.c 7 */ 8 #include "postgres_fe.h" 9 10 #ifndef WIN32 11 #include <unistd.h> 12 #else /* WIN32 */ 13 #include <io.h> 14 #include <win32.h> 15 #endif /* WIN32 */ 16 17 #include "getopt_long.h" 18 19 #include "common/logging.h" 20 #include "fe_utils/print.h" 21 22 #include "command.h" 23 #include "common.h" 24 #include "describe.h" 25 #include "help.h" 26 #include "input.h" 27 #include "mainloop.h" 28 #include "settings.h" 29 30 31 32 /* 33 * Global psql options 34 */ 35 PsqlSettings pset; 36 37 #ifndef WIN32 38 #define SYSPSQLRC "psqlrc" 39 #define PSQLRC ".psqlrc" 40 #else 41 #define SYSPSQLRC "psqlrc" 42 #define PSQLRC "psqlrc.conf" 43 #endif 44 45 /* 46 * Structures to pass information between the option parsing routine 47 * and the main function 48 */ 49 enum _actions 50 { 51 ACT_SINGLE_QUERY, 52 ACT_SINGLE_SLASH, 53 ACT_FILE 54 }; 55 56 typedef struct SimpleActionListCell 57 { 58 struct SimpleActionListCell *next; 59 enum _actions action; 60 char *val; 61 } SimpleActionListCell; 62 63 typedef struct SimpleActionList 64 { 65 SimpleActionListCell *head; 66 SimpleActionListCell *tail; 67 } SimpleActionList; 68 69 struct adhoc_opts 70 { 71 char *dbname; 72 char *host; 73 char *port; 74 char *username; 75 char *logfilename; 76 bool no_readline; 77 bool no_psqlrc; 78 bool single_txn; 79 bool list_dbs; 80 SimpleActionList actions; 81 }; 82 83 static void parse_psql_options(int argc, char *argv[], 84 struct adhoc_opts *options); 85 static void simple_action_list_append(SimpleActionList *list, 86 enum _actions action, const char *val); 87 static void process_psqlrc(char *argv0); 88 static void process_psqlrc_file(char *filename); 89 static void showVersion(void); 90 static void EstablishVariableSpace(void); 91 92 #define NOPAGER 0 93 94 static void 95 log_pre_callback(void) 96 { 97 if (pset.queryFout && pset.queryFout != stdout) 98 fflush(pset.queryFout); 99 } 100 101 static void 102 log_locus_callback(const char **filename, uint64 *lineno) 103 { 104 if (pset.inputfile) 105 { 106 *filename = pset.inputfile; 107 *lineno = pset.lineno; 108 } 109 else 110 { 111 *filename = NULL; 112 *lineno = 0; 113 } 114 } 115 116 /* 117 * 118 * main 119 * 120 */ 121 int 122 main(int argc, char *argv[]) 123 { 124 struct adhoc_opts options; 125 int successResult; 126 bool have_password = false; 127 char password[100]; 128 bool new_pass; 129 130 pg_logging_init(argv[0]); 131 pg_logging_set_pre_callback(log_pre_callback); 132 pg_logging_set_locus_callback(log_locus_callback); 133 set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("psql")); 134 135 if (argc > 1) 136 { 137 if ((strcmp(argv[1], "-?") == 0) || (argc == 2 && (strcmp(argv[1], "--help") == 0))) 138 { 139 usage(NOPAGER); 140 exit(EXIT_SUCCESS); 141 } 142 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0) 143 { 144 showVersion(); 145 exit(EXIT_SUCCESS); 146 } 147 } 148 149 pset.progname = get_progname(argv[0]); 150 151 pset.db = NULL; 152 setDecimalLocale(); 153 pset.encoding = PQenv2encoding(); 154 pset.queryFout = stdout; 155 pset.queryFoutPipe = false; 156 pset.copyStream = NULL; 157 pset.last_error_result = NULL; 158 pset.cur_cmd_source = stdin; 159 pset.cur_cmd_interactive = false; 160 161 /* We rely on unmentioned fields of pset.popt to start out 0/false/NULL */ 162 pset.popt.topt.format = PRINT_ALIGNED; 163 pset.popt.topt.border = 1; 164 pset.popt.topt.pager = 1; 165 pset.popt.topt.pager_min_lines = 0; 166 pset.popt.topt.start_table = true; 167 pset.popt.topt.stop_table = true; 168 pset.popt.topt.default_footer = true; 169 170 pset.popt.topt.csvFieldSep[0] = DEFAULT_CSV_FIELD_SEP; 171 pset.popt.topt.csvFieldSep[1] = '\0'; 172 173 pset.popt.topt.unicode_border_linestyle = UNICODE_LINESTYLE_SINGLE; 174 pset.popt.topt.unicode_column_linestyle = UNICODE_LINESTYLE_SINGLE; 175 pset.popt.topt.unicode_header_linestyle = UNICODE_LINESTYLE_SINGLE; 176 177 refresh_utf8format(&(pset.popt.topt)); 178 179 /* We must get COLUMNS here before readline() sets it */ 180 pset.popt.topt.env_columns = getenv("COLUMNS") ? atoi(getenv("COLUMNS")) : 0; 181 182 pset.notty = (!isatty(fileno(stdin)) || !isatty(fileno(stdout))); 183 184 pset.getPassword = TRI_DEFAULT; 185 186 EstablishVariableSpace(); 187 188 /* Create variables showing psql version number */ 189 SetVariable(pset.vars, "VERSION", PG_VERSION_STR); 190 SetVariable(pset.vars, "VERSION_NAME", PG_VERSION); 191 SetVariable(pset.vars, "VERSION_NUM", CppAsString2(PG_VERSION_NUM)); 192 193 /* Initialize variables for last error */ 194 SetVariable(pset.vars, "LAST_ERROR_MESSAGE", ""); 195 SetVariable(pset.vars, "LAST_ERROR_SQLSTATE", "00000"); 196 197 /* Default values for variables (that don't match the result of \unset) */ 198 SetVariableBool(pset.vars, "AUTOCOMMIT"); 199 SetVariable(pset.vars, "PROMPT1", DEFAULT_PROMPT1); 200 SetVariable(pset.vars, "PROMPT2", DEFAULT_PROMPT2); 201 SetVariable(pset.vars, "PROMPT3", DEFAULT_PROMPT3); 202 203 parse_psql_options(argc, argv, &options); 204 205 /* 206 * If no action was specified and we're in non-interactive mode, treat it 207 * as if the user had specified "-f -". This lets single-transaction mode 208 * work in this case. 209 */ 210 if (options.actions.head == NULL && pset.notty) 211 simple_action_list_append(&options.actions, ACT_FILE, NULL); 212 213 /* Bail out if -1 was specified but will be ignored. */ 214 if (options.single_txn && options.actions.head == NULL) 215 { 216 pg_log_fatal("-1 can only be used in non-interactive mode"); 217 exit(EXIT_FAILURE); 218 } 219 220 if (!pset.popt.topt.fieldSep.separator && 221 !pset.popt.topt.fieldSep.separator_zero) 222 { 223 pset.popt.topt.fieldSep.separator = pg_strdup(DEFAULT_FIELD_SEP); 224 pset.popt.topt.fieldSep.separator_zero = false; 225 } 226 if (!pset.popt.topt.recordSep.separator && 227 !pset.popt.topt.recordSep.separator_zero) 228 { 229 pset.popt.topt.recordSep.separator = pg_strdup(DEFAULT_RECORD_SEP); 230 pset.popt.topt.recordSep.separator_zero = false; 231 } 232 233 if (pset.getPassword == TRI_YES) 234 { 235 /* 236 * We can't be sure yet of the username that will be used, so don't 237 * offer a potentially wrong one. Typical uses of this option are 238 * noninteractive anyway. 239 */ 240 simple_prompt("Password: ", password, sizeof(password), false); 241 have_password = true; 242 } 243 244 /* loop until we have a password if requested by backend */ 245 do 246 { 247 #define PARAMS_ARRAY_SIZE 8 248 const char **keywords = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*keywords)); 249 const char **values = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*values)); 250 251 keywords[0] = "host"; 252 values[0] = options.host; 253 keywords[1] = "port"; 254 values[1] = options.port; 255 keywords[2] = "user"; 256 values[2] = options.username; 257 keywords[3] = "password"; 258 values[3] = have_password ? password : NULL; 259 keywords[4] = "dbname"; /* see do_connect() */ 260 values[4] = (options.list_dbs && options.dbname == NULL) ? 261 "postgres" : options.dbname; 262 keywords[5] = "fallback_application_name"; 263 values[5] = pset.progname; 264 keywords[6] = "client_encoding"; 265 values[6] = (pset.notty || getenv("PGCLIENTENCODING")) ? NULL : "auto"; 266 keywords[7] = NULL; 267 values[7] = NULL; 268 269 new_pass = false; 270 pset.db = PQconnectdbParams(keywords, values, true); 271 free(keywords); 272 free(values); 273 274 if (PQstatus(pset.db) == CONNECTION_BAD && 275 PQconnectionNeedsPassword(pset.db) && 276 !have_password && 277 pset.getPassword != TRI_NO) 278 { 279 /* 280 * Before closing the old PGconn, extract the user name that was 281 * actually connected with --- it might've come out of a URI or 282 * connstring "database name" rather than options.username. 283 */ 284 const char *realusername = PQuser(pset.db); 285 char *password_prompt; 286 287 if (realusername && realusername[0]) 288 password_prompt = psprintf(_("Password for user %s: "), 289 realusername); 290 else 291 password_prompt = pg_strdup(_("Password: ")); 292 PQfinish(pset.db); 293 294 simple_prompt(password_prompt, password, sizeof(password), false); 295 free(password_prompt); 296 have_password = true; 297 new_pass = true; 298 } 299 } while (new_pass); 300 301 if (PQstatus(pset.db) == CONNECTION_BAD) 302 { 303 pg_log_error("%s", PQerrorMessage(pset.db)); 304 PQfinish(pset.db); 305 exit(EXIT_BADCONN); 306 } 307 308 setup_cancel_handler(); 309 310 PQsetNoticeProcessor(pset.db, NoticeProcessor, NULL); 311 312 SyncVariables(); 313 314 if (options.list_dbs) 315 { 316 int success; 317 318 if (!options.no_psqlrc) 319 process_psqlrc(argv[0]); 320 321 success = listAllDbs(NULL, false); 322 PQfinish(pset.db); 323 exit(success ? EXIT_SUCCESS : EXIT_FAILURE); 324 } 325 326 if (options.logfilename) 327 { 328 pset.logfile = fopen(options.logfilename, "a"); 329 if (!pset.logfile) 330 { 331 pg_log_fatal("could not open log file \"%s\": %m", 332 options.logfilename); 333 exit(EXIT_FAILURE); 334 } 335 } 336 337 if (!options.no_psqlrc) 338 process_psqlrc(argv[0]); 339 340 /* 341 * If any actions were given by user, process them in the order in which 342 * they were specified. Note single_txn is only effective in this mode. 343 */ 344 if (options.actions.head != NULL) 345 { 346 PGresult *res; 347 SimpleActionListCell *cell; 348 349 successResult = EXIT_SUCCESS; /* silence compiler */ 350 351 if (options.single_txn) 352 { 353 if ((res = PSQLexec("BEGIN")) == NULL) 354 { 355 if (pset.on_error_stop) 356 { 357 successResult = EXIT_USER; 358 goto error; 359 } 360 } 361 else 362 PQclear(res); 363 } 364 365 for (cell = options.actions.head; cell; cell = cell->next) 366 { 367 if (cell->action == ACT_SINGLE_QUERY) 368 { 369 pg_logging_config(PG_LOG_FLAG_TERSE); 370 371 if (pset.echo == PSQL_ECHO_ALL) 372 puts(cell->val); 373 374 successResult = SendQuery(cell->val) 375 ? EXIT_SUCCESS : EXIT_FAILURE; 376 } 377 else if (cell->action == ACT_SINGLE_SLASH) 378 { 379 PsqlScanState scan_state; 380 ConditionalStack cond_stack; 381 382 pg_logging_config(PG_LOG_FLAG_TERSE); 383 384 if (pset.echo == PSQL_ECHO_ALL) 385 puts(cell->val); 386 387 scan_state = psql_scan_create(&psqlscan_callbacks); 388 psql_scan_setup(scan_state, 389 cell->val, strlen(cell->val), 390 pset.encoding, standard_strings()); 391 cond_stack = conditional_stack_create(); 392 psql_scan_set_passthrough(scan_state, (void *) cond_stack); 393 394 successResult = HandleSlashCmds(scan_state, 395 cond_stack, 396 NULL, 397 NULL) != PSQL_CMD_ERROR 398 ? EXIT_SUCCESS : EXIT_FAILURE; 399 400 psql_scan_destroy(scan_state); 401 conditional_stack_destroy(cond_stack); 402 } 403 else if (cell->action == ACT_FILE) 404 { 405 successResult = process_file(cell->val, false); 406 } 407 else 408 { 409 /* should never come here */ 410 Assert(false); 411 } 412 413 if (successResult != EXIT_SUCCESS && pset.on_error_stop) 414 break; 415 } 416 417 if (options.single_txn) 418 { 419 if ((res = PSQLexec("COMMIT")) == NULL) 420 { 421 if (pset.on_error_stop) 422 { 423 successResult = EXIT_USER; 424 goto error; 425 } 426 } 427 else 428 PQclear(res); 429 } 430 431 error: 432 ; 433 } 434 435 /* 436 * or otherwise enter interactive main loop 437 */ 438 else 439 { 440 pg_logging_config(PG_LOG_FLAG_TERSE); 441 connection_warnings(true); 442 if (!pset.quiet) 443 printf(_("Type \"help\" for help.\n\n")); 444 initializeInput(options.no_readline ? 0 : 1); 445 successResult = MainLoop(stdin); 446 } 447 448 /* clean up */ 449 if (pset.logfile) 450 fclose(pset.logfile); 451 PQfinish(pset.db); 452 setQFout(NULL); 453 454 return successResult; 455 } 456 457 458 /* 459 * Parse command line options 460 */ 461 462 static void 463 parse_psql_options(int argc, char *argv[], struct adhoc_opts *options) 464 { 465 static struct option long_options[] = 466 { 467 {"echo-all", no_argument, NULL, 'a'}, 468 {"no-align", no_argument, NULL, 'A'}, 469 {"command", required_argument, NULL, 'c'}, 470 {"dbname", required_argument, NULL, 'd'}, 471 {"echo-queries", no_argument, NULL, 'e'}, 472 {"echo-errors", no_argument, NULL, 'b'}, 473 {"echo-hidden", no_argument, NULL, 'E'}, 474 {"file", required_argument, NULL, 'f'}, 475 {"field-separator", required_argument, NULL, 'F'}, 476 {"field-separator-zero", no_argument, NULL, 'z'}, 477 {"host", required_argument, NULL, 'h'}, 478 {"html", no_argument, NULL, 'H'}, 479 {"list", no_argument, NULL, 'l'}, 480 {"log-file", required_argument, NULL, 'L'}, 481 {"no-readline", no_argument, NULL, 'n'}, 482 {"single-transaction", no_argument, NULL, '1'}, 483 {"output", required_argument, NULL, 'o'}, 484 {"port", required_argument, NULL, 'p'}, 485 {"pset", required_argument, NULL, 'P'}, 486 {"quiet", no_argument, NULL, 'q'}, 487 {"record-separator", required_argument, NULL, 'R'}, 488 {"record-separator-zero", no_argument, NULL, '0'}, 489 {"single-step", no_argument, NULL, 's'}, 490 {"single-line", no_argument, NULL, 'S'}, 491 {"tuples-only", no_argument, NULL, 't'}, 492 {"table-attr", required_argument, NULL, 'T'}, 493 {"username", required_argument, NULL, 'U'}, 494 {"set", required_argument, NULL, 'v'}, 495 {"variable", required_argument, NULL, 'v'}, 496 {"version", no_argument, NULL, 'V'}, 497 {"no-password", no_argument, NULL, 'w'}, 498 {"password", no_argument, NULL, 'W'}, 499 {"expanded", no_argument, NULL, 'x'}, 500 {"no-psqlrc", no_argument, NULL, 'X'}, 501 {"help", optional_argument, NULL, 1}, 502 {"csv", no_argument, NULL, 2}, 503 {NULL, 0, NULL, 0} 504 }; 505 506 int optindex; 507 int c; 508 509 memset(options, 0, sizeof *options); 510 511 while ((c = getopt_long(argc, argv, "aAbc:d:eEf:F:h:HlL:no:p:P:qR:sStT:U:v:VwWxXz?01", 512 long_options, &optindex)) != -1) 513 { 514 switch (c) 515 { 516 case 'a': 517 SetVariable(pset.vars, "ECHO", "all"); 518 break; 519 case 'A': 520 pset.popt.topt.format = PRINT_UNALIGNED; 521 break; 522 case 'b': 523 SetVariable(pset.vars, "ECHO", "errors"); 524 break; 525 case 'c': 526 if (optarg[0] == '\\') 527 simple_action_list_append(&options->actions, 528 ACT_SINGLE_SLASH, 529 optarg + 1); 530 else 531 simple_action_list_append(&options->actions, 532 ACT_SINGLE_QUERY, 533 optarg); 534 break; 535 case 'd': 536 options->dbname = pg_strdup(optarg); 537 break; 538 case 'e': 539 SetVariable(pset.vars, "ECHO", "queries"); 540 break; 541 case 'E': 542 SetVariableBool(pset.vars, "ECHO_HIDDEN"); 543 break; 544 case 'f': 545 simple_action_list_append(&options->actions, 546 ACT_FILE, 547 optarg); 548 break; 549 case 'F': 550 pset.popt.topt.fieldSep.separator = pg_strdup(optarg); 551 pset.popt.topt.fieldSep.separator_zero = false; 552 break; 553 case 'h': 554 options->host = pg_strdup(optarg); 555 break; 556 case 'H': 557 pset.popt.topt.format = PRINT_HTML; 558 break; 559 case 'l': 560 options->list_dbs = true; 561 break; 562 case 'L': 563 options->logfilename = pg_strdup(optarg); 564 break; 565 case 'n': 566 options->no_readline = true; 567 break; 568 case 'o': 569 if (!setQFout(optarg)) 570 exit(EXIT_FAILURE); 571 break; 572 case 'p': 573 options->port = pg_strdup(optarg); 574 break; 575 case 'P': 576 { 577 char *value; 578 char *equal_loc; 579 bool result; 580 581 value = pg_strdup(optarg); 582 equal_loc = strchr(value, '='); 583 if (!equal_loc) 584 result = do_pset(value, NULL, &pset.popt, true); 585 else 586 { 587 *equal_loc = '\0'; 588 result = do_pset(value, equal_loc + 1, &pset.popt, true); 589 } 590 591 if (!result) 592 { 593 pg_log_fatal("could not set printing parameter \"%s\"", value); 594 exit(EXIT_FAILURE); 595 } 596 597 free(value); 598 break; 599 } 600 case 'q': 601 SetVariableBool(pset.vars, "QUIET"); 602 break; 603 case 'R': 604 pset.popt.topt.recordSep.separator = pg_strdup(optarg); 605 pset.popt.topt.recordSep.separator_zero = false; 606 break; 607 case 's': 608 SetVariableBool(pset.vars, "SINGLESTEP"); 609 break; 610 case 'S': 611 SetVariableBool(pset.vars, "SINGLELINE"); 612 break; 613 case 't': 614 pset.popt.topt.tuples_only = true; 615 break; 616 case 'T': 617 pset.popt.topt.tableAttr = pg_strdup(optarg); 618 break; 619 case 'U': 620 options->username = pg_strdup(optarg); 621 break; 622 case 'v': 623 { 624 char *value; 625 char *equal_loc; 626 627 value = pg_strdup(optarg); 628 equal_loc = strchr(value, '='); 629 if (!equal_loc) 630 { 631 if (!DeleteVariable(pset.vars, value)) 632 exit(EXIT_FAILURE); /* error already printed */ 633 } 634 else 635 { 636 *equal_loc = '\0'; 637 if (!SetVariable(pset.vars, value, equal_loc + 1)) 638 exit(EXIT_FAILURE); /* error already printed */ 639 } 640 641 free(value); 642 break; 643 } 644 case 'V': 645 showVersion(); 646 exit(EXIT_SUCCESS); 647 case 'w': 648 pset.getPassword = TRI_NO; 649 break; 650 case 'W': 651 pset.getPassword = TRI_YES; 652 break; 653 case 'x': 654 pset.popt.topt.expanded = true; 655 break; 656 case 'X': 657 options->no_psqlrc = true; 658 break; 659 case 'z': 660 pset.popt.topt.fieldSep.separator_zero = true; 661 break; 662 case '0': 663 pset.popt.topt.recordSep.separator_zero = true; 664 break; 665 case '1': 666 options->single_txn = true; 667 break; 668 case '?': 669 if (optind <= argc && 670 strcmp(argv[optind - 1], "-?") == 0) 671 { 672 /* actual help option given */ 673 usage(NOPAGER); 674 exit(EXIT_SUCCESS); 675 } 676 else 677 { 678 /* getopt error (unknown option or missing argument) */ 679 goto unknown_option; 680 } 681 break; 682 case 1: 683 { 684 if (!optarg || strcmp(optarg, "options") == 0) 685 usage(NOPAGER); 686 else if (optarg && strcmp(optarg, "commands") == 0) 687 slashUsage(NOPAGER); 688 else if (optarg && strcmp(optarg, "variables") == 0) 689 helpVariables(NOPAGER); 690 else 691 goto unknown_option; 692 693 exit(EXIT_SUCCESS); 694 } 695 break; 696 case 2: 697 pset.popt.topt.format = PRINT_CSV; 698 break; 699 default: 700 unknown_option: 701 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), 702 pset.progname); 703 exit(EXIT_FAILURE); 704 break; 705 } 706 } 707 708 /* 709 * if we still have arguments, use it as the database name and username 710 */ 711 while (argc - optind >= 1) 712 { 713 if (!options->dbname) 714 options->dbname = argv[optind]; 715 else if (!options->username) 716 options->username = argv[optind]; 717 else if (!pset.quiet) 718 pg_log_warning("extra command-line argument \"%s\" ignored", 719 argv[optind]); 720 721 optind++; 722 } 723 } 724 725 726 /* 727 * Append a new item to the end of the SimpleActionList. 728 * Note that "val" is copied if it's not NULL. 729 */ 730 static void 731 simple_action_list_append(SimpleActionList *list, 732 enum _actions action, const char *val) 733 { 734 SimpleActionListCell *cell; 735 736 cell = (SimpleActionListCell *) pg_malloc(sizeof(SimpleActionListCell)); 737 738 cell->next = NULL; 739 cell->action = action; 740 if (val) 741 cell->val = pg_strdup(val); 742 else 743 cell->val = NULL; 744 745 if (list->tail) 746 list->tail->next = cell; 747 else 748 list->head = cell; 749 list->tail = cell; 750 } 751 752 753 /* 754 * Load .psqlrc file, if found. 755 */ 756 static void 757 process_psqlrc(char *argv0) 758 { 759 char home[MAXPGPATH]; 760 char rc_file[MAXPGPATH]; 761 char my_exec_path[MAXPGPATH]; 762 char etc_path[MAXPGPATH]; 763 char *envrc = getenv("PSQLRC"); 764 765 if (find_my_exec(argv0, my_exec_path) < 0) 766 { 767 pg_log_fatal("could not find own program executable"); 768 exit(EXIT_FAILURE); 769 } 770 771 get_etc_path(my_exec_path, etc_path); 772 773 snprintf(rc_file, MAXPGPATH, "%s/%s", etc_path, SYSPSQLRC); 774 process_psqlrc_file(rc_file); 775 776 if (envrc != NULL && strlen(envrc) > 0) 777 { 778 /* might need to free() this */ 779 char *envrc_alloc = pstrdup(envrc); 780 781 expand_tilde(&envrc_alloc); 782 process_psqlrc_file(envrc_alloc); 783 } 784 else if (get_home_path(home)) 785 { 786 snprintf(rc_file, MAXPGPATH, "%s/%s", home, PSQLRC); 787 process_psqlrc_file(rc_file); 788 } 789 } 790 791 792 793 static void 794 process_psqlrc_file(char *filename) 795 { 796 char *psqlrc_minor, 797 *psqlrc_major; 798 799 #if defined(WIN32) && (!defined(__MINGW32__)) 800 #define R_OK 4 801 #endif 802 803 psqlrc_minor = psprintf("%s-%s", filename, PG_VERSION); 804 psqlrc_major = psprintf("%s-%s", filename, PG_MAJORVERSION); 805 806 /* check for minor version first, then major, then no version */ 807 if (access(psqlrc_minor, R_OK) == 0) 808 (void) process_file(psqlrc_minor, false); 809 else if (access(psqlrc_major, R_OK) == 0) 810 (void) process_file(psqlrc_major, false); 811 else if (access(filename, R_OK) == 0) 812 (void) process_file(filename, false); 813 814 free(psqlrc_minor); 815 free(psqlrc_major); 816 } 817 818 819 820 /* showVersion 821 * 822 * This output format is intended to match GNU standards. 823 */ 824 static void 825 showVersion(void) 826 { 827 puts("psql (PostgreSQL) " PG_VERSION); 828 } 829 830 831 832 /* 833 * Substitute hooks and assign hooks for psql variables. 834 * 835 * This isn't an amazingly good place for them, but neither is anywhere else. 836 * 837 * By policy, every special variable that controls any psql behavior should 838 * have one or both hooks, even if they're just no-ops. This ensures that 839 * the variable will remain present in variables.c's list even when unset, 840 * which ensures that it's known to tab completion. 841 */ 842 843 static char * 844 bool_substitute_hook(char *newval) 845 { 846 if (newval == NULL) 847 { 848 /* "\unset FOO" becomes "\set FOO off" */ 849 newval = pg_strdup("off"); 850 } 851 else if (newval[0] == '\0') 852 { 853 /* "\set FOO" becomes "\set FOO on" */ 854 pg_free(newval); 855 newval = pg_strdup("on"); 856 } 857 return newval; 858 } 859 860 static bool 861 autocommit_hook(const char *newval) 862 { 863 return ParseVariableBool(newval, "AUTOCOMMIT", &pset.autocommit); 864 } 865 866 static bool 867 on_error_stop_hook(const char *newval) 868 { 869 return ParseVariableBool(newval, "ON_ERROR_STOP", &pset.on_error_stop); 870 } 871 872 static bool 873 quiet_hook(const char *newval) 874 { 875 return ParseVariableBool(newval, "QUIET", &pset.quiet); 876 } 877 878 static bool 879 singleline_hook(const char *newval) 880 { 881 return ParseVariableBool(newval, "SINGLELINE", &pset.singleline); 882 } 883 884 static bool 885 singlestep_hook(const char *newval) 886 { 887 return ParseVariableBool(newval, "SINGLESTEP", &pset.singlestep); 888 } 889 890 static char * 891 fetch_count_substitute_hook(char *newval) 892 { 893 if (newval == NULL) 894 newval = pg_strdup("0"); 895 return newval; 896 } 897 898 static bool 899 fetch_count_hook(const char *newval) 900 { 901 return ParseVariableNum(newval, "FETCH_COUNT", &pset.fetch_count); 902 } 903 904 static bool 905 histfile_hook(const char *newval) 906 { 907 /* 908 * Someday we might try to validate the filename, but for now, this is 909 * just a placeholder to ensure HISTFILE is known to tab completion. 910 */ 911 return true; 912 } 913 914 static char * 915 histsize_substitute_hook(char *newval) 916 { 917 if (newval == NULL) 918 newval = pg_strdup("500"); 919 return newval; 920 } 921 922 static bool 923 histsize_hook(const char *newval) 924 { 925 return ParseVariableNum(newval, "HISTSIZE", &pset.histsize); 926 } 927 928 static char * 929 ignoreeof_substitute_hook(char *newval) 930 { 931 int dummy; 932 933 /* 934 * This tries to mimic the behavior of bash, to wit "If set, the value is 935 * the number of consecutive EOF characters which must be typed as the 936 * first characters on an input line before bash exits. If the variable 937 * exists but does not have a numeric value, or has no value, the default 938 * value is 10. If it does not exist, EOF signifies the end of input to 939 * the shell." Unlike bash, however, we insist on the stored value 940 * actually being a valid integer. 941 */ 942 if (newval == NULL) 943 newval = pg_strdup("0"); 944 else if (!ParseVariableNum(newval, NULL, &dummy)) 945 newval = pg_strdup("10"); 946 return newval; 947 } 948 949 static bool 950 ignoreeof_hook(const char *newval) 951 { 952 return ParseVariableNum(newval, "IGNOREEOF", &pset.ignoreeof); 953 } 954 955 static char * 956 echo_substitute_hook(char *newval) 957 { 958 if (newval == NULL) 959 newval = pg_strdup("none"); 960 return newval; 961 } 962 963 static bool 964 echo_hook(const char *newval) 965 { 966 Assert(newval != NULL); /* else substitute hook messed up */ 967 if (pg_strcasecmp(newval, "queries") == 0) 968 pset.echo = PSQL_ECHO_QUERIES; 969 else if (pg_strcasecmp(newval, "errors") == 0) 970 pset.echo = PSQL_ECHO_ERRORS; 971 else if (pg_strcasecmp(newval, "all") == 0) 972 pset.echo = PSQL_ECHO_ALL; 973 else if (pg_strcasecmp(newval, "none") == 0) 974 pset.echo = PSQL_ECHO_NONE; 975 else 976 { 977 PsqlVarEnumError("ECHO", newval, "none, errors, queries, all"); 978 return false; 979 } 980 return true; 981 } 982 983 static bool 984 echo_hidden_hook(const char *newval) 985 { 986 Assert(newval != NULL); /* else substitute hook messed up */ 987 if (pg_strcasecmp(newval, "noexec") == 0) 988 pset.echo_hidden = PSQL_ECHO_HIDDEN_NOEXEC; 989 else 990 { 991 bool on_off; 992 993 if (ParseVariableBool(newval, NULL, &on_off)) 994 pset.echo_hidden = on_off ? PSQL_ECHO_HIDDEN_ON : PSQL_ECHO_HIDDEN_OFF; 995 else 996 { 997 PsqlVarEnumError("ECHO_HIDDEN", newval, "on, off, noexec"); 998 return false; 999 } 1000 } 1001 return true; 1002 } 1003 1004 static bool 1005 on_error_rollback_hook(const char *newval) 1006 { 1007 Assert(newval != NULL); /* else substitute hook messed up */ 1008 if (pg_strcasecmp(newval, "interactive") == 0) 1009 pset.on_error_rollback = PSQL_ERROR_ROLLBACK_INTERACTIVE; 1010 else 1011 { 1012 bool on_off; 1013 1014 if (ParseVariableBool(newval, NULL, &on_off)) 1015 pset.on_error_rollback = on_off ? PSQL_ERROR_ROLLBACK_ON : PSQL_ERROR_ROLLBACK_OFF; 1016 else 1017 { 1018 PsqlVarEnumError("ON_ERROR_ROLLBACK", newval, "on, off, interactive"); 1019 return false; 1020 } 1021 } 1022 return true; 1023 } 1024 1025 static char * 1026 comp_keyword_case_substitute_hook(char *newval) 1027 { 1028 if (newval == NULL) 1029 newval = pg_strdup("preserve-upper"); 1030 return newval; 1031 } 1032 1033 static bool 1034 comp_keyword_case_hook(const char *newval) 1035 { 1036 Assert(newval != NULL); /* else substitute hook messed up */ 1037 if (pg_strcasecmp(newval, "preserve-upper") == 0) 1038 pset.comp_case = PSQL_COMP_CASE_PRESERVE_UPPER; 1039 else if (pg_strcasecmp(newval, "preserve-lower") == 0) 1040 pset.comp_case = PSQL_COMP_CASE_PRESERVE_LOWER; 1041 else if (pg_strcasecmp(newval, "upper") == 0) 1042 pset.comp_case = PSQL_COMP_CASE_UPPER; 1043 else if (pg_strcasecmp(newval, "lower") == 0) 1044 pset.comp_case = PSQL_COMP_CASE_LOWER; 1045 else 1046 { 1047 PsqlVarEnumError("COMP_KEYWORD_CASE", newval, 1048 "lower, upper, preserve-lower, preserve-upper"); 1049 return false; 1050 } 1051 return true; 1052 } 1053 1054 static char * 1055 histcontrol_substitute_hook(char *newval) 1056 { 1057 if (newval == NULL) 1058 newval = pg_strdup("none"); 1059 return newval; 1060 } 1061 1062 static bool 1063 histcontrol_hook(const char *newval) 1064 { 1065 Assert(newval != NULL); /* else substitute hook messed up */ 1066 if (pg_strcasecmp(newval, "ignorespace") == 0) 1067 pset.histcontrol = hctl_ignorespace; 1068 else if (pg_strcasecmp(newval, "ignoredups") == 0) 1069 pset.histcontrol = hctl_ignoredups; 1070 else if (pg_strcasecmp(newval, "ignoreboth") == 0) 1071 pset.histcontrol = hctl_ignoreboth; 1072 else if (pg_strcasecmp(newval, "none") == 0) 1073 pset.histcontrol = hctl_none; 1074 else 1075 { 1076 PsqlVarEnumError("HISTCONTROL", newval, 1077 "none, ignorespace, ignoredups, ignoreboth"); 1078 return false; 1079 } 1080 return true; 1081 } 1082 1083 static bool 1084 prompt1_hook(const char *newval) 1085 { 1086 pset.prompt1 = newval ? newval : ""; 1087 return true; 1088 } 1089 1090 static bool 1091 prompt2_hook(const char *newval) 1092 { 1093 pset.prompt2 = newval ? newval : ""; 1094 return true; 1095 } 1096 1097 static bool 1098 prompt3_hook(const char *newval) 1099 { 1100 pset.prompt3 = newval ? newval : ""; 1101 return true; 1102 } 1103 1104 static char * 1105 verbosity_substitute_hook(char *newval) 1106 { 1107 if (newval == NULL) 1108 newval = pg_strdup("default"); 1109 return newval; 1110 } 1111 1112 static bool 1113 verbosity_hook(const char *newval) 1114 { 1115 Assert(newval != NULL); /* else substitute hook messed up */ 1116 if (pg_strcasecmp(newval, "default") == 0) 1117 pset.verbosity = PQERRORS_DEFAULT; 1118 else if (pg_strcasecmp(newval, "verbose") == 0) 1119 pset.verbosity = PQERRORS_VERBOSE; 1120 else if (pg_strcasecmp(newval, "terse") == 0) 1121 pset.verbosity = PQERRORS_TERSE; 1122 else if (pg_strcasecmp(newval, "sqlstate") == 0) 1123 pset.verbosity = PQERRORS_SQLSTATE; 1124 else 1125 { 1126 PsqlVarEnumError("VERBOSITY", newval, "default, verbose, terse, sqlstate"); 1127 return false; 1128 } 1129 1130 if (pset.db) 1131 PQsetErrorVerbosity(pset.db, pset.verbosity); 1132 return true; 1133 } 1134 1135 static char * 1136 show_context_substitute_hook(char *newval) 1137 { 1138 if (newval == NULL) 1139 newval = pg_strdup("errors"); 1140 return newval; 1141 } 1142 1143 static bool 1144 show_context_hook(const char *newval) 1145 { 1146 Assert(newval != NULL); /* else substitute hook messed up */ 1147 if (pg_strcasecmp(newval, "never") == 0) 1148 pset.show_context = PQSHOW_CONTEXT_NEVER; 1149 else if (pg_strcasecmp(newval, "errors") == 0) 1150 pset.show_context = PQSHOW_CONTEXT_ERRORS; 1151 else if (pg_strcasecmp(newval, "always") == 0) 1152 pset.show_context = PQSHOW_CONTEXT_ALWAYS; 1153 else 1154 { 1155 PsqlVarEnumError("SHOW_CONTEXT", newval, "never, errors, always"); 1156 return false; 1157 } 1158 1159 if (pset.db) 1160 PQsetErrorContextVisibility(pset.db, pset.show_context); 1161 return true; 1162 } 1163 1164 static bool 1165 hide_tableam_hook(const char *newval) 1166 { 1167 return ParseVariableBool(newval, "HIDE_TABLEAM", &pset.hide_tableam); 1168 } 1169 1170 static void 1171 EstablishVariableSpace(void) 1172 { 1173 pset.vars = CreateVariableSpace(); 1174 1175 SetVariableHooks(pset.vars, "AUTOCOMMIT", 1176 bool_substitute_hook, 1177 autocommit_hook); 1178 SetVariableHooks(pset.vars, "ON_ERROR_STOP", 1179 bool_substitute_hook, 1180 on_error_stop_hook); 1181 SetVariableHooks(pset.vars, "QUIET", 1182 bool_substitute_hook, 1183 quiet_hook); 1184 SetVariableHooks(pset.vars, "SINGLELINE", 1185 bool_substitute_hook, 1186 singleline_hook); 1187 SetVariableHooks(pset.vars, "SINGLESTEP", 1188 bool_substitute_hook, 1189 singlestep_hook); 1190 SetVariableHooks(pset.vars, "FETCH_COUNT", 1191 fetch_count_substitute_hook, 1192 fetch_count_hook); 1193 SetVariableHooks(pset.vars, "HISTFILE", 1194 NULL, 1195 histfile_hook); 1196 SetVariableHooks(pset.vars, "HISTSIZE", 1197 histsize_substitute_hook, 1198 histsize_hook); 1199 SetVariableHooks(pset.vars, "IGNOREEOF", 1200 ignoreeof_substitute_hook, 1201 ignoreeof_hook); 1202 SetVariableHooks(pset.vars, "ECHO", 1203 echo_substitute_hook, 1204 echo_hook); 1205 SetVariableHooks(pset.vars, "ECHO_HIDDEN", 1206 bool_substitute_hook, 1207 echo_hidden_hook); 1208 SetVariableHooks(pset.vars, "ON_ERROR_ROLLBACK", 1209 bool_substitute_hook, 1210 on_error_rollback_hook); 1211 SetVariableHooks(pset.vars, "COMP_KEYWORD_CASE", 1212 comp_keyword_case_substitute_hook, 1213 comp_keyword_case_hook); 1214 SetVariableHooks(pset.vars, "HISTCONTROL", 1215 histcontrol_substitute_hook, 1216 histcontrol_hook); 1217 SetVariableHooks(pset.vars, "PROMPT1", 1218 NULL, 1219 prompt1_hook); 1220 SetVariableHooks(pset.vars, "PROMPT2", 1221 NULL, 1222 prompt2_hook); 1223 SetVariableHooks(pset.vars, "PROMPT3", 1224 NULL, 1225 prompt3_hook); 1226 SetVariableHooks(pset.vars, "VERBOSITY", 1227 verbosity_substitute_hook, 1228 verbosity_hook); 1229 SetVariableHooks(pset.vars, "SHOW_CONTEXT", 1230 show_context_substitute_hook, 1231 show_context_hook); 1232 SetVariableHooks(pset.vars, "HIDE_TABLEAM", 1233 bool_substitute_hook, 1234 hide_tableam_hook); 1235 } 1236