aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/execQual.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2000-07-23 01:36:05 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2000-07-23 01:36:05 +0000
commite4e6459c0f34f102cf998661ed5619f3b9031b68 (patch)
treeb24890617768b5a4eb74ddb7c0f3687500f92ca4 /src/backend/executor/execQual.c
parentef2a6b8b833ffcd7686eeb77fd771d4613b0c144 (diff)
downloadpostgresql-e4e6459c0f34f102cf998661ed5619f3b9031b68.tar.gz
postgresql-e4e6459c0f34f102cf998661ed5619f3b9031b68.zip
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.
Diffstat (limited to 'src/backend/executor/execQual.c')
-rw-r--r--src/backend/executor/execQual.c61
1 files changed, 48 insertions, 13 deletions
diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c
index 1aeb07a7a9f..a445a57d9cf 100644
--- a/src/backend/executor/execQual.c
+++ b/src/backend/executor/execQual.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.75 2000/07/22 03:34:27 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.76 2000/07/23 01:35:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -64,18 +64,30 @@ static Datum ExecEvalVar(Var *variable, ExprContext *econtext, bool *isNull);
static Datum ExecMakeFunctionResult(Node *node, List *arguments,
ExprContext *econtext, bool *isNull, bool *isDone);
-/*
+/*----------
* ExecEvalArrayRef
*
* This function takes an ArrayRef and returns the extracted Datum
* if it's a simple reference, or the modified array value if it's
- * an array assignment (read array element insertion).
+ * an array assignment (i.e., array element or slice insertion).
+ *
+ * NOTE: if we get a NULL result from a subexpression, we return NULL when
+ * it's an array reference, or the unmodified source array when it's an
+ * array assignment. This may seem peculiar, but if we return NULL (as was
+ * done in versions up through 7.0) then an assignment like
+ * UPDATE table SET arrayfield[4] = NULL
+ * will result in setting the whole array to NULL, which is certainly not
+ * very desirable. By returning the source array we make the assignment
+ * into a no-op, instead. (Eventually we need to redesign arrays so that
+ * individual elements can be NULL, but for now, let's try to protect users
+ * from shooting themselves in the foot.)
*
* NOTE: we deliberately refrain from applying DatumGetArrayTypeP() here,
* even though that might seem natural, because this code needs to support
* both varlena arrays and fixed-length array types. DatumGetArrayTypeP()
* only works for the varlena kind. The routines we call in arrayfuncs.c
* have to know the difference (that's what they need refattrlength for).
+ *----------
*/
static Datum
ExecEvalArrayRef(ArrayRef *arrayRef,
@@ -85,6 +97,7 @@ ExecEvalArrayRef(ArrayRef *arrayRef,
{
ArrayType *array_source;
ArrayType *resultArray;
+ bool isAssignment = (arrayRef->refassgnexpr != NULL);
List *elt;
int i = 0,
j = 0;
@@ -102,7 +115,11 @@ ExecEvalArrayRef(ArrayRef *arrayRef,
econtext,
isNull,
isDone));
- /* If refexpr yields NULL, result is always NULL, for now anyway */
+ /*
+ * If refexpr yields NULL, result is always NULL, for now anyway.
+ * (This means you cannot assign to an element or slice of an array
+ * that's NULL; it'll just stay NULL.)
+ */
if (*isNull)
return (Datum) NULL;
}
@@ -110,7 +127,7 @@ ExecEvalArrayRef(ArrayRef *arrayRef,
{
/*
- * Null refexpr indicates we are doing an INSERT into an array
+ * Empty refexpr indicates we are doing an INSERT into an array
* column. For now, we just take the refassgnexpr (which the
* parser will have ensured is an array value) and return it
* as-is, ignoring any subscripts that may have been supplied in
@@ -130,9 +147,14 @@ ExecEvalArrayRef(ArrayRef *arrayRef,
econtext,
isNull,
&dummy));
- /* If any index expr yields NULL, result is NULL */
+ /* If any index expr yields NULL, result is NULL or source array */
if (*isNull)
- return (Datum) NULL;
+ {
+ if (! isAssignment || array_source == NULL)
+ return (Datum) NULL;
+ *isNull = false;
+ return PointerGetDatum(array_source);
+ }
}
if (arrayRef->reflowerindexpr != NIL)
@@ -147,9 +169,14 @@ ExecEvalArrayRef(ArrayRef *arrayRef,
econtext,
isNull,
&dummy));
- /* If any index expr yields NULL, result is NULL */
+ /* If any index expr yields NULL, result is NULL or source array */
if (*isNull)
- return (Datum) NULL;
+ {
+ if (! isAssignment || array_source == NULL)
+ return (Datum) NULL;
+ *isNull = false;
+ return PointerGetDatum(array_source);
+ }
}
if (i != j)
elog(ERROR,
@@ -159,18 +186,26 @@ ExecEvalArrayRef(ArrayRef *arrayRef,
else
lIndex = NULL;
- if (arrayRef->refassgnexpr != NULL)
+ if (isAssignment)
{
Datum sourceData = ExecEvalExpr(arrayRef->refassgnexpr,
econtext,
isNull,
&dummy);
- /* For now, can't cope with inserting NULL into an array */
+ /*
+ * For now, can't cope with inserting NULL into an array,
+ * so make it a no-op per discussion above...
+ */
if (*isNull)
- return (Datum) NULL;
+ {
+ if (array_source == NULL)
+ return (Datum) NULL;
+ *isNull = false;
+ return PointerGetDatum(array_source);
+ }
if (array_source == NULL)
- return sourceData; /* XXX do something else? */
+ return sourceData; /* XXX do something else? */
if (lIndex == NULL)
resultArray = array_set(array_source, i,