*
* parser.cpp
* Main entry point/driver for openGauss grammar
*
* Note that the grammar is not allowed to perform any table access
* (since we need to be able to do basic parsing even while inside an
* aborted transaction). Therefore, the data structures returned by
* the grammar are "raw" parsetrees that still need to be analyzed by
* analyze.c and related files.
*
*
* Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* src/common/backend/parser/parser.cpp
*
* -------------------------------------------------------------------------
*/
#include "postgres.h"
#include "storage/proc.h"
#include "knl/knl_variable.h"
#include "nodes/parsenodes.h"
#include "parser/gramparse.h"
#include "parser/parser.h"
#include "utils/guc.h"
#include "miscadmin.h"
#include "catalog/pg_namespace.h"
extern void resetOperatorPlusFlag();
static bool is_prefer_parse_cursor_parentheses_as_expr()
{
return PREFER_PARSE_CURSOR_PARENTHESES_AS_EXPR;
}
static bool is_cursor_function_exist()
{
return get_func_oid("cursor", InvalidOid, NULL, false) != InvalidOid;
}
static bool is_select_stmt_definitely(int start_token) {
return start_token == SELECT || start_token == WITH;
}
static void resetIsTimeCapsuleFlag()
{
u_sess->parser_cxt.isTimeCapsule = false;
}
static void resetHasPartitionComment()
{
u_sess->parser_cxt.hasPartitionComment = false;
}
static void resetCreateFuncFlag()
{
u_sess->parser_cxt.isCreateFuncOrProc = false;
}
static void resetForbidTruncateFlag()
{
u_sess->parser_cxt.isForbidTruncate = false;
}
static void resetHasSetUservarFlag()
{
u_sess->parser_cxt.has_set_uservar = false;
u_sess->parser_cxt.has_equal_uservar = false;
}
* raw_parser
* Given a query in string form, do lexical and grammatical analysis.
*
* Returns a list of raw (un-analyzed) parse trees.
*/
List* raw_parser(const char* str, List** query_string_locationlist)
{
core_yyscan_t yyscanner;
base_yy_extra_type yyextra;
int yyresult;
resetOperatorPlusFlag();
resetHasPartitionComment();
resetIsTimeCapsuleFlag();
resetCreateFuncFlag();
resetForbidTruncateFlag();
resetHasSetUservarFlag();
yyscanner = scanner_init(str, &yyextra.core_yy_extra, &ScanKeywords, ScanKeywordTokens);
yyextra.lookahead_len = 0;
parser_init(&yyextra);
yyresult = base_yyparse(yyscanner);
scanner_finish(yyscanner);
if (yyresult) {
return NIL;
}
if (query_string_locationlist != NULL) {
*query_string_locationlist = yyextra.core_yy_extra.query_string_locationlist;
if (PointerIsValid(*query_string_locationlist) &&
(size_t)lfirst_int(list_tail(*query_string_locationlist)) < (strlen(str) - 1)) {
*query_string_locationlist = lappend_int(*query_string_locationlist, strlen(str));
}
}
return yyextra.parsetree;
}
#define GET_NEXT_TOKEN_WITHOUT_YY() \
do { \
if (lookahead_len) { \
base_yy_lookahead& lookahead = lookaheads[lookahead_len - 1]; \
next_token = lookahead.token; \
next_yyleng = lookahead.yyleng; \
lvalp->core_yystype = lookahead.yylval; \
*llocp = lookahead.yylloc; \
scanbuf[lookahead.prev_hold_char_loc] = lookahead.prev_hold_char; \
scanbuf[lookahead.yylloc + lookahead.yyleng] = '\0'; \
lookahead_len--; \
} else { \
next_token = core_yylex(&(lvalp->core_yystype), llocp, yyscanner); \
next_yyleng = pg_yyget_leng(yyscanner); \
} \
} while (0)
#define GET_NEXT_TOKEN() \
do { \
cur_yylval = lvalp->core_yystype; \
cur_yylloc = *llocp; \
GET_NEXT_TOKEN_WITHOUT_YY(); \
} while (0)
#define SET_LOOKAHEAD_TOKEN() \
do { \
lookahead_len = 1; \
base_yy_lookahead& lookahead = lookaheads[0]; \
lookahead.token = next_token; \
lookahead.yylval = lvalp->core_yystype; \
lookahead.yylloc = *llocp; \
lookahead.yyleng = next_yyleng; \
lookahead.prev_hold_char_loc = cur_yylloc + cur_yyleng; \
lookahead.prev_hold_char = scanbuf[cur_yylloc + cur_yyleng]; \
} while (0)
#define PARSE_CURSOR_PARENTHESES_AS_EXPR() \
do { \
cur_token = CURSOR_EXPR; \
lookaheads[0].token = next_token_2; \
lookaheads[0].yylval = lvalp->core_yystype; \
lookaheads[0].yylloc = *llocp; \
lookaheads[0].yyleng = next_yyleng_2; \
lookaheads[0].prev_hold_char_loc = cur_yylloc_2 + next_yyleng_1; \
lookaheads[0].prev_hold_char = scanbuf[cur_yylloc_2 + next_yyleng_1]; \
lookahead_len = 1; \
lvalp->core_yystype = core_yystype_2; \
*llocp = cur_yylloc_2; \
} while (0)
#define SET_LOOKAHEAD_2_TOKEN() \
do { \
lookaheads[1].token = next_token_1; \
lookaheads[1].yylval = core_yystype_2; \
lookaheads[1].yylloc = cur_yylloc_2; \
lookaheads[1].yyleng = next_yyleng_1; \
lookaheads[1].prev_hold_char_loc = cur_yylloc_1 + cur_yyleng_1; \
lookaheads[1].prev_hold_char = scanbuf[cur_yylloc_1 + cur_yyleng_1]; \
lookaheads[0].token = next_token_2; \
lookaheads[0].yylval = lvalp->core_yystype; \
lookaheads[0].yylloc = *llocp; \
lookaheads[0].yyleng = next_yyleng_2; \
lookaheads[0].prev_hold_char_loc = cur_yylloc_2 + next_yyleng_1; \
lookaheads[0].prev_hold_char = scanbuf[cur_yylloc_2 + next_yyleng_1]; \
lookahead_len = 2; \
lvalp->core_yystype = core_yystype_1; \
*llocp = cur_yylloc_1; \
scanbuf[cur_yylloc_1 + cur_yyleng_1] = '\0'; \
} while (0)
#define SET_LOOKAHEAD_3_TOKEN() \
do { \
lookaheads[2].token = next_token_2; \
lookaheads[2].yylval = core_yystype_3; \
lookaheads[2].yylloc = cur_yylloc_3; \
lookaheads[1].token = next_token_1; \
lookaheads[1].yylval = core_yystype_2; \
lookaheads[1].yylloc = cur_yylloc_2; \
lookaheads[0].token = next_token_3; \
lookaheads[0].yylval = lvalp->core_yystype; \
lookaheads[0].yylloc = *llocp; \
lookahead_len = 3; \
lvalp->core_yystype = core_yystype_1; \
*llocp = cur_yylloc_1; \
} while (0)
* Intermediate filter between parser and core lexer (core_yylex in scan.l).
*
* The filter is needed because in some cases the standard SQL grammar
* requires more than one token lookahead. We reduce these cases to one-token
* lookahead by combining tokens here, in order to keep the grammar LALR(1).
*
* Using a filter is simpler than trying to recognize multiword tokens
* directly in scan.l, because we'd have to allow for comments between the
* words. Furthermore it's not clear how to do it without re-introducing
* scanner backtrack, which would cost more performance than this filter
* layer does.
*
* The filter also provides a convenient place to translate between
* the core_YYSTYPE and YYSTYPE representations (which are really the
* same thing anyway, but notationally they're different).
*/
int base_yylex(YYSTYPE* lvalp, YYLTYPE* llocp, core_yyscan_t yyscanner)
{
base_yy_extra_type* yyextra = pg_yyget_extra(yyscanner);
char* scanbuf = yyextra->core_yy_extra.scanbuf;
base_yy_lookahead* lookaheads = yyextra->lookaheads;
int& lookahead_len = yyextra->lookahead_len;
int cur_token;
YYLTYPE cur_yyleng = 0;
int next_token;
YYLTYPE next_yyleng;
core_YYSTYPE cur_yylval;
YYLTYPE cur_yylloc = 0;
int next_token_1 = 0;
YYLTYPE next_yyleng_1 = 0;
core_YYSTYPE core_yystype_1;
YYLTYPE cur_yylloc_1 = 0;
YYLTYPE cur_yyleng_1 = 0;
int next_token_2 = 0;
YYLTYPE next_yyleng_2 = 0;
core_YYSTYPE core_yystype_2;
YYLTYPE cur_yylloc_2 = 0;
int next_token_3 = 0;
core_YYSTYPE core_yystype_3;
YYLTYPE cur_yylloc_3 = 0;
if (lookahead_len != 0) {
const base_yy_lookahead& lookahead = lookaheads[lookahead_len - 1];
cur_token = lookahead.token;
cur_yyleng = lookahead.yyleng;
lvalp->core_yystype = lookahead.yylval;
*llocp = lookahead.yylloc;
scanbuf[lookahead.prev_hold_char_loc] = lookahead.prev_hold_char;
scanbuf[lookahead.yylloc + lookahead.yyleng] = '\0';
lookahead_len--;
} else {
cur_token = core_yylex(&(lvalp->core_yystype), llocp, yyscanner);
cur_yyleng = pg_yyget_leng(yyscanner);
}
if (u_sess->attr.attr_sql.sql_compatibility == B_FORMAT
&& lookahead_len == 0
&& !IsInitdb
&& !u_sess->attr.attr_common.IsInplaceUpgrade) {
bool is_last_colon;
if (cur_token == int(';')) {
is_last_colon = true;
} else {
is_last_colon = false;
}
if (yyextra->core_yy_extra.is_delimiter_name == true) {
if (strcmp(";",u_sess->attr.attr_common.delimiter_name) == 0) {
cur_token = END_OF_INPUT_COLON;
} else {
if (yyextra->core_yy_extra.is_last_colon == false ) {
cur_token = END_OF_INPUT_COLON;
} else {
cur_token = END_OF_INPUT;
}
}
}
if (yyextra->core_yy_extra.is_proc_end == true) {
cur_token = END_OF_PROC;
}
yyextra->core_yy_extra.is_proc_end = false;
yyextra->core_yy_extra.is_delimiter_name = false;
yyextra->core_yy_extra.is_last_colon = is_last_colon;
}
switch (cur_token) {
case NULLS_P:
* NULLS FIRST and NULLS LAST must be reduced to one token
*/
GET_NEXT_TOKEN();
switch (next_token) {
case FIRST_P:
cur_token = NULLS_FIRST;
break;
case LAST_P:
cur_token = NULLS_LAST;
break;
default:
SET_LOOKAHEAD_TOKEN();
lvalp->core_yystype = cur_yylval;
*llocp = cur_yylloc;
scanbuf[cur_yylloc + cur_yyleng] = '\0';
break;
}
break;
case NOT:
* @hdfs
* In order to solve the conflict in gram.y, NOT and ENFORCED must be reduced to one token.
*/
GET_NEXT_TOKEN();
switch (next_token) {
case ENFORCED:
cur_token = NOT_ENFORCED;
break;
case IN_P:
cur_token = NOT_IN;
break;
case BETWEEN:
cur_token = NOT_BETWEEN;
break;
case LIKE:
cur_token = NOT_LIKE;
break;
case ILIKE:
cur_token = NOT_ILIKE;
break;
case SIMILAR:
cur_token = NOT_SIMILAR;
break;
default:
SET_LOOKAHEAD_TOKEN();
lvalp->core_yystype = cur_yylval;
*llocp = cur_yylloc;
scanbuf[cur_yylloc + cur_yyleng] = '\0';
break;
}
break;
case EVENT:
* Event trigger must be reduced to one token
*/
GET_NEXT_TOKEN();
switch (next_token) {
case TRIGGER:
cur_token = EVENT_TRIGGER;
break;
default:
SET_LOOKAHEAD_TOKEN();
lvalp->core_yystype = cur_yylval;
*llocp = cur_yylloc;
scanbuf[cur_yylloc + cur_yyleng] = '\0';
break;
}
break;
case WITH:
* WITH TIME must be reduced to one token
*/
GET_NEXT_TOKEN();
switch (next_token) {
case TIME:
cur_token = WITH_TIME;
break;
default:
SET_LOOKAHEAD_TOKEN();
lvalp->core_yystype = cur_yylval;
*llocp = cur_yylloc;
scanbuf[cur_yylloc + cur_yyleng] = '\0';
break;
}
break;
case INCLUDING:
* INCLUDING ALL must be reduced to one token
*/
GET_NEXT_TOKEN();
switch (next_token) {
case ALL:
cur_token = INCLUDING_ALL;
break;
default:
SET_LOOKAHEAD_TOKEN();
lvalp->core_yystype = cur_yylval;
*llocp = cur_yylloc;
scanbuf[cur_yylloc + cur_yyleng] = '\0';
break;
}
break;
case RENAME:
* RENAME PARTITION must be reduced to one token
*/
GET_NEXT_TOKEN();
switch (next_token) {
case PARTITION:
cur_token = RENAME_PARTITION;
break;
default:
SET_LOOKAHEAD_TOKEN();
lvalp->core_yystype = cur_yylval;
*llocp = cur_yylloc;
scanbuf[cur_yylloc + cur_yyleng] = '\0';
break;
}
break;
case PARTITION:
* RENAME PARTITION must be reduced to one token
*/
GET_NEXT_TOKEN();
switch (next_token) {
case FOR:
cur_token = PARTITION_FOR;
break;
default:
SET_LOOKAHEAD_TOKEN();
lvalp->core_yystype = cur_yylval;
*llocp = cur_yylloc;
scanbuf[cur_yylloc + cur_yyleng] = '\0';
break;
}
break;
case SUBPARTITION:
GET_NEXT_TOKEN();
switch (next_token) {
case FOR:
cur_token = SUBPARTITION_FOR;
break;
default:
SET_LOOKAHEAD_TOKEN();
lvalp->core_yystype = cur_yylval;
*llocp = cur_yylloc;
scanbuf[cur_yylloc + cur_yyleng] = '\0';
break;
}
break;
case ADD_P:
* ADD PARTITION must be reduced to one token
*/
GET_NEXT_TOKEN();
switch (next_token) {
case PARTITION:
cur_token = ADD_PARTITION;
break;
case SUBPARTITION:
cur_token = ADD_SUBPARTITION;
break;
default:
SET_LOOKAHEAD_TOKEN();
lvalp->core_yystype = cur_yylval;
*llocp = cur_yylloc;
scanbuf[cur_yylloc + cur_yyleng] = '\0';
break;
}
break;
case DROP:
* DROP PARTITION must be reduced to one token
*/
GET_NEXT_TOKEN();
switch (next_token) {
case PARTITION:
cur_token = DROP_PARTITION;
break;
case SUBPARTITION:
cur_token = DROP_SUBPARTITION;
break;
default:
SET_LOOKAHEAD_TOKEN();
lvalp->core_yystype = cur_yylval;
*llocp = cur_yylloc;
scanbuf[cur_yylloc + cur_yyleng] = '\0';
break;
}
break;
case REBUILD:
* REBUILD PARTITION must be reduced to one token
*/
GET_NEXT_TOKEN();
switch (next_token) {
case PARTITION:
cur_token = REBUILD_PARTITION;
break;
default:
SET_LOOKAHEAD_TOKEN();
lvalp->core_yystype = cur_yylval;
*llocp = cur_yylloc;
scanbuf[cur_yylloc + cur_yyleng] = '\0';
break;
}
break;
case MODIFY_P:
* MODIFY PARTITION must be reduced to one token
*/
GET_NEXT_TOKEN();
switch (next_token) {
case PARTITION:
cur_token = MODIFY_PARTITION;
break;
default:
SET_LOOKAHEAD_TOKEN();
lvalp->core_yystype = cur_yylval;
*llocp = cur_yylloc;
scanbuf[cur_yylloc + cur_yyleng] = '\0';
break;
}
break;
case DECLARE:
* DECLARE foo CUROSR must be looked ahead, and if determined as a DECLARE_CURSOR, we should set the yylaval
* and yylloc back, letting the parser read the cursor name correctly.
* here we may still have token in lookaheads, so use GET_NEXT_TOKEN to get
*/
GET_NEXT_TOKEN();
lookaheads[1].token = next_token;
lookaheads[1].yylval = lvalp->core_yystype;
lookaheads[1].yylloc = *llocp;
lookaheads[1].yyleng = next_yyleng;
lookaheads[1].prev_hold_char_loc = cur_yylloc + cur_yyleng;
lookaheads[1].prev_hold_char = scanbuf[cur_yylloc + cur_yyleng];
* get the second token after DECLARE. If it is cursor grammar, we are sure that this is a cursr stmt
* in fact we don't have any token in lookaheads here for sure, cause MAX_LOOKAHEAD_LEN is 2.
* but maybe someday MAX_LOOKAHEAD_LEN increase, so we still use GET_NEXT_TOKEN_WITHOUT_SET_CURYY
*/
GET_NEXT_TOKEN_WITHOUT_YY();
lookaheads[0].token = next_token;
lookaheads[0].yylval = lvalp->core_yystype;
lookaheads[0].yylloc = *llocp;
lookaheads[0].yyleng = next_yyleng;
lookaheads[0].prev_hold_char_loc = lookaheads[1].yylloc + lookaheads[1].yyleng;
lookaheads[0].prev_hold_char = scanbuf[lookaheads[1].yylloc + lookaheads[1].yyleng];
lookahead_len = 2;
switch (next_token) {
case CURSOR:
case BINARY:
case INSENSITIVE:
case NO:
case SCROLL:
cur_token = DECLARE_CURSOR;
lvalp->core_yystype = cur_yylval;
*llocp = cur_yylloc;
scanbuf[cur_yylloc + cur_yyleng] = '\0';
break;
default:
lvalp->core_yystype = cur_yylval;
*llocp = cur_yylloc;
scanbuf[cur_yylloc + cur_yyleng] = '\0';
break;
}
break;
case VALID:
* VALID BEGIN must be reduced to one token, to avoid conflict with BEGIN TRANSACTIOn and BEGIN anonymous
* block.
*/
GET_NEXT_TOKEN();
switch (next_token) {
case BEGIN_P:
case BEGIN_NON_ANOYBLOCK:
cur_token = VALID_BEGIN;
break;
default:
SET_LOOKAHEAD_TOKEN();
lvalp->core_yystype = cur_yylval;
*llocp = cur_yylloc;
scanbuf[cur_yylloc + cur_yyleng] = '\0';
break;
}
break;
case START:
* START WITH must be reduced to one token, to allow START as table / column alias.
*/
GET_NEXT_TOKEN();
switch (next_token) {
case WITH:
cur_token = START_WITH;
break;
default:
SET_LOOKAHEAD_TOKEN();
lvalp->core_yystype = cur_yylval;
*llocp = cur_yylloc;
scanbuf[cur_yylloc + cur_yyleng] = '\0';
break;
}
break;
case CONNECT:
* CONNECT BY must be reduced to one token, to allow CONNECT as table / column alias.
*/
GET_NEXT_TOKEN();
switch (next_token) {
case BY:
cur_token = CONNECT_BY;
break;
default:
SET_LOOKAHEAD_TOKEN();
lvalp->core_yystype = cur_yylval;
*llocp = cur_yylloc;
scanbuf[cur_yylloc + cur_yyleng] = '\0';
break;
}
break;
case ON:
GET_NEXT_TOKEN();
lookaheads[1].token = next_token;
lookaheads[1].yylval = lvalp->core_yystype;
lookaheads[1].yylloc = *llocp;
lookaheads[1].yyleng = next_yyleng;
lookaheads[1].prev_hold_char_loc = cur_yylloc + cur_yyleng;
lookaheads[1].prev_hold_char = scanbuf[cur_yylloc + cur_yyleng];
* get the second token after ON.
* in fact we don't have any token in lookaheads here for sure, cause MAX_LOOKAHEAD_LEN is 2.
* but maybe someday MAX_LOOKAHEAD_LEN increase, so we still use GET_NEXT_TOKEN_WITHOUT_SET_CURYY
*/
GET_NEXT_TOKEN_WITHOUT_YY();
lookaheads[0].token = next_token;
lookaheads[0].yylval = lvalp->core_yystype;
lookaheads[0].yylloc = *llocp;
lookaheads[0].yyleng = next_yyleng;
lookaheads[0].prev_hold_char_loc = lookaheads[1].yylloc + lookaheads[1].yyleng;
lookaheads[0].prev_hold_char = scanbuf[lookaheads[1].yylloc + lookaheads[1].yyleng];
lookahead_len = 2;
switch (next_token) {
case CURRENT_TIMESTAMP:
case CURRENT_TIME:
case CURRENT_DATE:
case LOCALTIME:
case LOCALTIMESTAMP:
cur_token = ON_UPDATE_TIME;
lvalp->core_yystype = cur_yylval;
*llocp = cur_yylloc;
scanbuf[cur_yylloc + cur_yyleng] = '\0';
break;
default:
lvalp->core_yystype = cur_yylval;
*llocp = cur_yylloc;
scanbuf[cur_yylloc + cur_yyleng] = '\0';
break;
}
break;
case SHOW:
* SHOW ERRORS must be reduced to one token, to allow ERRORS as table / column alias.
*/
GET_NEXT_TOKEN();
switch (next_token) {
case ERRORS:
cur_token = SHOW_ERRORS;
break;
default:
SET_LOOKAHEAD_TOKEN();
lvalp->core_yystype = cur_yylval;
*llocp = cur_yylloc;
scanbuf[cur_yylloc + cur_yyleng] = '\0';
break;
}
break;
case USE_P:
* USE INDEX \USE KEY must be reduced to one token,to allow KEY\USE as table / column alias.
*/
GET_NEXT_TOKEN();
switch (next_token) {
case KEY:
cur_token = USE_INDEX;
break;
case INDEX:
cur_token = USE_INDEX;
break;
default:
SET_LOOKAHEAD_TOKEN();
lvalp->core_yystype = cur_yylval;
*llocp = cur_yylloc;
scanbuf[cur_yylloc + cur_yyleng] = '\0';
break;
}
break;
case FORCE:
* FORCE INDEX \FORCE KEY must be reduced to one token,to allow KEY\FORCE as table / column alias.
*/
GET_NEXT_TOKEN();
switch (next_token) {
case KEY:
cur_token = FORCE_INDEX;
break;
case INDEX:
cur_token = FORCE_INDEX;
break;
default:
SET_LOOKAHEAD_TOKEN();
lvalp->core_yystype = cur_yylval;
*llocp = cur_yylloc;
scanbuf[cur_yylloc + cur_yyleng] = '\0';
break;
}
break;
case IGNORE:
* IGNORE INDEX \IGNORE KEY must be reduced to one token,to allow KEY\IGNORE as table / column alias.
*/
GET_NEXT_TOKEN();
switch (next_token) {
case KEY:
case INDEX:
cur_token = IGNORE_INDEX;
break;
default:
SET_LOOKAHEAD_TOKEN();
lvalp->core_yystype = cur_yylval;
*llocp = cur_yylloc;
scanbuf[cur_yylloc + cur_yyleng] = '\0';
break;
}
break;
case CURSOR:
GET_NEXT_TOKEN();
core_yystype_1 = cur_yylval;
cur_yylloc_1 = cur_yylloc;
cur_yyleng_1 = cur_yyleng;
next_token_1 = next_token;
next_yyleng_1 = next_yyleng;
if (next_token_1 != '(') {
SET_LOOKAHEAD_TOKEN();
lvalp->core_yystype = cur_yylval;
*llocp = cur_yylloc;
scanbuf[cur_yylloc + cur_yyleng] = '\0';
} else {
GET_NEXT_TOKEN();
core_yystype_2 = cur_yylval;
cur_yylloc_2 = cur_yylloc;
next_token_2 = next_token;
next_yyleng_2 = next_yyleng;
if (next_token_1 == '(' && (is_select_stmt_definitely(next_token))) {
PARSE_CURSOR_PARENTHESES_AS_EXPR();
} else if (is_prefer_parse_cursor_parentheses_as_expr() && !is_cursor_function_exist()) {
PARSE_CURSOR_PARENTHESES_AS_EXPR();
} else {
SET_LOOKAHEAD_2_TOKEN();
}
if (t_thrd.proc->workingVersionNum < CURSOR_EXPRESSION_VERSION_NUMBER &&
cur_token == CURSOR_EXPR) {
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("Unsupported feature: cursor expression during the upgrade")));
}
}
break;
case LATERAL_P:
GET_NEXT_TOKEN();
core_yystype_1 = cur_yylval;
cur_yylloc_1 = cur_yylloc;
cur_yyleng_1 = cur_yyleng;
next_token_1 = next_token;
next_yyleng_1 = next_yyleng;
if (next_token_1 != IDENT) {
SET_LOOKAHEAD_TOKEN();
lvalp->core_yystype = cur_yylval;
*llocp = cur_yylloc;
scanbuf[cur_yylloc + cur_yyleng] = '\0';
} else {
GET_NEXT_TOKEN();
core_yystype_2 = cur_yylval;
cur_yylloc_2 = cur_yylloc;
next_token_2 = next_token;
next_yyleng_2 = next_yyleng;
if (next_token_1 == IDENT && next_token == '(') {
cur_token = LATERAL_EXPR;
}
SET_LOOKAHEAD_2_TOKEN();
}
break;
case STATIC_P:
GET_NEXT_TOKEN();
switch (next_token) {
case FUNCTION:
cur_token = STATIC_FUNCTION;
break;
case PROCEDURE:
cur_token = STATIC_PROCEDURE;
break;
default:
SET_LOOKAHEAD_TOKEN();
lvalp->core_yystype = cur_yylval;
*llocp = cur_yylloc;
scanbuf[cur_yylloc + cur_yyleng] = '\0';
break;
}
break;
case MEMBER:
GET_NEXT_TOKEN();
switch (next_token) {
case FUNCTION:
cur_token = MEMBER_FUNCTION;
break;
case PROCEDURE:
cur_token = MEMBER_PROCEDURE;
break;
default:
SET_LOOKAHEAD_TOKEN();
lvalp->core_yystype = cur_yylval;
*llocp = cur_yylloc;
scanbuf[cur_yylloc + cur_yyleng] = '\0';
break;
}
break;
case CONSTRUCTOR:
GET_NEXT_TOKEN();
switch (next_token) {
case FUNCTION:
cur_token = CONSTRUCTOR_FUNCTION;
break;
default:
SET_LOOKAHEAD_TOKEN();
lvalp->core_yystype = cur_yylval;
*llocp = cur_yylloc;
scanbuf[cur_yylloc + cur_yyleng] = '\0';
break;
}
break;
case MAP:
GET_NEXT_TOKEN();
switch (next_token) {
case MEMBER:
cur_token = MAP_MEMBER;
break;
default:
SET_LOOKAHEAD_TOKEN();
lvalp->core_yystype = cur_yylval;
*llocp = cur_yylloc;
scanbuf[cur_yylloc + cur_yyleng] = '\0';
break;
}
break;
case SELF:
GET_NEXT_TOKEN();
switch (next_token) {
case INOUT:
cur_token = SELF_INOUT;
break;
default:
SET_LOOKAHEAD_TOKEN();
lvalp->core_yystype = cur_yylval;
*llocp = cur_yylloc;
scanbuf[cur_yylloc + cur_yyleng] = '\0';
break;
}
break;
case FALSE_P:
GET_NEXT_TOKEN();
core_yystype_1 = cur_yylval;
cur_yylloc_1 = cur_yylloc;
cur_yyleng_1 = cur_yyleng;
next_token_1 = next_token;
next_yyleng_1 = next_yyleng;
switch (next_token) {
case ON:
GET_NEXT_TOKEN();
core_yystype_2 = cur_yylval;
cur_yylloc_2 = cur_yylloc;
next_token_2 = next_token;
next_yyleng_2 = next_yyleng;
switch (next_token) {
case ERROR_P:
cur_token = FALSE_ON_ERROR;
break;
default:
SET_LOOKAHEAD_2_TOKEN();
break;
}
break;
default:
SET_LOOKAHEAD_TOKEN();
lvalp->core_yystype = cur_yylval;
*llocp = cur_yylloc;
scanbuf[cur_yylloc + cur_yyleng] = '\0';
break;
}
break;
case TRUE_P:
GET_NEXT_TOKEN();
core_yystype_1 = cur_yylval;
cur_yylloc_1 = cur_yylloc;
cur_yyleng_1 = cur_yyleng;
next_token_1 = next_token;
next_yyleng_1 = next_yyleng;
switch (next_token) {
case ON:
GET_NEXT_TOKEN();
core_yystype_2 = cur_yylval;
cur_yylloc_2 = cur_yylloc;
next_token_2 = next_token;
next_yyleng_2 = next_yyleng;
switch (next_token) {
case ERROR_P:
cur_token = TRUE_ON_ERROR;
break;
default:
SET_LOOKAHEAD_2_TOKEN();
break;
}
break;
default:
SET_LOOKAHEAD_TOKEN();
lvalp->core_yystype = cur_yylval;
*llocp = cur_yylloc;
scanbuf[cur_yylloc + cur_yyleng] = '\0';
break;
}
break;
case ERROR_P:
GET_NEXT_TOKEN();
core_yystype_1 = cur_yylval;
cur_yylloc_1 = cur_yylloc;
cur_yyleng_1 = cur_yyleng;
next_token_1 = next_token;
next_yyleng_1 = next_yyleng;
switch (next_token) {
case ON:
GET_NEXT_TOKEN();
core_yystype_2 = cur_yylval;
cur_yylloc_2 = cur_yylloc;
next_token_2 = next_token;
next_yyleng_2 = next_yyleng;
switch (next_token) {
case ERROR_P:
cur_token = ERROR_ON_ERROR;
break;
default:
SET_LOOKAHEAD_2_TOKEN();
break;
}
break;
default:
SET_LOOKAHEAD_TOKEN();
lvalp->core_yystype = cur_yylval;
*llocp = cur_yylloc;
scanbuf[cur_yylloc + cur_yyleng] = '\0';
break;
}
break;
case RAW:
GET_NEXT_TOKEN();
core_yystype_1 = cur_yylval;
cur_yylloc_1 = cur_yylloc;
next_token_1 = next_token;
if (next_token == '(') {
GET_NEXT_TOKEN();
core_yystype_2 = cur_yylval;
cur_yylloc_2 = cur_yylloc;
next_token_2 = next_token;
if (next_token == ICONST) {
GET_NEXT_TOKEN();
core_yystype_3 = cur_yylval;
cur_yylloc_3 = cur_yylloc;
next_token_3 = next_token;
if (next_token == ')') {
cur_token = RAW;
} else {
SET_LOOKAHEAD_3_TOKEN();
}
} else {
SET_LOOKAHEAD_2_TOKEN();
}
} else {
SET_LOOKAHEAD_TOKEN();
lvalp->core_yystype = cur_yylval;
*llocp = cur_yylloc;
}
break;
default:
break;
}
return cur_token;
}
* @Description: Check whether its a empty query with only comments and semicolon.
* @Param query_string: the query need check.
* @return:true or false.
*/
static bool is_empty_query(char* query_string)
{
char begin_comment[3] = "/*";
char end_comment[3] = "*/";
char empty_query[2] = ";";
char* end_comment_position = NULL;
while (isspace((unsigned char)*query_string)) {
query_string++;
}
while (strncmp(query_string, begin_comment, 2) == 0) {
* As query_string have been through parser, whenever it contain the begin_comment
* it will contain the end_comment and end_comment_position can't be null here.
*/
end_comment_position = strstr(query_string, end_comment);
query_string = end_comment_position + 2;
while (isspace((unsigned char)*query_string)) {
query_string++;
}
}
if (strcmp(query_string, empty_query) == 0) {
return true;
} else {
return false;
}
}
* @Description: split the query_string to distinct single queries.
* @Param [IN] query_string_single: store the splited single queries.
* @Param [IN] query_string: initial query string which contain multi statements.
* @Param [IN] query_string_locationList: record single query terminator-semicolon locations which get from lexer.
* @Param [IN] stmt_num: show this is the n-ths single query of the multi query.
* @return [IN/OUT] query_string_single: store the point array of single query.
* @NOTICE:The caller is responsible for freeing the storage palloced here.
*/
char** get_next_snippet(
char** query_string_single, const char* query_string, List* query_string_locationlist, int* stmt_num)
{
int query_string_location_start = 0;
int query_string_location_end = -1;
char* query_string_single_p = NULL;
int single_query_string_len = 0;
int stmt_count = list_length(query_string_locationlist);
if (query_string_single == NULL) {
query_string_single = (char**)palloc0(sizeof(char*) * stmt_count);
}
* Get the snippet of multi_query until we get a non-empty query as the empty query string
* needn't be dealt with.
*/
for (; *stmt_num < stmt_count;) {
* Notice : The locationlist only store the end position of each single query but not any
* start position.
*/
if (*stmt_num == 0) {
query_string_location_start = 0;
} else {
query_string_location_start = list_nth_int(query_string_locationlist, *stmt_num - 1) + 1;
}
query_string_location_end = list_nth_int(query_string_locationlist, (*stmt_num)++);
single_query_string_len = query_string_location_end - query_string_location_start + 1;
query_string_single[*stmt_num - 1] = (char*)palloc0(sizeof(char) * (single_query_string_len + 1));
query_string_single_p = query_string_single[*stmt_num - 1];
while (query_string_location_start <= query_string_location_end) {
*query_string_single_p = *(query_string + query_string_location_start);
query_string_location_start++;
query_string_single_p++;
}
* If query_string_single is empty query which only contain comments or null strings,
* we will skip it.
*/
if (is_empty_query(query_string_single[*stmt_num - 1])) {
continue;
} else {
break;
}
}
return query_string_single;
}
const struct ignore_keyword_opt_data ignore_keywords[] = {
{"interval", INTERVAL},
{"binary_double_infinity", BINARY_DOUBLE_INF},
{"binary_double_nan", BINARY_DOUBLE_NAN},
{"excluded", EXCLUDED}
};
#define INGORE_KEYWORDS_LEN (sizeof(ignore_keywords) / sizeof(struct ignore_keyword_opt_data))
* @Description: Avoid hooks, privides public interface, this can select ignore_keywords_list based on database
* compatibility to find ignore_keywords.
* @Param [IN] item: keyword
* @return token: token value for import item in ignore_keywords_list, if not in ignore_keywords_list, reutrn -1.
*/
int16 semtc_get_ignore_keyword_token(const char *item)
{
const struct ignore_keyword_opt_data *ignore_keywords_list = ignore_keywords;
int ignore_keywords_length = (int)INGORE_KEYWORDS_LEN;
for (int i = 0; i < ignore_keywords_length; i++) {
if (strcmp(item, ignore_keywords_list[i].option_name) == 0) {
return ignore_keywords_list[i].token;
}
}
return -1;
}
bool semtc_is_token_in_ignore_keyword_list(int token, bool isPlpgsqlKeyword)
{
ListCell *cell = NULL;
List *keyword_list = isPlpgsqlKeyword ? NULL : u_sess->utils_cxt.ignore_keyword_list;
foreach(cell, keyword_list)
{
int ignore_token = lfirst_int(cell);
if (token == ignore_token) {
return true;
}
}
return false;
}