]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
pg_plan_advice: Fix failures to accept identifier keywords.
authorRobert Haas <rhaas@postgresql.org>
Mon, 16 Mar 2026 18:37:12 +0000 (14:37 -0400)
committerRobert Haas <rhaas@postgresql.org>
Mon, 16 Mar 2026 18:46:50 +0000 (14:46 -0400)
TOK_IDENT allows only non-keywords; identifier should be used
any place where either keywords or non-keywords should be accepted.
Hence, without this commit, any string that happens to be a keyword
can't be used as a partition schema, partition name, or plan name,
which is incorrect.

Author: Lukas Fittl <lukas@fittl.com>
Discussion: http://postgr.es/m/CAP53PkzKeD=t90OfeMsniYrcRe2THQbUx3g6wV17Y=ZtiwmWTQ@mail.gmail.com

contrib/pg_plan_advice/expected/syntax.out
contrib/pg_plan_advice/pgpa_parser.y
contrib/pg_plan_advice/sql/syntax.sql

index be61402b569450fc6450d600a85dc8a90db5e3bc..c3f2cbd6dca84d009ab82c316642a32a641e14ff 100644 (file)
@@ -190,3 +190,48 @@ DETAIL:  Could not parse advice: FOREIGN_JOIN targets must contain more than one
 SET pg_plan_advice.advice = 'FOREIGN_JOIN((a))';
 ERROR:  invalid value for parameter "pg_plan_advice.advice": "FOREIGN_JOIN((a))"
 DETAIL:  Could not parse advice: FOREIGN_JOIN targets must contain more than one relation identifier at or near ")"
+-- Tag keywords used as alias names work fine, because the 'identifier'
+-- nonterminal accepts all token types.
+SET pg_plan_advice.advice = 'SEQ_SCAN(hash_join)';
+EXPLAIN (COSTS OFF) SELECT 1;
+               QUERY PLAN                
+-----------------------------------------
+ Result
+ Supplied Plan Advice:
+   SEQ_SCAN(hash_join) /* not matched */
+(3 rows)
+
+SET pg_plan_advice.advice = 'SEQ_SCAN(seq_scan)';
+EXPLAIN (COSTS OFF) SELECT 1;
+               QUERY PLAN               
+----------------------------------------
+ Result
+ Supplied Plan Advice:
+   SEQ_SCAN(seq_scan) /* not matched */
+(3 rows)
+
+SET pg_plan_advice.advice = 'SEQ_SCAN(gather)';
+EXPLAIN (COSTS OFF) SELECT 1;
+              QUERY PLAN              
+--------------------------------------
+ Result
+ Supplied Plan Advice:
+   SEQ_SCAN(gather) /* not matched */
+(3 rows)
+
+SET pg_plan_advice.advice = 'SEQ_SCAN(join_order)';
+EXPLAIN (COSTS OFF) SELECT 1;
+                QUERY PLAN                
+------------------------------------------
+ Result
+ Supplied Plan Advice:
+   SEQ_SCAN(join_order) /* not matched */
+(3 rows)
+
+-- Tag keywords used as partition names or plan names should also work,
+-- since pgpa_identifier_string() can generate these from real partition
+-- and subquery names.
+SET pg_plan_advice.advice = 'SEQ_SCAN(t/public.hash_join)';
+SET pg_plan_advice.advice = 'SEQ_SCAN(t/hash_join.foo)';
+SET pg_plan_advice.advice = 'SEQ_SCAN(t@hash_join)';
+SET pg_plan_advice.advice = 'SEQ_SCAN(t@seq_scan)';
index 8bfd7666d0787f868bb61c3ee54aa661e7e8d834..598974d3f226d08197e190f23a20743816916a36 100644 (file)
@@ -200,16 +200,16 @@ identifier: TOK_IDENT
  * when parsing advice, we accept a specification that lacks one.
  */
 opt_partition:
-       '/' TOK_IDENT '.' TOK_IDENT
+       '/' identifier '.' identifier
                { $$ = list_make2($2, $4); }
-       | '/' TOK_IDENT
+       | '/' identifier
                { $$ = list_make1($2); }
        |
                { $$ = NIL; }
        ;
 
 opt_plan_name:
-       '@' TOK_IDENT
+       '@' identifier
                { $$ = $2; }
        |
                { $$ = NULL; }
index 56a5d54e2b51508e25ee0f01d17016cc3b689c56..f274fa4863657ddfbaaf3b697a0a2548a8ac9fb3 100644 (file)
@@ -66,3 +66,22 @@ SET pg_plan_advice.advice = '/*/* stuff */*/';
 -- Foreign join requires multiple relation identifiers.
 SET pg_plan_advice.advice = 'FOREIGN_JOIN(a)';
 SET pg_plan_advice.advice = 'FOREIGN_JOIN((a))';
+
+-- Tag keywords used as alias names work fine, because the 'identifier'
+-- nonterminal accepts all token types.
+SET pg_plan_advice.advice = 'SEQ_SCAN(hash_join)';
+EXPLAIN (COSTS OFF) SELECT 1;
+SET pg_plan_advice.advice = 'SEQ_SCAN(seq_scan)';
+EXPLAIN (COSTS OFF) SELECT 1;
+SET pg_plan_advice.advice = 'SEQ_SCAN(gather)';
+EXPLAIN (COSTS OFF) SELECT 1;
+SET pg_plan_advice.advice = 'SEQ_SCAN(join_order)';
+EXPLAIN (COSTS OFF) SELECT 1;
+
+-- Tag keywords used as partition names or plan names should also work,
+-- since pgpa_identifier_string() can generate these from real partition
+-- and subquery names.
+SET pg_plan_advice.advice = 'SEQ_SCAN(t/public.hash_join)';
+SET pg_plan_advice.advice = 'SEQ_SCAN(t/hash_join.foo)';
+SET pg_plan_advice.advice = 'SEQ_SCAN(t@hash_join)';
+SET pg_plan_advice.advice = 'SEQ_SCAN(t@seq_scan)';