backslashResult
HandleSlashCmds(PsqlScanState scan_state,
PQExpBuffer query_buf)
上一篇文章介绍了函数HandleSlashCmds,这里介绍下该函数主要调用的函数 exec_command,
/* And try to execute it */
status = exec_command(cmd, scan_state, query_buf);
看了下该函数的实现,对比对应命令形式,是不是感到很眼熟,
该函数的实现为:
/*
* Subroutine to actually try to execute a backslash command.
*/
static backslashResult
exec_command(const char *cmd,
PsqlScanState scan_state,
PQExpBuffer query_buf)
{
bool success = true; /* indicate here if the command ran ok or
* failed */
backslashResult status = PSQL_CMD_SKIP_LINE;
/*
* \a -- toggle field alignment This makes little sense but we keep it
* around.
*/
if (strcmp(cmd, "a") == 0)
{
if (pset.popt.topt.format != PRINT_ALIGNED)
success = do_pset("format", "aligned", &pset.popt, pset.quiet);
else
success = do_pset("format", "unaligned", &pset.popt, pset.quiet);
}
/* \C -- override table title (formerly change HTML caption) */
else if (strcmp(cmd, "C") == 0)
{
char *opt = psql_scan_slash_option(scan_state,
OT_NORMAL, NULL, true);
success = do_pset("title", opt, &pset.popt, pset.quiet);
free(opt);
}
/*
* \c or \connect -- connect to database using the specified parameters.
*
* \c dbname user host port
*
* If any of these parameters are omitted or specified as '-', the current
* value of the parameter will be used instead. If the parameter has no
* current value, the default value for that parameter will be used. Some
* examples:
*
* \c - - hst Connect to current database on current port of host
* "hst" as current user. \c - usr - prt Connect to current database on
* "prt" port of current host as user "usr". \c dbs Connect to
* "dbs" database on current port of current host as current user.
*/
else if (strcmp(cmd, "c") == 0 || strcmp(cmd, "connect") == 0)
{
char *opt1,
*opt2,
*opt3,
*opt4;
opt1 = read_connect_arg(scan_state);
opt2 = read_connect_arg(scan_state);
opt3 = read_connect_arg(scan_state);
opt4 = read_connect_arg(scan_state);
success = do_connect(opt1, opt2, opt3, opt4);
free(opt1);
free(opt2);
free(opt3);
free(opt4);
}
/* \cd */
else if (strcmp(cmd, "cd") == 0)
{
char *opt = psql_scan_slash_option(scan_state,
OT_NORMAL, NULL, true);
char *dir;
if (opt)
dir = opt;
else
{
#ifndef WIN32
struct passwd *pw;
pw = getpwuid(geteuid());
if (!pw)
{
psql_error("could not get home directory: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
dir = pw->pw_dir;
#else /* WIN32 */
/*
* On Windows, 'cd' without arguments prints the current
* directory, so if someone wants to code this here instead...
*/
dir = "/";
#endif /* WIN32 */
}
if (chdir(dir) == -1)
{
psql_error("\\%s: could not change directory to \"%s\": %s\n",
cmd, dir, strerror(errno));
success = false;
}
if (pset.dirname)
free(pset.dirname);
pset.dirname = pg_strdup(dir);
canonicalize_path(pset.dirname);
if (opt)
free(opt);
}
/* \conninfo -- display information about the current connection */
else if (strcmp(cmd, "conninfo") == 0)
{
char *db = PQdb(pset.db);
char *host = PQhost(pset.db);
if (db == NULL)
printf(_("You are currently not connected to a database.\n"));
else
{
if (host == NULL)
host = DEFAULT_PGSOCKET_DIR;
/* If the host is an absolute path, the connection is via socket */
if (is_absolute_path(host))
printf(_("You are connected to database \"%s\" as user \"%s\" via socket in \"%s\" at port \"%s\".\n"),
db, PQuser(pset.db), host, PQport(pset.db));
else
printf(_("You are connected to database \"%s\" as user \"%s\" on host \"%s\" at port \"%s\".\n"),
db, PQuser(pset.db), host, PQport(pset.db));
}
}
/* \copy */
else if (pg_strcasecmp(cmd, "copy") == 0)
{
/* Default fetch-it-all-and-print mode */
instr_time before,
after;
char *opt = psql_scan_slash_option(scan_state,
OT_WHOLE_LINE, NULL, false);
if (pset.timing)
INSTR_TIME_SET_CURRENT(before);
success = do_copy(opt);
if (pset.timing && success)
{
INSTR_TIME_SET_CURRENT(after);
INSTR_TIME_SUBTRACT(after, before);
printf(_("Time: %.3f ms\n"), INSTR_TIME_GET_MILLISEC(after));
}
free(opt);
}
/* \copyright */
else if (strcmp(cmd, "copyright") == 0)
print_copyright();
/* \d* commands */
else if (cmd[0] == 'd')
{
char *pattern;
bool show_verbose,
show_system;
/* We don't do SQLID reduction on the pattern yet */
pattern = psql_scan_slash_option(scan_state,
OT_NORMAL, NULL, true);
show_verbose = strchr(cmd, '+') ? true : false;
show_system = strchr(cmd, 'S') ? true : false;
switch (cmd[1])
{
case '\0':
case '+':
case 'S':
if (pattern)
success = describeTableDetails(pattern, show_verbose, show_system);
else
/* standard listing of interesting things */
success = listTables("tvsE", NULL, show_verbose, show_system);
break;
case 'a':
success = describeAggregates(pattern, show_verbose, show_system);
break;
case 'b':
success = describeTablespaces(pattern, show_verbose);
break;
case 'c':
success = listConversions(pattern, show_system);
break;
case 'C':
success = listCasts(pattern);
break;
case 'd':
if (strncmp(cmd, "ddp", 3) == 0)
success = listDefaultACLs(pattern);
else
success = objectDescription(pattern, show_system);
break;
case 'D':
success = listDomains(pattern, show_system);
break;
case 'f': /* function subsystem */
switch (cmd[2])
{
case '\0':
case '+':
case 'S':
case 'a':
case 'n':
case 't':
case 'w':
success = describeFunctions(&cmd[2], pattern, show_verbose, show_system);
break;
default:
status = PSQL_CMD_UNKNOWN;
break;
}
break;
case 'g':
/* no longer distinct from \du */
success = describeRoles(pattern, show_verbose);
break;
case 'l':
success = do_lo_list();
break;
case 'L':
success = listLanguages(pattern, show_verbose, show_system);
break;
case 'n':
success = listSchemas(pattern, show_verbose, show_system);
break;
case 'o':
success = describeOperators(pattern, show_system);
break;
case 'O':
success = listCollations(pattern, show_verbose, show_system);
break;
case 'p':
success = permissionsList(pattern);
break;
case 'T':
success = describeTypes(pattern, show_verbose, show_system);
break;
case 't':
case 'v':
case 'i':
case 's':
case 'E':
success = listTables(&cmd[1], pattern, show_verbose, show_system);
break;
case 'r':
if (cmd[2] == 'd' && cmd[3] == 's')
{
char *pattern2 = NULL;
if (pattern)
pattern2 = psql_scan_slash_option(scan_state,
OT_NORMAL, NULL, true);
success = listDbRoleSettings(pattern, pattern2);
}
else
success = PSQL_CMD_UNKNOWN;
break;
case 'u':
success = describeRoles(pattern, show_verbose);
break;
case 'F': /* text search subsystem */
switch (cmd[2])
{
case '\0':
case '+':
success = listTSConfigs(pattern, show_verbose);
break;
case 'p':
success = listTSParsers(pattern, show_verbose);
break;
case 'd':
success = listTSDictionaries(pattern, show_verbose);
break;
case 't':
success = listTSTemplates(pattern, show_verbose);
break;
default:
status = PSQL_CMD_UNKNOWN;
break;
}
break;
case 'e': /* SQL/MED subsystem */
switch (cmd[2])
{
case 's':
success = listForeignServers(pattern, show_verbose);
break;
case 'u':
success = listUserMappings(pattern, show_verbose);
break;
case 'w':
success = listForeignDataWrappers(pattern, show_verbose);
break;
case 't':
success = listForeignTables(pattern, show_verbose);
break;
default:
status = PSQL_CMD_UNKNOWN;
break;
}
break;
case 'x': /* Extensions */
if (show_verbose)
success = listExtensionContents(pattern);
else
success = listExtensions(pattern);
break;
default:
status = PSQL_CMD_UNKNOWN;
}
if (pattern)
free(pattern);
}
/*
* \e or \edit -- edit the current query buffer, or edit a file and make
* it the query buffer
*/
else if (strcmp(cmd, "e") == 0 || strcmp(cmd, "edit") == 0)
{
if (!query_buf)
{
psql_error("no query buffer\n");
status = PSQL_CMD_ERROR;
}
else
{
char *fname;
char *ln = NULL;
int lineno = -1;
fname = psql_scan_slash_option(scan_state,
OT_NORMAL, NULL, true);
if (fname)
{
/* try to get separate lineno arg */
ln = psql_scan_slash_option(scan_state,
OT_NORMAL, NULL, true);
if (ln == NULL)
{
/* only one arg; maybe it is lineno not fname */
if (fname[0] &&
strspn(fname, "0123456789") == strlen(fname))
{
/* all digits, so assume it is lineno */
ln = fname;
fname = NULL;
}
}
}
if (ln)
{
lineno = atoi(ln);
if (lineno < 1)
{
psql_error("invalid line number: %s\n", ln);
status = PSQL_CMD_ERROR;
}
}
if (status != PSQL_CMD_ERROR)
{
expand_tilde(&fname);
if (fname)
canonicalize_path(fname);
if (do_edit(fname, query_buf, lineno, NULL))
status = PSQL_CMD_NEWEDIT;
else
status = PSQL_CMD_ERROR;
}
if (fname)
free(fname);
if (ln)
free(ln);
}
}
/*
* \ef -- edit the named function, or present a blank CREATE FUNCTION
* template if no argument is given
*/
else if (strcmp(cmd, "ef") == 0)
{
int lineno = -1;
if (pset.sversion < 80400)
{
psql_error("The server (version %d.%d) does not support editing function source.\n",
pset.sversion / 10000, (pset.sversion / 100) % 100);
status = PSQL_CMD_ERROR;
}
else if (!query_buf)
{
psql_error("no query buffer\n");
status = PSQL_CMD_ERROR;
}
else
{
char *func;
Oid foid = InvalidOid;
func = psql_scan_slash_option(scan_state,
OT_WHOLE_LINE, NULL, true);
lineno = strip_lineno_from_funcdesc(func);
if (lineno == 0)
{
/* error already reported */
status = PSQL_CMD_ERROR;
}
else if (!func)
{
/* set up an empty command to fill in */
printfPQExpBuffer(query_buf,
"CREATE FUNCTION ( )\n"
" RETURNS \n"
" LANGUAGE \n"
" -- common options: IMMUTABLE STABLE STRICT SECURITY DEFINER\n"
"AS $function$\n"
"\n$function$\n");
}
else if (!lookup_function_oid(pset.db, func, &foid))
{
/* error already reported */
status = PSQL_CMD_ERROR;
}
else if (!get_create_function_cmd(pset.db, foid, query_buf))
{
/* error already reported */
status = PSQL_CMD_ERROR;
}
else if (lineno > 0)
{
/*
* lineno "1" should correspond to the first line of the
* function body. We expect that pg_get_functiondef() will
* emit that on a line beginning with "AS ", and that there
* can be no such line before the real start of the function
* body. Increment lineno by the number of lines before that
* line, so that it becomes relative to the first line of the
* function definition.
*/
const char *lines = query_buf->data;
while (*lines != '\0')
{
if (strncmp(lines, "AS ", 3) == 0)
break;
lineno++;
/* find start of next line */
lines = strchr(lines, '\n');
if (!lines)
break;
lines++;
}
}
if (func)
free(func);
}
if (status != PSQL_CMD_ERROR)
{
bool edited = false;
if (!do_edit(NULL, query_buf, lineno, &edited))
status = PSQL_CMD_ERROR;
else if (!edited)
puts(_("No changes"));
else
status = PSQL_CMD_NEWEDIT;
}
}
/* \echo and \qecho */
else if (strcmp(cmd, "echo") == 0 || strcmp(cmd, "qecho") == 0)
{
char *value;
char quoted;
bool no_newline = false;
bool first = true;
FILE *fout;
if (strcmp(cmd, "qecho") == 0)
fout = pset.queryFout;
else
fout = stdout;
while ((value = psql_scan_slash_option(scan_state,
OT_NORMAL, "ed, false)))
{
if (!quoted && strcmp(value, "-n") == 0)
no_newline = true;
else
{
if (first)
first = false;
else
fputc(' ', fout);
fputs(value, fout);
}
free(value);
}
if (!no_newline)
fputs("\n", fout);
}
/* \encoding -- set/show client side encoding */
else if (strcmp(cmd, "encoding") == 0)
{
char *encoding = psql_scan_slash_option(scan_state,
OT_NORMAL, NULL, false);
if (!encoding)
{
/* show encoding */
puts(pg_encoding_to_char(pset.encoding));
}
else
{
/* set encoding */
if (PQsetClientEncoding(pset.db, encoding) == -1)
psql_error("%s: invalid encoding name or conversion procedure not found\n", encoding);
else
{
/* save encoding info into psql internal data */
pset.encoding = PQclientEncoding(pset.db);
pset.popt.topt.encoding = pset.encoding;
SetVariable(pset.vars, "ENCODING",
pg_encoding_to_char(pset.encoding));
}
free(encoding);
}
}
/* \f -- change field separator */
else if (strcmp(cmd, "f") == 0)
{
char *fname = psql_scan_slash_option(scan_state,
OT_NORMAL, NULL, false);
success = do_pset("fieldsep", fname, &pset.popt, pset.quiet);
free(fname);
}
/* \g means send query */
else if (strcmp(cmd, "g") == 0)
{
char *fname = psql_scan_slash_option(scan_state,
OT_FILEPIPE, NULL, false);
if (!fname)
pset.gfname = NULL;
else
{
expand_tilde(&fname);
pset.gfname = pg_strdup(fname);
}
free(fname);
status = PSQL_CMD_SEND;
}
/* help */
else if (strcmp(cmd, "h") == 0 || strcmp(cmd, "help") == 0)
{
char *opt = psql_scan_slash_option(scan_state,
OT_WHOLE_LINE, NULL, false);
size_t len;
/* strip any trailing spaces and semicolons */
if (opt)
{
len = strlen(opt);
while (len > 0 &&
(isspace((unsigned char) opt[len - 1])
|| opt[len - 1] == ';'))
opt[--len] = '\0';
}
helpSQL(opt, pset.popt.topt.pager);
free(opt);
}
/* HTML mode */
else if (strcmp(cmd, "H") == 0 || strcmp(cmd, "html") == 0)
{
if (pset.popt.topt.format != PRINT_HTML)
success = do_pset("format", "html", &pset.popt, pset.quiet);
else
success = do_pset("format", "aligned", &pset.popt, pset.quiet);
}
/* \i is include file */
else if (strcmp(cmd, "i") == 0 || strcmp(cmd, "include") == 0)
{
char *fname = psql_scan_slash_option(scan_state,
OT_NORMAL, NULL, true);
if (!fname)
{
psql_error("\\%s: missing required argument\n", cmd);
success = false;
}
else
{
expand_tilde(&fname);
success = (process_file(fname, false) == EXIT_SUCCESS);
free(fname);
}
}
/* \l is list databases */
else if (strcmp(cmd, "l") == 0 || strcmp(cmd, "list") == 0)
success = listAllDbs(false);
else if (strcmp(cmd, "l+") == 0 || strcmp(cmd, "list+") == 0)
success = listAllDbs(true);
/*
* large object things
*/
else if (strncmp(cmd, "lo_", 3) == 0)
{
char *opt1,
*opt2;
opt1 = psql_scan_slash_option(scan_state,
OT_NORMAL, NULL, true);
opt2 = psql_scan_slash_option(scan_state,
OT_NORMAL, NULL, true);
if (strcmp(cmd + 3, "export") == 0)
{
if (!opt2)
{
psql_error("\\%s: missing required argument\n", cmd);
success = false;
}
else
{
expand_tilde(&opt2);
success = do_lo_export(opt1, opt2);
}
}
else if (strcmp(cmd + 3, "import") == 0)
{
if (!opt1)
{
psql_error("\\%s: missing required argument\n", cmd);
success = false;
}
else
{
expand_tilde(&opt1);
success = do_lo_import(opt1, opt2);
}
}
else if (strcmp(cmd + 3, "list") == 0)
success = do_lo_list();
else if (strcmp(cmd + 3, "unlink") == 0)
{
if (!opt1)
{
psql_error("\\%s: missing required argument\n", cmd);
success = false;
}
else
success = do_lo_unlink(opt1);
}
else
status = PSQL_CMD_UNKNOWN;
free(opt1);
free(opt2);
}
/* \o -- set query output */
else if (strcmp(cmd, "o") == 0 || strcmp(cmd, "out") == 0)
{
char *fname = psql_scan_slash_option(scan_state,
OT_FILEPIPE, NULL, true);
expand_tilde(&fname);
success = setQFout(fname);
free(fname);
}
/* \p prints the current query buffer */
else if (strcmp(cmd, "p") == 0 || strcmp(cmd, "print") == 0)
{
if (query_buf && query_buf->len > 0)
puts(query_buf->data);
else if (!pset.quiet)
puts(_("Query buffer is empty."));
fflush(stdout);
}
/* \password -- set user password */
else if (strcmp(cmd, "password") == 0)
{
char *pw1;
char *pw2;
pw1 = simple_prompt("Enter new password: ", 100, false);
pw2 = simple_prompt("Enter it again: ", 100, false);
if (strcmp(pw1, pw2) != 0)
{
fprintf(stderr, _("Passwords didn't match.\n"));
success = false;
}
else
{
char *opt0 = psql_scan_slash_option(scan_state, OT_SQLID, NULL, true);
char *user;
char *encrypted_password;
if (opt0)
user = opt0;
else
user = PQuser(pset.db);
encrypted_password = PQencryptPassword(pw1, user);
if (!encrypted_password)
{
fprintf(stderr, _("Password encryption failed.\n"));
success = false;
}
else
{
PQExpBufferData buf;
PGresult *res;
initPQExpBuffer(&buf);
printfPQExpBuffer(&buf, "ALTER USER %s PASSWORD ",
fmtId(user));
appendStringLiteralConn(&buf, encrypted_password, pset.db);
res = PSQLexec(buf.data, false);
termPQExpBuffer(&buf);
if (!res)
success = false;
else
PQclear(res);
PQfreemem(encrypted_password);
}
}
free(pw1);
free(pw2);
}
/* \prompt -- prompt and set variable */
else if (strcmp(cmd, "prompt") == 0)
{
char *opt,
*prompt_text = NULL;
char *arg1,
*arg2;
arg1 = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, false);
arg2 = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, false);
if (!arg1)
{
psql_error("\\%s: missing required argument\n", cmd);
success = false;
}
else
{
char *result;
if (arg2)
{
prompt_text = arg1;
opt = arg2;
}
else
opt = arg1;
if (!pset.inputfile)
result = simple_prompt(prompt_text, 4096, true);
else
{
if (prompt_text)
{
fputs(prompt_text, stdout);
fflush(stdout);
}
result = gets_fromFile(stdin);
}
if (!SetVariable(pset.vars, opt, result))
{
psql_error("\\%s: error\n", cmd);
success = false;
}
free(result);
if (prompt_text)
free(prompt_text);
free(opt);
}
}
/* \pset -- set printing parameters */
else if (strcmp(cmd, "pset") == 0)
{
char *opt0 = psql_scan_slash_option(scan_state,
OT_NORMAL, NULL, false);
char *opt1 = psql_scan_slash_option(scan_state,
OT_NORMAL, NULL, false);
if (!opt0)
{
psql_error("\\%s: missing required argument\n", cmd);
success = false;
}
else
success = do_pset(opt0, opt1, &pset.popt, pset.quiet);
free(opt0);
free(opt1);
}
/* \q or \quit */
else if (strcmp(cmd, "q") == 0 || strcmp(cmd, "quit") == 0)
status = PSQL_CMD_TERMINATE;
/* reset(clear) the buffer */
else if (strcmp(cmd, "r") == 0 || strcmp(cmd, "reset") == 0)
{
resetPQExpBuffer(query_buf);
psql_scan_reset(scan_state);
if (!pset.quiet)
puts(_("Query buffer reset (cleared)."));
}
/* \s save history in a file or show it on the screen */
else if (strcmp(cmd, "s") == 0)
{
char *fname = psql_scan_slash_option(scan_state,
OT_NORMAL, NULL, true);
#if defined(WIN32) && !defined(__CYGWIN__)
/*
* XXX This does not work for all terminal environments or for output
* containing non-ASCII characters; see comments in simple_prompt().
*/
#define DEVTTY "con"
#else
#define DEVTTY "/dev/tty"
#endif
expand_tilde(&fname);
/* This scrolls off the screen when using /dev/tty */
success = saveHistory(fname ? fname : DEVTTY, -1, false, false);
if (success && !pset.quiet && fname)
printf(gettext("Wrote history to file \"%s/%s\".\n"),
pset.dirname ? pset.dirname : ".", fname);
if (!fname)
putchar('\n');
free(fname);
}
/* \set -- generalized set variable/option command */
else if (strcmp(cmd, "set") == 0)
{
char *opt0 = psql_scan_slash_option(scan_state,
OT_NORMAL, NULL, false);
if (!opt0)
{
/* list all variables */
PrintVariables(pset.vars);
success = true;
}
else
{
/*
* Set variable to the concatenation of the arguments.
*/
char *newval;
char *opt;
opt = psql_scan_slash_option(scan_state,
OT_NORMAL, NULL, false);
newval = pg_strdup(opt ? opt : "");
free(opt);
while ((opt = psql_scan_slash_option(scan_state,
OT_NORMAL, NULL, false)))
{
newval = realloc(newval, strlen(newval) + strlen(opt) + 1);
if (!newval)
{
psql_error("out of memory\n");
exit(EXIT_FAILURE);
}
strcat(newval, opt);
free(opt);
}
if (!SetVariable(pset.vars, opt0, newval))
{
psql_error("\\%s: error\n", cmd);
success = false;
}
free(newval);
}
free(opt0);
}
/* \sf -- show a function's source code */
else if (strcmp(cmd, "sf") == 0 || strcmp(cmd, "sf+") == 0)
{
bool show_linenumbers = (strcmp(cmd, "sf+") == 0);
PQExpBuffer func_buf;
char *func;
Oid foid = InvalidOid;
func_buf = createPQExpBuffer();
func = psql_scan_slash_option(scan_state,
OT_WHOLE_LINE, NULL, true);
if (pset.sversion < 80400)
{
psql_error("The server (version %d.%d) does not support showing function source.\n",
pset.sversion / 10000, (pset.sversion / 100) % 100);
status = PSQL_CMD_ERROR;
}
else if (!func)
{
psql_error("function name is required\n");
status = PSQL_CMD_ERROR;
}
else if (!lookup_function_oid(pset.db, func, &foid))
{
/* error already reported */
status = PSQL_CMD_ERROR;
}
else if (!get_create_function_cmd(pset.db, foid, func_buf))
{
/* error already reported */
status = PSQL_CMD_ERROR;
}
else
{
FILE *output;
bool is_pager;
/* Select output stream: stdout, pager, or file */
if (pset.queryFout == stdout)
{
/* count lines in function to see if pager is needed */
int lineno = 0;
const char *lines = func_buf->data;
while (*lines != '\0')
{
lineno++;
/* find start of next line */
lines = strchr(lines, '\n');
if (!lines)
break;
lines++;
}
output = PageOutput(lineno, pset.popt.topt.pager);
is_pager = true;
}
else
{
/* use previously set output file, without pager */
output = pset.queryFout;
is_pager = false;
}
if (show_linenumbers)
{
bool in_header = true;
int lineno = 0;
char *lines = func_buf->data;
/*
* lineno "1" should correspond to the first line of the
* function body. We expect that pg_get_functiondef() will
* emit that on a line beginning with "AS ", and that there
* can be no such line before the real start of the function
* body.
*
* Note that this loop scribbles on func_buf.
*/
while (*lines != '\0')
{
char *eol;
if (in_header && strncmp(lines, "AS ", 3) == 0)
in_header = false;
/* increment lineno only for body's lines */
if (!in_header)
lineno++;
/* find and mark end of current line */
eol = strchr(lines, '\n');
if (eol != NULL)
*eol = '\0';
/* show current line as appropriate */
if (in_header)
fprintf(output, " %s\n", lines);
else
fprintf(output, "%-7d %s\n", lineno, lines);
/* advance to next line, if any */
if (eol == NULL)
break;
lines = ++eol;
}
}
else
{
/* just send the function definition to output */
fputs(func_buf->data, output);
}
if (is_pager)
ClosePager(output);
}
if (func)
free(func);
destroyPQExpBuffer(func_buf);
}
/* \t -- turn off headers and row count */
else if (strcmp(cmd, "t") == 0)
{
char *opt = psql_scan_slash_option(scan_state,
OT_NORMAL, NULL, true);
success = do_pset("tuples_only", opt, &pset.popt, pset.quiet);
free(opt);
}
/* \T -- define html <table ...> attributes */
else if (strcmp(cmd, "T") == 0)
{
char *value = psql_scan_slash_option(scan_state,
OT_NORMAL, NULL, false);
success = do_pset("tableattr", value, &pset.popt, pset.quiet);
free(value);
}
/* \timing -- toggle timing of queries */
else if (strcmp(cmd, "timing") == 0)
{
char *opt = psql_scan_slash_option(scan_state,
OT_NORMAL, NULL, false);
if (opt)
pset.timing = ParseVariableBool(opt);
else
pset.timing = !pset.timing;
if (!pset.quiet)
{
if (pset.timing)
puts(_("Timing is on."));
else
puts(_("Timing is off."));
}
free(opt);
}
/* \unset */
else if (strcmp(cmd, "unset") == 0)
{
char *opt = psql_scan_slash_option(scan_state,
OT_NORMAL, NULL, false);
if (!opt)
{
psql_error("\\%s: missing required argument\n", cmd);
success = false;
}
else if (!SetVariable(pset.vars, opt, NULL))
{
psql_error("\\%s: error\n", cmd);
success = false;
}
free(opt);
}
/* \w -- write query buffer to file */
else if (strcmp(cmd, "w") == 0 || strcmp(cmd, "write") == 0)
{
FILE *fd = NULL;
bool is_pipe = false;
char *fname = NULL;
if (!query_buf)
{
psql_error("no query buffer\n");
status = PSQL_CMD_ERROR;
}
else
{
fname = psql_scan_slash_option(scan_state,
OT_FILEPIPE, NULL, true);
expand_tilde(&fname);
if (!fname)
{
psql_error("\\%s: missing required argument\n", cmd);
success = false;
}
else
{
if (fname[0] == '|')
{
is_pipe = true;
fd = popen(&fname[1], "w");
}
else
{
canonicalize_path(fname);
fd = fopen(fname, "w");
}
if (!fd)
{
psql_error("%s: %s\n", fname, strerror(errno));
success = false;
}
}
}
if (fd)
{
int result;
if (query_buf && query_buf->len > 0)
fprintf(fd, "%s\n", query_buf->data);
if (is_pipe)
result = pclose(fd);
else
result = fclose(fd);
if (result == EOF)
{
psql_error("%s: %s\n", fname, strerror(errno));
success = false;
}
}
free(fname);
}
/* \x -- toggle expanded table representation */
else if (strcmp(cmd, "x") == 0)
{
char *opt = psql_scan_slash_option(scan_state,
OT_NORMAL, NULL, true);
success = do_pset("expanded", opt, &pset.popt, pset.quiet);
free(opt);
}
/* \z -- list table rights (equivalent to \dp) */
else if (strcmp(cmd, "z") == 0)
{
char *pattern = psql_scan_slash_option(scan_state,
OT_NORMAL, NULL, true);
success = permissionsList(pattern);
if (pattern)
free(pattern);
}
/* \! -- shell escape */
else if (strcmp(cmd, "!") == 0)
{
char *opt = psql_scan_slash_option(scan_state,
OT_WHOLE_LINE, NULL, false);
success = do_shell(opt);
free(opt);
}
/* \? -- slash command help */
else if (strcmp(cmd, "?") == 0)
slashUsage(pset.popt.topt.pager);
#if 0
/*
* These commands don't do anything. I just use them to test the parser.
*/
else if (strcmp(cmd, "void") == 0 || strcmp(cmd, "#") == 0)
{
int i = 0;
char *value;
while ((value = psql_scan_slash_option(scan_state,
OT_NORMAL, NULL, true)))
{
fprintf(stderr, "+ opt(%d) = |%s|\n", i++, value);
free(value);
}
}
#endif
else
status = PSQL_CMD_UNKNOWN;
if (!success)
status = PSQL_CMD_ERROR;
return status;
}
因篇幅问题不能全部显示,请点此查看更多更全内容