1 /*-------------------------------------------------------------------------
4 * an interactive front-end to postgres95
6 * Copyright (c) 1996, Regents of the University of California
10 * $Header: /cvsroot/pgsql/src/bin/psql/Attic/psql.c,v 1.6 1996/07/23 03:03:43 scrappy Exp $
12 *-------------------------------------------------------------------------
17 #include <sys/types.h>
22 #include "stringutils.h"
27 extern char *readline(char *); /* in rlstubs.c */
29 /* from the GNU readline library */
34 #include <readline/readline.h>
39 #define MAX_QUERY_BUFFER 20000
40 #define MAX_FIELD_SEP_LENGTH 40
42 #define COPYBUFSIZ 8192
44 #define DEFAULT_FIELD_SEP " "
45 #define DEFAULT_EDITOR "vi"
46 #define DEFAULT_SHELL "/bin/sh"
48 typedef struct _psqlSettings {
49 int echoQuery; /* if 1, echo the query before sending it */
50 int quiet; /* run quietly, no messages, no promt */
51 int singleStep; /* if 1, prompt for each query */
52 int singleLineMode; /* if 1, query terminated by newline */
53 int useReadline; /* use the readline routines or not */
54 int printHeader; /* print output field headers or not */
55 int fillAlign; /* fill align the fields */
56 FILE *queryFout; /* where to send the query results */
57 char fieldSep[MAX_FIELD_SEP_LENGTH]; /* field separator */
60 /* declarations for functions in this file */
61 static void usage(char* progname);
62 static void slashUsage();
63 static void handleCopyOut(PGresult *res, int quiet);
64 static void handleCopyIn(PGresult *res, int quiet);
65 static int tableList(PGconn* conn, int deep_tablelist);
66 static int tableDesc(PGconn* conn, char* table);
68 char* gets_noreadline(char* prompt, FILE* source);
69 char* gets_readline(char* prompt, FILE* source);
70 char* gets_fromFile(char* prompt, FILE* source);
71 int listAllDbs(PGconn *db, PsqlSettings *settings);
72 int SendQuery(PGconn* db, char* query, PsqlSettings *settings);
73 int HandleSlashCmds(PGconn** db_ptr,
77 PsqlSettings *settings);
78 int MainLoop(PGconn** db_ptr, FILE *source, PsqlSettings *settings);
79 FILE* setFout(char *fname);
84 * print out usage for command line arguments
90 fprintf(stderr,"Usage: %s [options] [dbname]\n",progname);
91 fprintf(stderr,"\t -a authsvc set authentication service\n");
92 fprintf(stderr,"\t -A turn off fill-justification when printing out attributes\n");
93 fprintf(stderr,"\t -c query run single query (slash commands too)\n");
94 fprintf(stderr,"\t -d dbName specify database name\n");
95 fprintf(stderr,"\t -e echo the query sent to the backend\n");
96 fprintf(stderr,"\t -f filename use file as a source of queries\n");
97 fprintf(stderr,"\t -F sep set the field separator (default is " ")\n");
98 fprintf(stderr,"\t -h help information\n");
99 fprintf(stderr,"\t -H host set database server host\n");
100 fprintf(stderr,"\t -l list available databases\n");
101 fprintf(stderr,"\t -n don't use readline library\n");
102 fprintf(stderr,"\t -o filename send output to filename\n");
103 fprintf(stderr,"\t -p port set port number\n");
104 fprintf(stderr,"\t -q run quietly (no messages, no prompts)\n");
105 fprintf(stderr,"\t -s single step mode (prompts for each query)\n");
106 fprintf(stderr,"\t -S single line mode (i.e. query terminated by newline)\n");
107 fprintf(stderr,"\t -T turn off printing of attribute names\n");
113 * print out usage for the backslash commands
119 fprintf(stderr,"\t \\a -- toggle fill-justification of display of attributes\n");
120 fprintf(stderr,"\t \\d [<table>] -- list tables in database or columns in <table>\n");
121 fprintf(stderr,"\t \\d * -- list tables in database and columns in all tables\n");
122 fprintf(stderr,"\t \\e [<fname>] -- edit the current query buffer or <fname>\n");
123 fprintf(stderr,"\t \\f <sep> -- change field separator\n");
124 fprintf(stderr,"\t \\g -- query to backend\n");
125 fprintf(stderr,"\t \\h <command> -- help on syntax of sql commands\n");
126 fprintf(stderr,"\t \\h * -- complete description of all sql commands\n");
127 fprintf(stderr,"\t \\g -- send query to backend\n");
128 fprintf(stderr,"\t \\i <fname> -- read queries from filename\n");
129 fprintf(stderr,"\t \\l -- list all databases\n");
130 fprintf(stderr,"\t \\o [<fname>] -- send query results file named <fname> or stdout\n");
131 fprintf(stderr,"\t \\p -- print the current query buffer\n");
132 fprintf(stderr,"\t \\q -- quit\n");
133 fprintf(stderr,"\t \\s [<fname>] -- save or print history\n");
134 fprintf(stderr,"\t \\t -- toggle output field headers (defaults to on)\n");
135 fprintf(stderr,"\t \\! [<cmd>] -- shell escape\n");
136 fprintf(stderr,"\t \\? -- help\n");
142 * list all the databases in the system
143 * returns 0 if all went well
148 listAllDbs(PGconn *db, PsqlSettings *settings)
151 char* query = "select * from pg_database;";
153 results = PQexec(db, query);
154 if (results == NULL) {
155 fprintf(stderr,"%s", PQerrorMessage(db));
159 if (PQresultStatus(results) != PGRES_TUPLES_OK)
161 fprintf(stderr,"Unexpected error from executing: %s\n", query);
166 PQdisplayTuples(results,
170 settings->printHeader,
178 * tableList (PGconn* conn)
180 * List The Database Tables
181 * returns 0 if all went well
185 tableList (PGconn* conn, int deep_tablelist)
197 strcat(listbuf,"SELECT usename, relname, relkind, relhasrules");
198 strcat(listbuf," FROM pg_class, pg_user ");
199 strcat(listbuf,"WHERE ( relkind = 'r' OR relkind = 'i') ");
200 strcat(listbuf," and relname !~ '^pg_'");
201 strcat(listbuf," and relname !~ '^Inv[0-9]+'");
202 /* the usesysid = relowner won't work on stock 1.0 dbs, need to
203 add in the int4oideq function */
204 strcat(listbuf," and usesysid = relowner");
205 strcat(listbuf," ORDER BY relname ");
206 res = PQexec(conn,listbuf);
208 fprintf(stderr,"%s", PQerrorMessage(conn));
212 if ((PQresultStatus(res) != PGRES_TUPLES_OK) || (PQntuples(res) <= 0)) {
213 fprintf(stderr,"No tables found in database %s.\n", PQdb(conn));
218 /* first, print out the attribute names */
219 nColumns = PQntuples(res);
222 if ( deep_tablelist ) {
223 /* describe everything here */
225 table = (char**)malloc(nColumns * sizeof(char*));
229 /* load table table*/
230 for (i=0; i < nColumns; i++) {
231 table[i] = (char *) malloc(PQgetlength(res,i,1) * sizeof(char) + 1);
232 if ( table[i] == NULL )
234 strcpy(table[i],PQgetvalue(res,i,1));
238 for (i=0; i < nColumns; i++) {
239 tableDesc(conn,table[i]);
244 /* Display the information */
246 printf ("\nDatabase = %s\n", PQdb(conn));
247 printf (" +------------------+----------------------------------+----------+\n");
248 printf (" | Owner | Relation | Type |\n");
249 printf (" +------------------+----------------------------------+----------+\n");
251 /* next, print out the instances */
252 for (i=0; i < PQntuples(res); i++) {
253 printf (" | %-16.16s", PQgetvalue(res,i,0));
254 printf (" | %-32.32s | ", PQgetvalue(res,i,1));
255 rk = PQgetvalue(res,i,2);
256 rr = PQgetvalue(res,i,3);
257 if (strcmp(rk, "r") == 0)
258 printf ("%-8.8s |", (rr[0] == 't') ? "view?" : "table" );
260 printf ("%-8.8s |", "index");
263 printf (" +------------------+----------------------------------+----------+\n");
269 fprintf (stderr, "Couldn't find any tables!\n");
275 * Describe a table (PGconn* conn, char* table)
277 * Describe the columns in a database table.
278 * returns 0 if all went well
283 tableDesc (PGconn* conn, char* table)
293 /* Build the query */
296 strcat(descbuf,"SELECT a.attnum, a.attname, t.typname, a.attlen");
297 strcat(descbuf," FROM pg_class c, pg_attribute a, pg_type t ");
298 strcat(descbuf," WHERE c.relname = '");
299 strcat(descbuf,table);
301 strcat(descbuf," and a.attnum > 0 ");
302 strcat(descbuf," and a.attrelid = c.oid ");
303 strcat(descbuf," and a.atttypid = t.oid ");
304 strcat(descbuf," ORDER BY attnum ");
305 res = PQexec(conn,descbuf);
307 fprintf(stderr,"%s", PQerrorMessage(conn));
310 if ((PQresultStatus(res) != PGRES_TUPLES_OK) || (PQntuples(res) <= 0)) {
311 fprintf(stderr,"Couldn't find table %s!\n", table);
315 /* first, print out the attribute names */
316 nColumns = PQntuples(res);
320 ** Display the information
323 printf ("\nTable = %s\n", table);
324 printf ("+----------------------------------+----------------------------------+-------+\n");
325 printf ("| Field | Type | Length|\n");
326 printf ("+----------------------------------+----------------------------------+-------+\n");
328 /* next, print out the instances */
329 for (i=0; i < PQntuples(res); i++) {
330 printf ("| %-32.32s | ", PQgetvalue(res,i,1));
331 rtype = PQgetvalue(res,i,2);
332 rsize = atoi(PQgetvalue(res,i,3));
333 if (strcmp(rtype, "text") == 0) {
334 printf ("%-32.32s |", rtype);
335 printf ("%-6s |", "var" );
337 else if (strcmp(rtype, "bpchar") == 0) {
338 printf ("%-32.32s |", "char");
339 printf ("%-6i |", rsize > 0 ? rsize - 4 : 0 );
341 else if (strcmp(rtype, "varchar") == 0) {
342 printf ("%-32.32s |", rtype);
343 printf ("%-6i |", rsize > 0 ? rsize - 4 : 0 );
346 /* array types start with an underscore */
348 printf ("%-32.32s |", rtype);
351 newname = malloc(strlen(rtype) + 2);
352 strcpy(newname, rtype+1);
353 strcat(newname, "[]");
354 printf ("%-32.32s |", newname);
358 printf ("%-6i |", rsize);
360 printf ("%-6s |", "var");
364 printf ("+----------------------------------+----------------------------------+-------+\n");
370 fprintf (stderr, "Couldn't find table %s!\n", table);
375 typedef char* (*READ_ROUTINE)(char* prompt, FILE* source);
377 /* gets_noreadline prompt source
378 gets a line of input without calling readline, the source is ignored
381 gets_noreadline(char* prompt, FILE* source)
383 fputs(prompt, stdout);
385 return(gets_fromFile(prompt,stdin));
389 * gets_readline prompt source
390 * the routine to get input from GNU readline(), the source is ignored
391 * the prompt argument is used as the prompting string
394 gets_readline(char* prompt, FILE* source)
396 return (readline(prompt));
401 * gets_fromFile prompt source
403 * the routine to read from a file, the prompt argument is ignored
404 * the source argument is a FILE*
407 gets_fromFile(char* prompt, FILE* source)
412 line = malloc(MAX_QUERY_BUFFER+1);
414 /* read up to MAX_QUERY_BUFFER characters */
415 if (fgets(line, MAX_QUERY_BUFFER, source) == NULL)
418 line[MAX_QUERY_BUFFER-1] = '\0';
420 if (len == MAX_QUERY_BUFFER)
422 fprintf(stderr, "line read exceeds maximum length. Truncating at %d\n", MAX_QUERY_BUFFER);
430 SendQuery: send the query string to the backend
432 * return 0 if the query executed successfully
433 * returns 1 otherwise
436 SendQuery(PGconn* db, char* query, PsqlSettings *settings)
442 if (settings->singleStep)
443 fprintf(stdout, "\n*******************************************************************************\n");
445 if (settings->echoQuery || settings->singleStep) {
446 fprintf(stderr,"QUERY: %s\n",query);
450 if (settings->singleStep) {
451 fprintf(stdout, "\n*******************************************************************************\n");
453 printf("\npress return to continue ..\n");
454 gets_fromFile("",stdin);
457 results = PQexec(db, query);
458 if (results == NULL) {
459 fprintf(stderr,"%s",PQerrorMessage(db));
463 switch (PQresultStatus(results)) {
464 case PGRES_TUPLES_OK:
465 PQdisplayTuples(results,
469 settings->printHeader,
473 case PGRES_EMPTY_QUERY:
476 case PGRES_COMMAND_OK:
477 if (!settings->quiet)
478 fprintf(stdout,"%s\n",PQcmdStatus(results));
481 handleCopyOut(results, settings->quiet);
484 handleCopyIn(results, settings->quiet);
486 case PGRES_NONFATAL_ERROR:
487 case PGRES_FATAL_ERROR:
488 case PGRES_BAD_RESPONSE:
490 fprintf(stderr,"%s",PQerrorMessage(db));
495 /* check for asynchronous returns */
496 notify = PQnotifies(db);
498 fprintf(stderr,"ASYNC NOTIFY of '%s' from backend pid '%d' received\n",
499 notify->relname, notify->be_pid);
510 Handles all the different commands that start with \
511 db_ptr is a pointer to the TgDb* structure
512 line is the current input line
513 prompt_ptr is a pointer to the prompt string,
514 a pointer is used because the prompt can be used with
515 a connection to a new database
517 0 - send currently constructed query to backend (i.e. we got a \g)
518 1 - skip processing of this line, continue building up query
519 2 - terminate processing of this query entirely
522 HandleSlashCmds(PGconn** db_ptr,
526 PsqlSettings *settings)
529 PGconn* db = *db_ptr;
530 char* dbname = PQdb(db);
536 optarg = leftTrim(line+2);
539 case 'a': /* toggles to fill fields on output */
540 if (settings->fillAlign)
541 settings->fillAlign = 0;
543 settings->fillAlign = 1;
544 if (!settings->quiet)
545 fprintf(stderr,"turning %s fill-justification\n",
546 (settings->fillAlign) ? "on" : "off" );
548 case 'c': /* \c means connect to new database */
551 fprintf(stderr,"\\c must be followed by a database name\n");
555 if (strcmp(optarg, dbname) == 0) {
556 fprintf(stderr,"already connected to %s\n", dbname);
563 printf("closing connection to database:%s\n", dbname);
565 db = PQsetdb(PQhost(olddb), PQport(olddb), NULL, NULL, optarg);
567 printf("connecting to new database: %s\n", optarg);
568 if (PQstatus(db) == CONNECTION_BAD) {
569 fprintf(stderr,"%s\n", PQerrorMessage(db));
570 printf("reconnecting to %s\n", dbname);
571 db = PQsetdb(PQhost(olddb), PQport(olddb),
574 if (PQstatus(db) == CONNECTION_BAD) {
576 "could not reconnect to %s. exiting\n", dbname);
584 *prompt_ptr = malloc(strlen(optarg) + 10);
585 sprintf(*prompt_ptr,"%s=> ", optarg);
591 case 'd': /* \d describe tables or columns in a table */
598 if ( strcmp(optarg,"*") == 0 ) {
603 tableDesc(db,optarg);
612 int ql = strlen(query);
622 sprintf(s, "/tmp/psql.%d.%d", geteuid(), getpid());
626 if ((fd=open(s, O_EXCL|O_CREAT|O_WRONLY, 0600))==-1)
631 if (query[ql-1]!='\n')
633 if (write(fd, query, ql)!=ql)
646 editorName = getenv("EDITOR");
647 if (editorName == NULL)
648 editorName = DEFAULT_EDITOR;
649 sprintf(sys, "exec %s %s", editorName, s);
652 if ((fd=open(s, O_RDONLY))==-1)
658 if ((cc=read(fd, query, MAX_QUERY_BUFFER))==-1)
671 if (query[strlen(query)-1]==';')
677 strcpy(settings->fieldSep,optarg);
679 strcpy(settings->fieldSep,DEFAULT_FIELD_SEP);
681 case 'g': /* \g means send query */
684 case 'i': /* \i is include file */
689 fprintf(stderr,"\\i must be followed by a file name\n");
694 if ( (fd = fopen(optarg, "r")) == NULL)
696 fprintf(stderr,"file named %s could not be opened\n",optarg);
700 MainLoop(&db, fd, settings);
712 printf("type \\h <cmd> where <cmd> is one of the following:\n");
714 while (QL_HELP[i].cmd != NULL)
716 printf("\t%s\n", QL_HELP[i].cmd);
719 printf("type \\h * for a complete description of all commands\n");
726 while (QL_HELP[numCmds++].cmd != NULL);
728 numCmds = numCmds - 1;
730 if ( strcmp(cmd,"*") == 0 ) {
734 for (i=0; i<numCmds;i++) {
735 if (strcmp(QL_HELP[i].cmd, cmd) == 0 || all_help) {
736 printf("Command: %s\n",QL_HELP[i].cmd);
737 printf("Description: %s\n", QL_HELP[i].help);
739 printf("%s\n", QL_HELP[i].syntax);
748 if (i == numCmds && ! all_help)
749 printf("command not found, try \\h with no arguments to see available help\n");
754 case 'l': /* \l is list database */
755 listAllDbs(db,settings);
759 settings->queryFout = setFout(optarg);
763 fputs(query, stdout);
768 case 'q': /* \q is quit */
775 case 's': /* \s is save history to a file */
780 fprintf(stderr,"\\s must be followed by a file name\n");
786 if (write_history(fname) != 0)
788 fprintf(stderr,"cannot write history to %s\n",fname);
794 if ( settings->printHeader )
795 settings->printHeader = 0;
797 settings->printHeader = 1;
798 if (!settings->quiet)
799 fprintf(stderr,"turning %s printing of field headers\n",
800 (settings->printHeader) ? "on" : "off" );
806 shellName = getenv("SHELL");
807 if (shellName == NULL)
808 shellName = DEFAULT_SHELL;
809 sprintf(sys,"exec %s", shellName);
816 case '?': /* \? is help */
825 MainLoop: main processing loop for reading lines of input
826 and sending them to the backend
828 this loop is re-entrant. May be called by \i command
829 which reads input from a file
831 *db_ptr must be initialized and set
834 MainLoop(PGconn** db_ptr,
836 PsqlSettings *settings)
838 char* prompt; /* readline prompt */
839 char* line; /* line of input*/
840 int len; /* length of the line */
841 char query[MAX_QUERY_BUFFER]; /* multi-line query storage */
842 PGconn* db = *db_ptr;
843 char* dbname = PQdb(db);
846 int slashCmdStatus = 0;
847 /* slashCmdStatus can be:
848 0 - send currently constructed query to backend (i.e. we got a \g)
849 1 - skip processing of this line, continue building up query
850 2 - terminate processing of this query entirely
855 READ_ROUTINE GetNextLine;
857 interactive = (source == stdin);
860 prompt = malloc(strlen(dbname) + 10);
864 sprintf(prompt,"%s=> ", dbname);
865 if (settings->useReadline) {
867 GetNextLine = gets_readline;
869 GetNextLine = gets_noreadline;
873 GetNextLine = gets_fromFile;
877 /* main loop for getting queries and executing them */
878 while ((line = GetNextLine(prompt, source)) != NULL)
881 line = rightTrim(line); /* remove whitespaces on the right, incl. \n's */
883 if (line[0] == '\0') {
888 /* filter out comment lines that begin with --,
889 this could be incorrect if -- is part of a quoted string.
890 But we won't go through the trouble of detecting that. If you have
891 -- in your quoted string, be careful and don't start a line with it*/
892 if (line[0] == '-' && line[1] == '-') {
893 if (settings->singleStep) /* in single step mode, show comments */
894 fprintf(stdout,"%s\n",line);
901 if (interactive && settings->useReadline)
902 add_history(line); /* save non-empty lines in history */
904 /* do the query immediately if we are doing single line queries
905 or if the last character is a semicolon */
906 send_query = settings->singleLineMode || (line[len-1] == ';') ;
908 /* normally, \ commands have to be start the line,
909 but for backwards compatibility with monitor,
910 check for \g at the end of line */
911 if (len > 2 && !send_query)
913 if (line[len-1]=='g' && line[len-2]=='\\')
920 /* slash commands have to be on their own line */
921 if (line[0] == '\\') {
922 slashCmdStatus = HandleSlashCmds(db_ptr,
927 db = *db_ptr; /* in case \c changed the database */
928 if (slashCmdStatus == 1)
930 if (slashCmdStatus == 2)
932 if (slashCmdStatus == 0)
936 if (strlen(query) + len > MAX_QUERY_BUFFER)
938 fprintf(stderr,"query buffer max length of %d exceeded\n",MAX_QUERY_BUFFER);
939 fprintf(stderr,"query line ignored\n");
942 if (query[0]!='\0') {
949 if (send_query && query[0] != '\0')
951 /* echo the line read from the file,
952 unless we are in single_step mode, because single_step mode
954 if (!interactive && !settings->singleStep)
955 fprintf(stderr,"%s\n",query);
957 exitStatus = SendQuery(db, query, settings);
961 free(line); /* free storage malloc'd by GetNextLine */
967 main(int argc, char** argv)
970 extern int optind, opterr;
976 char* qfilename = NULL;
977 char errbuf[ERROR_MSG_LENGTH];
979 PsqlSettings settings;
981 char* singleQuery = NULL;
983 int listDatabases = 0 ;
985 int singleSlashCmd = 0;
990 settings.useReadline = 0;
992 settings.useReadline = 1;
996 settings.fillAlign = 1;
997 settings.printHeader = 1;
998 settings.echoQuery = 0;
999 settings.singleStep = 0;
1000 settings.singleLineMode = 0;
1001 settings.queryFout = stdout;
1002 strcpy(settings.fieldSep, DEFAULT_FIELD_SEP);
1004 while ((c = getopt(argc, argv, "Aa:c:d:ef:F:lhH:nso:p:qST")) != EOF) {
1007 settings.fillAlign = 0;
1010 fe_setauthsvc(optarg, errbuf);
1013 singleQuery = optarg;
1014 if ( singleQuery[0] == '\\' ) {
1022 settings.echoQuery = 1;
1028 strncpy(settings.fieldSep,optarg,MAX_FIELD_SEP_LENGTH);
1037 settings.useReadline = 0;
1040 settings.queryFout = setFout(optarg);
1049 settings.singleStep = 1;
1052 settings.singleLineMode = 1;
1055 settings.printHeader = 0;
1063 /* if we still have an argument, use it as the database name */
1064 if (argc - optind == 1)
1065 dbname = argv[optind];
1068 dbname = "template1";
1070 db = PQsetdb(host, port, NULL, NULL, dbname);
1073 if (PQstatus(db) == CONNECTION_BAD) {
1074 fprintf(stderr,"Connection to database '%s' failed.\n", dbname);
1075 fprintf(stderr,"%s",PQerrorMessage(db));
1078 if (listDatabases) {
1079 exit(listAllDbs(db,&settings));
1082 if (!settings.quiet && !singleQuery && !qfilename) {
1083 printf("Welcome to the POSTGRES95 interactive sql monitor:\n");
1084 printf(" Please read the file COPYRIGHT for copyright terms of POSTGRES95\n\n");
1085 printf(" type \\? for help on slash commands\n");
1086 printf(" type \\q to quit\n");
1087 printf(" type \\g or terminate with semicolon to execute query\n");
1088 printf(" You are currently connected to the database: %s\n\n", dbname);
1091 if (qfilename || singleSlashCmd) {
1092 /* read in a file full of queries instead of reading in queries
1097 if ( singleSlashCmd ) {
1098 /* Not really a query, but "Do what I mean, not what I say." */
1102 line = malloc(strlen(qfilename) + 5);
1103 sprintf(line,"\\i %s", qfilename);
1105 HandleSlashCmds(&db, line, (char**)prompt, "", &settings);
1109 exitStatus = SendQuery(db, singleQuery, &settings);
1112 exitStatus = MainLoop(&db, stdin, &settings);
1122 handleCopyOut(PGresult *res, int quiet)
1124 bool copydone = false;
1125 char copybuf[COPYBUFSIZ];
1129 fprintf(stdout, "Copy command returns...\n");
1132 ret = PQgetline(res->conn, copybuf, COPYBUFSIZ);
1134 if (copybuf[0] == '.' && copybuf[1] =='\0') {
1135 copydone = true; /* don't print this... */
1137 fputs(copybuf, stdout);
1143 fputc('\n', stdout);
1151 PQendcopy(res->conn);
1156 handleCopyIn(PGresult *res, int quiet)
1158 bool copydone = false;
1161 char copybuf[COPYBUFSIZ];
1167 fputs("Enter info followed by a newline\n", stdout);
1168 fputs("End with a dot on a line by itself.\n", stdout);
1172 * eat extra newline still in input buffer
1176 if ((c = getc(stdin)) != '\n' && c != EOF) {
1177 (void) ungetc(c, stdin);
1180 while (!copydone) { /* for each input line ... */
1182 fputs(">> ", stdout);
1187 while (!linedone) { /* for each buffer ... */
1189 buflen = COPYBUFSIZ;
1190 for (; buflen > 1 &&
1191 !(linedone = (c = getc(stdin)) == '\n' || c == EOF);
1196 /* reading from stdin, but from a file */
1197 PQputline(res->conn, ".");
1202 PQputline(res->conn, copybuf);
1204 if (!strcmp(copybuf, ".")) {
1210 PQputline(res->conn, "\n");
1212 PQendcopy(res->conn);
1216 /* try to open fname and return a FILE*,
1217 if it fails, use stdout, instead */
1219 setFout(char *fname)
1226 queryFout = fopen(fname, "w");