]> granicus.if.org Git - postgresql/blob - src/bin/psql/psql.c
Fix \? syntax for copy command.
[postgresql] / src / bin / psql / psql.c
1 /*-------------------------------------------------------------------------
2  *
3  * psql.c--
4  *    an interactive front-end to postgreSQL
5  *
6  * Copyright (c) 1996, Regents of the University of California
7  *
8  *
9  * IDENTIFICATION
10  *    $Header: /cvsroot/pgsql/src/bin/psql/Attic/psql.c,v 1.56 1997/02/11 03:11:33 momjian Exp $
11  *
12  *-------------------------------------------------------------------------
13  */
14 #include <stdio.h>
15 #include <string.h>
16 #include <signal.h>
17 #include <errno.h>
18 #include <sys/types.h>
19 #include <sys/param.h>  /* for MAXPATHLEN */
20 #include <sys/stat.h>
21 #include <unistd.h>
22 #include <fcntl.h>
23 #include <ctype.h>
24 #include "postgres.h"
25 #include "libpq-fe.h"
26 #include "pqsignal.h"
27 #include "stringutils.h"
28 #include "psqlHelp.h"
29 #ifdef NEED_STRDUP
30 #include "strdup.h"
31 #endif
32
33 #ifdef HAVE_LIBREADLINE
34 # ifdef HAVE_READLINE_H
35 #  include <readline.h>
36 #  if defined(HAVE_HISTORY) || defined(HAVE_LIBHISTORY)
37 #   include <history.h>
38 #  endif
39 # else
40 #  include <readline/readline.h>
41 #  if defined(HAVE_HISTORY) || defined(HAVE_LIBHISTORY)
42 #   include <readline/history.h>
43 #  endif
44 # endif
45 #endif
46
47 #define PROMPT "=> "
48
49 #define MAX_QUERY_BUFFER 20000
50
51 #define COPYBUFSIZ  8192
52
53 #define DEFAULT_FIELD_SEP "|"
54 #define DEFAULT_EDITOR  "vi"
55 #define DEFAULT_SHELL  "/bin/sh"
56
57 typedef struct _psqlSettings {
58     PGconn         *db;         /* connection to backend */
59     FILE           *queryFout;  /* where to send the query results */
60     PQprintOpt      opt;        /* options to be passed to PQprint */
61     char           *prompt;     /* prompt to display */
62     char           *gfname;     /* one-shot file output argument for \g */
63     bool            notty;      /* input or output is not a tty */
64     bool            pipe;       /* queryFout is from a popen() */
65     bool            echoQuery;  /* echo the query before sending it */
66     bool            quiet;      /* run quietly, no messages, no promt */
67     bool            singleStep; /* prompt before for each query */
68     bool            singleLineMode;     /* query terminated by newline */
69     bool            useReadline;/* use libreadline routines */
70 }               PsqlSettings;
71
72 /* declarations for functions in this file */
73 static void     usage(char *progname);
74 static void     slashUsage();
75 static void     handleCopyOut(PGresult * res, bool quiet, FILE * copystream);
76 static void
77 handleCopyIn(PGresult * res, const bool mustprompt,
78              FILE * copystream);
79 static int      tableList(PsqlSettings * ps, bool deep_tablelist);
80 static int      tableDesc(PsqlSettings * ps, char *table);
81
82 char           *gets_noreadline(char *prompt, FILE * source);
83 char           *gets_readline(char *prompt, FILE * source);
84 char           *gets_fromFile(char *prompt, FILE * source);
85 int             listAllDbs(PsqlSettings * settings);
86 void
87 SendQuery(bool * success_p, PsqlSettings * settings, const char *query,
88           const bool copy_in, const bool copy_out, FILE * copystream);
89 int
90 HandleSlashCmds(PsqlSettings * settings,
91                 char *line,
92                 char *query);
93 int             MainLoop(PsqlSettings * settings, FILE * source);
94 /* probably should move this into libpq */
95 void
96 PQprint(FILE * fp,
97         PGresult * res,
98         PQprintOpt * po
99 );
100
101 FILE           *setFout(PsqlSettings * ps, char *fname);
102
103 /*
104  * usage print out usage for command line arguments
105  */
106
107 static void
108 usage(char *progname)
109 {
110     fprintf(stderr, "Usage: %s [options] [dbname]\n", progname);
111     fprintf(stderr, "\t -a authsvc              set authentication service\n");
112     fprintf(stderr, "\t -A                      turn off alignment when printing out attributes\n");
113     fprintf(stderr, "\t -c query                run single query (slash commands too)\n");
114     fprintf(stderr, "\t -d dbName               specify database name\n");
115     fprintf(stderr, "\t -e                      echo the query sent to the backend\n");
116     fprintf(stderr, "\t -f filename             use file as a source of queries\n");
117     fprintf(stderr, "\t -F sep                  set the field separator (default is " ")\n");
118     fprintf(stderr, "\t -h host                 set database server host\n");
119     fprintf(stderr, "\t -H                      turn on html3.0 table output\n");
120     fprintf(stderr, "\t -l                      list available databases\n");
121     fprintf(stderr, "\t -n                      don't use readline library\n");
122     fprintf(stderr, "\t -o filename             send output to filename or (|pipe)\n");
123     fprintf(stderr, "\t -p port                 set port number\n");
124     fprintf(stderr, "\t -q                      run quietly (no messages, no prompts)\n");
125     fprintf(stderr, "\t -s                      single step mode (prompts for each query)\n");
126     fprintf(stderr, "\t -S                      single line mode (i.e. query terminated by newline)\n");
127     fprintf(stderr, "\t -t                      turn off printing of headings and row count\n");
128     fprintf(stderr, "\t -T html                 set html3.0 table command options (cf. -H)\n");
129     fprintf(stderr, "\t -x                      turn on expanded output (field names on left)\n");
130     exit(1);
131 }
132
133 /*
134  * slashUsage print out usage for the backslash commands
135  */
136
137 static char    *
138 on(bool f)
139 {
140     return f ? "on" : "off";
141 }
142
143 static void
144 slashUsage(PsqlSettings * ps)
145 {
146     fprintf(stderr, " \\?           -- help\n");
147     fprintf(stderr, " \\a           -- toggle field-alignment (currenty %s)\n", on(ps->opt.align));
148     fprintf(stderr, " \\C [<captn>] -- set html3 caption (currently '%s')\n", ps->opt.caption ? ps->opt.caption : "");
149     fprintf(stderr, " \\connect <dbname>  -- connect to new database (currently '%s')\n", PQdb(ps->db));
150     fprintf(stderr, " \\copy table {from | to} <fname>\n");
151     fprintf(stderr, " \\d [<table>] -- list tables in database or columns in <table>, * for all\n");
152     fprintf(stderr, " \\e [<fname>] -- edit the current query buffer or <fname>, \\E execute too\n");
153     fprintf(stderr, " \\f [<sep>]   -- change field separater (currently '%s')\n", ps->opt.fieldSep);
154     fprintf(stderr, " \\g [<fname>] [|<cmd>] -- send query to backend [and results in <fname> or pipe]\n");
155     fprintf(stderr, " \\h [<cmd>]   -- help on syntax of sql commands, * for all commands\n");
156     fprintf(stderr, " \\H           -- toggle html3 output (currently %s)\n", on(ps->opt.html3));
157     fprintf(stderr, " \\i <fname>   -- read and execute queries from filename\n");
158     fprintf(stderr, " \\l           -- list all databases\n");
159     fprintf(stderr, " \\m           -- toggle monitor-like table display (currently %s)\n", on(ps->opt.standard));
160     fprintf(stderr, " \\o [<fname>] [|<cmd>] -- send all query results to stdout, <fname>, or pipe\n");
161     fprintf(stderr, " \\p           -- print the current query buffer\n");
162     fprintf(stderr, " \\q           -- quit\n");
163     fprintf(stderr, " \\r           -- reset(clear) the query buffer\n");
164     fprintf(stderr, " \\s [<fname>] -- print history or save it in <fname>\n");
165     fprintf(stderr, " \\t           -- toggle table headings and row count (currently %s)\n", on(ps->opt.header));
166     fprintf(stderr, " \\T [<html>]  -- set html3.0 <table ...> options (currently '%s')\n", ps->opt.tableOpt ? ps->opt.tableOpt : "");
167     fprintf(stderr, " \\x           -- toggle expanded output (currently %s)\n", on(ps->opt.expanded));
168     fprintf(stderr, " \\! [<cmd>]   -- shell escape or command\n");
169 }
170
171 static PGresult *
172 PSQLexec(PsqlSettings * ps, char *query)
173 {
174     PGresult       *res = PQexec(ps->db, query);
175     if (!res)
176         fputs(PQerrorMessage(ps->db), stderr);
177     else {
178         if (PQresultStatus(res) == PGRES_COMMAND_OK ||
179             PQresultStatus(res) == PGRES_TUPLES_OK)
180             return res;
181         if (!ps->quiet)
182             fputs(PQerrorMessage(ps->db), stderr);
183         PQclear(res);
184     }
185     return NULL;
186 }
187 /*
188  * listAllDbs
189  * 
190  * list all the databases in the system returns 0 if all went well
191  * 
192  * 
193  */
194
195 int
196 listAllDbs(PsqlSettings * ps)
197 {
198     PGresult       *results;
199     char           *query = "select * from pg_database;";
200
201     if (!(results = PSQLexec(ps, query)))
202         return 1;
203     else {
204         PQprint(ps->queryFout,
205                 results,
206                 &ps->opt);
207         PQclear(results);
208         return 0;
209     }
210 }
211
212 /*
213  * List The Database Tables returns 0 if all went well
214  * 
215  */
216 int
217 tableList(PsqlSettings * ps, bool deep_tablelist)
218 {
219     char            listbuf[256];
220     int             nColumns;
221     int             i;
222     char           *rk;
223     char           *rr;
224
225     PGresult       *res;
226
227     listbuf[0] = '\0';
228     strcat(listbuf, "SELECT usename, relname, relkind, relhasrules");
229     strcat(listbuf, "  FROM pg_class, pg_user ");
230     strcat(listbuf, "WHERE ( relkind = 'r' OR relkind = 'i') ");
231     strcat(listbuf, "  and relname !~ '^pg_'");
232     strcat(listbuf, "  and relname !~ '^Inv[0-9]+'");
233     /*
234      * the usesysid = relowner won't work on stock 1.0 dbs, need to add in
235      * the int4oideq function
236      */
237     strcat(listbuf, "  and usesysid = relowner");
238     strcat(listbuf, "  ORDER BY relname ");
239     if (!(res = PSQLexec(ps, listbuf)))
240         return -1;
241
242     /* first, print out the attribute names */
243     nColumns = PQntuples(res);
244     if (nColumns > 0) {
245         if (deep_tablelist) {
246             /* describe everything here */
247             char          **table;
248             table = (char **) malloc(nColumns * sizeof(char *));
249             if (table == NULL)
250                 perror("malloc");
251
252             /* load table table */
253             for (i = 0; i < nColumns; i++) {
254                 table[i] = (char *) malloc(PQgetlength(res, i, 1) * sizeof(char) + 1);
255                 if (table[i] == NULL)
256                     perror("malloc");
257                 strcpy(table[i], PQgetvalue(res, i, 1));
258             }
259
260             PQclear(res);
261             for (i = 0; i < nColumns; i++) {
262                 tableDesc(ps, table[i]);
263             }
264             free(table);
265         } else {
266             /* Display the information */
267
268             printf("\nDatabase    = %s\n", PQdb(ps->db));
269             printf(" +------------------+----------------------------------+----------+\n");
270             printf(" |  Owner           |             Relation             |   Type   |\n");
271             printf(" +------------------+----------------------------------+----------+\n");
272
273             /* next, print out the instances */
274             for (i = 0; i < PQntuples(res); i++) {
275                 printf(" | %-16.16s", PQgetvalue(res, i, 0));
276                 printf(" | %-32.32s | ", PQgetvalue(res, i, 1));
277                 rk = PQgetvalue(res, i, 2);
278                 rr = PQgetvalue(res, i, 3);
279                 if (strcmp(rk, "r") == 0)
280                     printf("%-8.8s |", (rr[0] == 't') ? "view?" : "table");
281                 else
282                     printf("%-8.8s |", "index");
283                 printf("\n");
284             }
285             printf(" +------------------+----------------------------------+----------+\n");
286             PQclear(res);
287         }
288         return (0);
289
290     } else {
291         fprintf(stderr, "Couldn't find any tables!\n");
292         return (-1);
293     }
294 }
295
296 /*
297  * Describe a table
298  * 
299  * Describe the columns in a database table. returns 0 if all went well
300  * 
301  * 
302  */
303 int
304 tableDesc(PsqlSettings * ps, char *table)
305 {
306     char            descbuf[256];
307     int             nColumns;
308     char           *rtype;
309     int             i;
310     int             rsize;
311
312     PGresult       *res;
313
314     /* Build the query */
315
316     descbuf[0] = '\0';
317     strcat(descbuf, "SELECT a.attnum, a.attname, t.typname, a.attlen");
318     strcat(descbuf, "  FROM pg_class c, pg_attribute a, pg_type t ");
319     strcat(descbuf, "    WHERE c.relname = '");
320     strcat(descbuf, table);
321     strcat(descbuf, "'");
322     strcat(descbuf, "    and a.attnum > 0 ");
323     strcat(descbuf, "    and a.attrelid = c.oid ");
324     strcat(descbuf, "    and a.atttypid = t.oid ");
325     strcat(descbuf, "  ORDER BY attnum ");
326     if (!(res = PSQLexec(ps, descbuf)))
327         return -1;
328     /* first, print out the attribute names */
329     nColumns = PQntuples(res);
330     if (nColumns > 0) {
331         /*
332          * * Display the information
333          */
334
335         printf("\nTable    = %s\n", table);
336         printf("+----------------------------------+----------------------------------+-------+\n");
337         printf("|              Field               |              Type                | Length|\n");
338         printf("+----------------------------------+----------------------------------+-------+\n");
339
340         /* next, print out the instances */
341         for (i = 0; i < PQntuples(res); i++) {
342             printf("| %-32.32s | ", PQgetvalue(res, i, 1));
343             rtype = PQgetvalue(res, i, 2);
344             rsize = atoi(PQgetvalue(res, i, 3));
345             if (strcmp(rtype, "text") == 0) {
346                 printf("%-32.32s |", rtype);
347                 printf("%6s |", "var");
348             } else if (strcmp(rtype, "bpchar") == 0) {
349                 printf("%-32.32s |", "(bp)char");
350                 printf("%6i |", rsize > 0 ? rsize - 4 : 0);
351             } else if (strcmp(rtype, "varchar") == 0) {
352                 printf("%-32.32s |", rtype);
353                 printf("%6i |", rsize > 0 ? rsize - 4 : 0);
354             } else {
355                 /* array types start with an underscore */
356                 if (rtype[0] != '_')
357                     printf("%-32.32s |", rtype);
358                 else {
359                     char           *newname;
360                     newname = malloc(strlen(rtype) + 2);
361                     strcpy(newname, rtype + 1);
362                     strcat(newname, "[]");
363                     printf("%-32.32s |", newname);
364                     free(newname);
365                 }
366                 if (rsize > 0)
367                     printf("%6i |", rsize);
368                 else
369                     printf("%6s |", "var");
370             }
371             printf("\n");
372         }
373         printf("+----------------------------------+----------------------------------+-------+\n");
374
375         PQclear(res);
376         return (0);
377
378     } else {
379         fprintf(stderr, "Couldn't find table %s!\n", table);
380         return (-1);
381     }
382 }
383
384 typedef char   *(*READ_ROUTINE) (char *prompt, FILE * source);
385
386 /*
387  * gets_noreadline  prompt source gets a line of input without calling
388  * readline, the source is ignored
389  */
390 char           *
391 gets_noreadline(char *prompt, FILE * source)
392 {
393     fputs(prompt, stdout);
394     fflush(stdout);
395     return (gets_fromFile(prompt, stdin));
396 }
397
398 /*
399  * gets_readline  prompt source the routine to get input from GNU readline(),
400  * the source is ignored the prompt argument is used as the prompting string
401  */
402 char           *
403 gets_readline(char *prompt, FILE * source)
404 {
405     char *s;
406 #ifdef HAVE_LIBREADLINE
407     s = readline(prompt);
408 #else
409     char buf[500];
410     printf("%s", prompt);
411     s = fgets(buf, 500, stdin);
412 #endif
413     fputc('\r', stdout);
414     fflush(stdout);
415     return s;
416 }
417
418 /*
419  * gets_fromFile  prompt source
420  * 
421  * the routine to read from a file, the prompt argument is ignored the source
422  * argument is a FILE *
423  */
424 char           *
425 gets_fromFile(char *prompt, FILE * source)
426 {
427     char           *line;
428     int             len;
429
430     line = malloc(MAX_QUERY_BUFFER + 1);
431
432     /* read up to MAX_QUERY_BUFFER characters */
433     if (fgets(line, MAX_QUERY_BUFFER, source) == NULL)
434         return NULL;
435
436     line[MAX_QUERY_BUFFER - 1] = '\0';
437     len = strlen(line);
438     if (len == MAX_QUERY_BUFFER) {
439         fprintf(stderr, "line read exceeds maximum length.  Truncating at %d\n",
440                 MAX_QUERY_BUFFER);
441     }
442     return line;
443 }
444
445 /*
446  * SendQuery: send the query string to the backend return *success_p = 1 if
447  * the query executed successfully returns *success_p = 0 otherwise
448  */
449 void
450 SendQuery(bool * success_p, PsqlSettings * settings, const char *query,
451           const bool copy_in, const bool copy_out, FILE * copystream)
452 {
453
454     PGresult       *results;
455     PGnotify       *notify;
456
457     if (settings->singleStep)
458         fprintf(stdout, "\n**************************************"
459                 "*****************************************\n");
460
461     if (settings->echoQuery || settings->singleStep) {
462         fprintf(stderr, "QUERY: %s\n", query);
463         fflush(stderr);
464     }
465     if (settings->singleStep) {
466         fprintf(stdout, "\n**************************************"
467                 "*****************************************\n");
468         fflush(stdout);
469         printf("\npress return to continue ..\n");
470         gets_fromFile("", stdin);
471     }
472     results = PQexec(settings->db, query);
473     if (results == NULL) {
474         fprintf(stderr, "%s", PQerrorMessage(settings->db));
475         *success_p = false;
476     } else {
477         switch (PQresultStatus(results)) {
478         case PGRES_TUPLES_OK:
479             if (settings->gfname) {
480                 PsqlSettings    ps = *settings;
481                 FILE           *fp;
482                 ps.queryFout = stdout;
483                 fp = setFout(&ps, settings->gfname);
484                 if (!fp || fp == stdout) {
485                     *success_p = false;
486                     break;
487                 } else
488                     *success_p = true;
489                 PQprint(fp,
490                         results,
491                         &(settings->opt));
492                 if (ps.pipe)
493                     pclose(fp);
494                 else
495                     fclose(fp);
496                 free(settings->gfname);
497                 settings->gfname = NULL;
498                 break;
499             } else {
500                 *success_p = true;
501                 PQprint(settings->queryFout,
502                         results,
503                         &(settings->opt));
504                 fflush(settings->queryFout);
505             }
506             PQclear(results);
507             break;
508         case PGRES_EMPTY_QUERY:
509             *success_p = true;
510             break;
511         case PGRES_COMMAND_OK:
512             *success_p = true;
513             if (!settings->quiet)
514                 fprintf(stdout, "%s\n", PQcmdStatus(results));
515             break;
516         case PGRES_COPY_OUT:
517             *success_p = true;
518             if (copy_out) {
519                 handleCopyOut(results, settings->quiet, copystream);
520             } else {
521                 if (!settings->quiet)
522                     fprintf(stdout, "Copy command returns...\n");
523
524                 handleCopyOut(results, settings->quiet, stdout);
525             }
526             break;
527         case PGRES_COPY_IN:
528             *success_p = true;
529             if (copy_in)
530                 handleCopyIn(results, false, copystream);
531             else
532                 handleCopyIn(results, !settings->quiet, stdin);
533             break;
534         case PGRES_NONFATAL_ERROR:
535         case PGRES_FATAL_ERROR:
536         case PGRES_BAD_RESPONSE:
537             *success_p = false;
538             fprintf(stderr, "%s", PQerrorMessage(settings->db));
539             break;
540         }
541
542         if (PQstatus(settings->db) == CONNECTION_BAD) {
543             fprintf(stderr,
544                     "We have lost the connection to the backend, so "
545                     "further processing is impossible.  "
546                     "Terminating.\n");
547             exit(2);            /* we are out'ta here */
548         }
549         /* check for asynchronous returns */
550         notify = PQnotifies(settings->db);
551         if (notify) {
552             fprintf(stderr,
553                     "ASYNC NOTIFY of '%s' from backend pid '%d' received\n",
554                     notify->relname, notify->be_pid);
555             free(notify);
556         }
557     }
558 }
559
560
561
562 static void
563 editFile(char *fname)
564 {
565     char           *editorName;
566     char           *sys;
567     editorName = getenv("EDITOR");
568     if (!editorName)
569         editorName = DEFAULT_EDITOR;
570     sys = malloc(strlen(editorName) + strlen(fname) + 32 + 1);
571     if (!sys) {
572         perror("malloc");
573         exit(1);
574     }
575     sprintf(sys, "exec '%s' '%s'", editorName, fname);
576     system(sys);
577     free(sys);
578 }
579
580 static          bool
581 toggle(PsqlSettings * settings, bool * sw, char *msg)
582 {
583     *sw = !*sw;
584     if (!settings->quiet)
585         fprintf(stderr, "turned %s %s\n", on(*sw), msg);
586     return *sw;
587 }
588
589
590
591 static void
592 unescape(char *dest, const char *source)
593 {
594     /*-----------------------------------------------------------------------------
595       Return as the string <dest> the value of string <source> with escape
596       sequences turned into the bytes they represent.
597     -----------------------------------------------------------------------------*/
598     char           *p;
599     bool            esc;        /* Last character we saw was the escape
600                                  * character (/) */
601
602     esc = false;                /* Haven't seen escape character yet */
603     for (p = (char *) source; *p; p++) {
604         char            c;      /* Our output character */
605
606         if (esc) {
607             switch (*p) {
608             case 'n':
609                 c = '\n';
610                 break;
611             case 'r':
612                 c = '\r';
613                 break;
614             case 't':
615                 c = '\t';
616                 break;
617             case 'f':
618                 c = '\f';
619                 break;
620             case '\\':
621                 c = '\\';
622                 break;
623             default:
624                 c = *p;
625             }
626             esc = false;
627         } else if (*p == '\\') {
628             esc = true;
629             c = ' ';            /* meaningless, but compiler doesn't know
630                                  * that */
631         } else {
632             c = *p;
633             esc = false;
634         }
635         if (!esc)
636             *dest++ = c;
637     }
638     *dest = '\0';               /* Terminating null character */
639 }
640
641
642
643 static void
644 parse_slash_copy(const char *args, char *table, const int table_len,
645                  char *file, const int file_len,
646                  bool * from_p, bool * error_p)
647 {
648
649     char            work_args[200];
650     /*
651      * A copy of the \copy command arguments, except that we modify it as we
652      * parse to suit our parsing needs.
653      */
654     char           *table_tok, *fromto_tok;
655
656     strncpy(work_args, args, sizeof(work_args));
657     work_args[sizeof(work_args) - 1] = '\0';
658
659     *error_p = false;           /* initial assumption */
660
661     table_tok = strtok(work_args, " ");
662     if (table_tok == NULL) {
663         fprintf(stderr, "\\copy needs arguments.\n");
664         *error_p = true;
665     } else {
666         strncpy(table, table_tok, table_len);
667         file[table_len - 1] = '\0';
668
669         fromto_tok = strtok(NULL, "  ");
670         if (fromto_tok == NULL) {
671             fprintf(stderr, "'FROM' or 'TO' must follow table name.\n");
672             *error_p = true;
673         } else {
674             if (strcasecmp(fromto_tok, "from") == 0)
675                 *from_p = true;
676             else if (strcasecmp(fromto_tok, "to") == 0)
677                 *from_p = false;
678             else {
679                 fprintf(stderr,
680                         "Unrecognized token found where "
681                         "'FROM' or 'TO' expected: '%s'.\n",
682                         fromto_tok);
683                 *error_p = true;
684             }
685             if (!*error_p) {
686                 char           *file_tok;
687
688                 file_tok = strtok(NULL, " ");
689                 if (file_tok == NULL) {
690                     fprintf(stderr, "A file pathname must follow '%s'.\n",
691                             fromto_tok);
692                     *error_p = true;
693                 } else {
694                     strncpy(file, file_tok, file_len);
695                     file[file_len - 1] = '\0';
696                     if (strtok(NULL, " ") != NULL) {
697                         fprintf(stderr,
698                              "You have extra tokens after the filename.\n");
699                         *error_p = true;
700                     }
701                 }
702             }
703         }
704     }
705 }
706
707
708
709 static void
710 do_copy(const char *args, PsqlSettings * settings)
711 {
712     /*---------------------------------------------------------------------------
713       Execute a \copy command (frontend copy).  We have to open a file, then
714       submit a COPY query to the backend and either feed it data from the
715       file or route its response into the file.
716
717       We do a text copy with default (tab) column delimiters.  Some day, we
718       should do all the things a backend copy can do.
719
720     ----------------------------------------------------------------------------*/
721     char            query[200];
722     /* The COPY command we send to the back end */
723     bool            from;
724     /* The direction of the copy is from a file to a table. */
725     char            file[MAXPATHLEN + 1];
726     /* The pathname of the file from/to which we copy */
727     char            table[NAMEDATALEN + 1];
728     /* The name of the table from/to which we copy */
729     bool            syntax_error;
730     /* The \c command has invalid syntax */
731     FILE           *copystream;
732
733     parse_slash_copy(args, table, sizeof(table), file, sizeof(file),
734                      &from, &syntax_error);
735
736     if (!syntax_error) {
737         strcpy(query, "COPY ");
738         strcat(query, table);
739
740         if (from)
741             strcat(query, " FROM stdin");
742         else
743             strcat(query, " TO stdout");
744
745         if (from) {
746             copystream = fopen(file, "r");
747         } else {
748             copystream = fopen(file, "w");
749         }
750         if (copystream == NULL)
751             fprintf(stderr,
752                     "Unable to open file %s which to copy, errno = %s (%d).",
753                     from ? "from" : "to", strerror(errno), errno);
754         else {
755             bool            success;    /* The query succeeded at the backend */
756
757             SendQuery(&success, settings, query, from, !from, copystream);
758             fclose(copystream);
759             if (!settings->quiet) {
760                 if (success)
761                     fprintf(stdout, "Successfully copied.\n");
762                 else
763                     fprintf(stdout, "Copy failed.\n");
764             }
765         }
766     }
767 }
768
769
770 static void
771 do_connect(const char *new_dbname, PsqlSettings * settings)
772 {
773
774     char           *dbname = PQdb(settings->db);
775     if (!new_dbname)
776         fprintf(stderr, "\\connect must be followed by a database name\n");
777     else {
778         PGconn         *olddb = settings->db;
779
780         printf("closing connection to database: %s\n", dbname);
781         settings->db = PQsetdb(PQhost(olddb), PQport(olddb),
782                                NULL, NULL, new_dbname);
783         printf("connecting to new database: %s\n", new_dbname);
784         if (PQstatus(settings->db) == CONNECTION_BAD) {
785             fprintf(stderr, "%s\n", PQerrorMessage(settings->db));
786             printf("reconnecting to %s\n", dbname);
787             settings->db = PQsetdb(PQhost(olddb), PQport(olddb),
788                                    NULL, NULL, dbname);
789             if (PQstatus(settings->db) == CONNECTION_BAD) {
790                 fprintf(stderr,
791                         "could not reconnect to %s. exiting\n", dbname);
792                 exit(2);
793             }
794         } else {
795             PQfinish(olddb);
796             free(settings->prompt);
797             settings->prompt = malloc(strlen(PQdb(settings->db)) + 10);
798             sprintf(settings->prompt, "%s%s", PQdb(settings->db), PROMPT);
799         }
800     }
801 }
802
803
804 static void
805 do_edit(const char *filename_arg, char *query, int *status_p)
806 {
807
808     int             fd;
809     char            tmp[64];
810     char           *fname;
811     int             cc;
812     const int       ql = strlen(query);
813     bool            error;
814
815     if (filename_arg) {
816         fname = (char *) filename_arg;
817         error = false;
818     } else {
819         sprintf(tmp, "/tmp/psql.%ld.%ld", (long) geteuid(), (long) getpid());
820         fname = tmp;
821         unlink(tmp);
822         if (ql > 0) {
823             if ((fd = open(tmp, O_EXCL | O_CREAT | O_WRONLY, 0600)) == -1) {
824                 perror(tmp);
825                 error = true;
826             } else {
827                 if (query[ql - 1] != '\n')
828                     strcat(query, "\n");
829                 if (write(fd, query, ql) != ql) {
830                     perror(tmp);
831                     close(fd);
832                     unlink(tmp);
833                     error = true;
834                 } else
835                     error = false;
836                 close(fd);
837             }
838         } else
839             error = false;
840     }
841
842     if (error)
843         *status_p = 1;
844     else {
845         editFile(fname);
846         if ((fd = open(fname, O_RDONLY)) == -1) {
847             perror(fname);
848             if (!filename_arg)
849                 unlink(fname);
850             *status_p = 1;
851         } else {
852             if ((cc = read(fd, query, MAX_QUERY_BUFFER)) == -1) {
853                 perror(fname);
854                 close(fd);
855                 if (!filename_arg)
856                     unlink(fname);
857                 *status_p = 1;
858             } else {
859                 query[cc] = '\0';
860                 close(fd);
861                 if (!filename_arg)
862                     unlink(fname);
863                 rightTrim(query);
864                 *status_p = 3;
865             }
866         }
867     }
868 }
869
870
871
872 static void
873 do_help(const char *topic)
874 {
875
876     if (!topic) {
877         char            left_center_right;      /* Which column we're
878                                                  * displaying */
879         int             i;      /* Index into QL_HELP[] */
880
881         printf("type \\h <cmd> where <cmd> is one of the following:\n");
882
883         left_center_right = 'L';/* Start with left column */
884         i = 0;
885         while (QL_HELP[i].cmd != NULL) {
886             switch (left_center_right) {
887             case 'L':
888                 printf("    %-25s", QL_HELP[i].cmd);
889                 left_center_right = 'C';
890                 break;
891             case 'C':
892                 printf("%-25s", QL_HELP[i].cmd);
893                 left_center_right = 'R';
894                 break;
895             case 'R':
896                 printf("%-25s\n", QL_HELP[i].cmd);
897                 left_center_right = 'L';
898                 break;
899             };
900             i++;
901         }
902         if (left_center_right != 'L')
903             puts("\n");
904         printf("type \\h * for a complete description of all commands\n");
905     } else {
906         int             i;      /* Index into QL_HELP[] */
907         bool            help_found;     /* We found the help he asked for */
908
909         help_found = false;     /* Haven't found it yet */
910         for (i = 0; QL_HELP[i].cmd; i++) {
911             if (strcmp(QL_HELP[i].cmd, topic) == 0 ||
912                 strcmp(topic, "*") == 0) {
913                 help_found = true;
914                 printf("Command: %s\n", QL_HELP[i].cmd);
915                 printf("Description: %s\n", QL_HELP[i].help);
916                 printf("Syntax:\n");
917                 printf("%s\n", QL_HELP[i].syntax);
918                 printf("\n");
919             }
920         }
921         if (!help_found)
922             printf("command not found, "
923                    "try \\h with no arguments to see available help\n");
924     }
925 }
926
927
928
929 static void
930 do_shell(const char *command)
931 {
932
933     if (!command) {
934         char           *sys;
935         char           *shellName;
936
937         shellName = getenv("SHELL");
938         if (shellName == NULL)
939             shellName = DEFAULT_SHELL;
940         sys = malloc(strlen(shellName) + 16);
941         if (!sys) {
942             perror("malloc");
943             exit(1);
944         }
945         sprintf(sys, "exec %s", shellName);
946         system(sys);
947         free(sys);
948     } else
949         system(command);
950 }
951
952
953
954 /*
955  * HandleSlashCmds:
956  * 
957  * Handles all the different commands that start with \ db_ptr is a pointer to
958  * the TgDb* structure line is the current input line prompt_ptr is a pointer
959  * to the prompt string, a pointer is used because the prompt can be used
960  * with a connection to a new database returns a status: 0 - send currently
961  * constructed query to backend (i.e. we got a \g) 1 - skip processing of
962  * this line, continue building up query 2 - terminate processing of this
963  * query entirely, 3 - new query supplied by edit
964  */
965 int
966 HandleSlashCmds(PsqlSettings * settings,
967                 char *line,
968                 char *query)
969 {
970     int             status = 1;
971     char           *optarg;
972     /*
973      * Pointer inside the <cmd> string to the argument of the slash command,
974      * assuming it is a one-character slash command.  If it's not a
975      * one-character command, this is meaningless.
976      */
977     char           *optarg2;
978     /*
979      * Pointer inside the <cmd> string to the argument of the slash command
980      * assuming it's not a one-character command.  If it's a one-character
981      * command, this is meaningless.
982      */
983     char           *cmd;
984     /*
985      * String: value of the slash command, less the slash and with escape
986      * sequences decoded.
987      */
988     int             blank_loc;
989     /* Offset within <cmd> of first blank */
990
991     cmd = malloc(strlen(line)); /* unescaping better not make string grow. */
992
993     unescape(cmd, line + 1);    /* sets cmd string */
994
995     /*
996      * Originally, there were just single character commands.  Now, we define
997      * some longer, friendly commands, but we have to keep the old single
998      * character commands too.  \c used to be what \connect is now.
999      * Complicating matters is the fact that with the single-character
1000      * commands, you can start the argument right after the single character,
1001      * so "\copy" would mean "connect to database named 'opy'".
1002      */
1003
1004     if (strlen(cmd) > 1)
1005         optarg = cmd + 1 + strspn(cmd + 1, " \t");
1006     else
1007         optarg = NULL;
1008
1009     blank_loc = strcspn(cmd, " \t");
1010     if (blank_loc == 0)
1011         optarg2 = NULL;
1012     else
1013         optarg2 = cmd + blank_loc + strspn(cmd + blank_loc, " \t");
1014
1015
1016     switch (cmd[0]) {
1017     case 'a':                   /* toggles to align fields on output */
1018         toggle(settings, &settings->opt.align, "field alignment");
1019         break;
1020     case 'C':                   /* define new caption */
1021         if (settings->opt.caption)
1022             free(settings->opt.caption);
1023         if (!optarg)
1024         {
1025             if (settings->opt.caption)
1026                 free(settings->opt.caption);
1027             settings->opt.caption = NULL;
1028         }
1029         else if (!(settings->opt.caption = strdup(optarg))) {
1030             perror("malloc");
1031             exit(1);
1032         }
1033         break;
1034     case 'c':{
1035             if (strncmp(cmd, "copy ", strlen("copy ")) == 0)
1036                 do_copy(optarg2, settings);
1037             else if (strncmp(cmd, "connect ", strlen("connect ")) == 0)
1038                 do_connect(optarg2, settings);
1039             else
1040                 do_connect(optarg, settings);
1041         }
1042         break;
1043     case 'd':                   /* \d describe tables or columns in a table */
1044         if (!optarg) {
1045             tableList(settings, 0);
1046             break;
1047         }
1048         if (strcmp(optarg, "*") == 0) {
1049             tableList(settings, 0);
1050             tableList(settings, 1);
1051         } else {
1052             tableDesc(settings, optarg);
1053         }
1054         break;
1055     case 'e':                   /* edit */
1056         {
1057             do_edit(optarg, query, &status);
1058             break;
1059         }
1060     case 'E':
1061         {
1062             FILE           *fd;
1063             static char    *lastfile;
1064             struct stat     st, st2;
1065             if (optarg) {
1066                 if (lastfile)
1067                     free(lastfile);
1068                 lastfile = malloc(strlen(optarg + 1));
1069                 if (!lastfile) {
1070                     perror("malloc");
1071                     exit(1);
1072                 }
1073                 strcpy(lastfile, optarg);
1074             } else if (!lastfile) {
1075                 fprintf(stderr, "\\r must be followed by a file name initially\n");
1076                 break;
1077             }
1078             stat(lastfile, &st);
1079             editFile(lastfile);
1080             if ((stat(lastfile, &st2) == -1) || ((fd = fopen(lastfile, "r")) == NULL)) {
1081                 perror(lastfile);
1082                 break;
1083             }
1084             if (st2.st_mtime == st.st_mtime) {
1085                 if (!settings->quiet)
1086                     fprintf(stderr, "warning: %s not modified. query not executed\n", lastfile);
1087                 fclose(fd);
1088                 break;
1089             }
1090             MainLoop(settings, fd);
1091             fclose(fd);
1092             break;
1093         }
1094     case 'f':
1095         {
1096             char           *fs = DEFAULT_FIELD_SEP;
1097             if (optarg)
1098                 fs = optarg;
1099             if (settings->opt.fieldSep)
1100                 free(settings->opt.fieldSep);
1101             if (!(settings->opt.fieldSep = strdup(fs))) {
1102                 perror("malloc");
1103                 exit(1);
1104             }
1105             if (!settings->quiet)
1106                 fprintf(stderr, "field separater changed to '%s'\n", settings->opt.fieldSep);
1107             break;
1108         }
1109     case 'g':                   /* \g means send query */
1110         if (!optarg)
1111             settings->gfname = NULL;
1112         else if (!(settings->gfname = strdup(optarg))) {
1113             perror("malloc");
1114             exit(1);
1115         }
1116         status = 0;
1117         break;
1118     case 'h':                   /* help */
1119         {
1120             do_help(optarg);
1121             break;
1122         }
1123     case 'i':                   /* \i is include file */
1124         {
1125             FILE           *fd;
1126
1127             if (!optarg) {
1128                 fprintf(stderr, "\\i must be followed by a file name\n");
1129                 break;
1130             }
1131             if ((fd = fopen(optarg, "r")) == NULL) {
1132                 fprintf(stderr, "file named %s could not be opened\n", optarg);
1133                 break;
1134             }
1135             MainLoop(settings, fd);
1136             fclose(fd);
1137             break;
1138         }
1139     case 'l':                   /* \l is list database */
1140         listAllDbs(settings);
1141         break;
1142     case 'H':
1143         if (toggle(settings, &settings->opt.html3, "HTML3.0 tabular output"))
1144             settings->opt.standard = 0;
1145         break;
1146     case 'o':
1147         setFout(settings, optarg);
1148         break;
1149     case 'p':
1150         if (query) {
1151             fputs(query, stdout);
1152             fputc('\n', stdout);
1153         }
1154         break;
1155     case 'q':                   /* \q is quit */
1156         status = 2;
1157         break;
1158     case 'r':                   /* reset(clear) the buffer */
1159         query[0] = '\0';
1160         if (!settings->quiet)
1161             fprintf(stderr, "buffer reset(cleared)\n");
1162         break;
1163     case 's':                   /* \s is save history to a file */
1164         if (!optarg)
1165             optarg = "/dev/tty";
1166 #ifdef HAVE_HISTORY
1167         if (write_history(optarg) != 0)
1168             fprintf(stderr, "cannot write history to %s\n", optarg);
1169 #endif
1170         break;
1171     case 'm':                   /* monitor like type-setting */
1172         if (toggle(settings, &settings->opt.standard, "standard SQL separaters and padding")) {
1173             settings->opt.html3 = settings->opt.expanded = 0;
1174             settings->opt.align = settings->opt.header = 1;
1175             if (settings->opt.fieldSep)
1176                 free(settings->opt.fieldSep);
1177             settings->opt.fieldSep = strdup("|");
1178             if (!settings->quiet)
1179                 fprintf(stderr, "field separater changed to '%s'\n", settings->opt.fieldSep);
1180         } else {
1181             if (settings->opt.fieldSep)
1182                 free(settings->opt.fieldSep);
1183             settings->opt.fieldSep = strdup(DEFAULT_FIELD_SEP);
1184             if (!settings->quiet)
1185                 fprintf(stderr, "field separater changed to '%s'\n", settings->opt.fieldSep);
1186         }
1187         break;
1188     case 't':                   /* toggle headers */
1189         toggle(settings, &settings->opt.header, "output headings and row count");
1190         break;
1191     case 'T':                   /* define html <table ...> option */
1192         if (settings->opt.tableOpt)
1193             free(settings->opt.tableOpt);
1194         if (!optarg)
1195             settings->opt.tableOpt = NULL;
1196         else if (!(settings->opt.tableOpt = strdup(optarg))) {
1197             perror("malloc");
1198             exit(1);
1199         }
1200         break;
1201     case 'x':
1202         toggle(settings, &settings->opt.expanded, "expanded table representation");
1203         break;
1204     case '!':
1205         do_shell(optarg);
1206         break;
1207     default:
1208     case '?':                   /* \? is help */
1209         slashUsage(settings);
1210         break;
1211     }
1212     free(cmd);
1213     return status;
1214 }
1215
1216 /*
1217  * MainLoop: main processing loop for reading lines of input and sending them
1218  * to the backend
1219  * 
1220  * this loop is re-entrant.  May be called by \i command which reads input from
1221  * a file
1222  * 
1223  * db_ptr must be initialized and set
1224  */
1225
1226 int
1227 MainLoop(PsqlSettings * settings, FILE * source)
1228 {
1229     char           *line;       /* line of input */
1230     int             len;        /* length of the line */
1231     char            query[MAX_QUERY_BUFFER];    /* multi-line query storage */
1232     int             successResult = 1;
1233     int             slashCmdStatus = 0;
1234     /*
1235      * slashCmdStatus can be: 0 - send currently constructed query to backend
1236      * (i.e. we got a \g) 1 - skip processing of this line, continue building
1237      * up query 2 - terminate processing of this query entirely 3 - new query
1238      * supplied by edit
1239      */
1240
1241     bool            querySent = false;
1242     bool            interactive;
1243     READ_ROUTINE    GetNextLine;
1244     bool            eof = 0;
1245     /* We've reached the end of our command input. */
1246     bool            success;
1247     bool            in_quote;
1248     bool            was_bslash; /* backslash */
1249     bool            was_dash;
1250     int             paren_level;
1251     char           *query_start;
1252
1253     interactive = ((source == stdin) && !settings->notty);
1254     if (interactive) {
1255         if (settings->prompt)
1256             free(settings->prompt);
1257         settings->prompt =
1258             malloc(strlen(PQdb(settings->db)) + strlen(PROMPT) + 1);
1259         if (settings->quiet)
1260             settings->prompt[0] = '\0';
1261         else
1262             sprintf(settings->prompt, "%s%s", PQdb(settings->db), PROMPT);
1263         if (settings->useReadline) {
1264 #ifdef HAVE_HISTORY
1265             using_history();
1266 #endif
1267             GetNextLine = gets_readline;
1268         } else
1269             GetNextLine = gets_noreadline;
1270     } else
1271         GetNextLine = gets_fromFile;
1272
1273     query[0] = '\0';
1274     in_quote = false;
1275     paren_level = 0;
1276     slashCmdStatus = -1;        /* set default */
1277
1278     /* main loop for getting queries and executing them */
1279     while (!eof) {
1280         if (slashCmdStatus == 3) {
1281             paren_level = 0;
1282             line = strdup(query);
1283             query[0] = '\0';
1284         } else {
1285             if (interactive && !settings->quiet) {
1286                 if (in_quote)
1287                     settings->prompt[strlen(settings->prompt)-3] = '\'';
1288                 else if (query[0] != '\0' && !querySent)
1289                     settings->prompt[strlen(settings->prompt)-3] = '-';
1290                 else
1291                     settings->prompt[strlen(settings->prompt)-3] = '=';
1292             }
1293             line = GetNextLine(settings->prompt, source);
1294 #ifdef HAVE_HISTORY
1295             if (interactive && settings->useReadline && line != NULL)
1296                 add_history(line);      /* save non-empty lines in history */
1297 #endif
1298         }
1299
1300         query_start = line;
1301
1302         if (line == NULL) {     /* No more input.  Time to quit */
1303             if (!settings->quiet)
1304                 printf("EOF\n");        /* Goes on prompt line */
1305             eof = true;
1306         } else {
1307             /* remove whitespaces on the right, incl. \n's */
1308             line = rightTrim(line);
1309
1310             if (!interactive && !settings->singleStep && !settings->quiet)
1311                 fprintf(stderr, "%s\n", line);
1312
1313             if (line[0] == '\0') {
1314                 free(line);
1315                 continue;
1316             }
1317
1318             len = strlen(line);
1319
1320             if (settings->singleLineMode) {
1321                 SendQuery(&success, settings, line, false, false, 0);
1322                 successResult &= success;
1323                 querySent = true;
1324             } else {
1325                 int             i;
1326                 was_bslash = false;
1327                 was_dash = false;
1328
1329                 for (i = 0; i < len; i++) {
1330                     if (!in_quote && line[i] == '\\') {
1331                         char            hold_char = line[i];
1332
1333                         line[i] = '\0';
1334                         if (query_start[0] != '\0') {
1335                             if (query[0] != '\0') {
1336                                 strcat(query, "\n");
1337                                 strcat(query, query_start);
1338                             } else
1339                                 strcpy(query, query_start);
1340                         }
1341                         line[i] = hold_char;
1342                         query_start = line + i;
1343                         break;  /* handle command */
1344                     }
1345                     if (querySent && !isspace(line[i])) {
1346                         query[0] = '\0';
1347                         querySent = false;
1348                     }
1349                     if (!in_quote && was_dash && line[i] == '-') {
1350                         /* print comment at top of query */
1351                         if (settings->singleStep)
1352                             fprintf(stdout, "%s\n", line + i - 1);
1353                         line[i - 1] = '\0';     /* remove comment */
1354                         break;
1355                     }
1356                     was_dash = false;
1357
1358                     if (!in_quote && !paren_level &&
1359                         line[i] == ';') {
1360                         char            hold_char = line[i + 1];
1361
1362                         line[i + 1] = '\0';
1363                         if (query_start[0] != '\0') {
1364                             if (query[0] != '\0') {
1365                                 strcat(query, "\n");
1366                                 strcat(query, query_start);
1367                             } else
1368                                 strcpy(query, query_start);
1369                         }
1370                         SendQuery(&success, settings, query, false, false, 0);
1371                         successResult &= success;
1372                         line[i + 1] = hold_char;
1373                         query_start = line + i + 1;
1374                         querySent = true;
1375                     }
1376                     if (was_bslash)
1377                         was_bslash = false;
1378                     else if (line[i] == '\\')
1379                         was_bslash = true;
1380                     else if (line[i] == '\'')
1381                         in_quote ^= 1;
1382                     else if (!in_quote && line[i] == '(')
1383                         paren_level++;
1384                     else if (!in_quote && paren_level && line[i] == ')')
1385                         paren_level--;
1386                     else if (!in_quote && line[i] == '-')
1387                         was_dash = true;
1388                 }
1389             }
1390
1391             slashCmdStatus = -1;
1392             /* slash commands have to be on their own line */
1393             if (!in_quote && query_start[0] == '\\') {
1394                 slashCmdStatus = HandleSlashCmds(settings,
1395                                                  query_start,
1396                                                  query);
1397                 if (slashCmdStatus == 1) {
1398                     if (query[0] == '\0')
1399                         paren_level = 0;
1400                     free(line);
1401                     continue;
1402                 }
1403                 if (slashCmdStatus == 2) {
1404                     free(line);
1405                     break;
1406                 }
1407             } else if (strlen(query) + strlen(query_start) > MAX_QUERY_BUFFER) {
1408                 fprintf(stderr, "query buffer max length of %d exceeded\n",
1409                         MAX_QUERY_BUFFER);
1410                 fprintf(stderr, "query line ignored\n");
1411             } else {
1412                 if (query_start[0] != '\0') {
1413                     querySent = false;
1414                     if (query[0] != '\0') {
1415                         strcat(query, "\n");
1416                         strcat(query, query_start);
1417                     } else
1418                         strcpy(query, query_start);
1419                 }
1420             }
1421
1422             if (slashCmdStatus == 0) {
1423                 SendQuery(&success, settings, query, false, false, 0);
1424                 successResult &= success;
1425                 querySent = true;
1426             }
1427             free(line);         /* free storage malloc'd by GetNextLine */
1428         }
1429     }                           /* while */
1430     return successResult;
1431 }
1432
1433 int
1434 main(int argc, char **argv)
1435 {
1436     extern char    *optarg;
1437     extern int      optind;
1438
1439     char           *dbname = NULL;
1440     char           *host = NULL;
1441     char           *port = NULL;
1442     char           *qfilename = NULL;
1443     char            errbuf[ERROR_MSG_LENGTH];
1444
1445     PsqlSettings    settings;
1446
1447     char           *singleQuery = NULL;
1448
1449     bool            listDatabases = 0;
1450     int             successResult = 1;
1451     bool            singleSlashCmd = 0;
1452     int             c;
1453
1454     memset(&settings, 0, sizeof settings);
1455     settings.opt.align = 1;
1456     settings.opt.header = 1;
1457     settings.queryFout = stdout;
1458     settings.opt.fieldSep = strdup(DEFAULT_FIELD_SEP);
1459     settings.opt.pager = 1;
1460     if (!isatty(0) || !isatty(1))
1461         settings.quiet = settings.notty = 1;
1462 #ifdef HAVE_LIBREADLINE
1463     else
1464         settings.useReadline = 1;
1465 #endif
1466
1467     while ((c = getopt(argc, argv, "Aa:c:d:ef:F:lh:Hnso:p:qStT:x")) != EOF) {
1468         switch (c) {
1469         case 'A':
1470             settings.opt.align = 0;
1471             break;
1472         case 'a':
1473             fe_setauthsvc(optarg, errbuf);
1474             break;
1475         case 'c':
1476             singleQuery = optarg;
1477             if (singleQuery[0] == '\\') {
1478                 singleSlashCmd = 1;
1479             }
1480             break;
1481         case 'd':
1482             dbname = optarg;
1483             break;
1484         case 'e':
1485             settings.echoQuery = 1;
1486             break;
1487         case 'f':
1488             qfilename = optarg;
1489             break;
1490         case 'F':
1491             settings.opt.fieldSep = optarg;
1492             break;
1493         case 'l':
1494             listDatabases = 1;
1495             break;
1496         case 'h':
1497             host = optarg;
1498             break;
1499         case 'H':
1500             settings.opt.html3 = 1;
1501             break;
1502         case 'n':
1503             settings.useReadline = 0;
1504             break;
1505         case 'o':
1506             setFout(&settings, optarg);
1507             break;
1508         case 'p':
1509             port = optarg;
1510             break;
1511         case 'q':
1512             settings.quiet = 1;
1513             break;
1514         case 's':
1515             settings.singleStep = 1;
1516             break;
1517         case 'S':
1518             settings.singleLineMode = 1;
1519             break;
1520         case 't':
1521             settings.opt.header = 0;
1522             break;
1523         case 'T':
1524             settings.opt.tableOpt = optarg;
1525             break;
1526         case 'x':
1527             settings.opt.expanded = 1;
1528             break;
1529         default:
1530             usage(argv[0]);
1531             break;
1532         }
1533     }
1534     /* if we still have an argument, use it as the database name */
1535     if (argc - optind == 1)
1536         dbname = argv[optind];
1537
1538     if (listDatabases)
1539         dbname = "template1";
1540
1541     settings.db = PQsetdb(host, port, NULL, NULL, dbname);
1542     dbname = PQdb(settings.db);
1543
1544     if (PQstatus(settings.db) == CONNECTION_BAD) {
1545         fprintf(stderr, "Connection to database '%s' failed.\n", dbname);
1546         fprintf(stderr, "%s", PQerrorMessage(settings.db));
1547         exit(1);
1548     }
1549     if (listDatabases) {
1550         exit(listAllDbs(&settings));
1551     }
1552     if (!settings.quiet && !singleQuery && !qfilename) {
1553         printf("Welcome to the POSTGRESQL interactive sql monitor:\n");
1554         printf("  Please read the file COPYRIGHT for copyright terms "
1555                "of POSTGRESQL\n\n");
1556         printf("   type \\? for help on slash commands\n");
1557         printf("   type \\q to quit\n");
1558         printf("   type \\g or terminate with semicolon to execute query\n");
1559         printf(" You are currently connected to the database: %s\n\n", dbname);
1560     }
1561     if (qfilename || singleSlashCmd) {
1562         /*
1563          * read in a file full of queries instead of reading in queries
1564          * interactively
1565          */
1566         char           *line;
1567
1568         if (singleSlashCmd) {
1569             /* Not really a query, but "Do what I mean, not what I say." */
1570             line = singleQuery;
1571         } else {
1572             line = malloc(strlen(qfilename) + 5);
1573             sprintf(line, "\\i %s", qfilename);
1574         }
1575         HandleSlashCmds(&settings, line, "");
1576     } else {
1577         if (singleQuery) {
1578             bool            success;    /* The query succeeded at the backend */
1579             SendQuery(&success, &settings, singleQuery, false, false, 0);
1580             successResult = success;
1581         } else
1582             successResult = MainLoop(&settings, stdin);
1583     }
1584
1585     PQfinish(settings.db);
1586
1587     return !successResult;
1588 }
1589
1590 #define COPYBUFSIZ  8192
1591
1592 static void
1593 handleCopyOut(PGresult * res, bool quiet, FILE * copystream)
1594 {
1595     bool            copydone;
1596     char            copybuf[COPYBUFSIZ];
1597     int             ret;
1598
1599     copydone = false;           /* Can't be done; haven't started. */
1600
1601     while (!copydone) {
1602         ret = PQgetline(res->conn, copybuf, COPYBUFSIZ);
1603
1604         if (copybuf[0] == '\\' &&
1605             copybuf[1] == '.' &&
1606             copybuf[2] == '\0') {
1607             copydone = true;    /* don't print this... */
1608         } else {
1609             fputs(copybuf, copystream);
1610             switch (ret) {
1611             case EOF:
1612                 copydone = true;
1613                 /* FALLTHROUGH */
1614             case 0:
1615                 fputc('\n', copystream);
1616                 break;
1617             case 1:
1618                 break;
1619             }
1620         }
1621     }
1622     fflush(copystream);
1623     PQendcopy(res->conn);
1624 }
1625
1626
1627
1628 static void
1629 handleCopyIn(PGresult * res, const bool mustprompt, FILE * copystream)
1630 {
1631     bool            copydone = false;
1632     bool            firstload;
1633     bool            linedone;
1634     char            copybuf[COPYBUFSIZ];
1635     char           *s;
1636     int             buflen;
1637     int             c;
1638
1639     if (mustprompt) {
1640         fputs("Enter info followed by a newline\n", stdout);
1641         fputs("End with a backslash and a "
1642               "period on a line by itself.\n", stdout);
1643     }
1644     while (!copydone) {         /* for each input line ... */
1645         if (mustprompt) {
1646             fputs(">> ", stdout);
1647             fflush(stdout);
1648         }
1649         firstload = true;
1650         linedone = false;
1651         while (!linedone) {     /* for each buffer ... */
1652             s = copybuf;
1653             buflen = COPYBUFSIZ;
1654             for (; buflen > 1 &&
1655                  !(linedone = (c = getc(copystream)) == '\n' || c == EOF);
1656                  --buflen) {
1657                 *s++ = c;
1658             }
1659             if (c == EOF) {
1660                 PQputline(res->conn, "\\.");
1661                 copydone = true;
1662                 break;
1663             }
1664             *s = '\0';
1665             PQputline(res->conn, copybuf);
1666             if (firstload) {
1667                 if (!strcmp(copybuf, "\\.")) {
1668                     copydone = true;
1669                 }
1670                 firstload = false;
1671             }
1672         }
1673         PQputline(res->conn, "\n");
1674     }
1675     PQendcopy(res->conn);
1676 }
1677
1678
1679
1680 /*
1681  * try to open fname and return a FILE *, if it fails, use stdout, instead
1682  */
1683
1684 FILE           *
1685 setFout(PsqlSettings * ps, char *fname)
1686 {
1687     if (ps->queryFout && ps->queryFout != stdout) {
1688         if (ps->pipe)
1689             pclose(ps->queryFout);
1690         else
1691             fclose(ps->queryFout);
1692     }
1693     if (!fname) {
1694         ps->queryFout = stdout;
1695         pqsignal(SIGPIPE, SIG_DFL);
1696     }
1697     else {
1698         if (*fname == '|') {
1699             pqsignal(SIGPIPE, SIG_IGN);
1700             ps->queryFout = popen(fname + 1, "w");
1701             ps->pipe = 1;
1702         } else {
1703             ps->queryFout = fopen(fname, "w");
1704             pqsignal(SIGPIPE, SIG_DFL);
1705             ps->pipe = 0;
1706         }
1707         if (!ps->queryFout) {
1708             perror(fname);
1709             ps->queryFout = stdout;
1710         }
1711     }
1712     return ps->queryFout;
1713 }