aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/executor/nodeSubplan.c77
-rw-r--r--src/backend/optimizer/plan/subselect.c10
-rw-r--r--src/include/nodes/primnodes.h6
3 files changed, 52 insertions, 41 deletions
diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c
index ac91ed1be64..f12d0143a38 100644
--- a/src/backend/executor/nodeSubplan.c
+++ b/src/backend/executor/nodeSubplan.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/nodeSubplan.c,v 1.89 2007/05/17 19:35:08 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/nodeSubplan.c,v 1.90 2007/08/26 21:44:25 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -259,10 +259,14 @@ ExecScanSubPlan(SubPlanState *node,
* ROWCOMPARE_SUBLINK.
*
* For EXPR_SUBLINK we require the subplan to produce no more than one
- * tuple, else an error is raised. For ARRAY_SUBLINK we allow the subplan
- * to produce more than one tuple. In either case, if zero tuples are
- * produced, we return NULL. Assuming we get a tuple, we just use its
- * first column (there can be only one non-junk column in this case).
+ * tuple, else an error is raised. If zero tuples are produced, we return
+ * NULL. Assuming we get a tuple, we just use its first column (there can
+ * be only one non-junk column in this case).
+ *
+ * For ARRAY_SUBLINK we allow the subplan to produce any number of tuples,
+ * and form an array of the first column's values. Note in particular
+ * that we produce a zero-element array if no tuples are produced (this
+ * is a change from pre-8.3 behavior of returning NULL).
*/
result = BoolGetDatum(subLinkType == ALL_SUBLINK);
*isNull = false;
@@ -317,10 +321,10 @@ ExecScanSubPlan(SubPlanState *node,
found = true;
/* stash away current value */
+ Assert(subplan->firstColType == tdesc->attrs[0]->atttypid);
dvalue = slot_getattr(slot, 1, &disnull);
astate = accumArrayResult(astate, dvalue, disnull,
- tdesc->attrs[0]->atttypid,
- oldcontext);
+ subplan->firstColType, oldcontext);
/* keep scanning subplan to collect all values */
continue;
}
@@ -385,29 +389,30 @@ ExecScanSubPlan(SubPlanState *node,
}
}
- if (!found)
+ MemoryContextSwitchTo(oldcontext);
+
+ if (subLinkType == ARRAY_SUBLINK)
+ {
+ /* We return the result in the caller's context */
+ if (astate != NULL)
+ result = makeArrayResult(astate, oldcontext);
+ else
+ result = PointerGetDatum(construct_empty_array(subplan->firstColType));
+ }
+ else if (!found)
{
/*
* deal with empty subplan result. result/isNull were previously
- * initialized correctly for all sublink types except EXPR, ARRAY, and
+ * initialized correctly for all sublink types except EXPR and
* ROWCOMPARE; for those, return NULL.
*/
if (subLinkType == EXPR_SUBLINK ||
- subLinkType == ARRAY_SUBLINK ||
subLinkType == ROWCOMPARE_SUBLINK)
{
result = (Datum) 0;
*isNull = true;
}
}
- else if (subLinkType == ARRAY_SUBLINK)
- {
- Assert(astate != NULL);
- /* We return the result in the caller's context */
- result = makeArrayResult(astate, oldcontext);
- }
-
- MemoryContextSwitchTo(oldcontext);
return result;
}
@@ -938,10 +943,10 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
found = true;
/* stash away current value */
+ Assert(subplan->firstColType == tdesc->attrs[0]->atttypid);
dvalue = slot_getattr(slot, 1, &disnull);
astate = accumArrayResult(astate, dvalue, disnull,
- tdesc->attrs[0]->atttypid,
- oldcontext);
+ subplan->firstColType, oldcontext);
/* keep scanning subplan to collect all values */
continue;
}
@@ -980,7 +985,25 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
}
}
- if (!found)
+ if (subLinkType == ARRAY_SUBLINK)
+ {
+ /* There can be only one param... */
+ int paramid = linitial_int(subplan->setParam);
+ ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
+
+ prm->execPlan = NULL;
+ /* We build the result in query context so it won't disappear */
+ if (astate != NULL)
+ prm->value = makeArrayResult(astate,
+ econtext->ecxt_per_query_memory);
+ else
+ {
+ MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
+ prm->value = PointerGetDatum(construct_empty_array(subplan->firstColType));
+ }
+ prm->isnull = false;
+ }
+ else if (!found)
{
if (subLinkType == EXISTS_SUBLINK)
{
@@ -1005,18 +1028,6 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
}
}
}
- else if (subLinkType == ARRAY_SUBLINK)
- {
- /* There can be only one param... */
- int paramid = linitial_int(subplan->setParam);
- ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
-
- Assert(astate != NULL);
- prm->execPlan = NULL;
- /* We build the result in query context so it won't disappear */
- prm->value = makeArrayResult(astate, econtext->ecxt_per_query_memory);
- prm->isnull = false;
- }
MemoryContextSwitchTo(oldcontext);
}
diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c
index 6a41138d3b2..8b739e16d44 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.123 2007/07/18 21:40:57 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.124 2007/08/26 21:44:25 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -208,10 +208,10 @@ 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.
+ * This is stored for ARRAY_SUBLINK and for 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)
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index cdcd4d5caa5..01e94bc5f0e 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -10,7 +10,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.132 2007/06/11 22:22:42 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.133 2007/08/26 21:44:25 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -388,7 +388,7 @@ typedef struct BoolExpr
* results. ALL and ANY combine the per-row results using AND and OR
* semantics respectively.
* ARRAY requires just one target column, and creates an array of the target
- * column's type using one or more rows resulting from the subselect.
+ * column's type using any number of rows resulting from the subselect.
*
* SubLink is classed as an Expr node, but it is not actually executable;
* it must be replaced in the expression tree by a SubPlan node during
@@ -468,7 +468,7 @@ typedef struct SubPlan
List *paramIds; /* IDs of Params embedded in the above */
/* Identification of the Plan tree to use: */
int plan_id; /* Index (from 1) in PlannedStmt.subplans */
- /* Extra data saved for the convenience of exprType(): */
+ /* Extra data useful for determining subplan's output type: */
Oid firstColType; /* Type of first column of subplan result */
/* Information about execution strategy: */
bool useHashTable; /* TRUE to store subselect output in a hash