⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 command.c

📁 PostgreSQL7.4.6 for Linux
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * psql - the PostgreSQL interactive terminal * * Copyright (c) 2000-2003, PostgreSQL Global Development Group * * $Header: /cvsroot/pgsql/src/bin/psql/command.c,v 1.105 2003/10/11 18:04:26 momjian Exp $ */#include "postgres_fe.h"#include "command.h"#include <errno.h>#include <assert.h>#include <ctype.h>#ifdef HAVE_PWD_H#include <pwd.h>#endif#ifndef WIN32#include <sys/types.h>			/* for umask() */#include <sys/stat.h>			/* for stat() */#include <fcntl.h>				/* open() flags */#include <unistd.h>				/* for geteuid(), getpid(), stat() */#else#include <win32.h>#include <io.h>#include <fcntl.h>#include <direct.h>#endif#include "libpq-fe.h"#include "pqexpbuffer.h"#include "common.h"#include "copy.h"#include "describe.h"#include "help.h"#include "input.h"#include "large_obj.h"#include "mainloop.h"#include "print.h"#include "settings.h"#include "variables.h"#include "mb/pg_wchar.h"/* functions for use in this file */static backslashResult exec_command(const char *cmd,			 const char *options_string,			 const char **continue_parse,			 PQExpBuffer query_buf,			 volatile int *paren_level);/* different ways for scan_option to handle parameter words */enum option_type{	OT_NORMAL,					/* normal case */	OT_SQLID,					/* treat as SQL identifier */	OT_SQLIDHACK,				/* SQL identifier, but don't downcase */	OT_FILEPIPE					/* it's a filename or pipe */};static char *scan_option(char **string, enum option_type type,			char *quote, bool semicolon);static char *unescape(const unsigned char *source, size_t len);static bool do_edit(const char *filename_arg, PQExpBuffer query_buf);static bool do_connect(const char *new_dbname, const char *new_user);static bool do_shell(const char *command);/*---------- * HandleSlashCmds: * * Handles all the different commands that start with '\', * ordinarily called by MainLoop(). * * 'line' is the current input line, which should not start with a '\' * but with the actual command name * (that is taken care of by MainLoop) * * 'query_buf' contains the query-so-far, which may be modified by * execution of the backslash command (for example, \r clears it) * query_buf can be NULL if there is no query so far. * * Returns a status code indicating what action is desired, see command.h. *---------- */backslashResultHandleSlashCmds(const char *line,				PQExpBuffer query_buf,				const char **end_of_cmd,				volatile int *paren_level){	backslashResult status = CMD_SKIP_LINE;	char	   *my_line;	char	   *options_string = NULL;	size_t		blank_loc;	const char *continue_parse = NULL;	/* tell the mainloop where the										 * backslash command ended */#ifdef USE_ASSERT_CHECKING	assert(line);#endif	my_line = xstrdup(line);	/*	 * Find the first whitespace. line[blank_loc] will now be the	 * whitespace character or the \0 at the end	 *	 * Also look for a backslash, so stuff like \p\g works.	 */	blank_loc = strcspn(my_line, " \t\n\r\\");	if (my_line[blank_loc] == '\\')	{		continue_parse = &my_line[blank_loc];		my_line[blank_loc] = '\0';		/* If it's a double backslash, we skip it. */		if (my_line[blank_loc + 1] == '\\')			continue_parse += 2;	}	/* do we have an option string? */	else if (my_line[blank_loc] != '\0')	{		options_string = &my_line[blank_loc + 1];		my_line[blank_loc] = '\0';	}	status = exec_command(my_line, options_string, &continue_parse, query_buf, paren_level);	if (status == CMD_UNKNOWN)	{		/*		 * If the command was not recognized, try to parse it as a		 * one-letter command with immediately following argument (a		 * still-supported, but no longer encouraged, syntax).		 */		char		new_cmd[2];		new_cmd[0] = my_line[0];		new_cmd[1] = '\0';		/* use line for options, because my_line was clobbered above */		status = exec_command(new_cmd, line + 1, &continue_parse, query_buf, paren_level);		/*		 * continue_parse must be relative to my_line for calculation		 * below		 */		continue_parse += my_line - line;#if 0							/* turned out to be too annoying */		if (status != CMD_UNKNOWN && isalpha((unsigned char) new_cmd[0]))			psql_error("Warning: This syntax is deprecated.\n");#endif	}	if (status == CMD_UNKNOWN)	{		if (pset.cur_cmd_interactive)			fprintf(stderr, gettext("Invalid command \\%s. Try \\? for help.\n"), my_line);		else			psql_error("invalid command \\%s\n", my_line);		status = CMD_ERROR;	}	if (continue_parse && *continue_parse && *(continue_parse + 1) == '\\')		continue_parse += 2;	if (end_of_cmd)	{		if (continue_parse)			*end_of_cmd = line + (continue_parse - my_line);		else			*end_of_cmd = line + strlen(line);	}	free(my_line);	return status;}static backslashResultexec_command(const char *cmd,			 const char *options_string,			 const char **continue_parse,			 PQExpBuffer query_buf,			 volatile int *paren_level){	bool		success = true; /* indicate here if the command ran ok or								 * failed */	bool		quiet = QUIET();	backslashResult status = CMD_SKIP_LINE;	char	   *string,			   *string_cpy,			   *val;	/*	 * The 'string' variable will be overwritten to point to the next	 * token, hence we need an extra pointer so we can free this at the	 * end.	 */	if (options_string)		string = string_cpy = xstrdup(options_string);	else		string = string_cpy = NULL;	/*	 * \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, quiet);		else			success = do_pset("format", "unaligned", &pset.popt, quiet);	}	/* \C -- override table title (formerly change HTML caption) */	else if (strcmp(cmd, "C") == 0)	{		char	   *opt = scan_option(&string, OT_NORMAL, NULL, true);		success = do_pset("title", opt, &pset.popt, quiet);		free(opt);	}	/*----------	 * \c or \connect -- connect to new database or as different user	 *	 * \c foo bar  connect to db "foo" as user "bar"	 * \c foo [-]  connect to db "foo" as current user	 * \c - bar    connect to current db as user "bar"	 * \c		   connect to default db as default user	 *----------	 */	else if (strcmp(cmd, "c") == 0 || strcmp(cmd, "connect") == 0)	{		char	   *opt1,				   *opt2;		char		opt1q,					opt2q;		/*		 * Ideally we should treat the arguments as SQL identifiers.  But		 * for backwards compatibility with 7.2 and older pg_dump files,		 * we have to take unquoted arguments verbatim (don't downcase		 * them). For now, double-quoted arguments may be stripped of		 * double quotes (as if SQL identifiers).  By 7.4 or so, pg_dump		 * files can be expected to double-quote all mixed-case \connect		 * arguments, and then we can get rid of OT_SQLIDHACK.		 */		opt1 = scan_option(&string, OT_SQLIDHACK, &opt1q, true);		opt2 = scan_option(&string, OT_SQLIDHACK, &opt2q, true);		if (opt2)			/* gave username */			success = do_connect(!opt1q && (strcmp(opt1, "-") == 0 || strcmp(opt1, "") == 0) ? "" : opt1,								 !opt2q && (strcmp(opt2, "-") == 0 || strcmp(opt2, "") == 0) ? "" : opt2);		else if (opt1)			/* gave database name */			success = do_connect(!opt1q && (strcmp(opt1, "-") == 0 || strcmp(opt1, "") == 0) ? "" : opt1, "");		else			/* connect to default db as default user */			success = do_connect(NULL, NULL);		free(opt1);		free(opt2);	}	/* \cd */	else if (strcmp(cmd, "cd") == 0)	{		char	   *opt = scan_option(&string, 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 (opt)			free(opt);	}	/* \copy */	else if (strcasecmp(cmd, "copy") == 0)	{		success = do_copy(options_string);		if (options_string)			string += strlen(string);	}	/* \copyright */	else if (strcmp(cmd, "copyright") == 0)		print_copyright();	/* \d* commands */	else if (cmd[0] == 'd')	{		char	   *pattern;		bool		show_verbose;		/* We don't do SQLID reduction on the pattern yet */		pattern = scan_option(&string, OT_NORMAL, NULL, true);		show_verbose = strchr(cmd, '+') ? true : false;		switch (cmd[1])		{			case '\0':			case '+':				if (pattern)					success = describeTableDetails(pattern, show_verbose);				else					/* standard listing of interesting things */					success = listTables("tvs", NULL, show_verbose);				break;			case 'a':				success = describeAggregates(pattern, show_verbose);				break;			case 'c':				success = listConversions(pattern);				break;			case 'C':				success = listCasts(pattern);				break;			case 'd':				success = objectDescription(pattern);				break;			case 'D':				success = listDomains(pattern);				break;			case 'f':				success = describeFunctions(pattern, show_verbose);				break;			case 'l':				success = do_lo_list();				break;			case 'n':				success = listSchemas(pattern);				break;			case 'o':				success = describeOperators(pattern);				break;			case 'p':				success = permissionsList(pattern);				break;			case 'T':				success = describeTypes(pattern, show_verbose);				break;			case 't':			case 'v':			case 'i':			case 's':			case 'S':				success = listTables(&cmd[1], pattern, show_verbose);				break;			case 'u':				success = describeUsers(pattern);				break;			default:				status = CMD_UNKNOWN;		}		if (pattern)			free(pattern);	}	/*	 * \e or \edit -- edit the current query buffer (or a file and make it	 * the query buffer	 */	else if (strcmp(cmd, "e") == 0 || strcmp(cmd, "edit") == 0)	{		char	   *fname;		if (!query_buf)		{			psql_error("no query buffer\n");			status = CMD_ERROR;		}		else		{			fname = scan_option(&string, OT_NORMAL, NULL, true);			status = do_edit(fname, query_buf) ? CMD_NEWEDIT : CMD_ERROR;			free(fname);		}	}	/* \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 = scan_option(&string, OT_NORMAL, &quoted, 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 = scan_option(&string, 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 = scan_option(&string, OT_NORMAL, NULL, false);		success = do_pset("fieldsep", fname, &pset.popt, quiet);		free(fname);	}	/* \g means send query */	else if (strcmp(cmd, "g") == 0)	{		char	   *fname = scan_option(&string, OT_FILEPIPE, NULL, false);		if (!fname)			pset.gfname = NULL;		else			pset.gfname = xstrdup(fname);		free(fname);		status = CMD_SEND;	}	/* help */	else if (strcmp(cmd, "h") == 0 || strcmp(cmd, "help") == 0)	{		helpSQL(options_string ? &options_string[strspn(options_string, " \t\n\r")] : NULL,				pset.popt.topt.pager);		/* set pointer to end of line */		if (string)			string += strlen(string);	}	/* 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, quiet);		else			success = do_pset("format", "aligned", &pset.popt, quiet);	}	/* \i is include file */	else if (strcmp(cmd, "i") == 0 || strcmp(cmd, "include") == 0)	{		char	   *fname = scan_option(&string, OT_NORMAL, NULL, true);		if (!fname)		{			psql_error("\\%s: missing required argument\n", cmd);			success = false;		}		else		{			success = (process_file(fname) == 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 = scan_option(&string, OT_NORMAL, NULL, true);		opt2 = scan_option(&string, OT_NORMAL, NULL, true);		if (strcmp(cmd + 3, "export") == 0)		{			if (!opt2)			{				psql_error("\\%s: missing required argument\n", cmd);				success = false;			}			else				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				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 = CMD_UNKNOWN;		free(opt1);		free(opt2);	}	/* \o -- set query output */	else if (strcmp(cmd, "o") == 0 || strcmp(cmd, "out") == 0)	{		char	   *fname = scan_option(&string, OT_FILEPIPE, NULL, true);		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 (!quiet)			puts(gettext("Query buffer is empty."));		fflush(stdout);	}	/* \pset -- set printing parameters */	else if (strcmp(cmd, "pset") == 0)	{		char	   *opt0 = scan_option(&string, OT_NORMAL, NULL, false);		char	   *opt1 = scan_option(&string, OT_NORMAL, NULL, false);		if (!opt0)		{			psql_error("\\%s: missing required argument\n", cmd);			success = false;		}		else			success = do_pset(opt0, opt1, &pset.popt, quiet);		free(opt0);		free(opt1);	}	/* \q or \quit */	else if (strcmp(cmd, "q") == 0 || strcmp(cmd, "quit") == 0)		status = CMD_TERMINATE;	/* reset(clear) the buffer */	else if (strcmp(cmd, "r") == 0 || strcmp(cmd, "reset") == 0)	{		resetPQExpBuffer(query_buf);		if (paren_level)			*paren_level = 0;		if (!quiet)			puts(gettext("Query buffer reset (cleared)."));	}	/* \s save history in a file or show it on the screen */	else if (strcmp(cmd, "s") == 0)	{		char	   *fname = scan_option(&string, OT_NORMAL, NULL, true);		success = saveHistory(fname ? fname : "/dev/tty");		if (success && !quiet && fname)			printf(gettext("Wrote history to file \"%s\".\n"), fname);		free(fname);	}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -