Fix declare as identifier.
This commit is contained in:
@ -2310,6 +2310,17 @@ analyze_state(const char* text,PsqlScanStateData* state)
|
||||
state->count_to_read = -1;
|
||||
break;
|
||||
case IDEN_PROCEDURE:
|
||||
if (state->declare_encountered && state->begin_state == BEGIN_UNDEFINED) {
|
||||
/*
|
||||
* declare_encountered is true means we have met a 'declare' already, sql may like
|
||||
* 'create trigger declare on declare execute procedure xx', 'declare' should be treat as an identifier
|
||||
* not a keyword. PROCEDURE is a reserve keyword, so it must be a keyword not a identifier.
|
||||
*/
|
||||
state->declare_encountered = false;
|
||||
state->gram_state[IDEN_PROCEDURE] = false;
|
||||
state->gram_state[IDEN_DECLARE] = false;
|
||||
break;
|
||||
}
|
||||
state->gram_state[IDEN_AS] = true;
|
||||
state->gram_state[IDEN_IS] = true;
|
||||
state->include_ora_comment = true;
|
||||
@ -2365,6 +2376,7 @@ analyze_state(const char* text,PsqlScanStateData* state)
|
||||
state->gram_state[IDEN_BINARY] = true;
|
||||
state->gram_state[IDEN_INSENSITIVE] = true;
|
||||
state->gram_state[IDEN_NO] = true;
|
||||
state->gram_state[IDEN_PROCEDURE] = true;
|
||||
state->declare_encountered = true;
|
||||
break;
|
||||
case IDEN_BEGIN:
|
||||
|
@ -108,21 +108,25 @@ List* raw_parser(const char* str, List** query_string_locationlist)
|
||||
return yyextra.parsetree;
|
||||
}
|
||||
|
||||
#define GET_NEXT_TOKEN() \
|
||||
#define GET_NEXT_TOKEN_WITHOUT_YY() \
|
||||
do { \
|
||||
cur_yylval = lvalp->core_yystype; \
|
||||
cur_yylloc = *llocp; \
|
||||
if (yyextra->lookahead_num != 0) { \
|
||||
next_token = yyextra->lookahead_token[yyextra->lookahead_num - 1]; \
|
||||
lvalp->core_yystype = yyextra->lookahead_yylval[yyextra->lookahead_num - 1]; \
|
||||
*llocp = yyextra->lookahead_yylloc[yyextra->lookahead_num - 1]; \
|
||||
yyextra->lookahead_num--; \
|
||||
Assert(yyextra->lookahead_num == 0); \
|
||||
} else { \
|
||||
next_token = core_yylex(&(lvalp->core_yystype), llocp, 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 { \
|
||||
yyextra->lookahead_token[0] = next_token; \
|
||||
@ -428,17 +432,20 @@ int base_yylex(YYSTYPE* lvalp, YYLTYPE* llocp, core_yyscan_t yyscanner)
|
||||
/*
|
||||
* 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 lookahead_token, so use GET_NEXT_TOKEN to get
|
||||
*/
|
||||
cur_yylval = lvalp->core_yystype;
|
||||
cur_yylloc = *llocp;
|
||||
next_token = core_yylex(&(lvalp->core_yystype), llocp, yyscanner);
|
||||
GET_NEXT_TOKEN();
|
||||
/* get first token after DECLARE. We don't care what it is */
|
||||
yyextra->lookahead_token[1] = next_token;
|
||||
yyextra->lookahead_yylval[1] = lvalp->core_yystype;
|
||||
yyextra->lookahead_yylloc[1] = *llocp;
|
||||
|
||||
/* get the second token after DECLARE. If it is cursor grammer, we are sure that this is a cursr stmt */
|
||||
next_token = core_yylex(&(lvalp->core_yystype), llocp, yyscanner);
|
||||
/*
|
||||
* get the second token after DECLARE. If it is cursor grammer, we are sure that this is a cursr stmt
|
||||
* in fact we don't have any lookahead_token here for sure, cause MAX_LOOKAHEAD_NUM is 2.
|
||||
* but maybe someday MAX_LOOKAHEAD_NUM increase, so we still use GET_NEXT_TOKEN_WITHOUT_SET_CURYY
|
||||
*/
|
||||
GET_NEXT_TOKEN_WITHOUT_YY();
|
||||
yyextra->lookahead_token[0] = next_token;
|
||||
yyextra->lookahead_yylval[0] = lvalp->core_yystype;
|
||||
yyextra->lookahead_yylloc[0] = *llocp;
|
||||
@ -523,35 +530,38 @@ int base_yylex(YYSTYPE* lvalp, YYLTYPE* llocp, core_yyscan_t yyscanner)
|
||||
}
|
||||
break;
|
||||
case ON:
|
||||
cur_yylval = lvalp->core_yystype;
|
||||
cur_yylloc = *llocp;
|
||||
next_token = core_yylex(&(lvalp->core_yystype), llocp, yyscanner);
|
||||
/* here we may still have token in lookahead_token, so use GET_NEXT_TOKEN to get */
|
||||
GET_NEXT_TOKEN();
|
||||
/* get first token after ON (Normal UPDATE). We don't care what it is */
|
||||
yyextra->lookahead_token[1] = next_token;
|
||||
yyextra->lookahead_yylval[1] = lvalp->core_yystype;
|
||||
yyextra->lookahead_yylloc[1] = *llocp;
|
||||
|
||||
/* get the second token after ON. */
|
||||
next_token = core_yylex(&(lvalp->core_yystype), llocp, yyscanner);
|
||||
/*
|
||||
* get the second token after ON.
|
||||
* in fact we don't have any lookahead_token here for sure, cause MAX_LOOKAHEAD_NUM is 2.
|
||||
* but maybe someday MAX_LOOKAHEAD_NUM increase, so we still use GET_NEXT_TOKEN_WITHOUT_SET_CURYY
|
||||
*/
|
||||
GET_NEXT_TOKEN_WITHOUT_YY();
|
||||
yyextra->lookahead_token[0] = next_token;
|
||||
yyextra->lookahead_yylval[0] = lvalp->core_yystype;
|
||||
yyextra->lookahead_yylloc[0] = *llocp;
|
||||
yyextra->lookahead_num = 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;
|
||||
break;
|
||||
default:
|
||||
/* and back up the output info to cur_token */
|
||||
lvalp->core_yystype = cur_yylval;
|
||||
*llocp = cur_yylloc;
|
||||
break;
|
||||
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;
|
||||
break;
|
||||
default:
|
||||
/* and back up the output info to cur_token */
|
||||
lvalp->core_yystype = cur_yylval;
|
||||
*llocp = cur_yylloc;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -1594,3 +1594,72 @@ drop table depth_a, depth_b, depth_c;
|
||||
drop function depth_a_tf();
|
||||
drop function depth_b_tf();
|
||||
drop function depth_c_tf();
|
||||
-- test declare + on in one sql.
|
||||
create schema trigger_declare_test;
|
||||
set current_schema to trigger_declare_test;
|
||||
create table declare_test(id int);
|
||||
create index declare on declare_test(id);
|
||||
\d declare_test
|
||||
Table "trigger_declare_test.declare_test"
|
||||
Column | Type | Modifiers
|
||||
--------+---------+-----------
|
||||
id | integer |
|
||||
Indexes:
|
||||
"declare" btree (id) TABLESPACE pg_default
|
||||
|
||||
drop index declare;
|
||||
create table declare(id int);
|
||||
create index id_test on declare(id);
|
||||
\d declare
|
||||
Table "trigger_declare_test.declare"
|
||||
Column | Type | Modifiers
|
||||
--------+---------+-----------
|
||||
id | integer |
|
||||
Indexes:
|
||||
"id_test" btree (id) TABLESPACE pg_default
|
||||
|
||||
CREATE OR REPLACE FUNCTION declare() RETURNS TRIGGER AS
|
||||
$$
|
||||
DECLARE
|
||||
BEGIN
|
||||
INSERT INTO declare_test VALUES(NEW.id);
|
||||
RETURN NEW;
|
||||
END
|
||||
$$ LANGUAGE PLPGSQL;
|
||||
CREATE TRIGGER declare AFTER INSERT ON declare FOR EACH ROW EXECUTE PROCEDURE declare();
|
||||
insert into declare values(1);
|
||||
drop TRIGGER declare on declare cascade;
|
||||
CREATE TRIGGER declare_test AFTER INSERT ON declare FOR EACH ROW EXECUTE PROCEDURE declare();
|
||||
insert into declare values(2);
|
||||
drop TRIGGER declare_test on declare cascade;
|
||||
CREATE OR REPLACE FUNCTION declare() RETURNS TRIGGER AS
|
||||
$$
|
||||
DECLARE
|
||||
BEGIN
|
||||
INSERT INTO declare VALUES(NEW.id);
|
||||
RETURN NEW;
|
||||
END
|
||||
$$ LANGUAGE PLPGSQL;
|
||||
CREATE TRIGGER declare AFTER INSERT ON declare_test FOR EACH ROW EXECUTE PROCEDURE declare();
|
||||
insert into declare_test values(3);
|
||||
drop TRIGGER declare on declare_test cascade;
|
||||
select * from declare order by 1;
|
||||
id
|
||||
----
|
||||
1
|
||||
2
|
||||
3
|
||||
(3 rows)
|
||||
|
||||
select * from declare_test order by 1;
|
||||
id
|
||||
----
|
||||
1
|
||||
2
|
||||
3
|
||||
(3 rows)
|
||||
|
||||
drop table declare;
|
||||
drop table declare_test;
|
||||
drop schema trigger_declare_test cascade;
|
||||
NOTICE: drop cascades to function declare()
|
||||
|
@ -1044,3 +1044,51 @@ drop table depth_a, depth_b, depth_c;
|
||||
drop function depth_a_tf();
|
||||
drop function depth_b_tf();
|
||||
drop function depth_c_tf();
|
||||
|
||||
-- test declare + on in one sql.
|
||||
create schema trigger_declare_test;
|
||||
set current_schema to trigger_declare_test;
|
||||
create table declare_test(id int);
|
||||
create index declare on declare_test(id);
|
||||
\d declare_test
|
||||
drop index declare;
|
||||
|
||||
create table declare(id int);
|
||||
create index id_test on declare(id);
|
||||
\d declare
|
||||
|
||||
CREATE OR REPLACE FUNCTION declare() RETURNS TRIGGER AS
|
||||
$$
|
||||
DECLARE
|
||||
BEGIN
|
||||
INSERT INTO declare_test VALUES(NEW.id);
|
||||
RETURN NEW;
|
||||
END
|
||||
$$ LANGUAGE PLPGSQL;
|
||||
|
||||
CREATE TRIGGER declare AFTER INSERT ON declare FOR EACH ROW EXECUTE PROCEDURE declare();
|
||||
insert into declare values(1);
|
||||
drop TRIGGER declare on declare cascade;
|
||||
|
||||
CREATE TRIGGER declare_test AFTER INSERT ON declare FOR EACH ROW EXECUTE PROCEDURE declare();
|
||||
insert into declare values(2);
|
||||
drop TRIGGER declare_test on declare cascade;
|
||||
|
||||
CREATE OR REPLACE FUNCTION declare() RETURNS TRIGGER AS
|
||||
$$
|
||||
DECLARE
|
||||
BEGIN
|
||||
INSERT INTO declare VALUES(NEW.id);
|
||||
RETURN NEW;
|
||||
END
|
||||
$$ LANGUAGE PLPGSQL;
|
||||
|
||||
CREATE TRIGGER declare AFTER INSERT ON declare_test FOR EACH ROW EXECUTE PROCEDURE declare();
|
||||
insert into declare_test values(3);
|
||||
drop TRIGGER declare on declare_test cascade;
|
||||
select * from declare order by 1;
|
||||
select * from declare_test order by 1;
|
||||
|
||||
drop table declare;
|
||||
drop table declare_test;
|
||||
drop schema trigger_declare_test cascade;
|
||||
|
Reference in New Issue
Block a user