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

📄 psqlscan.l

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 L
📖 第 1 页 / 共 3 页
字号:
	{		case LEXRES_EOL:		/* end of input */			switch (state->start_state)			{				case INITIAL:					if (state->paren_depth > 0)					{						result = PSCAN_INCOMPLETE;						*prompt = PROMPT_PAREN;					}					else if (query_buf->len > 0)					{						result = PSCAN_EOL;						*prompt = PROMPT_CONTINUE;					}					else					{						/* never bother to send an empty buffer */						result = PSCAN_INCOMPLETE;						*prompt = PROMPT_READY;					}					break;				case xb:					result = PSCAN_INCOMPLETE;					*prompt = PROMPT_SINGLEQUOTE;					break;				case xc:					result = PSCAN_INCOMPLETE;					*prompt = PROMPT_COMMENT;					break;				case xd:					result = PSCAN_INCOMPLETE;					*prompt = PROMPT_DOUBLEQUOTE;					break;				case xh:					result = PSCAN_INCOMPLETE;					*prompt = PROMPT_SINGLEQUOTE;					break;				case xq:					result = PSCAN_INCOMPLETE;					*prompt = PROMPT_SINGLEQUOTE;					break;				case xdolq:					result = PSCAN_INCOMPLETE;					*prompt = PROMPT_DOLLARQUOTE;					break;				default:					/* can't get here */					fprintf(stderr, "invalid YY_START\n");					exit(1);			}			break;		case LEXRES_SEMI:		/* semicolon */			result = PSCAN_SEMICOLON;			*prompt = PROMPT_READY;			break;		case LEXRES_BACKSLASH:	/* backslash */			result = PSCAN_BACKSLASH;			*prompt = PROMPT_READY;			break;		default:			/* can't get here */			fprintf(stderr, "invalid yylex result\n");			exit(1);	}	return result;}/* * Clean up after scanning a string.  This flushes any unread input and * releases resources (but not the PsqlScanState itself).  Note however * that this does not reset the lexer scan state; that can be done by * psql_scan_reset(), which is an orthogonal operation. * * It is legal to call this when not scanning anything (makes it easier * to deal with error recovery). */voidpsql_scan_finish(PsqlScanState state){	/* Drop any incomplete variable expansions. */	while (state->buffer_stack != NULL)	{		StackElem  *stackelem = state->buffer_stack;		state->buffer_stack = stackelem->next;		yy_delete_buffer(stackelem->buf);		free(stackelem->bufstring);		if (stackelem->origstring)			free(stackelem->origstring);		free(stackelem);	}	/* Done with the outer scan buffer, too */	if (state->scanbufhandle)		yy_delete_buffer(state->scanbufhandle);	state->scanbufhandle = NULL;	if (state->scanbuf)		free(state->scanbuf);	state->scanbuf = NULL;}/* * Reset lexer scanning state to start conditions.  This is appropriate * for executing \r psql commands (or any other time that we discard the * prior contents of query_buf).  It is not, however, necessary to do this * when we execute and clear the buffer after getting a PSCAN_SEMICOLON or * PSCAN_EOL scan result, because the scan state must be INITIAL when those * conditions are returned. * * Note that this is unrelated to flushing unread input; that task is * done by psql_scan_finish(). */voidpsql_scan_reset(PsqlScanState state){	state->start_state = INITIAL;	state->paren_depth = 0;	state->xcdepth = 0;			/* not really necessary */	if (state->dolqstart)		free(state->dolqstart);	state->dolqstart = NULL;}/* * Return true if lexer is currently in an "inside quotes" state. * * This is pretty grotty but is needed to preserve the old behavior * that mainloop.c drops blank lines not inside quotes without even * echoing them. */boolpsql_scan_in_quote(PsqlScanState state){	return state->start_state != INITIAL;}/* * Scan the command name of a psql backslash command.  This should be called * after psql_scan() returns PSCAN_BACKSLASH.  It is assumed that the input * has been consumed through the leading backslash. * * The return value is a malloc'd copy of the command name, as parsed off * from the input. */char *psql_scan_slash_command(PsqlScanState state){	PQExpBufferData mybuf;	int			lexresult;	/* Must be scanning already */	psql_assert(state->scanbufhandle);	/* Build a local buffer that we'll return the data of */	initPQExpBuffer(&mybuf);	/* Set up static variables that will be used by yylex */	cur_state = state;	output_buf = &mybuf;	if (state->buffer_stack != NULL)		yy_switch_to_buffer(state->buffer_stack->buf);	else		yy_switch_to_buffer(state->scanbufhandle);	BEGIN(xslashcmd);	/* And lex. */	lexresult = yylex();	/* There are no possible errors in this lex state... */	return mybuf.data;}/* * Parse off the next argument for a backslash command, and return it as a * malloc'd string.  If there are no more arguments, returns NULL. * * 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, unquoted trailing semicolon(s) that would otherwise * be taken as part of the option string will be stripped. * * NOTE: the only possible syntax errors for backslash options are unmatched * quotes, which are detected when we run out of input.  Therefore, on a * syntax error we just throw away the string and return NULL; there is no * need to worry about flushing remaining input. */char *psql_scan_slash_option(PsqlScanState state,					   enum slash_option_type type,					   char *quote,					   bool semicolon){	PQExpBufferData mybuf;	int			lexresult;	char		local_quote;	bool		badarg;	/* Must be scanning already */	psql_assert(state->scanbufhandle);	if (quote == NULL)		quote = &local_quote;	*quote = 0;	/* Build a local buffer that we'll return the data of */	initPQExpBuffer(&mybuf);	/* Set up static variables that will be used by yylex */	cur_state = state;	output_buf = &mybuf;	option_type = type;	option_quote = quote;	if (state->buffer_stack != NULL)		yy_switch_to_buffer(state->buffer_stack->buf);	else		yy_switch_to_buffer(state->scanbufhandle);	if (type == OT_WHOLE_LINE)		BEGIN(xslashwholeline);	else		BEGIN(xslasharg);	/* And lex. */	lexresult = yylex();	/*	 * Check the lex result: we should have gotten back either LEXRES_OK	 * or LEXRES_EOL (the latter indicating end of string).  If we were inside	 * a quoted string, as indicated by YY_START, EOL is an error.	 */	psql_assert(lexresult == LEXRES_EOL || lexresult == LEXRES_OK);	badarg = false;	switch (YY_START)	{		case xslasharg:			/* empty arg, or possibly a psql variable substitution */			break;		case xslashquote:			if (lexresult != LEXRES_OK)				badarg = true;		/* hit EOL not ending quote */			break;		case xslashbackquote:			if (lexresult != LEXRES_OK)				badarg = true;		/* hit EOL not ending quote */			else			{				/* Perform evaluation of backticked command */				char	   *cmd = mybuf.data;				FILE	   *fd;				bool		error = false;				PQExpBufferData output;				char		buf[512];				size_t		result;				fd = popen(cmd, PG_BINARY_R);				if (!fd)				{					psql_error("%s: %s\n", cmd, strerror(errno));					error = true;				}				initPQExpBuffer(&output);				if (!error)				{					do					{						result = fread(buf, 1, sizeof(buf), fd);						if (ferror(fd))						{							psql_error("%s: %s\n", cmd, strerror(errno));							error = true;							break;						}						appendBinaryPQExpBuffer(&output, buf, result);					} while (!feof(fd));				}				if (fd && pclose(fd) == -1)				{					psql_error("%s: %s\n", cmd, strerror(errno));					error = true;				}				/* Now done with cmd, transfer result to mybuf */				resetPQExpBuffer(&mybuf);				if (!error)				{					/* strip any trailing newline */					if (output.len > 0 &&						output.data[output.len - 1] == '\n')						output.len--;					appendBinaryPQExpBuffer(&mybuf, output.data, output.len);				}				termPQExpBuffer(&output);			}			break;		case xslashdefaultarg:			/* Strip any trailing semi-colons if requested */			if (semicolon)			{				while (mybuf.len > 0 &&					   mybuf.data[mybuf.len - 1] == ';')				{					mybuf.data[--mybuf.len] = '\0';				}			}			/*			 * If SQL identifier processing was requested, then we strip out			 * excess double quotes and downcase unquoted letters.			 * 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.			 */			if (type == OT_SQLID || type == OT_SQLIDHACK)			{				bool		inquotes = false;				char	   *cp = mybuf.data;				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));						mybuf.len--;						/* do not advance cp */					}					else					{						if (!inquotes && type == OT_SQLID)							*cp = pg_tolower((unsigned char) *cp);						cp += PQmblen(cp, pset.encoding);					}				}			}			break;		case xslashquotedarg:			/* must have hit EOL inside double quotes */			badarg = true;			break;		case xslashwholeline:			/* always okay */			break;		default:			/* can't get here */			fprintf(stderr, "invalid YY_START\n");			exit(1);	}	if (badarg)	{		psql_error("unterminated quoted string\n");		termPQExpBuffer(&mybuf);		return NULL;	}	/*	 * An unquoted empty argument isn't possible unless we are at end of	 * command.  Return NULL instead.	 */	if (mybuf.len == 0 && *quote == 0)	{		termPQExpBuffer(&mybuf);		return NULL;	}	/* Else return the completed string. */	return mybuf.data;}/* * Eat up any unused \\ to complete a backslash command. */voidpsql_scan_slash_command_end(PsqlScanState state){	int			lexresult;	/* Must be scanning already */	psql_assert(state->scanbufhandle);	/* Set up static variables that will be used by yylex */	cur_state = state;	output_buf = NULL;	if (state->buffer_stack != NULL)		yy_switch_to_buffer(state->buffer_stack->buf);	else		yy_switch_to_buffer(state->scanbufhandle);	BEGIN(xslashend);	/* And lex. */	lexresult = yylex();	/* There are no possible errors in this lex state... */}/* * "Push back" the passed string so that it will be rescanned by subsequent * psql_scan_slash_option calls.  This is presently only used in the case * where a single-letter command has been concatenated with its argument. * * We use the same buffer stack mechanism as for variable expansion. */voidpsql_scan_slash_pushback(PsqlScanState state, const char *str){	/* needed for push_new_buffer */	cur_state = state;	push_new_buffer(str);}/* * Push the given string onto the stack of stuff to scan. * * cur_state must point to the active PsqlScanState. * * NOTE SIDE EFFECT: the new buffer is made the active flex input buffer. */static voidpush_new_buffer(const char *newstr){	StackElem  *stackelem;	stackelem = (StackElem *) pg_malloc(sizeof(StackElem));	stackelem->buf = prepare_buffer(newstr, strlen(newstr),									&stackelem->bufstring);	cur_state->curline = stackelem->bufstring;	if (cur_state->safe_encoding)	{		stackelem->origstring = NULL;		cur_state->refline = stackelem->bufstring;	}	else	{		stackelem->origstring = pg_strdup(newstr);		cur_state->refline = stackelem->origstring;	}	stackelem->next = cur_state->buffer_stack;	cur_state->buffer_stack = stackelem;}/* * Set up a flex input buffer to scan the given data.  We always make a * copy of the data.  If working in an unsafe encoding, the copy has * multibyte sequences replaced by FFs to avoid fooling the lexer rules. * * cur_state must point to the active PsqlScanState. * * NOTE SIDE EFFECT: the new buffer is made the active flex input buffer. */static YY_BUFFER_STATEprepare_buffer(const char *txt, int len, char **txtcopy){	char	   *newtxt;	/* Flex wants two \0 characters after the actual data */	newtxt = pg_malloc(len + 2);	*txtcopy = newtxt;	newtxt[len] = newtxt[len + 1] = YY_END_OF_BUFFER_CHAR;	if (cur_state->safe_encoding)		memcpy(newtxt, txt, len);	else	{		/* Gotta do it the hard way */		int		i = 0;		while (i < len)		{			int		thislen = PQmblen(txt + i, cur_state->encoding);			/* first byte should always be okay... */			newtxt[i] = txt[i];			i++;			while (--thislen > 0)				newtxt[i++] = (char) 0xFF;		}	}	return yy_scan_buffer(newtxt, len + 2);}/* * emit() --- body for ECHO macro * * NB: this must be used for ALL and ONLY the text copied from the flex * input data.  If you pass it something that is not part of the yytext * string, you are making a mistake.  Internally generated text can be * appended directly to output_buf. */static voidemit(const char *txt, int len){	if (cur_state->safe_encoding)		appendBinaryPQExpBuffer(output_buf, txt, len);	else	{		/* Gotta do it the hard way */		const char *reference = cur_state->refline;		int		i;		reference += (txt - cur_state->curline);		for (i = 0; i < len; i++)		{			char	ch = txt[i];			if (ch == (char) 0xFF)				ch = reference[i];			appendPQExpBufferChar(output_buf, ch);		}	}}

⌨️ 快捷键说明

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