]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
De-reserve keywords EXECUTE and STRICT in PL/pgSQL.
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 30 Jun 2025 20:59:36 +0000 (16:59 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 30 Jun 2025 20:59:36 +0000 (16:59 -0400)
On close inspection, there does not seem to be a strong reason
why these should be fully-reserved keywords.  I guess they just
escaped consideration in previous attempts to minimize PL/pgSQL's
list of reserved words.

Author: Tom Lane <tgl@sss.pgh.pa.us>
Reviewed-by: Pavel Stehule <pavel.stehule@gmail.com>
Discussion: https://postgr.es/m/2185258.1745617445@sss.pgh.pa.us

src/pl/plpgsql/src/expected/plpgsql_misc.out
src/pl/plpgsql/src/pl_gram.y
src/pl/plpgsql/src/pl_reserved_kwlist.h
src/pl/plpgsql/src/pl_scanner.c
src/pl/plpgsql/src/pl_unreserved_kwlist.h
src/pl/plpgsql/src/sql/plpgsql_misc.sql

index a6511df08ec9fe7864e98451e3ec67986590faf5..7bb4f432e7dafe81a7a6143f2248ffaa5b89fbd0 100644 (file)
@@ -65,3 +65,17 @@ do $$ declare x public.foo%rowtype; begin end $$;
 ERROR:  relation "public.foo" does not exist
 CONTEXT:  compilation of PL/pgSQL function "inline_code_block" near line 1
 do $$ declare x public.misc_table%rowtype; begin end $$;
+-- Test handling of an unreserved keyword as a variable name
+-- and record field name.
+do $$
+declare
+  execute int;
+  r record;
+begin
+  execute := 10;
+  raise notice 'execute = %', execute;
+  select 1 as strict into r;
+  raise notice 'r.strict = %', r.strict;
+end $$;
+NOTICE:  execute = 10
+NOTICE:  r.strict = 1
index 5612e66d0239d2a78c921f382749fa22058eb1b5..7b672ea5179a61f6c439a505aebf056e01bc4889 100644 (file)
@@ -1368,7 +1368,8 @@ for_control               : for_variable K_IN
                                                int                     tok = yylex(&yylval, &yylloc, yyscanner);
                                                int                     tokloc = yylloc;
 
-                                               if (tok == K_EXECUTE)
+                                               if (tok_is_keyword(tok, &yylval,
+                                                                                  K_EXECUTE, "execute"))
                                                {
                                                        /* EXECUTE means it's a dynamic FOR loop */
                                                        PLpgSQL_stmt_dynfors *new;
@@ -2135,7 +2136,8 @@ stmt_open         : K_OPEN cursor_variable
                                                                yyerror(&yylloc, NULL, yyscanner, "syntax error, expected \"FOR\"");
 
                                                        tok = yylex(&yylval, &yylloc, yyscanner);
-                                                       if (tok == K_EXECUTE)
+                                                       if (tok_is_keyword(tok, &yylval,
+                                                                                          K_EXECUTE, "execute"))
                                                        {
                                                                int                     endtoken;
 
@@ -2536,6 +2538,7 @@ unreserved_keyword        :
                                | K_ERRCODE
                                | K_ERROR
                                | K_EXCEPTION
+                               | K_EXECUTE
                                | K_EXIT
                                | K_FETCH
                                | K_FIRST
@@ -2581,6 +2584,7 @@ unreserved_keyword        :
                                | K_SLICE
                                | K_SQLSTATE
                                | K_STACKED
+                               | K_STRICT
                                | K_TABLE
                                | K_TABLE_NAME
                                | K_TYPE
@@ -3514,7 +3518,8 @@ make_return_query_stmt(int location, YYSTYPE *yylvalp, YYLTYPE *yyllocp, yyscan_
        new->stmtid = ++plpgsql_curr_compile->nstatements;
 
        /* check for RETURN QUERY EXECUTE */
-       if ((tok = yylex(yylvalp, yyllocp, yyscanner)) != K_EXECUTE)
+       tok = yylex(yylvalp, yyllocp, yyscanner);
+       if (!tok_is_keyword(tok, yylvalp, K_EXECUTE, "execute"))
        {
                /* ordinary static query */
                plpgsql_push_back_token(tok, yylvalp, yyllocp, yyscanner);
@@ -3597,7 +3602,7 @@ read_into_target(PLpgSQL_variable **target, bool *strict, YYSTYPE *yylvalp, YYLT
                *strict = false;
 
        tok = yylex(yylvalp, yyllocp, yyscanner);
-       if (strict && tok == K_STRICT)
+       if (strict && tok_is_keyword(tok, yylvalp, K_STRICT, "strict"))
        {
                *strict = true;
                tok = yylex(yylvalp, yyllocp, yyscanner);
index ce7b0c9d331215174fd9a618dfd309e280e4e69d..f3ef2cbd8d7dc45d4d3d6f34c2ae94830f9a3cb7 100644 (file)
@@ -33,7 +33,6 @@ PG_KEYWORD("case", K_CASE)
 PG_KEYWORD("declare", K_DECLARE)
 PG_KEYWORD("else", K_ELSE)
 PG_KEYWORD("end", K_END)
-PG_KEYWORD("execute", K_EXECUTE)
 PG_KEYWORD("for", K_FOR)
 PG_KEYWORD("foreach", K_FOREACH)
 PG_KEYWORD("from", K_FROM)
@@ -44,7 +43,6 @@ PG_KEYWORD("loop", K_LOOP)
 PG_KEYWORD("not", K_NOT)
 PG_KEYWORD("null", K_NULL)
 PG_KEYWORD("or", K_OR)
-PG_KEYWORD("strict", K_STRICT)
 PG_KEYWORD("then", K_THEN)
 PG_KEYWORD("to", K_TO)
 PG_KEYWORD("using", K_USING)
index d08187dafcb4cb06f138354f7d912f7f1219d527..19825e5c71810eef92fc57efe8a56fe0e741d033 100644 (file)
@@ -53,7 +53,7 @@ IdentifierLookup plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_NORMAL;
  * We try to avoid reserving more keywords than we have to; but there's
  * little point in not reserving a word if it's reserved in the core grammar.
  * Currently, the following words are reserved here but not in the core:
- * BEGIN BY DECLARE EXECUTE FOREACH IF LOOP STRICT WHILE
+ * BEGIN BY DECLARE FOREACH IF LOOP WHILE
  */
 
 /* ScanKeywordList lookup data for PL/pgSQL keywords */
index 98f99ec470cf4b85c6c53fe9d02cca15f29ecd3c..b48c5a645ffafd7d0984f94cb4255b94b9c3dd0e 100644 (file)
@@ -58,6 +58,7 @@ PG_KEYWORD("elsif", K_ELSIF)
 PG_KEYWORD("errcode", K_ERRCODE)
 PG_KEYWORD("error", K_ERROR)
 PG_KEYWORD("exception", K_EXCEPTION)
+PG_KEYWORD("execute", K_EXECUTE)
 PG_KEYWORD("exit", K_EXIT)
 PG_KEYWORD("fetch", K_FETCH)
 PG_KEYWORD("first", K_FIRST)
@@ -103,6 +104,7 @@ PG_KEYWORD("scroll", K_SCROLL)
 PG_KEYWORD("slice", K_SLICE)
 PG_KEYWORD("sqlstate", K_SQLSTATE)
 PG_KEYWORD("stacked", K_STACKED)
+PG_KEYWORD("strict", K_STRICT)
 PG_KEYWORD("table", K_TABLE)
 PG_KEYWORD("table_name", K_TABLE_NAME)
 PG_KEYWORD("type", K_TYPE)
index d3a7f703a758d3324e1174c67fd59a3a811642fe..103a20bf8820c569cc7354aa9240d87a41b79f46 100644 (file)
@@ -37,3 +37,16 @@ do $$ declare x foo.bar%rowtype; begin end $$;
 do $$ declare x foo.bar.baz%rowtype; begin end $$;
 do $$ declare x public.foo%rowtype; begin end $$;
 do $$ declare x public.misc_table%rowtype; begin end $$;
+
+-- Test handling of an unreserved keyword as a variable name
+-- and record field name.
+do $$
+declare
+  execute int;
+  r record;
+begin
+  execute := 10;
+  raise notice 'execute = %', execute;
+  select 1 as strict into r;
+  raise notice 'r.strict = %', r.strict;
+end $$;