firtst release
Revision | ffc2832f84f93e922bca81329f8d733bf63c6e36 (tree) |
---|---|
Time | 2020-02-17 15:00:43 |
Author | Kyotaro Horiguchi <horikyota.ntt@gmai...> |
Commiter | Kyotaro Horiguchi |
Fix Rows hint parsing
This is a long standing bug that Rows hint with no parameter causees a
crash. Fixed the Rows hint parser.
@@ -276,6 +276,21 @@ Set(work_mem TO 1MB) | ||
276 | 276 | -> Index Scan using t2_pkey on t2 |
277 | 277 | (4 rows) |
278 | 278 | |
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 | + | |
279 | 294 | /*+SeqScan(t1 t2)*/ |
280 | 295 | EXPLAIN (COSTS false) SELECT * FROM t1, t2 WHERE t1.id = t2.id; |
281 | 296 | INFO: pg_hint_plan: hint syntax error at or near "" |
@@ -445,6 +460,36 @@ error hint: | ||
445 | 460 | Index Cond: (id = t1.id) |
446 | 461 | (5 rows) |
447 | 462 | |
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 | + | |
448 | 493 | /*+HashJoin(t1 t2)*/ |
449 | 494 | EXPLAIN (COSTS false) SELECT * FROM t1, t2 WHERE t1.id = t2.id; |
450 | 495 | LOG: pg_hint_plan: |
@@ -8765,6 +8810,37 @@ error hint: | ||
8765 | 8810 | -- Explain result includes "Planning time" if COSTS is enabled, but |
8766 | 8811 | -- this test needs it enabled for get rows count. So do tests via psql |
8767 | 8812 | -- and grep -v the mutable line. |
8813 | +-- Parse error check | |
8814 | +/*+ Rows() */ SELECT 1; | |
8815 | +INFO: pg_hint_plan: hint syntax error at or near " " | |
8816 | +DETAIL: Rows hint needs at least one relation followed by one correction term. | |
8817 | +LOG: pg_hint_plan: | |
8818 | +used hint: | |
8819 | +not used hint: | |
8820 | +duplication hint: | |
8821 | +error hint: | |
8822 | +Rows() | |
8823 | + | |
8824 | + ?column? | |
8825 | +---------- | |
8826 | + 1 | |
8827 | +(1 row) | |
8828 | + | |
8829 | +/*+ Rows(x) */ SELECT 1; | |
8830 | +INFO: pg_hint_plan: hint syntax error at or near " " | |
8831 | +DETAIL: Rows hint needs at least one relation followed by one correction term. | |
8832 | +LOG: pg_hint_plan: | |
8833 | +used hint: | |
8834 | +not used hint: | |
8835 | +duplication hint: | |
8836 | +error hint: | |
8837 | +Rows() | |
8838 | + | |
8839 | + ?column? | |
8840 | +---------- | |
8841 | + 1 | |
8842 | +(1 row) | |
8843 | + | |
8768 | 8844 | -- value types |
8769 | 8845 | \o results/pg_hint_plan.tmpout |
8770 | 8846 | EXPLAIN SELECT * FROM t1 JOIN t2 ON (t1.id = t2.id); |
@@ -1185,7 +1185,8 @@ RowsHintDesc(RowsHint *hint, StringInfo buf, bool nolf) | ||
1185 | 1185 | quote_value(buf, hint->relnames[i]); |
1186 | 1186 | } |
1187 | 1187 | } |
1188 | - appendStringInfo(buf, " %s", hint->rows_str); | |
1188 | + if (hint->rows_str != NULL) | |
1189 | + appendStringInfo(buf, " %s", hint->rows_str); | |
1189 | 1190 | appendStringInfoString(buf, ")"); |
1190 | 1191 | if (!nolf) |
1191 | 1192 | appendStringInfoChar(buf, '\n'); |
@@ -2374,6 +2375,8 @@ RowsHintParse(RowsHint *hint, HintState *hstate, Query *parse, | ||
2374 | 2375 | List *name_list = NIL; |
2375 | 2376 | char *rows_str; |
2376 | 2377 | char *end_ptr; |
2378 | + ListCell *l; | |
2379 | + int i = 0; | |
2377 | 2380 | |
2378 | 2381 | if ((str = parse_parentheses(str, &name_list, hint_keyword)) == NULL) |
2379 | 2382 | return NULL; |
@@ -2381,23 +2384,28 @@ RowsHintParse(RowsHint *hint, HintState *hstate, Query *parse, | ||
2381 | 2384 | /* Last element must be rows specification */ |
2382 | 2385 | hint->nrels = list_length(name_list) - 1; |
2383 | 2386 | |
2384 | - if (hint->nrels > 0) | |
2387 | + if (hint->nrels < 1) | |
2385 | 2388 | { |
2386 | - ListCell *l; | |
2387 | - int i = 0; | |
2389 | + hint_ereport(str, | |
2390 | + ("%s hint needs at least one relation followed by one correction term.", | |
2391 | + hint->base.keyword)); | |
2392 | + hint->base.state = HINT_STATE_ERROR; | |
2388 | 2393 | |
2389 | - /* | |
2390 | - * Transform relation names from list to array to sort them with qsort | |
2391 | - * after. | |
2392 | - */ | |
2393 | - hint->relnames = palloc(sizeof(char *) * hint->nrels); | |
2394 | - foreach (l, name_list) | |
2395 | - { | |
2396 | - if (hint->nrels <= i) | |
2397 | - break; | |
2398 | - hint->relnames[i] = lfirst(l); | |
2399 | - i++; | |
2400 | - } | |
2394 | + return str; | |
2395 | + } | |
2396 | + | |
2397 | + | |
2398 | + /* | |
2399 | + * Transform relation names from list to array to sort them with qsort | |
2400 | + * after. | |
2401 | + */ | |
2402 | + hint->relnames = palloc(sizeof(char *) * hint->nrels); | |
2403 | + foreach (l, name_list) | |
2404 | + { | |
2405 | + if (hint->nrels <= i) | |
2406 | + break; | |
2407 | + hint->relnames[i] = lfirst(l); | |
2408 | + i++; | |
2401 | 2409 | } |
2402 | 2410 | |
2403 | 2411 | /* Retieve rows estimation */ |
@@ -52,6 +52,7 @@ EXPLAIN (COSTS false) SELECT * FROM t1, t2 WHERE t1.id = t2.id; | ||
52 | 52 | /*+Set(work_mem TO "1MB")*/ |
53 | 53 | EXPLAIN (COSTS false) SELECT * FROM t1, t2 WHERE t1.id = t2.id; |
54 | 54 | |
55 | +/*+SeqScan() */ SELECT 1; | |
55 | 56 | /*+SeqScan(t1 t2)*/ |
56 | 57 | EXPLAIN (COSTS false) SELECT * FROM t1, t2 WHERE t1.id = t2.id; |
57 | 58 | /*+SeqScan(t1)*/ |
@@ -72,6 +73,8 @@ EXPLAIN (COSTS false) SELECT * FROM t3, t4 WHERE t3.id = t4.id AND t4.ctid = '(1 | ||
72 | 73 | /*+NoTidScan(t1)*/ |
73 | 74 | EXPLAIN (COSTS false) SELECT * FROM t1, t2 WHERE t1.id = t2.id AND t1.ctid = '(1,1)'; |
74 | 75 | |
76 | +/*+ NestLoop() */ SELECT 1; | |
77 | +/*+ NestLoop(x) */ SELECT 1; | |
75 | 78 | /*+HashJoin(t1 t2)*/ |
76 | 79 | EXPLAIN (COSTS false) SELECT * FROM t1, t2 WHERE t1.id = t2.id; |
77 | 80 | /*+NestLoop(t1 t2)*/ |
@@ -1049,6 +1052,10 @@ SELECT val::int FROM p2 WHERE id < 1000; | ||
1049 | 1052 | -- this test needs it enabled for get rows count. So do tests via psql |
1050 | 1053 | -- and grep -v the mutable line. |
1051 | 1054 | |
1055 | +-- Parse error check | |
1056 | +/*+ Rows() */ SELECT 1; | |
1057 | +/*+ Rows(x) */ SELECT 1; | |
1058 | + | |
1052 | 1059 | -- value types |
1053 | 1060 | \o results/pg_hint_plan.tmpout |
1054 | 1061 | EXPLAIN SELECT * FROM t1 JOIN t2 ON (t1.id = t2.id); |