Skip to content

Commit 029c5ac

Browse files
committed
psql: Refine lexing of BEGIN...END blocks in CREATE FUNCTION statements
Only track BEGIN...END blocks if they are in a CREATE [OR REPLACE] {FUNCTION|PROCEDURE} statement. Ignore if in parentheses. Reviewed-by: Laurenz Albe <laurenz.albe@cybertec.at> Discussion: https://www.postgresql.org/message-id/cee01d26fe55bc086b3bcf10bfe4e8d450e2f608.camel@cybertec.at
1 parent 25593d7 commit 029c5ac

File tree

2 files changed

+52
-9
lines changed

2 files changed

+52
-9
lines changed

src/fe_utils/psqlscan.l

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -870,18 +870,55 @@ other .
870870

871871

872872
{identifier} {
873-
cur_state->identifier_count++;
874-
if (pg_strcasecmp(yytext, "begin") == 0
875-
|| pg_strcasecmp(yytext, "case") == 0)
873+
/*
874+
* We need to track if we are inside a BEGIN .. END block
875+
* in a function definition, so that semicolons contained
876+
* therein don't terminate the whole statement. Short of
877+
* writing a full parser here, the following heuristic
878+
* should work. First, we track whether the beginning of
879+
* the statement matches CREATE [OR REPLACE]
880+
* {FUNCTION|PROCEDURE}
881+
*/
882+
883+
if (cur_state->identifier_count == 0)
884+
memset(cur_state->identifiers, 0, sizeof(cur_state->identifiers));
885+
886+
if (pg_strcasecmp(yytext, "create") == 0 ||
887+
pg_strcasecmp(yytext, "function") == 0 ||
888+
pg_strcasecmp(yytext, "procedure") == 0 ||
889+
pg_strcasecmp(yytext, "or") == 0 ||
890+
pg_strcasecmp(yytext, "replace") == 0)
876891
{
877-
if (cur_state->identifier_count > 1)
878-
cur_state->begin_depth++;
892+
if (cur_state->identifier_count < sizeof(cur_state->identifiers))
893+
cur_state->identifiers[cur_state->identifier_count] = pg_tolower((unsigned char) yytext[0]);
879894
}
880-
else if (pg_strcasecmp(yytext, "end") == 0)
895+
896+
cur_state->identifier_count++;
897+
898+
if (cur_state->identifiers[0] == 'c' &&
899+
(cur_state->identifiers[1] == 'f' || cur_state->identifiers[1] == 'p' ||
900+
(cur_state->identifiers[1] == 'o' && cur_state->identifiers[2] == 'r' &&
901+
(cur_state->identifiers[3] == 'f' || cur_state->identifiers[3] == 'p'))) &&
902+
cur_state->paren_depth == 0)
881903
{
882-
if (cur_state->begin_depth > 0)
883-
cur_state->begin_depth--;
904+
if (pg_strcasecmp(yytext, "begin") == 0)
905+
cur_state->begin_depth++;
906+
else if (pg_strcasecmp(yytext, "case") == 0)
907+
{
908+
/*
909+
* CASE also ends with END. We only need to track
910+
* this if we are already inside a BEGIN.
911+
*/
912+
if (cur_state->begin_depth >= 1)
913+
cur_state->begin_depth++;
914+
}
915+
else if (pg_strcasecmp(yytext, "end") == 0)
916+
{
917+
if (cur_state->begin_depth > 0)
918+
cur_state->begin_depth--;
919+
}
884920
}
921+
885922
ECHO;
886923
}
887924

src/include/fe_utils/psqlscan_int.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,14 @@ typedef struct PsqlScanStateData
114114
int paren_depth; /* depth of nesting in parentheses */
115115
int xcdepth; /* depth of nesting in slash-star comments */
116116
char *dolqstart; /* current $foo$ quote start string */
117+
118+
/*
119+
* State to track boundaries of BEGIN ... END blocks in function
120+
* definitions, so that semicolons do not send query too early.
121+
*/
117122
int identifier_count; /* identifiers since start of statement */
118-
int begin_depth; /* depth of begin/end routine body blocks */
123+
char identifiers[4]; /* records the first few identifiers */
124+
int begin_depth; /* depth of begin/end pairs */
119125

120126
/*
121127
* Callback functions provided by the program making use of the lexer,

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy