diff options
| author | Peter Eisentraut | 2021-04-16 09:46:01 +0000 |
|---|---|---|
| committer | Peter Eisentraut | 2021-04-16 10:20:23 +0000 |
| commit | 029c5ac03db72f1898ee17e417650a2e0764b239 (patch) | |
| tree | 7bd3241f78afd3966cb1cb85150f99d73d009a61 /src/fe_utils | |
| parent | 25593d7d338232fb855ba563b325237de8f14091 (diff) | |
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
Diffstat (limited to 'src/fe_utils')
| -rw-r--r-- | src/fe_utils/psqlscan.l | 53 |
1 files changed, 45 insertions, 8 deletions
diff --git a/src/fe_utils/psqlscan.l b/src/fe_utils/psqlscan.l index 4ec57e96a9..991b7de0b5 100644 --- a/src/fe_utils/psqlscan.l +++ b/src/fe_utils/psqlscan.l @@ -870,18 +870,55 @@ other . {identifier} { - cur_state->identifier_count++; - if (pg_strcasecmp(yytext, "begin") == 0 - || pg_strcasecmp(yytext, "case") == 0) + /* + * We need to track if we are inside a BEGIN .. END block + * in a function definition, so that semicolons contained + * therein don't terminate the whole statement. Short of + * writing a full parser here, the following heuristic + * should work. First, we track whether the beginning of + * the statement matches CREATE [OR REPLACE] + * {FUNCTION|PROCEDURE} + */ + + if (cur_state->identifier_count == 0) + memset(cur_state->identifiers, 0, sizeof(cur_state->identifiers)); + + if (pg_strcasecmp(yytext, "create") == 0 || + pg_strcasecmp(yytext, "function") == 0 || + pg_strcasecmp(yytext, "procedure") == 0 || + pg_strcasecmp(yytext, "or") == 0 || + pg_strcasecmp(yytext, "replace") == 0) { - if (cur_state->identifier_count > 1) - cur_state->begin_depth++; + if (cur_state->identifier_count < sizeof(cur_state->identifiers)) + cur_state->identifiers[cur_state->identifier_count] = pg_tolower((unsigned char) yytext[0]); } - else if (pg_strcasecmp(yytext, "end") == 0) + + cur_state->identifier_count++; + + if (cur_state->identifiers[0] == 'c' && + (cur_state->identifiers[1] == 'f' || cur_state->identifiers[1] == 'p' || + (cur_state->identifiers[1] == 'o' && cur_state->identifiers[2] == 'r' && + (cur_state->identifiers[3] == 'f' || cur_state->identifiers[3] == 'p'))) && + cur_state->paren_depth == 0) { - if (cur_state->begin_depth > 0) - cur_state->begin_depth--; + if (pg_strcasecmp(yytext, "begin") == 0) + cur_state->begin_depth++; + else if (pg_strcasecmp(yytext, "case") == 0) + { + /* + * CASE also ends with END. We only need to track + * this if we are already inside a BEGIN. + */ + if (cur_state->begin_depth >= 1) + cur_state->begin_depth++; + } + else if (pg_strcasecmp(yytext, "end") == 0) + { + if (cur_state->begin_depth > 0) + cur_state->begin_depth--; + } } + ECHO; } |
