]> granicus.if.org Git - postgresql/blob - src/bin/psql/startup.c
Set std error to no buffering on Win32.
[postgresql] / src / bin / psql / startup.c
1 /*
2  * psql - the PostgreSQL interactive terminal
3  *
4  * Copyright (c) 2000-2003, PostgreSQL Global Development Group
5  *
6  * $PostgreSQL: pgsql/src/bin/psql/startup.c,v 1.92 2004/05/02 04:25:45 momjian Exp $
7  */
8 #include "postgres_fe.h"
9
10 #include <sys/types.h>
11
12 #ifndef WIN32
13 #include <unistd.h>
14 #else                                                   /* WIN32 */
15 #include <io.h>
16 #include <windows.h>
17 #include <win32.h>
18 #endif   /* WIN32 */
19
20 #include "getopt_long.h"
21
22 #ifndef HAVE_OPTRESET
23 int                     optreset;
24 #endif
25
26 #include <locale.h>
27
28 #include "libpq-fe.h"
29
30 #include "command.h"
31 #include "common.h"
32 #include "describe.h"
33 #include "help.h"
34 #include "input.h"
35 #include "mainloop.h"
36 #include "print.h"
37 #include "settings.h"
38 #include "variables.h"
39
40 #include "mb/pg_wchar.h"
41
42 /*
43  * Global psql options
44  */
45 PsqlSettings pset;
46
47 #define SYSPSQLRC       "psqlrc"
48 #define PSQLRC          ".psqlrc"
49
50 /*
51  * Structures to pass information between the option parsing routine
52  * and the main function
53  */
54 enum _actions
55 {
56         ACT_NOTHING = 0,
57         ACT_SINGLE_SLASH,
58         ACT_LIST_DB,
59         ACT_SINGLE_QUERY,
60         ACT_FILE
61 };
62
63 struct adhoc_opts
64 {
65         char       *dbname;
66         char       *host;
67         char       *port;
68         char       *username;
69         enum _actions action;
70         char       *action_string;
71         bool            no_readline;
72         bool            no_psqlrc;
73 };
74
75 static void parse_psql_options(int argc, char *argv[],
76                                    struct adhoc_opts * options);
77 static void process_psqlrc(void);
78 static void process_psqlrc_file(char *filename);
79 static void showVersion(void);
80
81 #ifdef USE_SSL
82 static void printSSLInfo(void);
83 #endif
84
85 #ifdef WIN32
86 static void
87                         checkWin32Codepage(void);
88 #endif
89
90 /*
91  *
92  * main
93  *
94  */
95 int
96 main(int argc, char *argv[])
97 {
98         struct adhoc_opts options;
99         int                     successResult;
100
101         char       *username = NULL;
102         char       *password = NULL;
103         bool            need_pass;
104
105         setlocale(LC_ALL, "");
106 #ifdef ENABLE_NLS
107         bindtextdomain("psql", LOCALEDIR);
108         textdomain("psql");
109 #endif
110
111         pset.progname = get_progname(argv[0]);
112
113         if (argc > 1)
114         {
115                 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
116                 {
117                         usage();
118                         exit(EXIT_SUCCESS);
119                 }
120                 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
121                 {
122                         showVersion();
123                         exit(EXIT_SUCCESS);
124                 }
125         }
126
127 #ifdef WIN32
128         setvbuf(stderr,NULL,_IONBF,0);
129 #endif
130         pset.cur_cmd_source = stdin;
131         pset.cur_cmd_interactive = false;
132         pset.encoding = PQenv2encoding();
133
134         pset.vars = CreateVariableSpace();
135         if (!pset.vars)
136         {
137                 fprintf(stderr, gettext("%s: out of memory\n"), pset.progname);
138                 exit(EXIT_FAILURE);
139         }
140         pset.popt.topt.format = PRINT_ALIGNED;
141         pset.queryFout = stdout;
142         pset.popt.topt.border = 1;
143         pset.popt.topt.pager = 1;
144         pset.popt.default_footer = true;
145
146         SetVariable(pset.vars, "VERSION", PG_VERSION_STR);
147
148         /* Default values for variables that are used in noninteractive cases */
149         SetVariableBool(pset.vars, "AUTOCOMMIT");
150         SetVariable(pset.vars, "VERBOSITY", "default");
151         pset.verbosity = PQERRORS_DEFAULT;
152
153         pset.notty = (!isatty(fileno(stdin)) || !isatty(fileno(stdout)));
154
155         /* This is obsolete and should be removed sometime. */
156 #ifdef PSQL_ALWAYS_GET_PASSWORDS
157         pset.getPassword = true;
158 #else
159         pset.getPassword = false;
160 #endif
161
162 #ifndef HAVE_UNIX_SOCKETS
163         /* default to localhost on platforms without unix sockets */
164         options.host = "localhost";
165 #endif
166
167         parse_psql_options(argc, argv, &options);
168
169         if (!pset.popt.topt.fieldSep)
170                 pset.popt.topt.fieldSep = pg_strdup(DEFAULT_FIELD_SEP);
171         if (!pset.popt.topt.recordSep)
172                 pset.popt.topt.recordSep = pg_strdup(DEFAULT_RECORD_SEP);
173
174         if (options.username)
175         {
176                 /*
177                  * The \001 is a hack to support the deprecated -u option which
178                  * issues a username prompt. The recommended option is -U followed
179                  * by the name on the command line.
180                  */
181                 if (strcmp(options.username, "\001") == 0)
182                         username = simple_prompt("User name: ", 100, true);
183                 else
184                         username = pg_strdup(options.username);
185         }
186
187         if (pset.getPassword)
188                 password = simple_prompt("Password: ", 100, false);
189
190         /* loop until we have a password if requested by backend */
191         do
192         {
193                 need_pass = false;
194                 pset.db = PQsetdbLogin(options.host, options.port, NULL, NULL,
195                         options.action == ACT_LIST_DB ? "template1" : options.dbname,
196                                                            username, password);
197
198                 if (PQstatus(pset.db) == CONNECTION_BAD &&
199                         strcmp(PQerrorMessage(pset.db), "fe_sendauth: no password supplied\n") == 0 &&
200                         !feof(stdin))
201                 {
202                         PQfinish(pset.db);
203                         need_pass = true;
204                         free(password);
205                         password = NULL;
206                         password = simple_prompt("Password: ", 100, false);
207                 }
208         } while (need_pass);
209
210         free(username);
211         free(password);
212
213         if (PQstatus(pset.db) == CONNECTION_BAD)
214         {
215                 fprintf(stderr, "%s: %s", pset.progname, PQerrorMessage(pset.db));
216                 PQfinish(pset.db);
217                 exit(EXIT_BADCONN);
218         }
219
220         PQsetNoticeProcessor(pset.db, NoticeProcessor, NULL);
221
222         SyncVariables();
223
224         if (options.action == ACT_LIST_DB)
225         {
226                 int                     success = listAllDbs(false);
227
228                 PQfinish(pset.db);
229                 exit(success ? EXIT_SUCCESS : EXIT_FAILURE);
230         }
231
232         /*
233          * Now find something to do
234          */
235
236         /*
237          * process file given by -f
238          */
239         if (options.action == ACT_FILE && strcmp(options.action_string, "-") != 0)
240         {
241                 if (!options.no_psqlrc)
242                         process_psqlrc();
243
244                 successResult = process_file(options.action_string);
245         }
246
247         /*
248          * process slash command if one was given to -c
249          */
250         else if (options.action == ACT_SINGLE_SLASH)
251         {
252                 PsqlScanState scan_state;
253
254                 if (VariableEquals(pset.vars, "ECHO", "all"))
255                         puts(options.action_string);
256
257                 scan_state = psql_scan_create();
258                 psql_scan_setup(scan_state,
259                                                 options.action_string,
260                                                 strlen(options.action_string));
261
262                 successResult = HandleSlashCmds(scan_state, NULL) != CMD_ERROR
263                         ? EXIT_SUCCESS : EXIT_FAILURE;
264
265                 psql_scan_destroy(scan_state);
266         }
267
268         /*
269          * If the query given to -c was a normal one, send it
270          */
271         else if (options.action == ACT_SINGLE_QUERY)
272         {
273                 if (VariableEquals(pset.vars, "ECHO", "all"))
274                         puts(options.action_string);
275
276                 successResult = SendQuery(options.action_string)
277                         ? EXIT_SUCCESS : EXIT_FAILURE;
278         }
279
280         /*
281          * or otherwise enter interactive main loop
282          */
283         else
284         {
285                 if (!QUIET() && !pset.notty)
286                 {
287                         printf(gettext("Welcome to %s %s, the PostgreSQL interactive terminal.\n\n"
288                                                    "Type:  \\copyright for distribution terms\n"
289                                                    "       \\h for help with SQL commands\n"
290                                                    "       \\? for help with psql commands\n"
291                                                    "       \\g or terminate with semicolon to execute query\n"
292                                                    "       \\q to quit\n\n"),
293                                    pset.progname, PG_VERSION);
294 #ifdef USE_SSL
295                         printSSLInfo();
296 #endif
297 #ifdef WIN32
298                         checkWin32Codepage();
299 #endif
300                 }
301
302                 /* Default values for variables that are used in interactive case */
303                 SetVariable(pset.vars, "PROMPT1", DEFAULT_PROMPT1);
304                 SetVariable(pset.vars, "PROMPT2", DEFAULT_PROMPT2);
305                 SetVariable(pset.vars, "PROMPT3", DEFAULT_PROMPT3);
306
307                 if (!options.no_psqlrc)
308                         process_psqlrc();
309                 if (!pset.notty)
310                         initializeInput(options.no_readline ? 0 : 1);
311                 if (options.action_string)              /* -f - was used */
312                         pset.inputfile = "<stdin>";
313
314                 successResult = MainLoop(stdin);
315         }
316
317         /* clean up */
318         PQfinish(pset.db);
319         setQFout(NULL);
320
321         return successResult;
322 }
323
324
325
326 /*
327  * Parse command line options
328  */
329
330 static void
331 parse_psql_options(int argc, char *argv[], struct adhoc_opts * options)
332 {
333         static struct option long_options[] =
334         {
335                 {"echo-all", no_argument, NULL, 'a'},
336                 {"no-align", no_argument, NULL, 'A'},
337                 {"command", required_argument, NULL, 'c'},
338                 {"dbname", required_argument, NULL, 'd'},
339                 {"echo-queries", no_argument, NULL, 'e'},
340                 {"echo-hidden", no_argument, NULL, 'E'},
341                 {"file", required_argument, NULL, 'f'},
342                 {"field-separator", required_argument, NULL, 'F'},
343                 {"host", required_argument, NULL, 'h'},
344                 {"html", no_argument, NULL, 'H'},
345                 {"list", no_argument, NULL, 'l'},
346                 {"no-readline", no_argument, NULL, 'n'},
347                 {"output", required_argument, NULL, 'o'},
348                 {"port", required_argument, NULL, 'p'},
349                 {"pset", required_argument, NULL, 'P'},
350                 {"quiet", no_argument, NULL, 'q'},
351                 {"record-separator", required_argument, NULL, 'R'},
352                 {"single-step", no_argument, NULL, 's'},
353                 {"single-line", no_argument, NULL, 'S'},
354                 {"tuples-only", no_argument, NULL, 't'},
355                 {"table-attr", required_argument, NULL, 'T'},
356                 {"username", required_argument, NULL, 'U'},
357                 {"set", required_argument, NULL, 'v'},
358                 {"variable", required_argument, NULL, 'v'},
359                 {"version", no_argument, NULL, 'V'},
360                 {"password", no_argument, NULL, 'W'},
361                 {"expanded", no_argument, NULL, 'x'},
362                 {"no-psqlrc", no_argument, NULL, 'X'},
363                 {"help", no_argument, NULL, '?'},
364                 {NULL, 0, NULL, 0}
365         };
366
367         int                     optindex;
368         extern char *optarg;
369         extern int      optind;
370         int                     c;
371         bool            used_old_u_option = false;
372
373         memset(options, 0, sizeof *options);
374
375         while ((c = getopt_long(argc, argv, "aAc:d:eEf:F:h:Hlno:p:P:qR:sStT:uU:v:VWxX?",
376                                                         long_options, &optindex)) != -1)
377         {
378                 switch (c)
379                 {
380                         case 'a':
381                                 SetVariable(pset.vars, "ECHO", "all");
382                                 break;
383                         case 'A':
384                                 pset.popt.topt.format = PRINT_UNALIGNED;
385                                 break;
386                         case 'c':
387                                 options->action_string = optarg;
388                                 if (optarg[0] == '\\')
389                                 {
390                                         options->action = ACT_SINGLE_SLASH;
391                                         options->action_string++;
392                                 }
393                                 else
394                                         options->action = ACT_SINGLE_QUERY;
395                                 break;
396                         case 'd':
397                                 options->dbname = optarg;
398                                 break;
399                         case 'e':
400                                 SetVariable(pset.vars, "ECHO", "queries");
401                                 break;
402                         case 'E':
403                                 SetVariableBool(pset.vars, "ECHO_HIDDEN");
404                                 break;
405                         case 'f':
406                                 options->action = ACT_FILE;
407                                 options->action_string = optarg;
408                                 break;
409                         case 'F':
410                                 pset.popt.topt.fieldSep = pg_strdup(optarg);
411                                 break;
412                         case 'h':
413                                 options->host = optarg;
414                                 break;
415                         case 'H':
416                                 pset.popt.topt.format = PRINT_HTML;
417                                 break;
418                         case 'l':
419                                 options->action = ACT_LIST_DB;
420                                 break;
421                         case 'n':
422                                 options->no_readline = true;
423                                 break;
424                         case 'o':
425                                 setQFout(optarg);
426                                 break;
427                         case 'p':
428                                 options->port = optarg;
429                                 break;
430                         case 'P':
431                                 {
432                                         char       *value;
433                                         char       *equal_loc;
434                                         bool            result;
435
436                                         value = pg_strdup(optarg);
437                                         equal_loc = strchr(value, '=');
438                                         if (!equal_loc)
439                                                 result = do_pset(value, NULL, &pset.popt, true);
440                                         else
441                                         {
442                                                 *equal_loc = '\0';
443                                                 result = do_pset(value, equal_loc + 1, &pset.popt, true);
444                                         }
445
446                                         if (!result)
447                                         {
448                                                 fprintf(stderr, gettext("%s: couldn't set printing parameter \"%s\"\n"), pset.progname, value);
449                                                 exit(EXIT_FAILURE);
450                                         }
451
452                                         free(value);
453                                         break;
454                                 }
455                         case 'q':
456                                 SetVariableBool(pset.vars, "QUIET");
457                                 break;
458                         case 'R':
459                                 pset.popt.topt.recordSep = pg_strdup(optarg);
460                                 break;
461                         case 's':
462                                 SetVariableBool(pset.vars, "SINGLESTEP");
463                                 break;
464                         case 'S':
465                                 SetVariableBool(pset.vars, "SINGLELINE");
466                                 break;
467                         case 't':
468                                 pset.popt.topt.tuples_only = true;
469                                 break;
470                         case 'T':
471                                 pset.popt.topt.tableAttr = pg_strdup(optarg);
472                                 break;
473                         case 'u':
474                                 pset.getPassword = true;
475                                 options->username = "\001";             /* hopefully nobody has
476                                                                                                  * that username */
477                                 /* this option is out */
478                                 used_old_u_option = true;
479                                 break;
480                         case 'U':
481                                 options->username = optarg;
482                                 break;
483                         case 'v':
484                                 {
485                                         char       *value;
486                                         char       *equal_loc;
487
488                                         value = pg_strdup(optarg);
489                                         equal_loc = strchr(value, '=');
490                                         if (!equal_loc)
491                                         {
492                                                 if (!DeleteVariable(pset.vars, value))
493                                                 {
494                                                         fprintf(stderr, gettext("%s: could not delete variable \"%s\"\n"),
495                                                                         pset.progname, value);
496                                                         exit(EXIT_FAILURE);
497                                                 }
498                                         }
499                                         else
500                                         {
501                                                 *equal_loc = '\0';
502                                                 if (!SetVariable(pset.vars, value, equal_loc + 1))
503                                                 {
504                                                         fprintf(stderr, gettext("%s: could not set variable \"%s\"\n"),
505                                                                         pset.progname, value);
506                                                         exit(EXIT_FAILURE);
507                                                 }
508                                         }
509
510                                         free(value);
511                                         break;
512                                 }
513                         case 'V':
514                                 showVersion();
515                                 exit(EXIT_SUCCESS);
516                         case 'W':
517                                 pset.getPassword = true;
518                                 break;
519                         case 'x':
520                                 pset.popt.topt.expanded = true;
521                                 break;
522                         case 'X':
523                                 options->no_psqlrc = true;
524                                 break;
525                         case '?':
526                                 /* Actual help option given */
527                                 if (strcmp(argv[optind - 1], "-?") == 0 || strcmp(argv[optind - 1], "--help") == 0)
528                                 {
529                                         usage();
530                                         exit(EXIT_SUCCESS);
531                                 }
532                                 /* unknown option reported by getopt */
533                                 else
534                                 {
535                                         fprintf(stderr, gettext("Try \"%s --help\" for more information.\n"),
536                                                         pset.progname);
537                                         exit(EXIT_FAILURE);
538                                 }
539                                 break;
540                         default:
541                                 fprintf(stderr, gettext("Try \"%s --help\" for more information.\n"),
542                                                 pset.progname);
543                                 exit(EXIT_FAILURE);
544                                 break;
545                 }
546         }
547
548         /*
549          * if we still have arguments, use it as the database name and
550          * username
551          */
552         while (argc - optind >= 1)
553         {
554                 if (!options->dbname)
555                         options->dbname = argv[optind];
556                 else if (!options->username)
557                         options->username = argv[optind];
558                 else if (!QUIET())
559                         fprintf(stderr, gettext("%s: warning: extra command-line argument \"%s\" ignored\n"),
560                                         pset.progname, argv[optind]);
561
562                 optind++;
563         }
564
565         if (used_old_u_option && !QUIET())
566                 fprintf(stderr, gettext("%s: Warning: The -u option is deprecated. Use -U.\n"), pset.progname);
567
568 }
569
570 #ifndef SYSCONFDIR
571 #error "You must compile this file with SYSCONFDIR defined."
572 #endif
573
574
575 /*
576  * Load .psqlrc file, if found.
577  */
578 static void
579 process_psqlrc(void)
580 {
581         char       *globalFile = SYSCONFDIR "/" SYSPSQLRC;
582         char       *home;
583         char       *psqlrc;
584
585         process_psqlrc_file(globalFile);
586
587         if ((home = getenv("HOME")) != NULL)
588         {
589                 psqlrc = pg_malloc(strlen(home) + 1 + strlen(PSQLRC) + 1);
590                 sprintf(psqlrc, "%s/%s", home, PSQLRC);
591                 process_psqlrc_file(psqlrc);
592         }
593 }
594
595
596
597 static void
598 process_psqlrc_file(char *filename)
599 {
600         char       *psqlrc;
601
602 #if defined(WIN32) && (!defined(__MINGW32__))
603 #define R_OK 4
604 #endif
605
606         psqlrc = pg_malloc(strlen(filename) + 1 + strlen(PG_VERSION) + 1);
607         sprintf(psqlrc, "%s-%s", filename, PG_VERSION);
608
609         if (access(psqlrc, R_OK) == 0)
610                 process_file(psqlrc);
611         else if (access(filename, R_OK) == 0)
612                         process_file(filename);
613         free(psqlrc);
614 }
615
616
617
618 /* showVersion
619  *
620  * This output format is intended to match GNU standards.
621  */
622 static void
623 showVersion(void)
624 {
625         puts("psql (PostgreSQL) " PG_VERSION);
626
627 #if defined(USE_READLINE)
628         puts(gettext("contains support for command-line editing"));
629 #endif
630 }
631
632
633
634 /*
635  * printSSLInfo
636  *
637  * Prints information about the current SSL connection, if SSL is in use
638  */
639 #ifdef USE_SSL
640 static void
641 printSSLInfo(void)
642 {
643         int                     sslbits = -1;
644         SSL                *ssl;
645
646         ssl = PQgetssl(pset.db);
647         if (!ssl)
648                 return;                                 /* no SSL */
649
650         SSL_get_cipher_bits(ssl, &sslbits);
651         printf(gettext("SSL connection (cipher: %s, bits: %i)\n\n"),
652                    SSL_get_cipher(ssl), sslbits);
653 }
654
655 #endif
656
657
658
659 /*
660  * checkWin32Codepage
661  *
662  * Prints a warning when win32 console codepage differs from Windows codepage
663  */
664 #ifdef WIN32
665 static void
666 checkWin32Codepage(void)
667 {
668         unsigned int wincp, concp;
669
670         wincp = GetACP();
671         concp = GetConsoleCP();
672         if (wincp != concp) {
673           printf("Warning: Console codepage (%u) differs from windows codepage (%u)\n"
674                          "         8-bit characters will not work correctly. See PostgreSQL\n"
675                          "         documentation \"Installation on Windows\" for details.\n\n",
676                          concp, wincp);
677         }
678 }
679 #endif