mirror of
https://git.postgresql.org/git/postgresql.git
synced 2025-01-12 18:34:36 +08:00
Make ARRAY(SELECT ...) return an empty array, rather than a NULL, when the
sub-select returns zero rows. Per complaint from Jens Schicke. Since this is more in the nature of a definition change than a bug, not back-patched.
This commit is contained in:
parent
75d5f6fe79
commit
67bf7b919e
@ -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);
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user