summaryrefslogtreecommitdiff
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.c118
1 files changed, 76 insertions, 42 deletions
diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c
index b62aeb853d..d19e9d298c 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
- * $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.120 2007/02/19 07:03:30 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.121 2007/02/22 22:00:24 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -46,6 +46,7 @@ typedef struct process_sublinks_context
typedef struct finalize_primnode_context
{
+ PlannerInfo *root;
Bitmapset *paramids; /* Set of PARAM_EXEC paramids found */
Bitmapset *outer_params; /* Set of accessible outer paramids */
} finalize_primnode_context;
@@ -57,12 +58,13 @@ static Node *convert_testexpr(PlannerInfo *root,
List **righthandIds);
static Node *convert_testexpr_mutator(Node *node,
convert_testexpr_context *context);
-static bool subplan_is_hashable(SubLink *slink, SubPlan *node);
+static bool subplan_is_hashable(SubLink *slink, SubPlan *node, Plan *plan);
static bool hash_ok_operator(OpExpr *expr);
static Node *replace_correlation_vars_mutator(Node *node, PlannerInfo *root);
static Node *process_sublinks_mutator(Node *node,
process_sublinks_context *context);
-static Bitmapset *finalize_plan(Plan *plan, List *rtable,
+static Bitmapset *finalize_plan(PlannerInfo *root,
+ Plan *plan,
Bitmapset *outer_params,
Bitmapset *valid_params);
static bool finalize_primnode(Node *node, finalize_primnode_context *context);
@@ -204,6 +206,24 @@ generate_new_param(PlannerInfo *root, Oid paramtype, int32 paramtypmod)
}
/*
+ * Get the datatype of the first column of the plan's output.
+ *
+ * This is a hack to support exprType(), which doesn't have any way to get
+ * at the plan associated with a SubPlan node. We really only need the value
+ * for EXPR_SUBLINK and ARRAY_SUBLINK subplans, but for consistency we set
+ * it always.
+ */
+static Oid
+get_first_col_type(Plan *plan)
+{
+ TargetEntry *tent = (TargetEntry *) linitial(plan->targetlist);
+
+ Assert(IsA(tent, TargetEntry));
+ Assert(!tent->resjunk);
+ return exprType((Node *) tent->expr);
+}
+
+/*
* Convert a SubLink (as created by the parser) into a SubPlan.
*
* We are given the original SubLink and the already-processed testexpr
@@ -219,10 +239,11 @@ generate_new_param(PlannerInfo *root, Oid paramtype, int32 paramtypmod)
static Node *
make_subplan(PlannerInfo *root, SubLink *slink, Node *testexpr, bool isTopQual)
{
- SubPlan *node = makeNode(SubPlan);
Query *subquery = (Query *) (slink->subselect);
double tuple_fraction;
+ SubPlan *node;
Plan *plan;
+ PlannerInfo *subroot;
Bitmapset *tmpset;
int paramid;
Node *result;
@@ -266,22 +287,19 @@ make_subplan(PlannerInfo *root, SubLink *slink, Node *testexpr, bool isTopQual)
/*
* Generate the plan for the subquery.
*/
- node->plan = plan = subquery_planner(root->glob, subquery,
- root->query_level + 1,
- tuple_fraction,
- NULL);
-
- /* Assign quasi-unique ID to this SubPlan */
- node->plan_id = root->glob->next_plan_id++;
-
- node->rtable = subquery->rtable;
+ plan = subquery_planner(root->glob, subquery,
+ root->query_level + 1,
+ tuple_fraction,
+ &subroot);
/*
- * Initialize other fields of the SubPlan node.
+ * Initialize the SubPlan node. Note plan_id isn't set yet.
*/
+ node = makeNode(SubPlan);
node->subLinkType = slink->subLinkType;
node->testexpr = NULL;
node->paramIds = NIL;
+ node->firstColType = get_first_col_type(plan);
node->useHashTable = false;
/* At top level of a qual, can treat UNKNOWN the same as FALSE */
node->unknownEqFalse = isTopQual;
@@ -384,7 +402,7 @@ make_subplan(PlannerInfo *root, SubLink *slink, Node *testexpr, bool isTopQual)
* tuple. But if it's an IN (= ANY) test, we might be able to use a
* hashtable to avoid comparing all the tuples.
*/
- if (subplan_is_hashable(slink, node))
+ if (subplan_is_hashable(slink, node, plan))
node->useHashTable = true;
/*
@@ -411,7 +429,7 @@ make_subplan(PlannerInfo *root, SubLink *slink, Node *testexpr, bool isTopQual)
break;
}
if (use_material)
- node->plan = plan = materialize_finished_plan(plan);
+ plan = materialize_finished_plan(plan);
}
/*
@@ -435,6 +453,15 @@ make_subplan(PlannerInfo *root, SubLink *slink, Node *testexpr, bool isTopQual)
result = (Node *) node;
}
+ /*
+ * Add the subplan and its rtable to the global lists.
+ */
+ root->glob->subplans = lappend(root->glob->subplans,
+ plan);
+ root->glob->subrtables = lappend(root->glob->subrtables,
+ subroot->parse->rtable);
+ node->plan_id = list_length(root->glob->subplans);
+
return result;
}
@@ -539,7 +566,7 @@ convert_testexpr_mutator(Node *node,
* on its plan and parParam fields, however.
*/
static bool
-subplan_is_hashable(SubLink *slink, SubPlan *node)
+subplan_is_hashable(SubLink *slink, SubPlan *node, Plan *plan)
{
double subquery_size;
ListCell *l;
@@ -574,8 +601,8 @@ subplan_is_hashable(SubLink *slink, SubPlan *node)
* actually be stored as MinimalTuples; this provides some fudge factor
* for hashtable overhead.)
*/
- subquery_size = node->plan->plan_rows *
- (MAXALIGN(node->plan->plan_width) + MAXALIGN(sizeof(HeapTupleHeaderData)));
+ subquery_size = plan->plan_rows *
+ (MAXALIGN(plan->plan_width) + MAXALIGN(sizeof(HeapTupleHeaderData)));
if (subquery_size > work_mem * 1024L)
return false;
@@ -964,7 +991,7 @@ SS_finalize_plan(PlannerInfo *root, Plan *plan)
/*
* Now recurse through plan tree.
*/
- (void) finalize_plan(plan, root->parse->rtable, outer_params, valid_params);
+ (void) finalize_plan(root, plan, outer_params, valid_params);
bms_free(outer_params);
bms_free(valid_params);
@@ -988,16 +1015,16 @@ SS_finalize_plan(PlannerInfo *root, Plan *plan)
initplan_cost = 0;
foreach(l, plan->initPlan)
{
- SubPlan *initplan = (SubPlan *) lfirst(l);
+ SubPlan *initsubplan = (SubPlan *) lfirst(l);
+ Plan *initplan = planner_subplan_get_plan(root, initsubplan);
ListCell *l2;
- initExtParam = bms_add_members(initExtParam,
- initplan->plan->extParam);
- foreach(l2, initplan->setParam)
+ initExtParam = bms_add_members(initExtParam, initplan->extParam);
+ foreach(l2, initsubplan->setParam)
{
initSetParam = bms_add_member(initSetParam, lfirst_int(l2));
}
- initplan_cost += initplan->plan->total_cost;
+ initplan_cost += initplan->total_cost;
}
/* allParam must include all these params */
plan->allParam = bms_add_members(plan->allParam, initExtParam);
@@ -1019,7 +1046,7 @@ SS_finalize_plan(PlannerInfo *root, Plan *plan)
* This is just an internal notational convenience.
*/
static Bitmapset *
-finalize_plan(Plan *plan, List *rtable,
+finalize_plan(PlannerInfo *root, Plan *plan,
Bitmapset *outer_params, Bitmapset *valid_params)
{
finalize_primnode_context context;
@@ -1027,6 +1054,7 @@ finalize_plan(Plan *plan, List *rtable,
if (plan == NULL)
return NULL;
+ context.root = root;
context.paramids = NULL; /* initialize set to empty */
context.outer_params = outer_params;
@@ -1110,8 +1138,8 @@ finalize_plan(Plan *plan, List *rtable,
{
context.paramids =
bms_add_members(context.paramids,
- finalize_plan((Plan *) lfirst(l),
- rtable,
+ finalize_plan(root,
+ (Plan *) lfirst(l),
outer_params,
valid_params));
}
@@ -1126,8 +1154,8 @@ finalize_plan(Plan *plan, List *rtable,
{
context.paramids =
bms_add_members(context.paramids,
- finalize_plan((Plan *) lfirst(l),
- rtable,
+ finalize_plan(root,
+ (Plan *) lfirst(l),
outer_params,
valid_params));
}
@@ -1142,8 +1170,8 @@ finalize_plan(Plan *plan, List *rtable,
{
context.paramids =
bms_add_members(context.paramids,
- finalize_plan((Plan *) lfirst(l),
- rtable,
+ finalize_plan(root,
+ (Plan *) lfirst(l),
outer_params,
valid_params));
}
@@ -1193,14 +1221,14 @@ finalize_plan(Plan *plan, List *rtable,
/* Process left and right child plans, if any */
context.paramids = bms_add_members(context.paramids,
- finalize_plan(plan->lefttree,
- rtable,
+ finalize_plan(root,
+ plan->lefttree,
outer_params,
valid_params));
context.paramids = bms_add_members(context.paramids,
- finalize_plan(plan->righttree,
- rtable,
+ finalize_plan(root,
+ plan->righttree,
outer_params,
valid_params));
@@ -1252,10 +1280,11 @@ finalize_primnode(Node *node, finalize_primnode_context *context)
if (is_subplan(node))
{
SubPlan *subplan = (SubPlan *) node;
+ Plan *plan = planner_subplan_get_plan(context->root, subplan);
/* Add outer-level params needed by the subplan to paramids */
context->paramids = bms_join(context->paramids,
- bms_intersect(subplan->plan->extParam,
+ bms_intersect(plan->extParam,
context->outer_params));
/* fall through to recurse into subplan args */
}
@@ -1300,15 +1329,20 @@ SS_make_initplan_from_plan(PlannerInfo *root, Plan *plan,
root->init_plans = saved_init_plans;
/*
+ * Add the subplan and its rtable to the global lists.
+ */
+ root->glob->subplans = lappend(root->glob->subplans,
+ plan);
+ root->glob->subrtables = lappend(root->glob->subrtables,
+ root->parse->rtable);
+
+ /*
* Create a SubPlan node and add it to the outer list of InitPlans.
*/
node = makeNode(SubPlan);
node->subLinkType = EXPR_SUBLINK;
- node->plan = plan;
- /* Assign quasi-unique ID to this SubPlan */
- node->plan_id = root->glob->next_plan_id++;
-
- node->rtable = root->parse->rtable;
+ node->firstColType = get_first_col_type(plan);
+ node->plan_id = list_length(root->glob->subplans);
root->init_plans = lappend(root->init_plans, node);