77 * Portions Copyright (c) 1994, Regents of the University of California
88 *
99 * IDENTIFICATION
10- * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.28 2000/02/15 20:49:18 tgl Exp $
10+ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.29 2000/03/02 04:08:16 tgl Exp $
1111 *
1212 *-------------------------------------------------------------------------
1313 */
1818#include "nodes/makefuncs.h"
1919#include "nodes/nodeFuncs.h"
2020#include "optimizer/clauses.h"
21+ #include "optimizer/cost.h"
22+ #include "optimizer/planmain.h"
2123#include "optimizer/planner.h"
2224#include "optimizer/subselect.h"
2325#include "parser/parse_expr.h"
@@ -123,6 +125,7 @@ static Node *
123125make_subplan (SubLink * slink )
124126{
125127SubPlan * node = makeNode (SubPlan );
128+ Query * subquery = (Query * ) (slink -> subselect );
126129double tuple_fraction ;
127130Plan * plan ;
128131List * lst ;
@@ -151,8 +154,7 @@ make_subplan(SubLink *slink)
151154else
152155tuple_fraction = 0.5 ;/* 50% */
153156
154- node -> plan = plan = union_planner ((Query * )slink -> subselect ,
155- tuple_fraction );
157+ node -> plan = plan = union_planner (subquery ,tuple_fraction );
156158
157159/*
158160 * Assign subPlan, extParam and locParam to plan nodes. At the moment,
@@ -179,7 +181,7 @@ make_subplan(SubLink *slink)
179181PlannerQueryLevel -- ;
180182
181183node -> plan_id = PlannerPlanId ++ ;
182- node -> rtable = (( Query * ) slink -> subselect ) -> rtable ;
184+ node -> rtable = subquery -> rtable ;
183185node -> sublink = slink ;
184186slink -> subselect = NULL ;/* cool ?! */
185187
@@ -287,12 +289,76 @@ make_subplan(SubLink *slink)
287289}
288290else
289291{
290- /* make expression of SUBPLAN type */
291292Expr * expr = makeNode (Expr );
292293List * args = NIL ;
293294List * newoper = NIL ;
294295int i = 0 ;
295296
297+ /*
298+ * We can't convert subplans of ALL_SUBLINK or ANY_SUBLINK types to
299+ * initPlans, even when they are uncorrelated or undirect correlated,
300+ * because we need to scan the output of the subplan for each outer
301+ * tuple. However, we have the option to tack a MATERIAL node onto
302+ * the top of an uncorrelated/undirect correlated subplan, which lets
303+ * us do the work of evaluating the subplan only once. We do this
304+ * if the subplan's top plan node is anything more complicated than
305+ * a sequential or index scan, and we do it even for those plan types
306+ * if the qual appears selective enough to eliminate many tuples.
307+ */
308+ if (node -> parParam == NIL )
309+ {
310+ bool use_material ;
311+
312+ switch (nodeTag (plan ))
313+ {
314+ case T_SeqScan :
315+ {
316+ Selectivity qualsel ;
317+
318+ qualsel = clauselist_selectivity (subquery ,plan -> qual ,0 );
319+ /* Is 10% selectivity a good threshold?? */
320+ use_material = qualsel < 0.10 ;
321+ break ;
322+ }
323+ case T_IndexScan :
324+ {
325+ List * indxqual = ((IndexScan * )plan )-> indxqualorig ;
326+ Selectivity qualsel ;
327+
328+ qualsel = clauselist_selectivity (subquery ,plan -> qual ,0 );
329+ qualsel *=clauselist_selectivity (subquery ,indxqual ,0 );
330+ /* Note: if index is lossy, we just double-counted the
331+ * index selectivity. Worth fixing?
332+ */
333+ /* Is 10% selectivity a good threshold?? */
334+ use_material = qualsel < 0.10 ;
335+ break ;
336+ }
337+ case T_Material :
338+ case T_Sort :
339+ /* Don't add another Material node if there's one already,
340+ * nor if the top node is a Sort, since Sort materializes
341+ * its output anyway. (I doubt either case can happen in
342+ * practice for a subplan, but...)
343+ */
344+ use_material = false;
345+ break ;
346+ default :
347+ use_material = true;
348+ break ;
349+ }
350+ if (use_material )
351+ {
352+ plan = (Plan * )make_noname (plan -> targetlist ,
353+ NIL ,
354+ plan );
355+ node -> plan = plan ;
356+ }
357+ }
358+
359+ /*
360+ * Make expression of SUBPLAN type
361+ */
296362expr -> typeOid = BOOLOID ;/* bogus, but we don't really care */
297363expr -> opType = SUBPLAN_EXPR ;
298364expr -> oper = (Node * )node ;