|
8 | 8 | *
|
9 | 9 | *
|
10 | 10 | * IDENTIFICATION
|
11 |
| - * $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.76 2001/06/05 17:13:51 tgl Exp $ |
| 11 | + * $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.77 2001/07/16 17:57:02 tgl Exp $ |
12 | 12 | *
|
13 | 13 | *-------------------------------------------------------------------------
|
14 | 14 | */
|
@@ -37,6 +37,8 @@ static void set_plain_rel_pathlist(Query *root, RelOptInfo *rel,
|
37 | 37 | static void set_inherited_rel_pathlist(Query *root, RelOptInfo *rel,
|
38 | 38 | Index rti, RangeTblEntry *rte,
|
39 | 39 | List *inheritlist);
|
| 40 | +static void set_subquery_pathlist(Query *root, RelOptInfo *rel, |
| 41 | + Index rti, RangeTblEntry *rte); |
40 | 42 | static RelOptInfo *make_one_rel_by_joins(Query *root, int levels_needed,
|
41 | 43 | List *initial_rels);
|
42 | 44 |
|
@@ -101,94 +103,7 @@ set_base_rel_pathlists(Query *root)
|
101 | 103 | if (rel->issubquery)
|
102 | 104 | {
|
103 | 105 | /* Subquery --- generate a separate plan for it */
|
104 |
| - |
105 |
| - /* |
106 |
| - * If there are any restriction clauses that have been |
107 |
| - * attached to the subquery relation, consider pushing them |
108 |
| - * down to become HAVING quals of the subquery itself. (Not |
109 |
| - * WHERE clauses, since they may refer to subquery outputs |
110 |
| - * that are aggregate results. But planner.c will transfer |
111 |
| - * them into the subquery's WHERE if they do not.) This |
112 |
| - * transformation is useful because it may allow us to |
113 |
| - * generate a better plan for the subquery than evaluating all |
114 |
| - * the subquery output rows and then filtering them. |
115 |
| - * |
116 |
| - * Currently, we do not push down clauses that contain |
117 |
| - * subselects, mainly because I'm not sure it will work |
118 |
| - * correctly (the subplan hasn't yet transformed sublinks to |
119 |
| - * subselects). Also, if the subquery contains set ops |
120 |
| - * (UNION/INTERSECT/EXCEPT) we do not push down any qual |
121 |
| - * clauses, since the planner doesn't support quals at the top |
122 |
| - * level of a setop. (With suitable analysis we could try to |
123 |
| - * push the quals down into the component queries of the |
124 |
| - * setop, but getting it right is not trivial.) |
125 |
| - * Non-pushed-down clauses will get evaluated as qpquals of |
126 |
| - * the SubqueryScan node. |
127 |
| - * |
128 |
| - * XXX Are there any cases where we want to make a policy |
129 |
| - * decision not to push down, because it'd result in a worse |
130 |
| - * plan? |
131 |
| - */ |
132 |
| - if (rte->subquery->setOperations == NULL) |
133 |
| - { |
134 |
| - /* OK to consider pushing down individual quals */ |
135 |
| - List *upperrestrictlist = NIL; |
136 |
| - List *lst; |
137 |
| - |
138 |
| - foreach(lst, rel->baserestrictinfo) |
139 |
| - { |
140 |
| - RestrictInfo *rinfo = (RestrictInfo *) lfirst(lst); |
141 |
| - Node *clause = (Node *) rinfo->clause; |
142 |
| - |
143 |
| - if (contain_subplans(clause)) |
144 |
| - { |
145 |
| - /* Keep it in the upper query */ |
146 |
| - upperrestrictlist = lappend(upperrestrictlist, rinfo); |
147 |
| - } |
148 |
| - else |
149 |
| - { |
150 |
| - |
151 |
| - /* |
152 |
| - * We need to replace Vars in the clause (which |
153 |
| - * must refer to outputs of the subquery) with |
154 |
| - * copies of the subquery's targetlist |
155 |
| - * expressions. Note that at this point, any |
156 |
| - * uplevel Vars in the clause should have been |
157 |
| - * replaced with Params, so they need no work. |
158 |
| - */ |
159 |
| - clause = ResolveNew(clause, rti, 0, |
160 |
| - rte->subquery->targetList, |
161 |
| - CMD_SELECT, 0); |
162 |
| - rte->subquery->havingQual = |
163 |
| - make_and_qual(rte->subquery->havingQual, |
164 |
| - clause); |
165 |
| - |
166 |
| - /* |
167 |
| - * We need not change the subquery's hasAggs or |
168 |
| - * hasSublinks flags, since we can't be pushing |
169 |
| - * down any aggregates that weren't there before, |
170 |
| - * and we don't push down subselects at all. |
171 |
| - */ |
172 |
| - } |
173 |
| - } |
174 |
| - rel->baserestrictinfo = upperrestrictlist; |
175 |
| - } |
176 |
| - |
177 |
| - /* Generate the plan for the subquery */ |
178 |
| - rel->subplan = subquery_planner(rte->subquery, |
179 |
| - -1.0 /* default case */ ); |
180 |
| - |
181 |
| - /* Copy number of output rows from subplan */ |
182 |
| - rel->tuples = rel->subplan->plan_rows; |
183 |
| - |
184 |
| - /* Mark rel with estimated output rows, width, etc */ |
185 |
| - set_baserel_size_estimates(root, rel); |
186 |
| - |
187 |
| - /* Generate appropriate path */ |
188 |
| - add_path(rel, create_subqueryscan_path(rel)); |
189 |
| - |
190 |
| - /* Select cheapest path (pretty easy in this case...) */ |
191 |
| - set_cheapest(rel); |
| 106 | + set_subquery_pathlist(root, rel, rti, rte); |
192 | 107 | }
|
193 | 108 | else if ((inheritlist = expand_inherted_rtentry(root, rti, true))
|
194 | 109 | != NIL)
|
@@ -353,6 +268,106 @@ set_inherited_rel_pathlist(Query *root, RelOptInfo *rel,
|
353 | 268 | set_cheapest(rel);
|
354 | 269 | }
|
355 | 270 |
|
| 271 | +/* |
| 272 | + * set_subquery_pathlist |
| 273 | + * Build the (single) access path for a subquery RTE |
| 274 | + */ |
| 275 | +static void |
| 276 | +set_subquery_pathlist(Query *root, RelOptInfo *rel, |
| 277 | + Index rti, RangeTblEntry *rte) |
| 278 | +{ |
| 279 | + Query *subquery = rte->subquery; |
| 280 | + |
| 281 | + /* |
| 282 | + * If there are any restriction clauses that have been attached to the |
| 283 | + * subquery relation, consider pushing them down to become HAVING quals |
| 284 | + * of the subquery itself. (Not WHERE clauses, since they may refer to |
| 285 | + * subquery outputs that are aggregate results. But planner.c will |
| 286 | + * transfer them into the subquery's WHERE if they do not.) This |
| 287 | + * transformation is useful because it may allow us to generate a better |
| 288 | + * plan for the subquery than evaluating all the subquery output rows |
| 289 | + * and then filtering them. |
| 290 | + * |
| 291 | + * There are several cases where we cannot push down clauses: |
| 292 | + * |
| 293 | + * 1. If the subquery contains set ops (UNION/INTERSECT/EXCEPT) we do not |
| 294 | + * push down any qual clauses, since the planner doesn't support quals at |
| 295 | + * the top level of a setop. (With suitable analysis we could try to push |
| 296 | + * the quals down into the component queries of the setop, but getting it |
| 297 | + * right seems nontrivial. Work on this later.) |
| 298 | + * |
| 299 | + * 2. If the subquery has a LIMIT clause we must not push down any quals, |
| 300 | + * since that could change the set of rows returned. |
| 301 | + * |
| 302 | + * 3. We do not push down clauses that contain subselects, mainly because |
| 303 | + * I'm not sure it will work correctly (the subplan hasn't yet transformed |
| 304 | + * sublinks to subselects). |
| 305 | + * |
| 306 | + * Non-pushed-down clauses will get evaluated as qpquals of the |
| 307 | + * SubqueryScan node. |
| 308 | + * |
| 309 | + * XXX Are there any cases where we want to make a policy decision not to |
| 310 | + * push down, because it'd result in a worse plan? |
| 311 | + */ |
| 312 | + if (subquery->setOperations == NULL && |
| 313 | + subquery->limitOffset == NULL && |
| 314 | + subquery->limitCount == NULL) |
| 315 | + { |
| 316 | + /* OK to consider pushing down individual quals */ |
| 317 | + List *upperrestrictlist = NIL; |
| 318 | + List *lst; |
| 319 | + |
| 320 | + foreach(lst, rel->baserestrictinfo) |
| 321 | + { |
| 322 | + RestrictInfo *rinfo = (RestrictInfo *) lfirst(lst); |
| 323 | + Node *clause = (Node *) rinfo->clause; |
| 324 | + |
| 325 | + if (contain_subplans(clause)) |
| 326 | + { |
| 327 | + /* Keep it in the upper query */ |
| 328 | + upperrestrictlist = lappend(upperrestrictlist, rinfo); |
| 329 | + } |
| 330 | + else |
| 331 | + { |
| 332 | + /* |
| 333 | + * We need to replace Vars in the clause (which must refer to |
| 334 | + * outputs of the subquery) with copies of the subquery's |
| 335 | + * targetlist expressions. Note that at this point, any |
| 336 | + * uplevel Vars in the clause should have been replaced with |
| 337 | + * Params, so they need no work. |
| 338 | + */ |
| 339 | + clause = ResolveNew(clause, rti, 0, |
| 340 | + subquery->targetList, |
| 341 | + CMD_SELECT, 0); |
| 342 | + subquery->havingQual = make_and_qual(subquery->havingQual, |
| 343 | + clause); |
| 344 | + /* |
| 345 | + * We need not change the subquery's hasAggs or |
| 346 | + * hasSublinks flags, since we can't be pushing |
| 347 | + * down any aggregates that weren't there before, |
| 348 | + * and we don't push down subselects at all. |
| 349 | + */ |
| 350 | + } |
| 351 | + } |
| 352 | + rel->baserestrictinfo = upperrestrictlist; |
| 353 | + } |
| 354 | + |
| 355 | + /* Generate the plan for the subquery */ |
| 356 | + rel->subplan = subquery_planner(subquery, |
| 357 | + -1.0 /* default case */ ); |
| 358 | + |
| 359 | + /* Copy number of output rows from subplan */ |
| 360 | + rel->tuples = rel->subplan->plan_rows; |
| 361 | + |
| 362 | + /* Mark rel with estimated output rows, width, etc */ |
| 363 | + set_baserel_size_estimates(root, rel); |
| 364 | + |
| 365 | + /* Generate appropriate path */ |
| 366 | + add_path(rel, create_subqueryscan_path(rel)); |
| 367 | + |
| 368 | + /* Select cheapest path (pretty easy in this case...) */ |
| 369 | + set_cheapest(rel); |
| 370 | +} |
356 | 371 |
|
357 | 372 | /*
|
358 | 373 | * make_fromexpr_rel
|
|
0 commit comments