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

📄 command.c

📁 PostgreSQL7.4.6 for Linux
💻 C
📖 第 1 页 / 共 3 页
字号:
	/* \set -- generalized set variable/option command */	else if (strcmp(cmd, "set") == 0)	{		char	   *opt0 = scan_option(&string, 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 = NULL;			char	   *opt;			opt = scan_option(&string, OT_NORMAL, NULL, false);			newval = xstrdup(opt ? opt : "");			free(opt);			while ((opt = scan_option(&string, 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))			{				/* Check for special variables */				if (strcmp(opt0, "VERBOSITY") == 0)					SyncVerbosityVariable();			}			else			{				psql_error("\\%s: error\n", cmd);				success = false;			}			free(newval);		}		free(opt0);	}	/* \t -- turn off headers and row count */	else if (strcmp(cmd, "t") == 0)		success = do_pset("tuples_only", NULL, &pset.popt, quiet);	/* \T -- define html <table ...> attributes */	else if (strcmp(cmd, "T") == 0)	{		char	   *value = scan_option(&string, OT_NORMAL, NULL, false);		success = do_pset("tableattr", value, &pset.popt, quiet);		free(value);	}	/* \timing -- toggle timing of queries */	else if (strcmp(cmd, "timing") == 0)	{		pset.timing = !pset.timing;		if (!quiet)		{			if (pset.timing)				puts(gettext("Timing is on."));			else				puts(gettext("Timing is off."));		}	}	/* \unset */	else if (strcmp(cmd, "unset") == 0)	{		char	   *opt = scan_option(&string, 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 = CMD_ERROR;		}		else		{			fname = scan_option(&string, OT_FILEPIPE, NULL, true);			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					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)		success = do_pset("expanded", NULL, &pset.popt, quiet);	/* \z -- list table rights (equivalent to \dp) */	else if (strcmp(cmd, "z") == 0)	{		char	   *pattern = scan_option(&string, OT_NORMAL, NULL, true);		success = permissionsList(pattern);		if (pattern)			free(pattern);	}	/* \! -- shell escape */	else if (strcmp(cmd, "!") == 0)	{		success = do_shell(options_string);		/* wind pointer to end of line */		if (string)			string += strlen(string);	}	/* \? -- 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;		fprintf(stderr, "+ optstr = |%s|\n", options_string);		while ((value = scan_option(&string, OT_NORMAL, NULL, true)))		{			fprintf(stderr, "+ opt(%d) = |%s|\n", i++, value);			free(value);		}	}#endif	else		status = CMD_UNKNOWN;	if (!success)		status = CMD_ERROR;	/* eat the rest of the options string */	while ((val = scan_option(&string, OT_NORMAL, NULL, false)))	{		if (status != CMD_UNKNOWN)			psql_error("\\%s: extra argument \"%s\" ignored\n", cmd, val);		if (val)			free(val);	}	if (options_string && continue_parse)		*continue_parse = options_string + (string - string_cpy);	free(string_cpy);	return status;}/* * scan_option() * * *string points to possible option string on entry; on exit, it's updated * to point past the option string (if any). * * type tells what processing, if any, to perform on the option string; * for example, if it's a SQL identifier, we want to downcase any unquoted * letters. * * if quote is not NULL, *quote is set to 0 if no quoting was found, else * the quote symbol. * * if semicolon is true, trailing semicolon(s) that would otherwise be taken * as part of the option string will be stripped. * * Return value is NULL if no option found, else a malloc'd copy of the * processed option value. */static char *scan_option(char **string, enum option_type type, char *quote, bool semicolon){	unsigned int pos;	char	   *options_string;	char	   *return_val;	if (quote)		*quote = 0;	if (!string || !(*string))		return NULL;	options_string = *string;	/* skip leading whitespace */	pos = strspn(options_string, " \t\n\r");	switch (options_string[pos])	{			/*			 * End of line: no option present			 */		case '\0':			*string = &options_string[pos];			return NULL;			/*			 * Next command: treat like end of line			 *			 * XXX this means we can't conveniently accept options that start			 * with a backslash; therefore, option processing that			 * encourages use of backslashes is rather broken.			 */		case '\\':			*string = &options_string[pos];			return NULL;			/*			 * A single quote has a psql internal meaning, such as for			 * delimiting file names, and it also allows for such escape			 * sequences as \t.			 */		case '\'':			{				unsigned int jj;				unsigned short int bslash_count = 0;				for (jj = pos + 1; options_string[jj]; jj += PQmblen(&options_string[jj], pset.encoding))				{					if (options_string[jj] == '\'' && bslash_count % 2 == 0)						break;					if (options_string[jj] == '\\')						bslash_count++;					else						bslash_count = 0;				}				if (options_string[jj] == 0)				{					psql_error("parse error at the end of line\n");					*string = &options_string[jj];					return NULL;				}				return_val = unescape(&options_string[pos + 1], jj - pos - 1);				*string = &options_string[jj + 1];				if (quote)					*quote = '\'';				return return_val;			}			/*			 * Backticks are for command substitution, like in shells			 */		case '`':			{				bool		error = false;				FILE	   *fd;				char	   *file;				PQExpBufferData output;				char		buf[512];				size_t		result,							len;				len = strcspn(options_string + pos + 1, "`");				if (options_string[pos + 1 + len] == 0)				{					psql_error("parse error at the end of line\n");					*string = &options_string[pos + 1 + len];					return NULL;				}				options_string[pos + 1 + len] = '\0';				file = options_string + pos + 1;				fd = popen(file, "r");				if (!fd)				{					psql_error("%s: %s\n", file, strerror(errno));					error = true;				}				initPQExpBuffer(&output);				if (!error)				{					do					{						result = fread(buf, 1, 512, fd);						if (ferror(fd))						{							psql_error("%s: %s\n", file, strerror(errno));							error = true;							break;						}						appendBinaryPQExpBuffer(&output, buf, result);					} while (!feof(fd));					appendPQExpBufferChar(&output, '\0');				}				if (fd && pclose(fd) == -1)				{					psql_error("%s: %s\n", file, strerror(errno));					error = true;				}				if (!error)				{					if (output.data[strlen(output.data) - 1] == '\n')						output.data[strlen(output.data) - 1] = '\0';					return_val = output.data;				}				else				{					return_val = xstrdup("");					termPQExpBuffer(&output);				}				options_string[pos + 1 + len] = '`';				*string = options_string + pos + len + 2;				if (quote)					*quote = '`';				return return_val;			}			/*			 * Variable substitution			 */		case ':':			{				size_t		token_end;				const char *value;				char		save_char;				token_end = strcspn(&options_string[pos + 1], " \t\n\r");				save_char = options_string[pos + token_end + 1];				options_string[pos + token_end + 1] = '\0';				value = GetVariable(pset.vars, options_string + pos + 1);				return_val = xstrdup(value ? value : "");				options_string[pos + token_end + 1] = save_char;				*string = &options_string[pos + token_end + 1];				/* XXX should we set *quote to ':' here? */				return return_val;			}			/*			 * | could be the beginning of a pipe if so, take rest of line			 * as command			 */		case '|':			if (type == OT_FILEPIPE)			{				*string += strlen(*string);				return xstrdup(options_string + pos);			}			/* fallthrough for other option types */			/*			 * Default case: token extends to next whitespace, except that			 * whitespace within double quotes doesn't end the token.			 *			 * If we are processing the option as a SQL identifier, then			 * downcase unquoted letters and remove double-quotes --- but			 * doubled double-quotes become output double-quotes, per			 * spec.			 *			 * Note that a string like FOO"BAR"BAZ will be converted to			 * fooBARbaz; this is somewhat inconsistent with the SQL spec,			 * which would have us parse it as several identifiers.  But			 * for psql's purposes, we want a string like "foo"."bar" to			 * be treated as one option, so there's little choice.			 */		default:			{				bool		inquotes = false;				size_t		token_len;				char	   *cp;				/* Find end of option */				cp = &options_string[pos];				for (;;)				{					/* Find next quote, whitespace, or end of string */					cp += strcspn(cp, "\" \t\n\r");					if (inquotes)					{						if (*cp == '\0')						{							psql_error("parse error at the end of line\n");							*string = cp;							return NULL;						}						if (*cp == '"')							inquotes = false;						cp++;					}					else					{						if (*cp != '"')							break;		/* whitespace or end of string */						if (quote)							*quote = '"';						inquotes = true;						cp++;					}				}				*string = cp;				/* Copy the option */				token_len = cp - &options_string[pos];				return_val = malloc(token_len + 1);				if (!return_val)				{					psql_error("out of memory\n");					exit(EXIT_FAILURE);				}				memcpy(return_val, &options_string[pos], token_len);				return_val[token_len] = '\0';				/* Strip any trailing semi-colons if requested */				if (semicolon)				{					int			i;					for (i = token_len - 1;						 i >= 0 && return_val[i] == ';';						 i--)						 /* skip */ ;					if (i < 0)					{						/* nothing left after stripping the semicolon... */						free(return_val);						return NULL;					}					if (i < (int) token_len - 1)						return_val[i + 1] = '\0';				}				/*				 * If SQL identifier processing was requested, then we				 * strip out excess double quotes and downcase unquoted				 * letters.				 */				if (type == OT_SQLID || type == OT_SQLIDHACK)				{					inquotes = false;					cp = return_val;					while (*cp)					{						if (*cp == '"')						{							if (inquotes && cp[1] == '"')							{								/* Keep the first quote, remove the second */								cp++;							}							inquotes = !inquotes;							/* Collapse out quote at *cp */							memmove(cp, cp + 1, strlen(cp));							/* do not advance cp */						}						else						{							if (!inquotes && type == OT_SQLID)							{								if (isupper((unsigned char) *cp))									*cp = tolower((unsigned char) *cp);							}							cp += PQmblen(cp, pset.encoding);						}					}				}				return return_val;			}	}}/* * unescape * * Replaces \n, \t, and the like. * * The return value is malloc()'ed. */static char *unescape(const unsigned char *source, size_t len){	const unsigned char *p;	bool		esc = false;	/* Last character we saw was the escape								 * character */	char	   *destination,			   *tmp;	size_t		length;#ifdef USE_ASSERT_CHECKING	assert(source);#endif	length = Min(len, strlen(source)) + 1;	tmp = destination = malloc(length);	if (!tmp)	{		psql_error("out of memory\n");		exit(EXIT_FAILURE);	}	for (p = source; p - source < (int) len && *p; p += PQmblen(p, pset.encoding))	{		if (esc)		{			char		c;			switch (*p)			{				case 'n':					c = '\n';					break;				case 't':					c = '\t';					break;				case 'b':					c = '\b';					break;				case 'r':					c = '\r';					break;				case 'f':					c = '\f';					break;				case '0':				case '1':				case '2':				case '3':				case '4':				case '5':				case '6':				case '7':				case '8':				case '9':					c = parse_char((char **) &p);					break;				default:					c = *p;			}			*tmp++ = c;			esc = false;		}		else if (*p == '\\')			esc = true;		else		{			int			i;			const unsigned char *mp = p;			for (i = 0; i < PQmblen(p, pset.encoding); i++)				*tmp++ = *mp++;			esc = false;		}	}	*tmp = '\0';	return destination;}/* do_connect * -- handler for \connect * * Connects to a database (new_dbname) as a certain user (new_user). * The new user can be NULL. A db name of "-" is the same as the old one. * (That is, the one currently in pset. But pset.db can also be NULL. A NULL * dbname is handled by libpq.) * Returns true if all ok, false if the new connection couldn't be established. * The old connection will be kept if the session is interactive. */static booldo_connect(const char *new_dbname, const char *new_user){	PGconn	   *oldconn = pset.db;

⌨️ 快捷键说明

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