|
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 | staticvoidset_inherited_rel_pathlist(Query*root,RelOptInfo*rel, |
38 | 38 | Indexrti,RangeTblEntry*rte, |
39 | 39 | List*inheritlist); |
| 40 | +staticvoidset_subquery_pathlist(Query*root,RelOptInfo*rel, |
| 41 | +Indexrti,RangeTblEntry*rte); |
40 | 42 | staticRelOptInfo*make_one_rel_by_joins(Query*root,intlevels_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 | elseif ((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 | +staticvoid |
| 276 | +set_subquery_pathlist(Query*root,RelOptInfo*rel, |
| 277 | +Indexrti,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 |
|