Skip to content

Commit e4e6459

Browse files
committed
Further cleanup of array behavior. Slice assignments to arrays with
varlena elements work now. Allow assignment to previously-nonexistent subscript position to extend array, but only for 1-D arrays and only if adjacent to existing positions (could do more if we had a way to represent nulls in arrays, but I don't want to tackle that now). Arrange for assignment of NULL to an array element in UPDATE to be a no-op, rather than setting the entire array to NULL as it used to. (Throwing an error would be a reasonable alternative, but it's never done that...) Update regress test accordingly.
1 parent ef2a6b8 commit e4e6459

File tree

4 files changed

+612
-249
lines changed

4 files changed

+612
-249
lines changed

src/backend/executor/execQual.c

Lines changed: 48 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.75 2000/07/22 03:34:27 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.76 2000/07/23 01:35:58 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -64,18 +64,30 @@ static Datum ExecEvalVar(Var *variable, ExprContext *econtext, bool *isNull);
6464
static Datum ExecMakeFunctionResult(Node *node, List *arguments,
6565
ExprContext *econtext, bool *isNull, bool *isDone);
6666

67-
/*
67+
/*----------
6868
* ExecEvalArrayRef
6969
*
7070
* This function takes an ArrayRef and returns the extracted Datum
7171
* if it's a simple reference, or the modified array value if it's
72-
* an array assignment (read array element insertion).
72+
* an array assignment (i.e., array element or slice insertion).
73+
*
74+
* NOTE: if we get a NULL result from a subexpression, we return NULL when
75+
* it's an array reference, or the unmodified source array when it's an
76+
* array assignment. This may seem peculiar, but if we return NULL (as was
77+
* done in versions up through 7.0) then an assignment like
78+
* UPDATE table SET arrayfield[4] = NULL
79+
* will result in setting the whole array to NULL, which is certainly not
80+
* very desirable. By returning the source array we make the assignment
81+
* into a no-op, instead. (Eventually we need to redesign arrays so that
82+
* individual elements can be NULL, but for now, let's try to protect users
83+
* from shooting themselves in the foot.)
7384
*
7485
* NOTE: we deliberately refrain from applying DatumGetArrayTypeP() here,
7586
* even though that might seem natural, because this code needs to support
7687
* both varlena arrays and fixed-length array types. DatumGetArrayTypeP()
7788
* only works for the varlena kind. The routines we call in arrayfuncs.c
7889
* have to know the difference (that's what they need refattrlength for).
90+
*----------
7991
*/
8092
static Datum
8193
ExecEvalArrayRef(ArrayRef *arrayRef,
@@ -85,6 +97,7 @@ ExecEvalArrayRef(ArrayRef *arrayRef,
8597
{
8698
ArrayType *array_source;
8799
ArrayType *resultArray;
100+
bool isAssignment = (arrayRef->refassgnexpr != NULL);
88101
List *elt;
89102
int i = 0,
90103
j = 0;
@@ -102,15 +115,19 @@ ExecEvalArrayRef(ArrayRef *arrayRef,
102115
econtext,
103116
isNull,
104117
isDone));
105-
/* If refexpr yields NULL, result is always NULL, for now anyway */
118+
/*
119+
* If refexpr yields NULL, result is always NULL, for now anyway.
120+
* (This means you cannot assign to an element or slice of an array
121+
* that's NULL; it'll just stay NULL.)
122+
*/
106123
if (*isNull)
107124
return (Datum) NULL;
108125
}
109126
else
110127
{
111128

112129
/*
113-
* Null refexpr indicates we are doing an INSERT into an array
130+
* Empty refexpr indicates we are doing an INSERT into an array
114131
* column. For now, we just take the refassgnexpr (which the
115132
* parser will have ensured is an array value) and return it
116133
* as-is, ignoring any subscripts that may have been supplied in
@@ -130,9 +147,14 @@ ExecEvalArrayRef(ArrayRef *arrayRef,
130147
econtext,
131148
isNull,
132149
&dummy));
133-
/* If any index expr yields NULL, result is NULL */
150+
/* If any index expr yields NULL, result is NULL or source array */
134151
if (*isNull)
135-
return (Datum) NULL;
152+
{
153+
if (! isAssignment || array_source == NULL)
154+
return (Datum) NULL;
155+
*isNull = false;
156+
return PointerGetDatum(array_source);
157+
}
136158
}
137159

138160
if (arrayRef->reflowerindexpr != NIL)
@@ -147,9 +169,14 @@ ExecEvalArrayRef(ArrayRef *arrayRef,
147169
econtext,
148170
isNull,
149171
&dummy));
150-
/* If any index expr yields NULL, result is NULL */
172+
/* If any index expr yields NULL, result is NULL or source array */
151173
if (*isNull)
152-
return (Datum) NULL;
174+
{
175+
if (! isAssignment || array_source == NULL)
176+
return (Datum) NULL;
177+
*isNull = false;
178+
return PointerGetDatum(array_source);
179+
}
153180
}
154181
if (i != j)
155182
elog(ERROR,
@@ -159,18 +186,26 @@ ExecEvalArrayRef(ArrayRef *arrayRef,
159186
else
160187
lIndex = NULL;
161188

162-
if (arrayRef->refassgnexpr != NULL)
189+
if (isAssignment)
163190
{
164191
Datum sourceData = ExecEvalExpr(arrayRef->refassgnexpr,
165192
econtext,
166193
isNull,
167194
&dummy);
168-
/* For now, can't cope with inserting NULL into an array */
195+
/*
196+
* For now, can't cope with inserting NULL into an array,
197+
* so make it a no-op per discussion above...
198+
*/
169199
if (*isNull)
170-
return (Datum) NULL;
200+
{
201+
if (array_source == NULL)
202+
return (Datum) NULL;
203+
*isNull = false;
204+
return PointerGetDatum(array_source);
205+
}
171206

172207
if (array_source == NULL)
173-
return sourceData; /* XXX do something else? */
208+
return sourceData; /* XXX do something else? */
174209

175210
if (lIndex == NULL)
176211
resultArray = array_set(array_source, i,

0 commit comments

Comments
 (0)