2 * psql - the PostgreSQL interactive terminal
4 * Copyright 2000 by PostgreSQL Global Development Team
6 * $Header: /cvsroot/pgsql/src/bin/psql/command.c,v 1.14 2000/01/22 14:20:51 petere Exp $
17 #include <sys/types.h> /* for umask() */
18 #include <sys/stat.h> /* for umask(), stat() */
19 #include <unistd.h> /* for geteuid(), getpid(), stat() */
24 #include <pqexpbuffer.h>
26 #include "stringutils.h"
32 #include "large_obj.h"
36 #include "variables.h"
39 #include "../../interfaces/libpq/win32.h"
40 #define popen(x,y) _popen(x,y)
41 #define pclose(x) _pclose(x)
45 /* functions for use in this file */
47 static backslashResult exec_command(const char *cmd,
48 char *const * options,
49 const char *options_string,
50 PQExpBuffer query_buf);
52 static bool do_edit(const char *filename_arg, PQExpBuffer query_buf);
54 static char * unescape(const char *source);
56 static bool do_connect(const char *new_dbname,
57 const char *new_user);
60 static bool do_shell(const char *command);
63 * Perhaps this should be changed to "infinity",
64 * but there is no convincing reason to bother
73 * Handles all the different commands that start with '\',
74 * ordinarily called by MainLoop().
76 * 'line' is the current input line, which should not start with a '\'
77 * but with the actual command name
78 * (that is taken care of by MainLoop)
80 * 'query_buf' contains the query-so-far, which may be modified by
81 * execution of the backslash command (for example, \r clears it)
82 * query_buf can be NULL if there is no query-so-far.
84 * Returns a status code indicating what action is desired, see command.h.
89 HandleSlashCmds(const char *line,
90 PQExpBuffer query_buf,
91 const char **end_of_cmd)
93 backslashResult status = CMD_SKIP_LINE;
95 char *options[NR_OPTIONS+1];
97 const char *options_string = NULL;
101 const char *continue_parse = NULL; /* tell the mainloop where the
102 * backslash command ended */
104 #ifdef USE_ASSERT_CHECKING
110 my_line = xstrdup(line);
113 * Find the first whitespace. line[blank_loc] will now
114 * be the whitespace character or the \0 at the end
116 * Also look for a backslash, so stuff like \p\g works.
118 blank_loc = strcspn(my_line, " \t\\");
120 if (my_line[blank_loc] == '\\')
122 continue_parse = &my_line[blank_loc];
123 my_line[blank_loc] = '\0';
125 /* do we have an option string? */
126 else if (my_line[blank_loc] != '\0')
128 options_string = &my_line[blank_loc + 1];
129 my_line[blank_loc] = '\0';
139 options_string = &options_string[strspn(options_string, " \t")]; /* skip leading
143 token = strtokx(options_string, " \t", "\"'`", '\\', "e, &pos, pset.encoding);
145 for (i = 0; token && i < NR_OPTIONS; i++)
150 options[i] = unescape(token);
153 options[i] = xstrdup(token);
159 char *file = unescape(token);
160 PQExpBufferData output;
164 fd = popen(file, "r");
167 psql_error("%s: %s\n", file, strerror(errno));
173 initPQExpBuffer(&output);
177 result = fread(buf, 1, 512, fd);
180 psql_error("%s: %s\n", file, strerror(errno));
184 appendBinaryPQExpBuffer(&output, buf, result);
186 appendPQExpBufferChar(&output, '\0');
188 if (pclose(fd) == -1)
190 psql_error("%s: %s\n", file, strerror(errno));
197 if (output.data[strlen(output.data) - 1] == '\n')
198 output.data[strlen(output.data) - 1] = '\0';
203 options[i] = output.data;
206 options[i] = xstrdup("");
207 termPQExpBuffer(&output);
213 if (token[0] == '\\')
214 continue_parse = options_string + pos;
215 else if (token[0] == '$')
217 const char * value = GetVariable(pset.vars, token+1);
220 options[i] = xstrdup(value);
223 options[i] = xstrdup(token);
229 token = strtokx(NULL, " \t", "\"'`", '\\', "e, &pos, pset.encoding);
236 status = exec_command(cmd, options, options_string, query_buf);
238 if (status == CMD_UNKNOWN)
242 * If the command was not recognized, try inserting a space after
243 * the first letter and call again. The one letter commands allow
244 * arguments to start immediately after the command, but that is
245 * no longer encouraged.
247 const char *new_options[NR_OPTIONS+1];
251 for (i = 1; i < NR_OPTIONS+1; i++)
252 new_options[i] = options[i - 1];
253 new_options[0] = cmd + 1;
258 status = exec_command(new_cmd, (char *const *) new_options, my_line + 2, query_buf);
261 if (status == CMD_UNKNOWN)
263 if (pset.cur_cmd_interactive)
264 fprintf(stderr, "Invalid command \\%s. Try \\? for help.\n", cmd);
266 psql_error("invalid command \\%s\n", cmd);
270 if (continue_parse && *(continue_parse + 1) == '\\')
275 *end_of_cmd = line + (continue_parse - my_line);
277 *end_of_cmd = line + strlen(line);
280 for (i = 0; i < NR_OPTIONS && options[i]; i++)
291 static backslashResult
292 exec_command(const char *cmd,
293 char *const * options,
294 const char *options_string,
295 PQExpBuffer query_buf)
297 bool success = true; /* indicate here if the command ran ok or
299 bool quiet = QUIET();
301 backslashResult status = CMD_SKIP_LINE;
304 /* \a -- toggle field alignment This makes little sense but we keep it around. */
305 if (strcmp(cmd, "a") == 0)
307 if (pset.popt.topt.format != PRINT_ALIGNED)
308 success = do_pset("format", "aligned", &pset.popt, quiet);
310 success = do_pset("format", "unaligned", &pset.popt, quiet);
314 /* \C -- override table title (formerly change HTML caption) */
315 else if (strcmp(cmd, "C") == 0)
316 success = do_pset("title", options[0], &pset.popt, quiet);
320 * \c or \connect -- connect to new database or as different user
322 * \c foo bar: connect to db "foo" as user "bar"
323 * \c foo [-]: connect to db "foo" as current user
324 * \c - bar: connect to current db as user "bar"
325 * \c: connect to default db as default user
328 else if (strcmp(cmd, "c") == 0 || strcmp(cmd, "connect") == 0)
332 success = do_connect(options[0], options[1]);
336 /* gave database name */
337 success = do_connect(options[0], ""); /* empty string is same
338 * username as before,
339 * NULL would mean libpq
342 /* connect to default db as default user */
343 success = do_connect(NULL, NULL);
349 else if (strcasecmp(cmd, "copy") == 0)
350 success = do_copy(options_string);
353 else if (strcmp(cmd, "copyright") == 0)
357 else if (cmd[0] == 'd')
359 bool show_verbose = strchr(cmd, '+') ? true : false;
366 success = describeTableDetails(options[0], show_verbose);
368 /* standard listing of interesting things */
369 success = listTables("tvs", NULL, show_verbose);
372 success = describeAggregates(options[0]);
375 success = objectDescription(options[0]);
378 success = describeFunctions(options[0], show_verbose);
381 success = do_lo_list();
384 success = describeOperators(options[0]);
387 success = permissionsList(options[0]);
390 success = describeTypes(options[0], show_verbose);
397 if (cmd[1] == 'S' && cmd[2] == '\0')
398 success = listTables("Stvs", NULL, show_verbose);
400 success = listTables(&cmd[1], options[0], show_verbose);
403 status = CMD_UNKNOWN;
409 * \e or \edit -- edit the current query buffer (or a file and make it
412 else if (strcmp(cmd, "e") == 0 || strcmp(cmd, "edit") == 0)
413 status = do_edit(options[0], query_buf) ? CMD_NEWEDIT : CMD_ERROR;
417 else if (strcmp(cmd, "echo") == 0)
421 for (i = 0; i < 16 && options[i]; i++)
422 fputs(options[i], stdout);
426 /* \f -- change field separator */
427 else if (strcmp(cmd, "f") == 0)
428 success = do_pset("fieldsep", options[0], &pset.popt, quiet);
430 /* \g means send query */
431 else if (strcmp(cmd, "g") == 0)
436 pset.gfname = xstrdup(options[0]);
441 else if (strcmp(cmd, "h") == 0 || strcmp(cmd, "help") == 0)
445 for (i=0; options && options[i] && strlen(buf)<255; i++)
447 strncat(buf, options[i], 255 - strlen(buf));
448 if (strlen(buf)<255 && options[i+1])
456 else if (strcmp(cmd, "H") == 0 || strcmp(cmd, "html") == 0)
458 if (pset.popt.topt.format != PRINT_HTML)
459 success = do_pset("format", "html", &pset.popt, quiet);
461 success = do_pset("format", "aligned", &pset.popt, quiet);
465 /* \i is include file */
466 else if (strcmp(cmd, "i") == 0 || strcmp(cmd, "include") == 0)
470 psql_error("\\%s: missing required argument\n", cmd);
474 success = process_file(options[0]);
478 /* \l is list databases */
479 else if (strcmp(cmd, "l") == 0 || strcmp(cmd, "list") == 0)
480 success = listAllDbs(false);
481 else if (strcmp(cmd, "l+") == 0 || strcmp(cmd, "list+") == 0)
482 success = listAllDbs(true);
485 /* large object things */
486 else if (strncmp(cmd, "lo_", 3) == 0)
488 if (strcmp(cmd + 3, "export") == 0)
492 psql_error("\\%s: missing required argument\n", cmd);
496 success = do_lo_export(options[0], options[1]);
499 else if (strcmp(cmd + 3, "import") == 0)
503 psql_error("\\%s: missing required argument\n", cmd);
507 success = do_lo_import(options[0], options[1]);
510 else if (strcmp(cmd + 3, "list") == 0)
511 success = do_lo_list();
513 else if (strcmp(cmd + 3, "unlink") == 0)
517 psql_error("\\%s: missing required argument\n", cmd);
521 success = do_lo_unlink(options[0]);
525 status = CMD_UNKNOWN;
528 /* \o -- set query output */
529 else if (strcmp(cmd, "o") == 0 || strcmp(cmd, "out") == 0)
530 success = setQFout(options[0]);
533 /* \p prints the current query buffer */
534 else if (strcmp(cmd, "p") == 0 || strcmp(cmd, "print") == 0)
536 if (query_buf && query_buf->len > 0)
537 puts(query_buf->data);
539 puts("Query buffer is empty.");
543 /* \pset -- set printing parameters */
544 else if (strcmp(cmd, "pset") == 0)
548 psql_error("\\%s: missing required argument\n", cmd);
552 success = do_pset(options[0], options[1], &pset.popt, quiet);
556 else if (strcmp(cmd, "q") == 0 || strcmp(cmd, "quit") == 0)
557 status = CMD_TERMINATE;
560 else if (strcmp(cmd, "qecho") == 0)
564 for (i = 0; i < 16 && options[i]; i++)
565 fputs(options[i], pset.queryFout);
566 fputs("\n", pset.queryFout);
569 /* reset(clear) the buffer */
570 else if (strcmp(cmd, "r") == 0 || strcmp(cmd, "reset") == 0)
572 resetPQExpBuffer(query_buf);
574 puts("Query buffer reset (cleared).");
578 /* \s save history in a file or show it on the screen */
579 else if (strcmp(cmd, "s") == 0)
588 success = saveHistory(fname);
590 if (success && !quiet && options[0])
591 printf("Wrote history to %s.\n", fname);
595 /* \set -- generalized set option command */
596 else if (strcmp(cmd, "set") == 0)
600 /* list all variables */
603 * (This is in utter violation of the GetVariable abstraction,
604 * but I have not dreamt up a better way.)
606 struct _variable *ptr;
608 for (ptr = pset.vars; ptr->next; ptr = ptr->next)
609 fprintf(stdout, "%s = '%s'\n", ptr->next->name, ptr->next->value);
614 const char * val = options[1];
617 if (!SetVariable(pset.vars, options[0], val))
619 psql_error("\\%s: error\n", cmd);
625 /* \t -- turn off headers and row count */
626 else if (strcmp(cmd, "t") == 0)
627 success = do_pset("tuples_only", NULL, &pset.popt, quiet);
630 /* \T -- define html <table ...> attributes */
631 else if (strcmp(cmd, "T") == 0)
632 success = do_pset("tableattr", options[0], &pset.popt, quiet);
635 else if (strcmp(cmd, "unset") == 0)
637 if (!SetVariable(pset.vars, options[0], NULL))
639 psql_error("\\%s: error\n", cmd);
645 /* \w -- write query buffer to file */
646 else if (strcmp(cmd, "w") == 0 || strcmp(cmd, "write") == 0)
653 psql_error("\\%s: missing required argument\n", cmd);
658 if (options[0][0] == '|')
661 fd = popen(&options[0][1], "w");
665 fd = fopen(options[0], "w");
670 psql_error("%s: %s\n", options[0], strerror(errno));
679 if (query_buf && query_buf->len > 0)
680 fprintf(fd, "%s\n", query_buf->data);
689 psql_error("%s: %s\n", options[0], strerror(errno));
695 /* \x -- toggle expanded table representation */
696 else if (strcmp(cmd, "x") == 0)
697 success = do_pset("expanded", NULL, &pset.popt, quiet);
700 /* list table rights (grant/revoke) */
701 else if (strcmp(cmd, "z") == 0)
702 success = permissionsList(options[0]);
705 else if (strcmp(cmd, "!") == 0)
706 success = do_shell(options_string);
708 else if (strcmp(cmd, "?") == 0)
714 * These commands don't do anything. I just use them to test the
717 else if (strcmp(cmd, "void") == 0 || strcmp(cmd, "#") == 0)
721 fprintf(stderr, "+ optline = |%s|\n", options_string);
722 for (i = 0; options[i]; i++)
723 fprintf(stderr, "+ opt%d = |%s|\n", i, options[i]);
728 status = CMD_UNKNOWN;
740 * Replaces \n, \t, and the like.
741 * Also interpolates ${variables}.
743 * The return value is malloc()'ed.
746 unescape(const char *source)
749 bool esc = false; /* Last character we saw was the escape
755 #ifdef USE_ASSERT_CHECKING
759 length = strlen(source) + 1;
761 tmp = destination = (char *) malloc(length);
764 psql_error("out of memory\n");
768 for (p = (char *) source; *p; p += PQmblen(p, pset.encoding))
802 l = strtol(p, &end, 0);
830 len = strcspn(p + 2, "}");
831 copy = xstrdup(p + 2);
833 value = GetVariable(pset.vars, copy);
836 length += strlen(value) - (len + 3);
837 new = realloc(destination, length);
840 psql_error("out of memory\n");
843 tmp = new + (tmp - destination);
847 tmp += strlen(value);
870 * -- handler for \connect
872 * Connects to a database (new_dbname) as a certain user (new_user).
873 * The new user can be NULL. A db name of "-" is the same as the old one.
874 * (That is, the one currently in pset. But pset.db can also be NULL. A NULL
875 * dbname is handled by libpq.)
876 * Returns true if all ok, false if the new connection couldn't be established
877 * but the old one was set back. Otherwise it terminates the program.
880 do_connect(const char *new_dbname, const char *new_user)
882 PGconn *oldconn = pset.db;
883 const char *dbparam = NULL;
884 const char *userparam = NULL;
885 const char *pwparam = NULL;
886 char *prompted_password = NULL;
888 bool success = false;
890 /* Delete variables (in case we fail before setting them anew) */
891 SetVariable(pset.vars, "DBNAME", NULL);
892 SetVariable(pset.vars, "USER", NULL);
893 SetVariable(pset.vars, "HOST", NULL);
894 SetVariable(pset.vars, "PORT", NULL);
896 /* If dbname is "-" then use old name, else new one (even if NULL) */
897 if (oldconn && new_dbname && PQdb(oldconn) && strcmp(new_dbname, "-") == 0)
898 dbparam = PQdb(oldconn);
900 dbparam = new_dbname;
902 /* If user is "" then use the old one */
903 if (new_user && PQuser(oldconn) && strcmp(new_user, "")==0)
904 userparam = PQuser(oldconn);
906 userparam = new_user;
908 /* need to prompt for password? */
909 if (pset.getPassword)
910 pwparam = prompted_password = simple_prompt("Password: ", 100, false); /* need to save for
914 * Use old password if no new one given (if you didn't have an old
917 if (!pwparam && oldconn)
918 pwparam = PQpass(oldconn);
923 pset.db = PQsetdbLogin(PQhost(oldconn), PQport(oldconn),
924 NULL, NULL, dbparam, userparam, pwparam);
926 if (PQstatus(pset.db) == CONNECTION_BAD &&
927 strcmp(PQerrorMessage(pset.db), "fe_sendauth: no password supplied\n") == 0)
930 free(prompted_password);
931 prompted_password = NULL;
932 pwparam = prompted_password = simple_prompt("Password: ", 100, false);
936 free(prompted_password);
939 * If connection failed, try at least keep the old one. That's
940 * probably more convenient than just kicking you out of the program.
942 if (!pset.db || PQstatus(pset.db) == CONNECTION_BAD)
944 if (pset.cur_cmd_interactive)
946 psql_error("%s", PQerrorMessage(pset.db));
950 fputs("Previous connection kept\n", stderr);
958 /* we don't want unpredictable things to
959 * happen in scripting mode */
960 psql_error("\\connect: %s", PQerrorMessage(pset.db));
971 if (userparam != new_user) /* no new user */
972 printf("You are now connected to database %s.\n", dbparam);
973 else if (dbparam != new_dbname) /* no new db */
974 printf("You are now connected as new user %s.\n", new_user);
976 printf("You are now connected to database %s as user %s.\n",
977 PQdb(pset.db), PQuser(pset.db));
986 PQsetNoticeProcessor(pset.db, NoticeProcessor, NULL);
987 pset.encoding = PQclientencoding(pset.db);
989 /* Update variables */
990 SetVariable(pset.vars, "DBNAME", PQdb(pset.db));
991 SetVariable(pset.vars, "USER", PQuser(pset.db));
992 SetVariable(pset.vars, "HOST", PQhost(pset.db));
993 SetVariable(pset.vars, "PORT", PQport(pset.db));
1001 * do_edit -- handler for \e
1003 * If you do not specify a filename, the current query buffer will be copied
1004 * into a temporary one.
1008 editFile(const char *fname)
1014 #ifdef USE_ASSERT_CHECKING
1021 /* Find an editor to use */
1022 editorName = getenv("PSQL_EDITOR");
1024 editorName = getenv("EDITOR");
1026 editorName = getenv("VISUAL");
1028 editorName = DEFAULT_EDITOR;
1030 sys = malloc(strlen(editorName) + strlen(fname) + 32 + 1);
1033 sprintf(sys, "exec %s %s", editorName, fname);
1034 result = system(sys);
1036 psql_error("could not start editor\n");
1037 else if (result == 127)
1038 psql_error("could not start /bin/sh\n");
1047 do_edit(const char *filename_arg, PQExpBuffer query_buf)
1049 char fnametmp[MAXPGPATH];
1060 #ifdef USE_ASSERT_CHECKING
1069 fname = filename_arg;
1073 /* make a temp file to edit */
1076 const char *tmpdirenv = getenv("TMPDIR");
1078 sprintf(fnametmp, "%s/psql.edit.%ld.%ld",
1079 tmpdirenv ? tmpdirenv : "/tmp",
1080 (long) geteuid(), (long) getpid());
1082 GetTempFileName(".", "psql", 0, fnametmp);
1084 fname = (const char *) fnametmp;
1087 oldumask = umask(0177);
1089 stream = fopen(fname, "w");
1096 psql_error("couldn't open temp file %s: %s\n", fname, strerror(errno));
1101 unsigned int ql = query_buf->len;
1103 if (ql == 0 || query_buf->data[ql - 1] != '\n')
1105 appendPQExpBufferChar(query_buf, '\n');
1109 if (fwrite(query_buf->data, 1, ql, stream) != ql)
1111 psql_error("%s: %s\n", fname, strerror(errno));
1122 if (!error && stat(fname, &before) != 0)
1124 psql_error("%s: %s\n", fname, strerror(errno));
1131 error = !editFile(fname);
1134 if (!error && stat(fname, &after) != 0)
1136 psql_error("%s: %s\n", fname, strerror(errno));
1140 if (!error && before.st_mtime != after.st_mtime)
1146 stream = fopen(fname, "r");
1149 psql_error("%s: %s\n", fname, strerror(errno));
1154 /* read file back in */
1158 resetPQExpBuffer(query_buf);
1161 result = fread(line, 1, 1024, stream);
1164 psql_error("%s: %s\n", fname, strerror(errno));
1168 appendBinaryPQExpBuffer(query_buf, line, result);
1169 } while (!feof(stream));
1170 appendPQExpBufferChar(query_buf, '\0');
1175 /* remove temp file */
1178 if (remove(fname)==-1)
1180 psql_error("%s: %s\n", fname, strerror(errno));
1193 * Read commands from filename and then them to the main processing loop
1194 * Handler for \i, but can be used for other things as well.
1197 process_file(char *filename)
1206 fd = fopen(filename, "rb");
1208 fd = fopen(filename, "r");
1213 psql_error("%s: %s\n", filename, strerror(errno));
1217 pset.inputfile = filename;
1218 result = MainLoop(fd);
1220 pset.inputfile = NULL;
1221 return (result == EXIT_SUCCESS);
1231 _align2string(enum printFormat in)
1238 case PRINT_UNALIGNED:
1256 do_pset(const char *param, const char *value, printQueryOpt * popt, bool quiet)
1260 #ifdef USE_ASSERT_CHECKING
1268 vallen = strlen(value);
1271 if (strcmp(param, "format") == 0)
1275 else if (strncasecmp("unaligned", value, vallen) == 0)
1276 popt->topt.format = PRINT_UNALIGNED;
1277 else if (strncasecmp("aligned", value, vallen) == 0)
1278 popt->topt.format = PRINT_ALIGNED;
1279 else if (strncasecmp("html", value, vallen) == 0)
1280 popt->topt.format = PRINT_HTML;
1281 else if (strncasecmp("latex", value, vallen) == 0)
1282 popt->topt.format = PRINT_LATEX;
1285 psql_error("\\pset: allowed formats are unaligned, aligned, html, latex\n");
1290 printf("Output format is %s.\n", _align2string(popt->topt.format));
1293 /* set border style/width */
1294 else if (strcmp(param, "border") == 0)
1297 popt->topt.border = atoi(value);
1300 printf("Border style is %d.\n", popt->topt.border);
1303 /* set expanded/vertical mode */
1304 else if (strcmp(param, "x") == 0 || strcmp(param, "expanded") == 0 || strcmp(param, "vertical") == 0)
1306 popt->topt.expanded = !popt->topt.expanded;
1308 printf("Expanded display is %s.\n", popt->topt.expanded ? "on" : "off");
1312 else if (strcmp(param, "null") == 0)
1316 free(popt->nullPrint);
1317 popt->nullPrint = xstrdup(value);
1320 printf("Null display is \"%s\".\n", popt->nullPrint ? popt->nullPrint : "");
1323 /* field separator for unaligned text */
1324 else if (strcmp(param, "fieldsep") == 0)
1328 free(popt->topt.fieldSep);
1329 popt->topt.fieldSep = xstrdup(value);
1332 printf("Field separator is '%s'.\n", popt->topt.fieldSep);
1335 /* record separator for unaligned text */
1336 else if (strcmp(param, "recordsep") == 0)
1340 free(popt->topt.recordSep);
1341 popt->topt.recordSep = xstrdup(value);
1344 if (strcmp(popt->topt.recordSep, "\n")==0)
1345 printf("Record separator is <newline>.");
1347 printf("Record separator is '%s'.\n", popt->topt.recordSep);
1351 /* toggle between full and barebones format */
1352 else if (strcmp(param, "t") == 0 || strcmp(param, "tuples_only") == 0)
1354 popt->topt.tuples_only = !popt->topt.tuples_only;
1357 if (popt->topt.tuples_only)
1358 puts("Showing only tuples.");
1360 puts("Tuples only is off.");
1364 /* set title override */
1365 else if (strcmp(param, "title") == 0)
1371 popt->title = xstrdup(value);
1376 printf("Title is \"%s\".\n", popt->title);
1378 printf("Title is unset.\n");
1382 /* set HTML table tag options */
1383 else if (strcmp(param, "T") == 0 || strcmp(param, "tableattr") == 0)
1385 free(popt->topt.tableAttr);
1387 popt->topt.tableAttr = NULL;
1389 popt->topt.tableAttr = xstrdup(value);
1393 if (popt->topt.tableAttr)
1394 printf("Table attribute is \"%s\".\n", popt->topt.tableAttr);
1396 printf("Table attributes unset.\n");
1400 /* toggle use of pager */
1401 else if (strcmp(param, "pager") == 0)
1403 popt->topt.pager = !popt->topt.pager;
1406 if (popt->topt.pager)
1407 puts("Using pager is on.");
1409 puts("Using pager is off.");
1416 psql_error("\\pset: unknown option: %s\n", param);
1425 #define DEFAULT_SHELL "/bin/sh"
1428 do_shell(const char *command)
1437 shellName = getenv("SHELL");
1438 if (shellName == NULL)
1439 shellName = DEFAULT_SHELL;
1441 sys = malloc(strlen(shellName) + 16);
1443 psql_error("out of memory\n");
1444 if (pset.cur_cmd_interactive)
1449 sprintf(sys, "exec %s", shellName);
1450 result = system(sys);
1454 result = system(command);
1456 if (result == 127 || result == -1)
1458 psql_error("\\!: failed\n");