• R/O
  • HTTP
  • SSH
  • HTTPS

pg_hint_plan: Commit

firtst release


Commit MetaInfo

Revisiondd5ea9685ee83db934eab9ed8203f44b0b2f5cac (tree)
Time2020-02-17 15:05:09
AuthorKyotaro Horiguchi <horikyota.ntt@gmai...>
CommiterKyotaro Horiguchi

Log Message

Fix Rows hint parsing

This is a long standing bug that Rows hint with no parameter causees a
crash. Fixed the Rows hint parser.

Change Summary

Incremental Difference

--- a/expected/pg_hint_plan.out
+++ b/expected/pg_hint_plan.out
@@ -276,6 +276,21 @@ Set(work_mem TO 1MB)
276276 -> Index Scan using t2_pkey on t2
277277 (4 rows)
278278
279+/*+SeqScan() */ SELECT 1;
280+INFO: pg_hint_plan: hint syntax error at or near " "
281+DETAIL: SeqScan hint requires a relation.
282+LOG: pg_hint_plan:
283+used hint:
284+not used hint:
285+duplication hint:
286+error hint:
287+SeqScan()
288+
289+ ?column?
290+----------
291+ 1
292+(1 row)
293+
279294 /*+SeqScan(t1 t2)*/
280295 EXPLAIN (COSTS false) SELECT * FROM t1, t2 WHERE t1.id = t2.id;
281296 INFO: pg_hint_plan: hint syntax error at or near ""
@@ -445,6 +460,36 @@ error hint:
445460 Index Cond: (id = t1.id)
446461 (5 rows)
447462
463+/*+ NestLoop() */ SELECT 1;
464+INFO: pg_hint_plan: hint syntax error at or near " "
465+DETAIL: NestLoop hint requires at least two relations.
466+LOG: pg_hint_plan:
467+used hint:
468+not used hint:
469+duplication hint:
470+error hint:
471+NestLoop()
472+
473+ ?column?
474+----------
475+ 1
476+(1 row)
477+
478+/*+ NestLoop(x) */ SELECT 1;
479+INFO: pg_hint_plan: hint syntax error at or near " "
480+DETAIL: NestLoop hint requires at least two relations.
481+LOG: pg_hint_plan:
482+used hint:
483+not used hint:
484+duplication hint:
485+error hint:
486+NestLoop(x)
487+
488+ ?column?
489+----------
490+ 1
491+(1 row)
492+
448493 /*+HashJoin(t1 t2)*/
449494 EXPLAIN (COSTS false) SELECT * FROM t1, t2 WHERE t1.id = t2.id;
450495 LOG: pg_hint_plan:
@@ -8727,6 +8772,37 @@ error hint:
87278772 -- Explain result includes "Planning time" if COSTS is enabled, but
87288773 -- this test needs it enabled for get rows count. So do tests via psql
87298774 -- and grep -v the mutable line.
8775+-- Parse error check
8776+/*+ Rows() */ SELECT 1;
8777+INFO: pg_hint_plan: hint syntax error at or near " "
8778+DETAIL: Rows hint needs at least one relation followed by one correction term.
8779+LOG: pg_hint_plan:
8780+used hint:
8781+not used hint:
8782+duplication hint:
8783+error hint:
8784+Rows()
8785+
8786+ ?column?
8787+----------
8788+ 1
8789+(1 row)
8790+
8791+/*+ Rows(x) */ SELECT 1;
8792+INFO: pg_hint_plan: hint syntax error at or near " "
8793+DETAIL: Rows hint needs at least one relation followed by one correction term.
8794+LOG: pg_hint_plan:
8795+used hint:
8796+not used hint:
8797+duplication hint:
8798+error hint:
8799+Rows()
8800+
8801+ ?column?
8802+----------
8803+ 1
8804+(1 row)
8805+
87308806 -- value types
87318807 \o results/pg_hint_plan.tmpout
87328808 EXPLAIN SELECT * FROM t1 JOIN t2 ON (t1.id = t2.id);
--- a/pg_hint_plan.c
+++ b/pg_hint_plan.c
@@ -1180,7 +1180,8 @@ RowsHintDesc(RowsHint *hint, StringInfo buf, bool nolf)
11801180 quote_value(buf, hint->relnames[i]);
11811181 }
11821182 }
1183- appendStringInfo(buf, " %s", hint->rows_str);
1183+ if (hint->rows_str != NULL)
1184+ appendStringInfo(buf, " %s", hint->rows_str);
11841185 appendStringInfoString(buf, ")");
11851186 if (!nolf)
11861187 appendStringInfoChar(buf, '\n');
@@ -2369,6 +2370,8 @@ RowsHintParse(RowsHint *hint, HintState *hstate, Query *parse,
23692370 List *name_list = NIL;
23702371 char *rows_str;
23712372 char *end_ptr;
2373+ ListCell *l;
2374+ int i = 0;
23722375
23732376 if ((str = parse_parentheses(str, &name_list, hint_keyword)) == NULL)
23742377 return NULL;
@@ -2376,23 +2379,28 @@ RowsHintParse(RowsHint *hint, HintState *hstate, Query *parse,
23762379 /* Last element must be rows specification */
23772380 hint->nrels = list_length(name_list) - 1;
23782381
2379- if (hint->nrels > 0)
2382+ if (hint->nrels < 1)
23802383 {
2381- ListCell *l;
2382- int i = 0;
2384+ hint_ereport(str,
2385+ ("%s hint needs at least one relation followed by one correction term.",
2386+ hint->base.keyword));
2387+ hint->base.state = HINT_STATE_ERROR;
23832388
2384- /*
2385- * Transform relation names from list to array to sort them with qsort
2386- * after.
2387- */
2388- hint->relnames = palloc(sizeof(char *) * hint->nrels);
2389- foreach (l, name_list)
2390- {
2391- if (hint->nrels <= i)
2392- break;
2393- hint->relnames[i] = lfirst(l);
2394- i++;
2395- }
2389+ return str;
2390+ }
2391+
2392+
2393+ /*
2394+ * Transform relation names from list to array to sort them with qsort
2395+ * after.
2396+ */
2397+ hint->relnames = palloc(sizeof(char *) * hint->nrels);
2398+ foreach (l, name_list)
2399+ {
2400+ if (hint->nrels <= i)
2401+ break;
2402+ hint->relnames[i] = lfirst(l);
2403+ i++;
23962404 }
23972405
23982406 /* Retieve rows estimation */
--- a/sql/pg_hint_plan.sql
+++ b/sql/pg_hint_plan.sql
@@ -52,6 +52,7 @@ EXPLAIN (COSTS false) SELECT * FROM t1, t2 WHERE t1.id = t2.id;
5252 /*+Set(work_mem TO "1MB")*/
5353 EXPLAIN (COSTS false) SELECT * FROM t1, t2 WHERE t1.id = t2.id;
5454
55+/*+SeqScan() */ SELECT 1;
5556 /*+SeqScan(t1 t2)*/
5657 EXPLAIN (COSTS false) SELECT * FROM t1, t2 WHERE t1.id = t2.id;
5758 /*+SeqScan(t1)*/
@@ -72,6 +73,8 @@ EXPLAIN (COSTS false) SELECT * FROM t3, t4 WHERE t3.id = t4.id AND t4.ctid = '(1
7273 /*+NoTidScan(t1)*/
7374 EXPLAIN (COSTS false) SELECT * FROM t1, t2 WHERE t1.id = t2.id AND t1.ctid = '(1,1)';
7475
76+/*+ NestLoop() */ SELECT 1;
77+/*+ NestLoop(x) */ SELECT 1;
7578 /*+HashJoin(t1 t2)*/
7679 EXPLAIN (COSTS false) SELECT * FROM t1, t2 WHERE t1.id = t2.id;
7780 /*+NestLoop(t1 t2)*/
@@ -1046,6 +1049,10 @@ SELECT val::int FROM p2 WHERE id < 1000;
10461049 -- this test needs it enabled for get rows count. So do tests via psql
10471050 -- and grep -v the mutable line.
10481051
1052+-- Parse error check
1053+/*+ Rows() */ SELECT 1;
1054+/*+ Rows(x) */ SELECT 1;
1055+
10491056 -- value types
10501057 \o results/pg_hint_plan.tmpout
10511058 EXPLAIN SELECT * FROM t1 JOIN t2 ON (t1.id = t2.id);
Show on old repository browser