aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/plan/subselect.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/plan/subselect.c')
-rw-r--r--src/backend/optimizer/plan/subselect.c173
1 files changed, 93 insertions, 80 deletions
diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c
index 780bed6c2bf..154804d3d0f 100644
--- a/src/backend/optimizer/plan/subselect.c
+++ b/src/backend/optimizer/plan/subselect.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.79 2003/07/25 00:01:08 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.80 2003/08/04 00:43:20 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -71,26 +71,26 @@ typedef struct PlannerParamItem
{
Node *item; /* the Var, Aggref, or Param */
Index abslevel; /* its absolute query level */
-} PlannerParamItem;
+} PlannerParamItem;
typedef struct finalize_primnode_context
{
- Bitmapset *paramids; /* Set of PARAM_EXEC paramids found */
- Bitmapset *outer_params; /* Set of accessible outer paramids */
-} finalize_primnode_context;
+ Bitmapset *paramids; /* Set of PARAM_EXEC paramids found */
+ Bitmapset *outer_params; /* Set of accessible outer paramids */
+} finalize_primnode_context;
static List *convert_sublink_opers(List *lefthand, List *operOids,
- List *targetlist, int rtindex,
- List **righthandIds);
+ List *targetlist, int rtindex,
+ List **righthandIds);
static bool subplan_is_hashable(SubLink *slink, SubPlan *node);
static Node *replace_correlation_vars_mutator(Node *node, void *context);
static Node *process_sublinks_mutator(Node *node, bool *isTopQual);
static Bitmapset *finalize_plan(Plan *plan, List *rtable,
- Bitmapset *outer_params,
- Bitmapset *valid_params);
-static bool finalize_primnode(Node *node, finalize_primnode_context *context);
+ Bitmapset * outer_params,
+ Bitmapset * valid_params);
+static bool finalize_primnode(Node *node, finalize_primnode_context * context);
/*
@@ -125,7 +125,7 @@ replace_outer_var(Var *var)
pitem = (PlannerParamItem *) lfirst(ppl);
if (pitem->abslevel == abslevel && IsA(pitem->item, Var))
{
- Var *pvar = (Var *) pitem->item;
+ Var *pvar = (Var *) pitem->item;
if (pvar->varno == var->varno &&
pvar->varattno == var->varattno &&
@@ -177,7 +177,7 @@ replace_outer_agg(Aggref *agg)
* Just make a new slot every time.
*/
agg = (Aggref *) copyObject(agg);
- IncrementVarSublevelsUp((Node *) agg, - ((int) agg->agglevelsup), 0);
+ IncrementVarSublevelsUp((Node *) agg, -((int) agg->agglevelsup), 0);
Assert(agg->agglevelsup == 0);
pitem = (PlannerParamItem *) palloc(sizeof(PlannerParamItem));
@@ -238,7 +238,7 @@ generate_new_param(Oid paramtype, int32 paramtypmod)
static Node *
make_subplan(SubLink *slink, List *lefthand, bool isTopQual)
{
- SubPlan *node = makeNode(SubPlan);
+ SubPlan *node = makeNode(SubPlan);
Query *subquery = (Query *) (slink->subselect);
double tuple_fraction;
Plan *plan;
@@ -268,8 +268,8 @@ make_subplan(SubLink *slink, List *lefthand, bool isTopQual)
* in path/costsize.c.
*
* XXX If an ALL/ANY subplan is uncorrelated, we may decide to hash or
- * materialize its result below. In that case it would've been better to
- * specify full retrieval. At present, however, we can only detect
+ * materialize its result below. In that case it would've been better
+ * to specify full retrieval. At present, however, we can only detect
* correlation or lack of it after we've made the subplan :-(. Perhaps
* detection of correlation should be done as a separate step.
* Meanwhile, we don't want to be too optimistic about the percentage
@@ -323,12 +323,13 @@ make_subplan(SubLink *slink, List *lefthand, bool isTopQual)
bms_free(tmpset);
/*
- * Un-correlated or undirect correlated plans of EXISTS, EXPR, ARRAY, or
- * MULTIEXPR types can be used as initPlans. For EXISTS, EXPR, or ARRAY,
- * we just produce a Param referring to the result of evaluating the
- * initPlan. For MULTIEXPR, we must build an AND or OR-clause of the
- * individual comparison operators, using the appropriate lefthand
- * side expressions and Params for the initPlan's target items.
+ * Un-correlated or undirect correlated plans of EXISTS, EXPR, ARRAY,
+ * or MULTIEXPR types can be used as initPlans. For EXISTS, EXPR, or
+ * ARRAY, we just produce a Param referring to the result of
+ * evaluating the initPlan. For MULTIEXPR, we must build an AND or
+ * OR-clause of the individual comparison operators, using the
+ * appropriate lefthand side expressions and Params for the initPlan's
+ * target items.
*/
if (node->parParam == NIL && slink->subLinkType == EXISTS_SUBLINK)
{
@@ -368,7 +369,7 @@ make_subplan(SubLink *slink, List *lefthand, bool isTopQual)
}
else if (node->parParam == NIL && slink->subLinkType == MULTIEXPR_SUBLINK)
{
- List *exprs;
+ List *exprs;
/* Convert the lefthand exprs and oper OIDs into executable exprs */
exprs = convert_sublink_opers(lefthand,
@@ -378,6 +379,7 @@ make_subplan(SubLink *slink, List *lefthand, bool isTopQual)
&node->paramIds);
node->setParam = listCopy(node->paramIds);
PlannerInitPlan = lappend(PlannerInitPlan, node);
+
/*
* The executable expressions are returned to become part of the
* outer plan's expression tree; they are not kept in the initplan
@@ -402,15 +404,16 @@ make_subplan(SubLink *slink, List *lefthand, bool isTopQual)
*/
if (subplan_is_hashable(slink, node))
node->useHashTable = true;
+
/*
- * Otherwise, we have the option to tack a MATERIAL node onto the top
- * of the subplan, to reduce the cost of reading it repeatedly. This
- * is pointless for a direct-correlated subplan, since we'd have to
- * recompute its results each time anyway. For uncorrelated/undirect
- * correlated subplans, we add MATERIAL if the subplan's top plan node
- * is anything more complicated than a plain sequential scan, and we
- * do it even for seqscan if the qual appears selective enough to
- * eliminate many tuples.
+ * Otherwise, we have the option to tack a MATERIAL node onto the
+ * top of the subplan, to reduce the cost of reading it
+ * repeatedly. This is pointless for a direct-correlated subplan,
+ * since we'd have to recompute its results each time anyway. For
+ * uncorrelated/undirect correlated subplans, we add MATERIAL if
+ * the subplan's top plan node is anything more complicated than a
+ * plain sequential scan, and we do it even for seqscan if the
+ * qual appears selective enough to eliminate many tuples.
*/
else if (node->parParam == NIL)
{
@@ -448,9 +451,7 @@ make_subplan(SubLink *slink, List *lefthand, bool isTopQual)
break;
}
if (use_material)
- {
node->plan = plan = materialize_finished_plan(plan);
- }
}
/* Convert the lefthand exprs and oper OIDs into executable exprs */
@@ -470,7 +471,7 @@ make_subplan(SubLink *slink, List *lefthand, bool isTopQual)
/*
* The Var or Aggref has already been adjusted to have the
- * correct varlevelsup or agglevelsup. We probably don't even
+ * correct varlevelsup or agglevelsup. We probably don't even
* need to copy it again, but be safe.
*/
args = lappend(args, copyObject(pitem->item));
@@ -485,14 +486,14 @@ make_subplan(SubLink *slink, List *lefthand, bool isTopQual)
/*
* convert_sublink_opers: given a lefthand-expressions list and a list of
- * operator OIDs, build a list of actually executable expressions. The
+ * operator OIDs, build a list of actually executable expressions. The
* righthand sides of the expressions are Params or Vars representing the
* results of the sub-select.
*
* If rtindex is 0, we build Params to represent the sub-select outputs.
* The paramids of the Params created are returned in the *righthandIds list.
*
- * If rtindex is not 0, we build Vars using that rtindex as varno. The
+ * If rtindex is not 0, we build Vars using that rtindex as varno. The
* Vars themselves are returned in *righthandIds (this is a bit of a type
* cheat, but we can get away with it).
*/
@@ -549,10 +550,10 @@ convert_sublink_opers(List *lefthand, List *operOids,
/*
* Make the expression node.
*
- * Note: we use make_op_expr in case runtime type conversion
- * function calls must be inserted for this operator! (But we
- * are not expecting to have to resolve unknown Params, so
- * it's okay to pass a null pstate.)
+ * Note: we use make_op_expr in case runtime type conversion function
+ * calls must be inserted for this operator! (But we are not
+ * expecting to have to resolve unknown Params, so it's okay to
+ * pass a null pstate.)
*/
result = lappend(result,
make_op_expr(NULL,
@@ -584,9 +585,9 @@ subplan_is_hashable(SubLink *slink, SubPlan *node)
List *opids;
/*
- * The sublink type must be "= ANY" --- that is, an IN operator.
- * (We require the operator name to be unqualified, which may be
- * overly paranoid, or may not be.) XXX since we also check that the
+ * The sublink type must be "= ANY" --- that is, an IN operator. (We
+ * require the operator name to be unqualified, which may be overly
+ * paranoid, or may not be.) XXX since we also check that the
* operators are hashable, the test on operator name may be redundant?
*/
if (slink->subLinkType != ANY_SUBLINK)
@@ -594,33 +595,37 @@ subplan_is_hashable(SubLink *slink, SubPlan *node)
if (length(slink->operName) != 1 ||
strcmp(strVal(lfirst(slink->operName)), "=") != 0)
return false;
+
/*
* The subplan must not have any direct correlation vars --- else we'd
- * have to recompute its output each time, so that the hashtable wouldn't
- * gain anything.
+ * have to recompute its output each time, so that the hashtable
+ * wouldn't gain anything.
*/
if (node->parParam != NIL)
return false;
+
/*
- * The estimated size of the subquery result must fit in SortMem.
- * (XXX what about hashtable overhead?)
+ * The estimated size of the subquery result must fit in SortMem. (XXX
+ * what about hashtable overhead?)
*/
subquery_size = node->plan->plan_rows *
(MAXALIGN(node->plan->plan_width) + MAXALIGN(sizeof(HeapTupleData)));
if (subquery_size > SortMem * 1024L)
return false;
+
/*
- * The combining operators must be hashable, strict, and self-commutative.
- * The need for hashability is obvious, since we want to use hashing.
- * Without strictness, behavior in the presence of nulls is too
- * unpredictable. (We actually must assume even more than plain
- * strictness, see nodeSubplan.c for details.) And commutativity ensures
- * that the left and right datatypes are the same; this allows us to
- * assume that the combining operators are equality for the righthand
- * datatype, so that they can be used to compare righthand tuples as
- * well as comparing lefthand to righthand tuples. (This last restriction
- * could be relaxed by using two different sets of operators with the
- * hash table, but there is no obvious usefulness to that at present.)
+ * The combining operators must be hashable, strict, and
+ * self-commutative. The need for hashability is obvious, since we
+ * want to use hashing. Without strictness, behavior in the presence
+ * of nulls is too unpredictable. (We actually must assume even more
+ * than plain strictness, see nodeSubplan.c for details.) And
+ * commutativity ensures that the left and right datatypes are the
+ * same; this allows us to assume that the combining operators are
+ * equality for the righthand datatype, so that they can be used to
+ * compare righthand tuples as well as comparing lefthand to righthand
+ * tuples. (This last restriction could be relaxed by using two
+ * different sets of operators with the hash table, but there is no
+ * obvious usefulness to that at present.)
*/
foreach(opids, slink->operOids)
{
@@ -665,25 +670,27 @@ convert_IN_to_join(Query *parse, SubLink *sublink)
int rtindex;
RangeTblEntry *rte;
RangeTblRef *rtr;
- InClauseInfo *ininfo;
+ InClauseInfo *ininfo;
List *exprs;
/*
- * The sublink type must be "= ANY" --- that is, an IN operator.
- * (We require the operator name to be unqualified, which may be
- * overly paranoid, or may not be.)
+ * The sublink type must be "= ANY" --- that is, an IN operator. (We
+ * require the operator name to be unqualified, which may be overly
+ * paranoid, or may not be.)
*/
if (sublink->subLinkType != ANY_SUBLINK)
return NULL;
if (length(sublink->operName) != 1 ||
strcmp(strVal(lfirst(sublink->operName)), "=") != 0)
return NULL;
+
/*
* The sub-select must not refer to any Vars of the parent query.
* (Vars of higher levels should be okay, though.)
*/
if (contain_vars_of_level((Node *) subselect, 1))
return NULL;
+
/*
* The left-hand expressions must contain some Vars of the current
* query, else it's not gonna be a join.
@@ -691,6 +698,7 @@ convert_IN_to_join(Query *parse, SubLink *sublink)
left_varnos = pull_varnos((Node *) sublink->lefthand);
if (bms_is_empty(left_varnos))
return NULL;
+
/*
* The left-hand expressions mustn't be volatile. (Perhaps we should
* test the combining operators, too? We'd only need to point the
@@ -698,13 +706,14 @@ convert_IN_to_join(Query *parse, SubLink *sublink)
*/
if (contain_volatile_functions((Node *) sublink->lefthand))
return NULL;
+
/*
* Okay, pull up the sub-select into top range table and jointree.
*
* We rely here on the assumption that the outer query has no references
* to the inner (necessarily true, other than the Vars that we build
- * below). Therefore this is a lot easier than what pull_up_subqueries
- * has to go through.
+ * below). Therefore this is a lot easier than what
+ * pull_up_subqueries has to go through.
*/
rte = addRangeTableEntryForSubquery(NULL,
subselect,
@@ -715,6 +724,7 @@ convert_IN_to_join(Query *parse, SubLink *sublink)
rtr = makeNode(RangeTblRef);
rtr->rtindex = rtindex;
parse->jointree->fromlist = lappend(parse->jointree->fromlist, rtr);
+
/*
* Now build the InClauseInfo node.
*/
@@ -722,6 +732,7 @@ convert_IN_to_join(Query *parse, SubLink *sublink)
ininfo->lefthand = left_varnos;
ininfo->righthand = bms_make_singleton(rtindex);
parse->in_info_list = lcons(ininfo, parse->in_info_list);
+
/*
* Build the result qual expressions. As a side effect,
* ininfo->sub_targetlist is filled with a list of the Vars
@@ -744,9 +755,9 @@ convert_IN_to_join(Query *parse, SubLink *sublink)
* Since we do not recurse into the arguments of uplevel aggregates, they will
* get copied to the appropriate subplan args list in the parent query with
* uplevel vars not replaced by Params, but only adjusted in level (see
- * replace_outer_agg). That's exactly what we want for the vars of the parent
+ * replace_outer_agg). That's exactly what we want for the vars of the parent
* level --- but if an aggregate's argument contains any further-up variables,
- * they have to be replaced with Params in their turn. That will happen when
+ * they have to be replaced with Params in their turn. That will happen when
* the parent level runs SS_replace_correlation_vars. Therefore it must do
* so after expanding its sublinks to subplans. And we don't want any steps
* in between, else those steps would never get applied to the aggregate
@@ -796,7 +807,7 @@ SS_process_sublinks(Node *expr, bool isQual)
static Node *
process_sublinks_mutator(Node *node, bool *isTopQual)
{
- bool locTopQual;
+ bool locTopQual;
if (node == NULL)
return NULL;
@@ -806,11 +817,13 @@ process_sublinks_mutator(Node *node, bool *isTopQual)
List *lefthand;
/*
- * First, recursively process the lefthand-side expressions, if any.
+ * First, recursively process the lefthand-side expressions, if
+ * any.
*/
locTopQual = false;
lefthand = (List *)
process_sublinks_mutator((Node *) sublink->lefthand, &locTopQual);
+
/*
* Now build the SubPlan node and make the expr to return.
*/
@@ -818,9 +831,9 @@ process_sublinks_mutator(Node *node, bool *isTopQual)
}
/*
- * We should never see a SubPlan expression in the input (since this is
- * the very routine that creates 'em to begin with). We shouldn't find
- * ourselves invoked directly on a Query, either.
+ * We should never see a SubPlan expression in the input (since this
+ * is the very routine that creates 'em to begin with). We shouldn't
+ * find ourselves invoked directly on a Query, either.
*/
Assert(!is_subplan(node));
Assert(!IsA(node, Query));
@@ -854,9 +867,9 @@ SS_finalize_plan(Plan *plan, List *rtable)
List *lst;
/*
- * First, scan the param list to discover the sets of params that
- * are available from outer query levels and my own query level.
- * We do this once to save time in the per-plan recursion steps.
+ * First, scan the param list to discover the sets of params that are
+ * available from outer query levels and my own query level. We do
+ * this once to save time in the per-plan recursion steps.
*/
paramid = 0;
foreach(lst, PlannerParamList)
@@ -896,7 +909,7 @@ SS_finalize_plan(Plan *plan, List *rtable)
*/
static Bitmapset *
finalize_plan(Plan *plan, List *rtable,
- Bitmapset *outer_params, Bitmapset *valid_params)
+ Bitmapset * outer_params, Bitmapset * valid_params)
{
finalize_primnode_context context;
List *lst;
@@ -1038,8 +1051,8 @@ finalize_plan(Plan *plan, List *rtable,
plan->allParam = context.paramids;
/*
- * For speed at execution time, make sure extParam/allParam are actually
- * NULL if they are empty sets.
+ * For speed at execution time, make sure extParam/allParam are
+ * actually NULL if they are empty sets.
*/
if (bms_is_empty(plan->extParam))
{
@@ -1060,7 +1073,7 @@ finalize_plan(Plan *plan, List *rtable,
* expression tree to the result set.
*/
static bool
-finalize_primnode(Node *node, finalize_primnode_context *context)
+finalize_primnode(Node *node, finalize_primnode_context * context)
{
if (node == NULL)
return false;
@@ -1076,12 +1089,12 @@ finalize_primnode(Node *node, finalize_primnode_context *context)
}
if (is_subplan(node))
{
- SubPlan *subplan = (SubPlan *) node;
+ SubPlan *subplan = (SubPlan *) node;
/* Add outer-level params needed by the subplan to paramids */
context->paramids = bms_join(context->paramids,
- bms_intersect(subplan->plan->extParam,
- context->outer_params));
+ bms_intersect(subplan->plan->extParam,
+ context->outer_params));
/* fall through to recurse into subplan args */
}
return expression_tree_walker(node, finalize_primnode,