OSDN Git Service

Fix Rows hint parsing
authorKyotaro Horiguchi <horikyota.ntt@gmail.com>
Mon, 17 Feb 2020 05:53:27 +0000 (14:53 +0900)
committerKyotaro Horiguchi <horikyota.ntt@gmail.com>
Mon, 17 Feb 2020 06:00:43 +0000 (15:00 +0900)
This is a long standing bug that Rows hint with no parameter causees a
crash. Fixed the Rows hint parser.

expected/pg_hint_plan.out
pg_hint_plan.c
sql/pg_hint_plan.sql

index a3d2b31..e8ca578 100644 (file)
@@ -276,6 +276,21 @@ Set(work_mem TO 1MB)
    ->  Index Scan using t2_pkey on t2
 (4 rows)
 
+/*+SeqScan() */ SELECT 1;
+INFO:  pg_hint_plan: hint syntax error at or near " "
+DETAIL:  SeqScan hint requires a relation.
+LOG:  pg_hint_plan:
+used hint:
+not used hint:
+duplication hint:
+error hint:
+SeqScan()
+
+ ?column? 
+----------
+        1
+(1 row)
+
 /*+SeqScan(t1 t2)*/
 EXPLAIN (COSTS false) SELECT * FROM t1, t2 WHERE t1.id = t2.id;
 INFO:  pg_hint_plan: hint syntax error at or near ""
@@ -445,6 +460,36 @@ error hint:
          Index Cond: (id = t1.id)
 (5 rows)
 
+/*+ NestLoop() */ SELECT 1;
+INFO:  pg_hint_plan: hint syntax error at or near " "
+DETAIL:  NestLoop hint requires at least two relations.
+LOG:  pg_hint_plan:
+used hint:
+not used hint:
+duplication hint:
+error hint:
+NestLoop()
+
+ ?column? 
+----------
+        1
+(1 row)
+
+/*+ NestLoop(x) */ SELECT 1;
+INFO:  pg_hint_plan: hint syntax error at or near " "
+DETAIL:  NestLoop hint requires at least two relations.
+LOG:  pg_hint_plan:
+used hint:
+not used hint:
+duplication hint:
+error hint:
+NestLoop(x)
+
+ ?column? 
+----------
+        1
+(1 row)
+
 /*+HashJoin(t1 t2)*/
 EXPLAIN (COSTS false) SELECT * FROM t1, t2 WHERE t1.id = t2.id;
 LOG:  pg_hint_plan:
@@ -8765,6 +8810,37 @@ error hint:
 -- Explain result includes "Planning time" if COSTS is enabled, but
 -- this test needs it enabled for get rows count. So do tests via psql
 -- and grep -v the mutable line.
+-- Parse error check
+/*+ Rows() */ SELECT 1;
+INFO:  pg_hint_plan: hint syntax error at or near " "
+DETAIL:  Rows hint needs at least one relation followed by one correction term.
+LOG:  pg_hint_plan:
+used hint:
+not used hint:
+duplication hint:
+error hint:
+Rows()
+
+ ?column? 
+----------
+        1
+(1 row)
+
+/*+ Rows(x) */ SELECT 1;
+INFO:  pg_hint_plan: hint syntax error at or near " "
+DETAIL:  Rows hint needs at least one relation followed by one correction term.
+LOG:  pg_hint_plan:
+used hint:
+not used hint:
+duplication hint:
+error hint:
+Rows()
+
+ ?column? 
+----------
+        1
+(1 row)
+
 -- value types
 \o results/pg_hint_plan.tmpout
 EXPLAIN SELECT * FROM t1 JOIN t2 ON (t1.id = t2.id);
index fe19bf5..783c07c 100644 (file)
@@ -1185,7 +1185,8 @@ RowsHintDesc(RowsHint *hint, StringInfo buf, bool nolf)
                        quote_value(buf, hint->relnames[i]);
                }
        }
-       appendStringInfo(buf, " %s", hint->rows_str);
+       if (hint->rows_str != NULL)
+               appendStringInfo(buf, " %s", hint->rows_str);
        appendStringInfoString(buf, ")");
        if (!nolf)
                appendStringInfoChar(buf, '\n');
@@ -2374,6 +2375,8 @@ RowsHintParse(RowsHint *hint, HintState *hstate, Query *parse,
        List               *name_list = NIL;
        char               *rows_str;
        char               *end_ptr;
+       ListCell   *l;
+       int                     i = 0;
 
        if ((str = parse_parentheses(str, &name_list, hint_keyword)) == NULL)
                return NULL;
@@ -2381,23 +2384,28 @@ RowsHintParse(RowsHint *hint, HintState *hstate, Query *parse,
        /* Last element must be rows specification */
        hint->nrels = list_length(name_list) - 1;
 
-       if (hint->nrels > 0)
+       if (hint->nrels < 1)
        {
-               ListCell   *l;
-               int                     i = 0;
+               hint_ereport(str,
+                                        ("%s hint needs at least one relation followed by one correction term.",
+                                         hint->base.keyword));
+               hint->base.state = HINT_STATE_ERROR;
 
-               /*
-                * Transform relation names from list to array to sort them with qsort
-                * after.
-                */
-               hint->relnames = palloc(sizeof(char *) * hint->nrels);
-               foreach (l, name_list)
-               {
-                       if (hint->nrels <= i)
-                               break;
-                       hint->relnames[i] = lfirst(l);
-                       i++;
-               }
+               return str;
+       }
+       
+
+       /*
+        * Transform relation names from list to array to sort them with qsort
+        * after.
+        */
+       hint->relnames = palloc(sizeof(char *) * hint->nrels);
+       foreach (l, name_list)
+       {
+               if (hint->nrels <= i)
+                       break;
+               hint->relnames[i] = lfirst(l);
+               i++;
        }
 
        /* Retieve rows estimation */
index c699c37..a3be617 100644 (file)
@@ -52,6 +52,7 @@ EXPLAIN (COSTS false) SELECT * FROM t1, t2 WHERE t1.id = t2.id;
 /*+Set(work_mem TO "1MB")*/
 EXPLAIN (COSTS false) SELECT * FROM t1, t2 WHERE t1.id = t2.id;
 
+/*+SeqScan() */ SELECT 1;
 /*+SeqScan(t1 t2)*/
 EXPLAIN (COSTS false) SELECT * FROM t1, t2 WHERE t1.id = t2.id;
 /*+SeqScan(t1)*/
@@ -72,6 +73,8 @@ EXPLAIN (COSTS false) SELECT * FROM t3, t4 WHERE t3.id = t4.id AND t4.ctid = '(1
 /*+NoTidScan(t1)*/
 EXPLAIN (COSTS false) SELECT * FROM t1, t2 WHERE t1.id = t2.id AND t1.ctid = '(1,1)';
 
+/*+ NestLoop() */ SELECT 1;
+/*+ NestLoop(x) */ SELECT 1;
 /*+HashJoin(t1 t2)*/
 EXPLAIN (COSTS false) SELECT * FROM t1, t2 WHERE t1.id = t2.id;
 /*+NestLoop(t1 t2)*/
@@ -1049,6 +1052,10 @@ SELECT val::int FROM p2 WHERE id < 1000;
 -- this test needs it enabled for get rows count. So do tests via psql
 -- and grep -v the mutable line.
 
+-- Parse error check
+/*+ Rows() */ SELECT 1;
+/*+ Rows(x) */ SELECT 1;
+
 -- value types
 \o results/pg_hint_plan.tmpout
 EXPLAIN SELECT * FROM t1 JOIN t2 ON (t1.id = t2.id);