Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 67bf7b9

Browse filesBrowse files
committed
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.
1 parent 75d5f6f commit 67bf7b9
Copy full SHA for 67bf7b9

File tree

Expand file treeCollapse file tree

3 files changed

+52
-41
lines changed
Filter options
Expand file treeCollapse file tree

3 files changed

+52
-41
lines changed

‎src/backend/executor/nodeSubplan.c

Copy file name to clipboardExpand all lines: src/backend/executor/nodeSubplan.c
+44-33Lines changed: 44 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1994, Regents of the University of California
88
*
99
* IDENTIFICATION
10-
* $PostgreSQL: pgsql/src/backend/executor/nodeSubplan.c,v 1.89 2007/05/17 19:35:08 tgl Exp $
10+
* $PostgreSQL: pgsql/src/backend/executor/nodeSubplan.c,v 1.90 2007/08/26 21:44:25 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -259,10 +259,14 @@ ExecScanSubPlan(SubPlanState *node,
259259
* ROWCOMPARE_SUBLINK.
260260
*
261261
* For EXPR_SUBLINK we require the subplan to produce no more than one
262-
* tuple, else an error is raised. For ARRAY_SUBLINK we allow the subplan
263-
* to produce more than one tuple. In either case, if zero tuples are
264-
* produced, we return NULL. Assuming we get a tuple, we just use its
265-
* first column (there can be only one non-junk column in this case).
262+
* tuple, else an error is raised. If zero tuples are produced, we return
263+
* NULL. Assuming we get a tuple, we just use its first column (there can
264+
* be only one non-junk column in this case).
265+
*
266+
* For ARRAY_SUBLINK we allow the subplan to produce any number of tuples,
267+
* and form an array of the first column's values. Note in particular
268+
* that we produce a zero-element array if no tuples are produced (this
269+
* is a change from pre-8.3 behavior of returning NULL).
266270
*/
267271
result = BoolGetDatum(subLinkType == ALL_SUBLINK);
268272
*isNull = false;
@@ -317,10 +321,10 @@ ExecScanSubPlan(SubPlanState *node,
317321

318322
found = true;
319323
/* stash away current value */
324+
Assert(subplan->firstColType == tdesc->attrs[0]->atttypid);
320325
dvalue = slot_getattr(slot, 1, &disnull);
321326
astate = accumArrayResult(astate, dvalue, disnull,
322-
tdesc->attrs[0]->atttypid,
323-
oldcontext);
327+
subplan->firstColType, oldcontext);
324328
/* keep scanning subplan to collect all values */
325329
continue;
326330
}
@@ -385,29 +389,30 @@ ExecScanSubPlan(SubPlanState *node,
385389
}
386390
}
387391

388-
if (!found)
392+
MemoryContextSwitchTo(oldcontext);
393+
394+
if (subLinkType == ARRAY_SUBLINK)
395+
{
396+
/* We return the result in the caller's context */
397+
if (astate != NULL)
398+
result = makeArrayResult(astate, oldcontext);
399+
else
400+
result = PointerGetDatum(construct_empty_array(subplan->firstColType));
401+
}
402+
else if (!found)
389403
{
390404
/*
391405
* deal with empty subplan result. result/isNull were previously
392-
* initialized correctly for all sublink types except EXPR, ARRAY, and
406+
* initialized correctly for all sublink types except EXPR and
393407
* ROWCOMPARE; for those, return NULL.
394408
*/
395409
if (subLinkType == EXPR_SUBLINK ||
396-
subLinkType == ARRAY_SUBLINK ||
397410
subLinkType == ROWCOMPARE_SUBLINK)
398411
{
399412
result = (Datum) 0;
400413
*isNull = true;
401414
}
402415
}
403-
else if (subLinkType == ARRAY_SUBLINK)
404-
{
405-
Assert(astate != NULL);
406-
/* We return the result in the caller's context */
407-
result = makeArrayResult(astate, oldcontext);
408-
}
409-
410-
MemoryContextSwitchTo(oldcontext);
411416

412417
return result;
413418
}
@@ -938,10 +943,10 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
938943

939944
found = true;
940945
/* stash away current value */
946+
Assert(subplan->firstColType == tdesc->attrs[0]->atttypid);
941947
dvalue = slot_getattr(slot, 1, &disnull);
942948
astate = accumArrayResult(astate, dvalue, disnull,
943-
tdesc->attrs[0]->atttypid,
944-
oldcontext);
949+
subplan->firstColType, oldcontext);
945950
/* keep scanning subplan to collect all values */
946951
continue;
947952
}
@@ -980,7 +985,25 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
980985
}
981986
}
982987

983-
if (!found)
988+
if (subLinkType == ARRAY_SUBLINK)
989+
{
990+
/* There can be only one param... */
991+
int paramid = linitial_int(subplan->setParam);
992+
ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
993+
994+
prm->execPlan = NULL;
995+
/* We build the result in query context so it won't disappear */
996+
if (astate != NULL)
997+
prm->value = makeArrayResult(astate,
998+
econtext->ecxt_per_query_memory);
999+
else
1000+
{
1001+
MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
1002+
prm->value = PointerGetDatum(construct_empty_array(subplan->firstColType));
1003+
}
1004+
prm->isnull = false;
1005+
}
1006+
else if (!found)
9841007
{
9851008
if (subLinkType == EXISTS_SUBLINK)
9861009
{
@@ -1005,18 +1028,6 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
10051028
}
10061029
}
10071030
}
1008-
else if (subLinkType == ARRAY_SUBLINK)
1009-
{
1010-
/* There can be only one param... */
1011-
int paramid = linitial_int(subplan->setParam);
1012-
ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]);
1013-
1014-
Assert(astate != NULL);
1015-
prm->execPlan = NULL;
1016-
/* We build the result in query context so it won't disappear */
1017-
prm->value = makeArrayResult(astate, econtext->ecxt_per_query_memory);
1018-
prm->isnull = false;
1019-
}
10201031

10211032
MemoryContextSwitchTo(oldcontext);
10221033
}

‎src/backend/optimizer/plan/subselect.c

Copy file name to clipboardExpand all lines: src/backend/optimizer/plan/subselect.c
+5-5Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1994, Regents of the University of California
88
*
99
* IDENTIFICATION
10-
* $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.123 2007/07/18 21:40:57 tgl Exp $
10+
* $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.124 2007/08/26 21:44:25 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -208,10 +208,10 @@ generate_new_param(PlannerInfo *root, Oid paramtype, int32 paramtypmod)
208208
/*
209209
* Get the datatype of the first column of the plan's output.
210210
*
211-
* This is a hack to support exprType(), which doesn't have any way to get
212-
* at the plan associated with a SubPlan node. We really only need the value
213-
* for EXPR_SUBLINK and ARRAY_SUBLINK subplans, but for consistency we set
214-
* it always.
211+
* This is stored for ARRAY_SUBLINK and for exprType(), which doesn't have any
212+
* way to get at the plan associated with a SubPlan node. We really only need
213+
* the value for EXPR_SUBLINK and ARRAY_SUBLINK subplans, but for consistency
214+
* we set it always.
215215
*/
216216
static Oid
217217
get_first_col_type(Plan *plan)

‎src/include/nodes/primnodes.h

Copy file name to clipboardExpand all lines: src/include/nodes/primnodes.h
+3-3Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
1111
* Portions Copyright (c) 1994, Regents of the University of California
1212
*
13-
* $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.132 2007/06/11 22:22:42 tgl Exp $
13+
* $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.133 2007/08/26 21:44:25 tgl Exp $
1414
*
1515
*-------------------------------------------------------------------------
1616
*/
@@ -388,7 +388,7 @@ typedef struct BoolExpr
388388
* results. ALL and ANY combine the per-row results using AND and OR
389389
* semantics respectively.
390390
* ARRAY requires just one target column, and creates an array of the target
391-
* column's type using one or more rows resulting from the subselect.
391+
* column's type using any number of rows resulting from the subselect.
392392
*
393393
* SubLink is classed as an Expr node, but it is not actually executable;
394394
* it must be replaced in the expression tree by a SubPlan node during
@@ -468,7 +468,7 @@ typedef struct SubPlan
468468
List *paramIds; /* IDs of Params embedded in the above */
469469
/* Identification of the Plan tree to use: */
470470
int plan_id; /* Index (from 1) in PlannedStmt.subplans */
471-
/* Extra data saved for the convenience of exprType(): */
471+
/* Extra data useful for determining subplan's output type: */
472472
Oid firstColType; /* Type of first column of subplan result */
473473
/* Information about execution strategy: */
474474
bool useHashTable; /* TRUE to store subselect output in a hash

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.