• R/O
  • HTTP
  • SSH
  • HTTPS

Commit

Tags
Aucun tag

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

firtst release


Commit MetaInfo

Révisiond56ce3df2b4198e6e0fd4c6e6865caead9d48ca9 (tree)
l'heure2013-12-09 16:35:24
AuteurShigeru HANADA <shigeru.hanada@gmai...>
CommiterShigeru HANADA

Message de Log

PG92との差分から生成したパッチを適用。

ただし、PG9.3対応として加えた修正はそのまま残した。

Change Summary

Modification

--- a/core.c
+++ b/core.c
@@ -6,7 +6,6 @@
66 * src/backend/optimizer/path/allpaths.c
77 * set_append_rel_pathlist()
88 * generate_mergeappend_paths()
9- * get_cheapest_parameterized_child_path()
109 * accumulate_append_subpath()
1110 * standard_join_search()
1211 *
@@ -37,7 +36,6 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
3736 int parentRTindex = rti;
3837 List *live_childrels = NIL;
3938 List *subpaths = NIL;
40- bool subpaths_valid = true;
4139 List *all_child_pathkeys = NIL;
4240 List *all_child_outers = NIL;
4341 ListCell *l;
@@ -77,20 +75,14 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
7775 continue;
7876
7977 /*
80- * Child is live, so add it to the live_childrels list for use below.
78+ * Child is live, so add its cheapest access path to the Append path
79+ * we are constructing for the parent.
8180 */
82- live_childrels = lappend(live_childrels, childrel);
81+ subpaths = accumulate_append_subpath(subpaths,
82+ childrel->cheapest_total_path);
8383
84- /*
85- * If child has an unparameterized cheapest-total path, add that to
86- * the unparameterized Append path we are constructing for the parent.
87- * If not, there's no workable unparameterized path.
88- */
89- if (childrel->cheapest_total_path->param_info == NULL)
90- subpaths = accumulate_append_subpath(subpaths,
91- childrel->cheapest_total_path);
92- else
93- subpaths_valid = false;
84+ /* Remember which childrels are live, for logic below */
85+ live_childrels = lappend(live_childrels, childrel);
9486
9587 /*
9688 * Collect lists of all the available path orderings and
@@ -158,20 +150,17 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
158150 }
159151
160152 /*
161- * If we found unparameterized paths for all children, build an unordered,
162- * unparameterized Append path for the rel. (Note: this is correct even
163- * if we have zero or one live subpath due to constraint exclusion.)
153+ * Next, build an unordered, unparameterized Append path for the rel.
154+ * (Note: this is correct even if we have zero or one live subpath due to
155+ * constraint exclusion.)
164156 */
165- if (subpaths_valid)
166- add_path(rel, (Path *) create_append_path(rel, subpaths, NULL));
157+ add_path(rel, (Path *) create_append_path(rel, subpaths, NULL));
167158
168159 /*
169- * Also build unparameterized MergeAppend paths based on the collected
170- * list of child pathkeys.
160+ * Build unparameterized MergeAppend paths based on the collected list of
161+ * child pathkeys.
171162 */
172- if (subpaths_valid)
173- generate_mergeappend_paths(root, rel, live_childrels,
174- all_child_pathkeys);
163+ generate_mergeappend_paths(root, rel, live_childrels, all_child_pathkeys);
175164
176165 /*
177166 * Build Append paths for each parameterization seen among the child rels.
@@ -189,29 +178,39 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
189178 foreach(l, all_child_outers)
190179 {
191180 Relids required_outer = (Relids) lfirst(l);
181+ bool ok = true;
192182 ListCell *lcr;
193183
194184 /* Select the child paths for an Append with this parameterization */
195185 subpaths = NIL;
196- subpaths_valid = true;
197186 foreach(lcr, live_childrels)
198187 {
199188 RelOptInfo *childrel = (RelOptInfo *) lfirst(lcr);
200- Path *subpath;
189+ Path *cheapest_total;
190+
191+ cheapest_total =
192+ get_cheapest_path_for_pathkeys(childrel->pathlist,
193+ NIL,
194+ required_outer,
195+ TOTAL_COST);
196+ Assert(cheapest_total != NULL);
201197
202- subpath = get_cheapest_parameterized_child_path(root,
203- childrel,
204- required_outer);
205- if (subpath == NULL)
198+ /* Children must have exactly the desired parameterization */
199+ if (!bms_equal(PATH_REQ_OUTER(cheapest_total), required_outer))
206200 {
207- /* failed to make a suitable path for this child */
208- subpaths_valid = false;
209- break;
201+ cheapest_total = reparameterize_path(root, cheapest_total,
202+ required_outer, 1.0);
203+ if (cheapest_total == NULL)
204+ {
205+ ok = false;
206+ break;
207+ }
210208 }
211- subpaths = accumulate_append_subpath(subpaths, subpath);
209+
210+ subpaths = accumulate_append_subpath(subpaths, cheapest_total);
212211 }
213212
214- if (subpaths_valid)
213+ if (ok)
215214 add_path(rel, (Path *)
216215 create_append_path(rel, subpaths, required_outer));
217216 }
@@ -285,8 +284,7 @@ generate_mergeappend_paths(PlannerInfo *root, RelOptInfo *rel,
285284 {
286285 cheapest_startup = cheapest_total =
287286 childrel->cheapest_total_path;
288- /* Assert we do have an unparameterized path for this child */
289- Assert(cheapest_total->param_info == NULL);
287+ Assert(cheapest_total != NULL);
290288 }
291289
292290 /*
@@ -319,79 +317,6 @@ generate_mergeappend_paths(PlannerInfo *root, RelOptInfo *rel,
319317 }
320318
321319 /*
322- * get_cheapest_parameterized_child_path
323- * Get cheapest path for this relation that has exactly the requested
324- * parameterization.
325- *
326- * Returns NULL if unable to create such a path.
327- */
328-static Path *
329-get_cheapest_parameterized_child_path(PlannerInfo *root, RelOptInfo *rel,
330- Relids required_outer)
331-{
332- Path *cheapest;
333- ListCell *lc;
334-
335- /*
336- * Look up the cheapest existing path with no more than the needed
337- * parameterization. If it has exactly the needed parameterization, we're
338- * done.
339- */
340- cheapest = get_cheapest_path_for_pathkeys(rel->pathlist,
341- NIL,
342- required_outer,
343- TOTAL_COST);
344- Assert(cheapest != NULL);
345- if (bms_equal(PATH_REQ_OUTER(cheapest), required_outer))
346- return cheapest;
347-
348- /*
349- * Otherwise, we can "reparameterize" an existing path to match the given
350- * parameterization, which effectively means pushing down additional
351- * joinquals to be checked within the path's scan. However, some existing
352- * paths might check the available joinquals already while others don't;
353- * therefore, it's not clear which existing path will be cheapest after
354- * reparameterization. We have to go through them all and find out.
355- */
356- cheapest = NULL;
357- foreach(lc, rel->pathlist)
358- {
359- Path *path = (Path *) lfirst(lc);
360-
361- /* Can't use it if it needs more than requested parameterization */
362- if (!bms_is_subset(PATH_REQ_OUTER(path), required_outer))
363- continue;
364-
365- /*
366- * Reparameterization can only increase the path's cost, so if it's
367- * already more expensive than the current cheapest, forget it.
368- */
369- if (cheapest != NULL &&
370- compare_path_costs(cheapest, path, TOTAL_COST) <= 0)
371- continue;
372-
373- /* Reparameterize if needed, then recheck cost */
374- if (!bms_equal(PATH_REQ_OUTER(path), required_outer))
375- {
376- path = reparameterize_path(root, path, required_outer, 1.0);
377- if (path == NULL)
378- continue; /* failed to reparameterize this one */
379- Assert(bms_equal(PATH_REQ_OUTER(path), required_outer));
380-
381- if (cheapest != NULL &&
382- compare_path_costs(cheapest, path, TOTAL_COST) <= 0)
383- continue;
384- }
385-
386- /* We have a new best path */
387- cheapest = path;
388- }
389-
390- /* Return the best path, or NULL if we found no suitable candidate */
391- return cheapest;
392-}
393-
394-/*
395320 * accumulate_append_subpath
396321 * Add a subpath to the list being built for an Append or MergeAppend
397322 *
@@ -701,14 +626,11 @@ join_search_one_level(PlannerInfo *root, int level)
701626 * to accept failure at level 4 and go on to discover a workable
702627 * bushy plan at level 5.
703628 *
704- * However, if there are no special joins and no lateral references
705- * then join_is_legal() should never fail, and so the following sanity
706- * check is useful.
629+ * However, if there are no special joins then join_is_legal() should
630+ * never fail, and so the following sanity check is useful.
707631 *----------
708632 */
709- if (joinrels[level] == NIL &&
710- root->join_info_list == NIL &&
711- root->lateral_info_list == NIL)
633+ if (joinrels[level] == NIL && root->join_info_list == NIL)
712634 elog(ERROR, "failed to build any %d-way joins", level);
713635 }
714636 }
@@ -808,8 +730,6 @@ join_is_legal(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2,
808730 bool reversed;
809731 bool unique_ified;
810732 bool is_valid_inner;
811- bool lateral_fwd;
812- bool lateral_rev;
813733 ListCell *l;
814734
815735 /*
@@ -989,47 +909,6 @@ join_is_legal(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2,
989909 (match_sjinfo == NULL || unique_ified))
990910 return false; /* invalid join path */
991911
992- /*
993- * We also have to check for constraints imposed by LATERAL references.
994- * The proposed rels could each contain lateral references to the other,
995- * in which case the join is impossible. If there are lateral references
996- * in just one direction, then the join has to be done with a nestloop
997- * with the lateral referencer on the inside. If the join matches an SJ
998- * that cannot be implemented by such a nestloop, the join is impossible.
999- */
1000- lateral_fwd = lateral_rev = false;
1001- foreach(l, root->lateral_info_list)
1002- {
1003- LateralJoinInfo *ljinfo = (LateralJoinInfo *) lfirst(l);
1004-
1005- if (bms_is_subset(ljinfo->lateral_rhs, rel2->relids) &&
1006- bms_overlap(ljinfo->lateral_lhs, rel1->relids))
1007- {
1008- /* has to be implemented as nestloop with rel1 on left */
1009- if (lateral_rev)
1010- return false; /* have lateral refs in both directions */
1011- lateral_fwd = true;
1012- if (!bms_is_subset(ljinfo->lateral_lhs, rel1->relids))
1013- return false; /* rel1 can't compute the required parameter */
1014- if (match_sjinfo &&
1015- (reversed || match_sjinfo->jointype == JOIN_FULL))
1016- return false; /* not implementable as nestloop */
1017- }
1018- if (bms_is_subset(ljinfo->lateral_rhs, rel1->relids) &&
1019- bms_overlap(ljinfo->lateral_lhs, rel2->relids))
1020- {
1021- /* has to be implemented as nestloop with rel2 on left */
1022- if (lateral_fwd)
1023- return false; /* have lateral refs in both directions */
1024- lateral_rev = true;
1025- if (!bms_is_subset(ljinfo->lateral_lhs, rel2->relids))
1026- return false; /* rel2 can't compute the required parameter */
1027- if (match_sjinfo &&
1028- (!reversed || match_sjinfo->jointype == JOIN_FULL))
1029- return false; /* not implementable as nestloop */
1030- }
1031- }
1032-
1033912 /* Otherwise, it's a valid join */
1034913 *sjinfo_p = match_sjinfo;
1035914 *reversed_p = reversed;
@@ -1038,9 +917,8 @@ join_is_legal(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2,
1038917
1039918 /*
1040919 * has_join_restriction
1041- * Detect whether the specified relation has join-order restrictions,
1042- * due to being inside an outer join or an IN (sub-SELECT),
1043- * or participating in any LATERAL references.
920+ * Detect whether the specified relation has join-order restrictions
921+ * due to being inside an outer join or an IN (sub-SELECT).
1044922 *
1045923 * Essentially, this tests whether have_join_order_restriction() could
1046924 * succeed with this rel and some other one. It's OK if we sometimes
@@ -1052,15 +930,6 @@ has_join_restriction(PlannerInfo *root, RelOptInfo *rel)
1052930 {
1053931 ListCell *l;
1054932
1055- foreach(l, root->lateral_info_list)
1056- {
1057- LateralJoinInfo *ljinfo = (LateralJoinInfo *) lfirst(l);
1058-
1059- if (bms_is_subset(ljinfo->lateral_rhs, rel->relids) ||
1060- bms_overlap(ljinfo->lateral_lhs, rel->relids))
1061- return true;
1062- }
1063-
1064933 foreach(l, root->join_info_list)
1065934 {
1066935 SpecialJoinInfo *sjinfo = (SpecialJoinInfo *) lfirst(l);
--- a/doc/hint_list-ja.html
+++ b/doc/hint_list-ja.html
@@ -74,6 +74,17 @@ PostgreSQL 9.2以降で動作します。</td></tr>
7474 <tr><td nowrap>Leading((テーブル集合<Sup>注1</Sup> テーブル集合<Sup>注1</Sup>))</td>
7575 <td>1つ目に指定したテーブル集合を外部表として、2つ目に指定したテーブル集合を内部表として結合します。</td></tr>
7676
77+<tr><td>見積もり件数補正</td>
78+ <td nowrap>Rows(テーブル テーブル[ テーブル...] 件数補正)</td>
79+ <td>指定したテーブル間の結合結果の見積もり件数を補正します。件数補正として指定できるのは以下の4パターンです。
80+ <p><dl>
81+ <dt>#件数</dt><dd>指定した件数で本来の見積もり件を上書きします。</dd>
82+ <dt>+件数</dt><dd>指定した件数を本来の見積もり件数に加算します。</dd>
83+ <dt>-件数</dt><dd>指定した件数を本来の見積もり件数から減算します。</dd>
84+ <dt>*倍率</dt><dd>本来の見積もり件数を指定した倍率に補正します。「*2」とすると見積もり件数が2倍になり、「*0.01」とすると見積もり件数が1/100になります。</dd>
85+ </dl></p>
86+</td></tr>
87+
7788 <tr><td>GUCパラメータ</td>
7889 <td nowrap>Set(GUCパラメータ 値)</td>
7990 <td>そのクエリの実行計画を作成している間だけ、指定したGUCパラメータを指定した値に変更します。</td></tr>
--- a/doc/pg_hint_plan-ja.html
+++ b/doc/pg_hint_plan-ja.html
@@ -240,7 +240,7 @@ postgres-# ORDER BY a.aid;
240240 </div>
241241
242242 <h3 id="hint-group">ヒント句のグループ</h3>
243-<p>pg_hint_planで使えるヒント句の種類は、スキャン方式と結合方式、結合順序、GUCパラメータの4グループです。各グループの具体的なヒント句は、<a href="hint_list-ja.html">ヒント句一覧</a>を参照してください。</p>
243+<p>pg_hint_planで使えるヒント句の種類は、スキャン方式と結合方式、結合順序、見積もり件数補正、GUCパラメータの5グループです。各グループの具体的なヒント句は、<a href="hint_list-ja.html">ヒント句一覧</a>を参照してください。</p>
244244
245245 <h4>スキャン方式</h4>
246246 <p>あるオブジェクトでどのスキャン方式を選択するかを指定できるヒント句のグループです。「SeqScan」や「IndexScan」などを含みます。</p>
@@ -273,6 +273,10 @@ postgres-# JOIN table table3 t3 ON (t2.key = t3.key);
273273 </pre>
274274 </div>
275275
276+<h4>見積もり件数補正</h4>
277+<p>あるオブジェクトの結合結果の件数を補正できるヒント句のグループです。「Rows」のみを含みます。</p>
278+<p>見積もり件数補正対象として指定できるオブジェクトは結合方式と同じです。補正できるのは結合結果の見積もり件数だけで、スキャンの見積もり件数を補正することはできません。</p>
279+
276280 <h4>GUCパラメータ</h4>
277281 <p>そのクエリの実行計画を作成している間だけGUCパラメータを変更できるヒント句のグループです。「Set」のみを含みます。</p>
278282 <p>設定したいGUCパラメータとそのパラメータの値を指定します。指定できるGUCパラメータは<a href="http://www.postgresql.jp/document/current/html/runtime-config-query.html">問い合わせ計画</a>のGUCパラメータのみです。同じGUCパラメータのヒント句を2回以上指定した場合は、最後に指定したヒント句が適用されます。</p>
--- a/make_join_rel.c
+++ b/make_join_rel.c
@@ -6,7 +6,8 @@
66 * src/backend/optimizer/path/joinrels.c
77 * make_join_rel()
88 *
9- * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
9+ * Portions Copyright (c) 2013, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
10+ * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
1011 * Portions Copyright (c) 1994, Regents of the University of California
1112 *
1213 *-------------------------------------------------------------------------
@@ -24,6 +25,29 @@
2425 * when working with outer joins, or with IN or EXISTS clauses that have been
2526 * turned into joins.
2627 */
28+static double
29+adjust_rows(double rows, RowsHint *hint)
30+{
31+ double result = 0.0; /* keep compiler quiet */
32+
33+ if (hint->value_type == RVT_ABSOLUTE)
34+ result = hint->rows;
35+ else if (hint->value_type == RVT_ADD)
36+ result = rows + hint->rows;
37+ else if (hint->value_type == RVT_SUB)
38+ result = rows - hint->rows;
39+ else if (hint->value_type == RVT_MULTI)
40+ result = rows * hint->rows;
41+ else
42+ Assert(false); /* unrecognized rows value type */
43+
44+ hint->base.state = HINT_STATE_USED;
45+ result = clamp_row_est(result);
46+ elog(DEBUG1, "adjusted rows %d to %d", (int) rows, (int) result);
47+
48+ return result;
49+}
50+
2751 RelOptInfo *
2852 make_join_rel(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2)
2953 {
@@ -34,6 +58,9 @@ make_join_rel(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2)
3458 RelOptInfo *joinrel;
3559 List *restrictlist;
3660
61+ RowsHint *rows_hint = NULL;
62+ int i;
63+
3764 /* We should never try to join two overlapping sets of rels. */
3865 Assert(!bms_overlap(rel1->relids, rel2->relids));
3966
@@ -85,6 +112,54 @@ make_join_rel(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2)
85112 joinrel = build_join_rel(root, joinrelids, rel1, rel2, sjinfo,
86113 &restrictlist);
87114
115+ /* Apply appropriate Rows hint to the join node, if any. */
116+ for (i = 0; i < current_hint->num_hints[HINT_TYPE_ROWS]; i++)
117+ {
118+ rows_hint = current_hint->rows_hints[i];
119+
120+ if (bms_equal(joinrelids, rows_hint->joinrelids))
121+ {
122+ /*
123+ * This join RelOptInfo is exactly a Rows hint specifies, so adjust
124+ * rows estimateion with the hint's content. Here we never have
125+ * another hint which has same relation combination, so we can skip
126+ * rest of hints.
127+ */
128+ if (rows_hint->base.state == HINT_STATE_NOTUSED)
129+ joinrel->rows = adjust_rows(joinrel->rows, rows_hint);
130+ }
131+ else if (bms_is_subset(rows_hint->joinrelids, rel1->relids) ||
132+ bms_is_subset(rows_hint->joinrelids, rel2->relids))
133+ {
134+ /*
135+ * Otherwise if the relation combination specified in thee Rows
136+ * hint is subset of the set of join elements, re-estimate rows and
137+ * costs again to reflect the adjustment done in down. This is
138+ * necessary for the first permutation of the combination the
139+ * relations, but it's difficult to determine that this is the
140+ * first, so do this everytime.
141+ */
142+ set_joinrel_size_estimates(root, joinrel, rel1, rel2, sjinfo,
143+ restrictlist);
144+ }
145+ else if (bms_is_subset(rows_hint->joinrelids, joinrelids))
146+ {
147+ /*
148+ * If the combination specifed in the Rows hints is subset of the
149+ * join relation and spreads over both children,
150+ *
151+ * We do adjust rows estimation only when the value type was
152+ * multiplication, because other value types are meanless.
153+ */
154+ if (rows_hint->value_type == RVT_MULTI)
155+ {
156+ set_joinrel_size_estimates(root, joinrel, rel1, rel2, sjinfo,
157+ restrictlist);
158+ joinrel->rows = adjust_rows(joinrel->rows, rows_hint);
159+ }
160+ }
161+ }
162+
88163 /*
89164 * If we've already proven this join is empty, we needn't consider any
90165 * more paths for it.
--- a/pg_hint_plan.c
+++ b/pg_hint_plan.c
@@ -37,6 +37,7 @@
3737
3838 #include "executor/spi.h"
3939 #include "catalog/pg_type.h"
40+
4041 /*
4142 * We have our own header file "plpgsql-9.1", which is necessary to support
4243 * hints for queries in PL/pgSQL blocks, in pg_hint_plan source package,
@@ -87,6 +88,7 @@ PG_MODULE_MAGIC;
8788 #define HINT_NOHASHJOIN "NoHashJoin"
8889 #define HINT_LEADING "Leading"
8990 #define HINT_SET "Set"
91+#define HINT_ROWS "Rows"
9092
9193 #define HINT_ARRAY_DEFAULT_INITSIZE 8
9294
@@ -146,6 +148,7 @@ typedef enum HintKeyword
146148 HINT_KEYWORD_NOHASHJOIN,
147149 HINT_KEYWORD_LEADING,
148150 HINT_KEYWORD_SET,
151+ HINT_KEYWORD_ROWS,
149152 HINT_KEYWORD_UNRECOGNIZED
150153 } HintKeyword;
151154
@@ -162,20 +165,22 @@ typedef const char *(*HintParseFunction) (Hint *hint, HintState *hstate,
162165 Query *parse, const char *str);
163166
164167 /* hint types */
165-#define NUM_HINT_TYPE 4
168+#define NUM_HINT_TYPE 5
166169 typedef enum HintType
167170 {
168171 HINT_TYPE_SCAN_METHOD,
169172 HINT_TYPE_JOIN_METHOD,
170173 HINT_TYPE_LEADING,
171- HINT_TYPE_SET
174+ HINT_TYPE_SET,
175+ HINT_TYPE_ROWS,
172176 } HintType;
173177
174178 static const char *HintTypeName[] = {
175179 "scan method",
176180 "join method",
177181 "leading",
178- "set"
182+ "set",
183+ "rows",
179184 };
180185
181186 /* hint status */
@@ -262,6 +267,26 @@ typedef struct SetHint
262267 List *words;
263268 } SetHint;
264269
270+/* rows hints */
271+typedef enum RowsValueType {
272+ RVT_ABSOLUTE, /* Rows(... #1000) */
273+ RVT_ADD, /* Rows(... +1000) */
274+ RVT_SUB, /* Rows(... -1000) */
275+ RVT_MULTI, /* Rows(... *1.2) */
276+} RowsValueType;
277+typedef struct RowsHint
278+{
279+ Hint base;
280+ int nrels;
281+ int inner_nrels;
282+ char **relnames;
283+ Relids joinrelids;
284+ Relids inner_joinrelids;
285+ char *rows_str;
286+ RowsValueType value_type;
287+ double rows;
288+} RowsHint;
289+
265290 /*
266291 * Describes a context of hint processing.
267292 */
@@ -297,6 +322,9 @@ struct HintState
297322 /* for Set hints */
298323 SetHint **set_hints; /* parsed Set hints */
299324 GucContext context; /* which GUC parameters can we set? */
325+
326+ /* for Rows hints */
327+ RowsHint **rows_hints; /* parsed Rows hints */
300328 };
301329
302330 /*
@@ -358,6 +386,15 @@ static void SetHintDesc(SetHint *hint, StringInfo buf);
358386 static int SetHintCmp(const SetHint *a, const SetHint *b);
359387 static const char *SetHintParse(SetHint *hint, HintState *hstate, Query *parse,
360388 const char *str);
389+static Hint *RowsHintCreate(const char *hint_str, const char *keyword,
390+ HintKeyword hint_keyword);
391+static void RowsHintDelete(RowsHint *hint);
392+static void RowsHintDesc(RowsHint *hint, StringInfo buf);
393+static int RowsHintCmp(const RowsHint *a, const RowsHint *b);
394+static const char *RowsHintParse(RowsHint *hint, HintState *hstate,
395+ Query *parse, const char *str);
396+static Hint *LeadingHintCreate(const char *hint_str, const char *keyword,
397+ HintKeyword hint_keyword);
361398
362399 static void quote_value(StringInfo buf, const char *value);
363400
@@ -379,9 +416,6 @@ static void set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
379416 static void generate_mergeappend_paths(PlannerInfo *root, RelOptInfo *rel,
380417 List *live_childrels,
381418 List *all_child_pathkeys);
382-static Path *get_cheapest_parameterized_child_path(PlannerInfo *root,
383- RelOptInfo *rel,
384- Relids required_outer);
385419 static List *accumulate_append_subpath(List *subpaths, Path *path);
386420 RelOptInfo *pg_hint_plan_make_join_rel(PlannerInfo *root, RelOptInfo *rel1,
387421 RelOptInfo *rel2);
@@ -462,6 +496,7 @@ static const HintParser parsers[] = {
462496 {HINT_NOHASHJOIN, JoinMethodHintCreate, HINT_KEYWORD_NOHASHJOIN},
463497 {HINT_LEADING, LeadingHintCreate, HINT_KEYWORD_LEADING},
464498 {HINT_SET, SetHintCreate, HINT_KEYWORD_SET},
499+ {HINT_ROWS, RowsHintCreate, HINT_KEYWORD_ROWS},
465500 {NULL, NULL, HINT_KEYWORD_UNRECOGNIZED}
466501 };
467502
@@ -730,6 +765,54 @@ SetHintDelete(SetHint *hint)
730765 pfree(hint);
731766 }
732767
768+static Hint *
769+RowsHintCreate(const char *hint_str, const char *keyword,
770+ HintKeyword hint_keyword)
771+{
772+ RowsHint *hint;
773+
774+ hint = palloc(sizeof(RowsHint));
775+ hint->base.hint_str = hint_str;
776+ hint->base.keyword = keyword;
777+ hint->base.hint_keyword = hint_keyword;
778+ hint->base.type = HINT_TYPE_ROWS;
779+ hint->base.state = HINT_STATE_NOTUSED;
780+ hint->base.delete_func = (HintDeleteFunction) RowsHintDelete;
781+ hint->base.desc_func = (HintDescFunction) RowsHintDesc;
782+ hint->base.cmp_func = (HintCmpFunction) RowsHintCmp;
783+ hint->base.parse_func = (HintParseFunction) RowsHintParse;
784+ hint->nrels = 0;
785+ hint->inner_nrels = 0;
786+ hint->relnames = NULL;
787+ hint->joinrelids = NULL;
788+ hint->inner_joinrelids = NULL;
789+ hint->rows_str = NULL;
790+ hint->value_type = RVT_ABSOLUTE;
791+ hint->rows = 0;
792+
793+ return (Hint *) hint;
794+}
795+
796+static void
797+RowsHintDelete(RowsHint *hint)
798+{
799+ if (!hint)
800+ return;
801+
802+ if (hint->relnames)
803+ {
804+ int i;
805+
806+ for (i = 0; i < hint->nrels; i++)
807+ pfree(hint->relnames[i]);
808+ pfree(hint->relnames);
809+ }
810+
811+ bms_free(hint->joinrelids);
812+ bms_free(hint->inner_joinrelids);
813+ pfree(hint);
814+}
815+
733816 static HintState *
734817 HintStateCreate(void)
735818 {
@@ -753,6 +836,7 @@ HintStateCreate(void)
753836 hstate->leading_hint = NULL;
754837 hstate->context = superuser() ? PGC_SUSET : PGC_USERSET;
755838 hstate->set_hints = NULL;
839+ hstate->rows_hints = NULL;
756840
757841 return hstate;
758842 }
@@ -917,6 +1001,26 @@ SetHintDesc(SetHint *hint, StringInfo buf)
9171001 appendStringInfo(buf, ")\n");
9181002 }
9191003
1004+static void
1005+RowsHintDesc(RowsHint *hint, StringInfo buf)
1006+{
1007+ int i;
1008+
1009+ appendStringInfo(buf, "%s(", hint->base.keyword);
1010+ if (hint->relnames != NULL)
1011+ {
1012+ quote_value(buf, hint->relnames[0]);
1013+ for (i = 1; i < hint->nrels; i++)
1014+ {
1015+ appendStringInfoCharMacro(buf, ' ');
1016+ quote_value(buf, hint->relnames[i]);
1017+ }
1018+ }
1019+ appendStringInfo(buf, " %s", hint->rows_str);
1020+ appendStringInfoString(buf, ")\n");
1021+
1022+}
1023+
9201024 /*
9211025 * Append string which represents all hints in a given state to buf, with
9221026 * preceding title with them.
@@ -1014,6 +1118,24 @@ SetHintCmp(const SetHint *a, const SetHint *b)
10141118 }
10151119
10161120 static int
1121+RowsHintCmp(const RowsHint *a, const RowsHint *b)
1122+{
1123+ int i;
1124+
1125+ if (a->nrels != b->nrels)
1126+ return a->nrels - b->nrels;
1127+
1128+ for (i = 0; i < a->nrels; i++)
1129+ {
1130+ int result;
1131+ if ((result = RelnameCmp(&a->relnames[i], &b->relnames[i])) != 0)
1132+ return result;
1133+ }
1134+
1135+ return 0;
1136+}
1137+
1138+static int
10171139 HintCmp(const void *a, const void *b)
10181140 {
10191141 const Hint *hinta = *((const Hint **) a);
@@ -1612,6 +1734,8 @@ create_hintstate(Query *parse, const char *hints)
16121734 hstate->num_hints[HINT_TYPE_JOIN_METHOD]);
16131735 hstate->set_hints = (SetHint **) (hstate->leading_hint +
16141736 hstate->num_hints[HINT_TYPE_LEADING]);
1737+ hstate->rows_hints = (RowsHint **) (hstate->set_hints +
1738+ hstate->num_hints[HINT_TYPE_SET]);
16151739
16161740 return hstate;
16171741 }
@@ -1903,6 +2027,97 @@ SetHintParse(SetHint *hint, HintState *hstate, Query *parse, const char *str)
19032027 return str;
19042028 }
19052029
2030+static const char *
2031+RowsHintParse(RowsHint *hint, HintState *hstate, Query *parse,
2032+ const char *str)
2033+{
2034+ HintKeyword hint_keyword = hint->base.hint_keyword;
2035+ List *name_list = NIL;
2036+ char *rows_str;
2037+ char *end_ptr;
2038+
2039+ if ((str = parse_parentheses(str, &name_list, hint_keyword)) == NULL)
2040+ return NULL;
2041+
2042+ /* Last element must be rows specification */
2043+ hint->nrels = list_length(name_list) - 1;
2044+
2045+ if (hint->nrels > 0)
2046+ {
2047+ ListCell *l;
2048+ int i = 0;
2049+
2050+ /*
2051+ * Transform relation names from list to array to sort them with qsort
2052+ * after.
2053+ */
2054+ hint->relnames = palloc(sizeof(char *) * hint->nrels);
2055+ foreach (l, name_list)
2056+ {
2057+ if (hint->nrels <= i)
2058+ break;
2059+ hint->relnames[i] = lfirst(l);
2060+ i++;
2061+ }
2062+ }
2063+
2064+ /* Retieve rows estimation */
2065+ rows_str = list_nth(name_list, hint->nrels);
2066+ hint->rows_str = rows_str; /* store as-is for error logging */
2067+ if (rows_str[0] == '#')
2068+ {
2069+ hint->value_type = RVT_ABSOLUTE;
2070+ rows_str++;
2071+ }
2072+ else if (rows_str[0] == '+')
2073+ {
2074+ hint->value_type = RVT_ADD;
2075+ rows_str++;
2076+ }
2077+ else if (rows_str[0] == '-')
2078+ {
2079+ hint->value_type = RVT_SUB;
2080+ rows_str++;
2081+ }
2082+ else if (rows_str[0] == '*')
2083+ {
2084+ hint->value_type = RVT_MULTI;
2085+ rows_str++;
2086+ }
2087+ else
2088+ {
2089+ hint_ereport(rows_str, ("unrecognized rows value type notation."));
2090+ hint->base.state = HINT_STATE_ERROR;
2091+ return str;
2092+ }
2093+ hint->rows = strtod(rows_str, &end_ptr);
2094+ if (*end_ptr)
2095+ {
2096+ hint_ereport(rows_str,
2097+ ("%s hint requires valid number as rows estimation.",
2098+ hint->base.keyword));
2099+ hint->base.state = HINT_STATE_ERROR;
2100+ return str;
2101+ }
2102+
2103+ /* A join hint requires at least two relations */
2104+ if (hint->nrels < 2)
2105+ {
2106+ hint_ereport(str,
2107+ ("%s hint requires at least two relations.",
2108+ hint->base.keyword));
2109+ hint->base.state = HINT_STATE_ERROR;
2110+ return str;
2111+ }
2112+
2113+ list_free(name_list);
2114+
2115+ /* Sort relnames in alphabetical order. */
2116+ qsort(hint->relnames, hint->nrels, sizeof(char *), RelnameCmp);
2117+
2118+ return str;
2119+}
2120+
19062121 /*
19072122 * set GUC parameter functions
19082123 */
@@ -2973,6 +3188,40 @@ OuterInnerJoinCreate(OuterInnerRels *outer_inner, LeadingHint *leading_hint,
29733188 return join_relids;
29743189 }
29753190
3191+static Relids
3192+create_bms_of_relids(Hint *base, PlannerInfo *root, List *initial_rels,
3193+ int nrels, char **relnames)
3194+{
3195+ int relid;
3196+ Relids relids = NULL;
3197+ int j;
3198+ char *relname;
3199+
3200+ for (j = 0; j < nrels; j++)
3201+ {
3202+ relname = relnames[j];
3203+
3204+ relid = find_relid_aliasname(root, relname, initial_rels,
3205+ base->hint_str);
3206+
3207+ if (relid == -1)
3208+ base->state = HINT_STATE_ERROR;
3209+
3210+ if (relid <= 0)
3211+ break;
3212+
3213+ if (bms_is_member(relid, relids))
3214+ {
3215+ hint_ereport(base->hint_str,
3216+ ("Relation name \"%s\" is duplicated.", relname));
3217+ base->state = HINT_STATE_ERROR;
3218+ break;
3219+ }
3220+
3221+ relids = bms_add_member(relids, relid);
3222+ }
3223+ return relids;
3224+}
29763225 /*
29773226 * Transform join method hint into handy form.
29783227 *
@@ -3000,43 +3249,36 @@ transform_join_hints(HintState *hstate, PlannerInfo *root, int nbaserel,
30003249 for (i = 0; i < hstate->num_hints[HINT_TYPE_JOIN_METHOD]; i++)
30013250 {
30023251 JoinMethodHint *hint = hstate->join_hints[i];
3003- int j;
30043252
30053253 if (!hint_state_enabled(hint) || hint->nrels > nbaserel)
30063254 continue;
30073255
3008- bms_free(hint->joinrelids);
3009- hint->joinrelids = NULL;
3010- relid = 0;
3011- for (j = 0; j < hint->nrels; j++)
3012- {
3013- relname = hint->relnames[j];
3256+ hint->joinrelids = create_bms_of_relids(&(hint->base), root,
3257+ initial_rels, hint->nrels, hint->relnames);
30143258
3015- relid = find_relid_aliasname(root, relname, initial_rels,
3016- hint->base.hint_str);
3259+ if (hint->joinrelids == NULL || hint->base.state == HINT_STATE_ERROR)
3260+ continue;
30173261
3018- if (relid == -1)
3019- hint->base.state = HINT_STATE_ERROR;
3262+ hstate->join_hint_level[hint->nrels] =
3263+ lappend(hstate->join_hint_level[hint->nrels], hint);
3264+ }
30203265
3021- if (relid <= 0)
3022- break;
3266+ /*
3267+ * Create bitmap of relids from alias names for each rows hint.
3268+ * Bitmaps are more handy than strings in join searching.
3269+ */
3270+ for (i = 0; i < hstate->num_hints[HINT_TYPE_ROWS]; i++)
3271+ {
3272+ RowsHint *hint = hstate->rows_hints[i];
30233273
3024- if (bms_is_member(relid, hint->joinrelids))
3025- {
3026- hint_ereport(hint->base.hint_str,
3027- ("Relation name \"%s\" is duplicated.", relname));
3028- hint->base.state = HINT_STATE_ERROR;
3029- break;
3030- }
3274+ if (!hint_state_enabled(hint) || hint->nrels > nbaserel)
3275+ continue;
30313276
3032- hint->joinrelids = bms_add_member(hint->joinrelids, relid);
3033- }
3277+ hint->joinrelids = create_bms_of_relids(&(hint->base), root,
3278+ initial_rels, hint->nrels, hint->relnames);
30343279
3035- if (relid <= 0 || hint->base.state == HINT_STATE_ERROR)
3280+ if (hint->joinrelids == NULL || hint->base.state == HINT_STATE_ERROR)
30363281 continue;
3037-
3038- hstate->join_hint_level[hint->nrels] =
3039- lappend(hstate->join_hint_level[hint->nrels], hint);
30403282 }
30413283
30423284 /* Do nothing if no Leading hint was supplied. */
@@ -3242,17 +3484,7 @@ static void
32423484 set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
32433485 {
32443486 /* Consider sequential scan */
3245- Relids required_outer;
3246-
3247- /*
3248- * We don't support pushing join clauses into the quals of a seqscan, but
3249- * it could still have required parameterization due to LATERAL refs in
3250- * its tlist.
3251- */
3252- required_outer = rel->lateral_relids;
3253-
3254- /* Consider sequential scan */
3255- add_path(rel, create_seqscan_path(root, rel, required_outer));
3487+ add_path(rel, create_seqscan_path(root, rel, NULL));
32563488
32573489 /* Consider index scans */
32583490 create_index_paths(root, rel);
--- a/sql/pg_hint_plan.sql
+++ b/sql/pg_hint_plan.sql
@@ -845,3 +845,32 @@ BEGIN
845845 END;
846846 $$;
847847 DROP EXTENSION pg_hint_plan;
848+
849+--
850+-- Rows hint tests
851+--
852+-- value types
853+EXPLAIN SELECT * FROM t1 JOIN t2 ON (t1.id = t2.id);
854+/*+ Rows(t1 t2 #99) */
855+EXPLAIN SELECT * FROM t1 JOIN t2 ON (t1.id = t2.id);
856+/*+ Rows(t1 t2 +99) */
857+EXPLAIN SELECT * FROM t1 JOIN t2 ON (t1.id = t2.id);
858+/*+ Rows(t1 t2 -99) */
859+EXPLAIN SELECT * FROM t1 JOIN t2 ON (t1.id = t2.id);
860+/*+ Rows(t1 t2 *99) */
861+EXPLAIN SELECT * FROM t1 JOIN t2 ON (t1.id = t2.id);
862+/*+ Rows(t1 t2 *0.01) */
863+EXPLAIN SELECT * FROM t1 JOIN t2 ON (t1.id = t2.id);
864+/*+ Rows(t1 t2 #aa) */
865+EXPLAIN SELECT * FROM t1 JOIN t2 ON (t1.id = t2.id); -- ERROR
866+/*+ Rows(t1 t2 /99) */
867+EXPLAIN SELECT * FROM t1 JOIN t2 ON (t1.id = t2.id); -- ERROR
868+-- round up to 1
869+/*+ Rows(t1 t2 -99999) */
870+EXPLAIN SELECT * FROM t1 JOIN t2 ON (t1.id = t2.id);
871+-- complex join tree
872+EXPLAIN SELECT * FROM t1 JOIN t2 ON (t1.id = t2.id) JOIN t3 ON (t3.id = t2.id);
873+/*+ Rows(t1 t2 #22) */
874+EXPLAIN SELECT * FROM t1 JOIN t2 ON (t1.id = t2.id) JOIN t3 ON (t3.id = t2.id);
875+/*+ Rows(t1 t3 *10) */
876+EXPLAIN SELECT * FROM t1 JOIN t2 ON (t1.id = t2.id) JOIN t3 ON (t3.id = t2.id);
--- a/sql/ut-A.sql
+++ b/sql/ut-A.sql
@@ -1107,6 +1107,9 @@ EXPLAIN (COSTS false) SELECT nested_planner(2) FROM s1.t1 t_1 ORDER BY t_1.c1;
11071107 EXPLAIN (COSTS false) SELECT nested_planner(2) FROM s1.t1 t_1 ORDER BY t_1.c1;
11081108
11091109 --No.13-3-3
1110+--
1111+-- Redefine not to use cached plan
1112+--
11101113 CREATE OR REPLACE FUNCTION nested_planner(cnt int) RETURNS int AS $$
11111114 DECLARE
11121115 new_cnt int;
--- a/sql/ut-J.sql
+++ b/sql/ut-J.sql
@@ -152,6 +152,10 @@ EXPLAIN (COSTS false) SELECT * FROM s1.v1 t1, s1.v1_ t2 WHERE t1.c1 = t2.c1;
152152 EXPLAIN (COSTS false) SELECT * FROM s1.t1, s1.t2 WHERE t1.c1 = t2.c1 AND t1.c1 = (SELECT max(st1.c1) FROM s1.t1 st1, s1.t2 st2 WHERE st1.c1 = st2.c1);
153153 /*+MergeJoin(t1 t2)NestLoop(st1 st2)*/
154154 EXPLAIN (COSTS true) SELECT * FROM s1.t1, s1.t2 WHERE t1.c1 = t2.c1 AND t1.c1 = (SELECT max(st1.c1) FROM s1.t1 st1, s1.t2 st2 WHERE st1.c1 = st2.c1);
155+--
156+-- There are cases where difference in the measured value and predicted value
157+-- depending upon the version of PostgreSQL
158+--
155159
156160 EXPLAIN (COSTS false) SELECT * FROM s1.t1, (SELECT t2.c1 FROM s1.t2) st2 WHERE t1.c1 = st2.c1;
157161 /*+HashJoin(t1 st2)*/
--- a/sql/ut-S.sql
+++ b/sql/ut-S.sql
@@ -614,7 +614,7 @@ EXPLAIN (COSTS false) SELECT c2 FROM s1.ti1 WHERE ti1.c2 >= 1;
614614 EXPLAIN (COSTS false) SELECT * FROM s1.ti1 WHERE ti1.c2 = 1 AND ctid = '(1,1)';
615615
616616 -- No. S-3-3-2
617-/*+IndexScan(ti1 ti1_i3 ti1_i4)*/
617+/*+IndexScan(ti1 ti1_i3 ti1_i2)*/
618618 EXPLAIN (COSTS false) SELECT * FROM s1.ti1 WHERE ti1.c2 = 1 AND ctid = '(1,1)';
619619
620620 -- No. S-3-3-3
@@ -626,7 +626,7 @@ EXPLAIN (COSTS false) SELECT * FROM s1.ti1 WHERE ti1.c2 = 1 AND ctid = '(1,1)';
626626 EXPLAIN (COSTS false) SELECT * FROM s1.ti1 WHERE ti1.c2 = 1 AND ctid = '(1,1)';
627627
628628 -- No. S-3-3-5
629-/*+BitmapScan(ti1 ti1_i3 ti1_i4)*/
629+/*+BitmapScan(ti1 ti1_i3 ti1_i2)*/
630630 EXPLAIN (COSTS false) SELECT * FROM s1.ti1 WHERE ti1.c2 = 1 AND ctid = '(1,1)';
631631
632632 -- No. S-3-3-6
@@ -638,7 +638,7 @@ EXPLAIN (COSTS false) SELECT * FROM s1.ti1 WHERE ti1.c2 = 1 AND ctid = '(1,1)';
638638 EXPLAIN (COSTS false) SELECT c2 FROM s1.ti1 WHERE ti1.c2 >= 1;
639639
640640 -- No. S-3-3-8
641-/*+IndexOnlyScan(ti1 ti1_i3 ti1_i4)*/
641+/*+IndexOnlyScan(ti1 ti1_i3 ti1_i2)*/
642642 EXPLAIN (COSTS false) SELECT c2 FROM s1.ti1 WHERE ti1.c2 >= 1;
643643
644644 -- No. S-3-3-9
@@ -962,195 +962,195 @@ EXPLAIN SELECT c2 FROM s1.p1 WHERE c2 = 1;
962962 EXPLAIN (COSTS true) SELECT * FROM s1.p2 WHERE c1 = 1;
963963
964964 ----
965----- No. S-3-12 specified same table
965+---- No. S-3-11 specified same table
966966 ----
967967
968--- No. S-3-12-1
968+-- No. S-3-11-1
969969 /*+IndexScan(ti1) BitmapScan(ti1)*/
970970 EXPLAIN (COSTS false) SELECT * FROM s1.ti1 WHERE c1 = 1 AND ctid = '(1,1)';
971971
972--- No. S-3-12-2
972+-- No. S-3-11-2
973973 /*+IndexScan(ti1 ti1_pkey) BitmapScan(ti1 ti1_btree)*/
974974 EXPLAIN (COSTS false) SELECT * FROM s1.ti1 WHERE c1 = 1 AND ctid = '(1,1)';
975975
976--- No. S-3-12-3
976+-- No. S-3-11-3
977977 /*+BitmapScan(ti1) IndexScan(ti1) BitmapScan(ti1)*/
978978 EXPLAIN (COSTS false) SELECT * FROM s1.ti1 WHERE c1 = 1 AND ctid = '(1,1)';
979979
980--- No. S-3-12-4
980+-- No. S-3-11-4
981981 /*+BitmapScan(ti1 ti1_hash) IndexScan(ti1 ti1_pkey) BitmapScan(ti1 ti1_btree)*/
982982 EXPLAIN (COSTS false) SELECT * FROM s1.ti1 WHERE c1 = 1 AND ctid = '(1,1)';
983983
984984 ----
985----- No. S-3-13 message output
985+---- No. S-3-12 message output
986986 ----
987987
988--- No. S-3-13-1
988+-- No. S-3-12-1
989989 /*+SeqScan(ti1)*/
990990 EXPLAIN (COSTS false) SELECT * FROM s1.ti1 WHERE c1 = 1 AND ctid = '(1,1)';
991991
992--- No. S-3-13-2
992+-- No. S-3-12-2
993993 /*+SeqScan(ti1 ti1_pkey)*/
994994 EXPLAIN (COSTS false) SELECT * FROM s1.ti1 WHERE c1 = 1 AND ctid = '(1,1)';
995995
996--- No. S-3-13-3
996+-- No. S-3-12-3
997997 /*+SeqScan(ti1 ti1_pkey ti1_btree)*/
998998 EXPLAIN (COSTS false) SELECT * FROM s1.ti1 WHERE c1 = 1 AND ctid = '(1,1)';
999999
1000--- No. S-3-13-4
1000+-- No. S-3-12-4
10011001 /*+IndexScan(ti1)*/
10021002 EXPLAIN (COSTS false) SELECT * FROM s1.ti1 WHERE c1 = 1 AND ctid = '(1,1)';
10031003
1004--- No. S-3-13-5
1004+-- No. S-3-12-5
10051005 /*+IndexScan(ti1 ti1_pkey)*/
10061006 EXPLAIN (COSTS false) SELECT * FROM s1.ti1 WHERE c1 = 1 AND ctid = '(1,1)';
10071007
1008--- No. S-3-13-6
1008+-- No. S-3-12-6
10091009 /*+IndexScan(ti1 ti1_pkey ti1_btree)*/
10101010 EXPLAIN (COSTS false) SELECT * FROM s1.ti1 WHERE c1 = 1 AND ctid = '(1,1)';
10111011
1012--- No. S-3-13-7
1012+-- No. S-3-12-7
10131013 /*+BitmapScan(ti1)*/
10141014 EXPLAIN (COSTS false) SELECT * FROM s1.ti1 WHERE c1 = 1 AND ctid = '(1,1)';
10151015
1016--- No. S-3-13-8
1016+-- No. S-3-12-8
10171017 /*+BitmapScan(ti1 ti1_pkey)*/
10181018 EXPLAIN (COSTS false) SELECT * FROM s1.ti1 WHERE c1 = 1 AND ctid = '(1,1)';
10191019
1020--- No. S-3-13-9
1020+-- No. S-3-12-9
10211021 /*+BitmapScan(ti1 ti1_pkey ti1_btree)*/
10221022 EXPLAIN (COSTS false) SELECT * FROM s1.ti1 WHERE c1 = 1 AND ctid = '(1,1)';
10231023
1024--- No. S-3-13-10
1024+-- No. S-3-12-10
10251025 /*+TidScan(ti1)*/
10261026 EXPLAIN (COSTS false) SELECT * FROM s1.ti1 WHERE c1 = 1 AND ctid = '(1,1)';
10271027
1028--- No. S-3-13-11
1028+-- No. S-3-12-11
10291029 /*+TidScan(ti1 ti1_pkey)*/
10301030 EXPLAIN (COSTS false) SELECT * FROM s1.ti1 WHERE c1 = 1 AND ctid = '(1,1)';
10311031
1032--- No. S-3-13-12
1032+-- No. S-3-12-12
10331033 /*+TidScan(ti1 ti1_pkey ti1_btree)*/
10341034 EXPLAIN (COSTS false) SELECT * FROM s1.ti1 WHERE c1 = 1 AND ctid = '(1,1)';
10351035
1036--- No. S-3-13-13
1036+-- No. S-3-12-13
10371037 /*+NoSeqScan(ti1)*/
10381038 EXPLAIN (COSTS false) SELECT * FROM s1.ti1 WHERE c1 = 1 AND ctid = '(1,1)';
10391039
1040--- No. S-3-13-14
1040+-- No. S-3-12-14
10411041 /*+NoSeqScan(ti1 ti1_pkey)*/
10421042 EXPLAIN (COSTS false) SELECT * FROM s1.ti1 WHERE c1 = 1 AND ctid = '(1,1)';
10431043
1044--- No. S-3-13-15
1044+-- No. S-3-12-15
10451045 /*+NoSeqScan(ti1 ti1_pkey ti1_btree)*/
10461046 EXPLAIN (COSTS false) SELECT * FROM s1.ti1 WHERE c1 = 1 AND ctid = '(1,1)';
10471047
1048--- No. S-3-13-16
1048+-- No. S-3-12-16
10491049 /*+NoIndexScan(ti1)*/
10501050 EXPLAIN (COSTS false) SELECT * FROM s1.ti1 WHERE c1 = 1 AND ctid = '(1,1)';
10511051
1052--- No. S-3-13-17
1052+-- No. S-3-12-17
10531053 /*+NoIndexScan(ti1 ti1_pkey)*/
10541054 EXPLAIN (COSTS false) SELECT * FROM s1.ti1 WHERE c1 = 1 AND ctid = '(1,1)';
10551055
1056--- No. S-3-13-18
1056+-- No. S-3-12-18
10571057 /*+NoIndexScan(ti1 ti1_pkey ti1_btree)*/
10581058 EXPLAIN (COSTS false) SELECT * FROM s1.ti1 WHERE c1 = 1 AND ctid = '(1,1)';
10591059
1060--- No. S-3-13-19
1060+-- No. S-3-12-19
10611061 /*+NoBitmapScan(ti1)*/
10621062 EXPLAIN (COSTS false) SELECT * FROM s1.ti1 WHERE c1 = 1 AND ctid = '(1,1)';
10631063
1064--- No. S-3-13-20
1064+-- No. S-3-12-20
10651065 /*+NoBitmapScan(ti1 ti1_pkey)*/
10661066 EXPLAIN (COSTS false) SELECT * FROM s1.ti1 WHERE c1 = 1 AND ctid = '(1,1)';
10671067
1068--- No. S-3-13-21
1068+-- No. S-3-12-21
10691069 /*+NoBitmapScan(ti1 ti1_pkey ti1_btree)*/
10701070 EXPLAIN (COSTS false) SELECT * FROM s1.ti1 WHERE c1 = 1 AND ctid = '(1,1)';
10711071
1072--- No. S-3-13-22
1072+-- No. S-3-12-22
10731073 /*+NoTidScan(ti1)*/
10741074 EXPLAIN (COSTS false) SELECT * FROM s1.ti1 WHERE c1 = 1 AND ctid = '(1,1)';
10751075
1076--- No. S-3-13-23
1076+-- No. S-3-12-23
10771077 /*+NoTidScan(ti1 ti1_pkey)*/
10781078 EXPLAIN (COSTS false) SELECT * FROM s1.ti1 WHERE c1 = 1 AND ctid = '(1,1)';
10791079
1080--- No. S-3-13-24
1080+-- No. S-3-12-24
10811081 /*+NoTidScan(ti1 ti1_pkey ti1_btree)*/
10821082 EXPLAIN (COSTS false) SELECT * FROM s1.ti1 WHERE c1 = 1 AND ctid = '(1,1)';
10831083
1084--- No. S-3-13-25
1084+-- No. S-3-12-25
10851085 /*+IndexOnlyScan(ti1)*/
10861086 EXPLAIN (COSTS false) SELECT c1 FROM s1.ti1 WHERE c1 >= 1;
10871087
1088--- No. S-3-13-26
1088+-- No. S-3-12-26
10891089 /*+IndexOnlyScan(ti1 ti1_pkey)*/
10901090 EXPLAIN (COSTS false) SELECT c1 FROM s1.ti1 WHERE c1 >= 1;
10911091
1092--- No. S-3-13-27
1092+-- No. S-3-12-27
10931093 /*+IndexOnlyScan(ti1 ti1_pkey ti1_btree)*/
10941094 EXPLAIN (COSTS false) SELECT c1 FROM s1.ti1 WHERE c1 >= 1;
10951095
1096--- No. S-3-13-28
1096+-- No. S-3-12-28
10971097 /*+NoIndexOnlyScan(ti1)*/
10981098 EXPLAIN (COSTS false) SELECT c1 FROM s1.ti1 WHERE c1 = 1;
10991099
1100--- No. S-3-13-29
1100+-- No. S-3-12-29
11011101 /*+NoIndexOnlyScan(ti1 ti1_pkey)*/
11021102 EXPLAIN (COSTS false) SELECT c1 FROM s1.ti1 WHERE c1 = 1;
11031103
1104--- No. S-3-13-30
1104+-- No. S-3-12-30
11051105 /*+NoIndexOnlyScan(ti1 ti1_pkey ti1_btree)*/
11061106 EXPLAIN (COSTS false) SELECT c1 FROM s1.ti1 WHERE c1 = 1;
11071107
11081108
11091109 ----
1110----- No. S-3-14 regular expression
1110+---- No. S-3-13 message output
11111111 ----
11121112 EXPLAIN (COSTS false) SELECT * FROM s1.ti1 WHERE c2 = 1;
11131113
1114--- No. S-3-14-1
1114+-- No. S-3-13-1
11151115 /*+IndexScanRegexp(ti1 ti1_.*_key)*/
11161116 EXPLAIN (COSTS false) SELECT * FROM s1.ti1 WHERE c2 = 1;
11171117
1118--- No. S-3-14-2
1118+-- No. S-3-13-2
11191119 /*+IndexScanRegexp(ti1 ti1_i.)*/
11201120 EXPLAIN (COSTS false) SELECT * FROM s1.ti1 WHERE c2 = 1;
11211121
1122--- No. S-3-14-3
1122+-- No. S-3-13-3
11231123 /*+IndexScanRegexp(ti1 no.*_exist)*/
11241124 EXPLAIN (COSTS false) SELECT * FROM s1.ti1 WHERE c2 = 1;
11251125
1126--- No. S-3-14-4
1126+-- No. S-3-13-4
11271127 /*+IndexScanRegexp(p1 .*pkey)*/
11281128 EXPLAIN (COSTS false) SELECT * FROM s1.p1 WHERE c1 = 1;
11291129
1130--- No. S-3-14-5
1130+-- No. S-3-13-5
11311131 /*+IndexScanRegexp(p1 p1.*i)*/
11321132 EXPLAIN (COSTS false) SELECT * FROM s1.p1 WHERE c1 = 1;
11331133
1134--- No. S-3-14-6
1134+-- No. S-3-13-6
11351135 /*+IndexScanRegexp(p1 no.*_exist)*/
11361136 EXPLAIN (COSTS false) SELECT * FROM s1.p1 WHERE c1 = 1;
11371137
11381138 ----
1139----- No. S-3-15 message output of candidate for index
1139+---- No. S-3-14 message output
11401140 ----
11411141
1142--- No. S-3-15-1
1142+-- No. S-3-14-1
11431143 /*+IndexScan(ti1 ti1_i1)*/
11441144 EXPLAIN (COSTS false) SELECT * FROM s1.ti1 WHERE c2 = 1;
1145--- No. S-3-15-2
1145+-- No. S-3-14-2
11461146 /*+IndexScan(ti1 not_exist)*/
11471147 EXPLAIN (COSTS false) SELECT * FROM s1.ti1 WHERE c2 = 1;
1148--- No. S-3-15-3
1148+-- No. S-3-14-3
11491149 /*+IndexScan(ti1 ti1_i1 ti1_i2)*/
11501150 EXPLAIN (COSTS false) SELECT * FROM s1.ti1 WHERE c2 = 1;
1151--- No. S-3-15-4
1151+-- No. S-3-14-4
11521152 /*+IndexScan(ti1 ti1_i1 not_exist)*/
11531153 EXPLAIN (COSTS false) SELECT * FROM s1.ti1 WHERE c2 = 1;
1154--- No. S-3-15-5
1154+-- No. S-3-14-5
11551155 /*+IndexScan(ti1 not_exist1 not_exist2)*/
11561156 EXPLAIN (COSTS false) SELECT * FROM s1.ti1 WHERE c2 = 1;