Commit e4e6459c authored by Tom Lane's avatar Tom Lane

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.
parent ef2a6b8b
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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); ...@@ -64,18 +64,30 @@ static Datum ExecEvalVar(Var *variable, ExprContext *econtext, bool *isNull);
static Datum ExecMakeFunctionResult(Node *node, List *arguments, static Datum ExecMakeFunctionResult(Node *node, List *arguments,
ExprContext *econtext, bool *isNull, bool *isDone); ExprContext *econtext, bool *isNull, bool *isDone);
/* /*----------
* ExecEvalArrayRef * ExecEvalArrayRef
* *
* This function takes an ArrayRef and returns the extracted Datum * This function takes an ArrayRef and returns the extracted Datum
* if it's a simple reference, or the modified array value if it's * 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, * NOTE: we deliberately refrain from applying DatumGetArrayTypeP() here,
* even though that might seem natural, because this code needs to support * even though that might seem natural, because this code needs to support
* both varlena arrays and fixed-length array types. DatumGetArrayTypeP() * both varlena arrays and fixed-length array types. DatumGetArrayTypeP()
* only works for the varlena kind. The routines we call in arrayfuncs.c * 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). * have to know the difference (that's what they need refattrlength for).
*----------
*/ */
static Datum static Datum
ExecEvalArrayRef(ArrayRef *arrayRef, ExecEvalArrayRef(ArrayRef *arrayRef,
...@@ -85,6 +97,7 @@ ExecEvalArrayRef(ArrayRef *arrayRef, ...@@ -85,6 +97,7 @@ ExecEvalArrayRef(ArrayRef *arrayRef,
{ {
ArrayType *array_source; ArrayType *array_source;
ArrayType *resultArray; ArrayType *resultArray;
bool isAssignment = (arrayRef->refassgnexpr != NULL);
List *elt; List *elt;
int i = 0, int i = 0,
j = 0; j = 0;
...@@ -102,7 +115,11 @@ ExecEvalArrayRef(ArrayRef *arrayRef, ...@@ -102,7 +115,11 @@ ExecEvalArrayRef(ArrayRef *arrayRef,
econtext, econtext,
isNull, isNull,
isDone)); 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) if (*isNull)
return (Datum) NULL; return (Datum) NULL;
} }
...@@ -110,7 +127,7 @@ ExecEvalArrayRef(ArrayRef *arrayRef, ...@@ -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 * column. For now, we just take the refassgnexpr (which the
* parser will have ensured is an array value) and return it * parser will have ensured is an array value) and return it
* as-is, ignoring any subscripts that may have been supplied in * as-is, ignoring any subscripts that may have been supplied in
...@@ -130,9 +147,14 @@ ExecEvalArrayRef(ArrayRef *arrayRef, ...@@ -130,9 +147,14 @@ ExecEvalArrayRef(ArrayRef *arrayRef,
econtext, econtext,
isNull, isNull,
&dummy)); &dummy));
/* If any index expr yields NULL, result is NULL */ /* If any index expr yields NULL, result is NULL or source array */
if (*isNull) if (*isNull)
return (Datum) NULL; {
if (! isAssignment || array_source == NULL)
return (Datum) NULL;
*isNull = false;
return PointerGetDatum(array_source);
}
} }
if (arrayRef->reflowerindexpr != NIL) if (arrayRef->reflowerindexpr != NIL)
...@@ -147,9 +169,14 @@ ExecEvalArrayRef(ArrayRef *arrayRef, ...@@ -147,9 +169,14 @@ ExecEvalArrayRef(ArrayRef *arrayRef,
econtext, econtext,
isNull, isNull,
&dummy)); &dummy));
/* If any index expr yields NULL, result is NULL */ /* If any index expr yields NULL, result is NULL or source array */
if (*isNull) if (*isNull)
return (Datum) NULL; {
if (! isAssignment || array_source == NULL)
return (Datum) NULL;
*isNull = false;
return PointerGetDatum(array_source);
}
} }
if (i != j) if (i != j)
elog(ERROR, elog(ERROR,
...@@ -159,18 +186,26 @@ ExecEvalArrayRef(ArrayRef *arrayRef, ...@@ -159,18 +186,26 @@ ExecEvalArrayRef(ArrayRef *arrayRef,
else else
lIndex = NULL; lIndex = NULL;
if (arrayRef->refassgnexpr != NULL) if (isAssignment)
{ {
Datum sourceData = ExecEvalExpr(arrayRef->refassgnexpr, Datum sourceData = ExecEvalExpr(arrayRef->refassgnexpr,
econtext, econtext,
isNull, isNull,
&dummy); &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) if (*isNull)
return (Datum) NULL; {
if (array_source == NULL)
return (Datum) NULL;
*isNull = false;
return PointerGetDatum(array_source);
}
if (array_source == NULL) if (array_source == NULL)
return sourceData; /* XXX do something else? */ return sourceData; /* XXX do something else? */
if (lIndex == NULL) if (lIndex == NULL)
resultArray = array_set(array_source, i, resultArray = array_set(array_source, i,
......
This diff is collapsed.
...@@ -39,17 +39,17 @@ SELECT a[1:3], ...@@ -39,17 +39,17 @@ SELECT a[1:3],
a | b | c | d a | b | c | d
------------+-----------------+---------------+------------------- ------------+-----------------+---------------+-------------------
{1,2,3} | {{{0,0},{1,2}}} | | {1,2,3} | {{{0,0},{1,2}}} | |
{11,12,23} | | | {{"elt1","elt2"}} {11,12,23} | | {"foobar"} | {{"elt1","elt2"}}
| | {"foo","bar"} | | | {"foo","bar"} |
(3 rows) (3 rows)
-- returns three different results-- SELECT array_dims(a) AS a,array_dims(b) AS b,array_dims(c) AS c
SELECT array_dims(arrtest.b) AS x; FROM arrtest;
x a | b | c
----------------- -------+-----------------+-------
[1:1][1:2][1:2] [1:5] | [1:1][1:2][1:2] |
[1:2][1:2] [1:3] | [1:2][1:2] | [1:1]
[1:2] | [1:2] | [1:2]
(3 rows) (3 rows)
-- returns nothing -- returns nothing
...@@ -62,18 +62,32 @@ SELECT * ...@@ -62,18 +62,32 @@ SELECT *
(0 rows) (0 rows)
UPDATE arrtest UPDATE arrtest
SET a[1:2] = '{16,25}', SET a[1:2] = '{16,25}'
b[1:1][1:1][1:2] = '{113, 117}', WHERE NOT a = '{}'::_int2;
c[1:1] = '{"new_word"}'; UPDATE arrtest
SET b[1:1][1:1][1:2] = '{113, 117}',
b[1:1][1:2][2:2] = '{142, 147}'
WHERE array_dims(b) = '[1:1][1:2][1:2]';
UPDATE arrtest
SET c[2:2] = '{"new_word"}'
WHERE array_dims(c) is not null;
SELECT a,b,c FROM arrtest;
a | b | c
---------------+-----------------------+-----------------------
{16,25,3,4,5} | {{{113,142},{1,147}}} | {}
{16,25,23} | {{3,4},{4,5}} | {"foobar","new_word"}
{} | {3,4} | {"foo","new_word"}
(3 rows)
SELECT a[1:3], SELECT a[1:3],
b[1:1][1:2][1:2], b[1:1][1:2][1:2],
c[1:2], c[1:2],
d[1:1][2:2] d[1:1][2:2]
FROM arrtest; FROM arrtest;
a | b | c | d a | b | c | d
------------+---------------------+--------------------+------------ ------------+-----------------------+-----------------------+------------
{16,25,3} | {{{113,117},{1,2}}} | | {16,25,3} | {{{113,142},{1,147}}} | |
{16,25,23} | | | {{"elt2"}} {16,25,23} | | {"foobar","new_word"} | {{"elt2"}}
| | {"new_word","bar"} | | | {"foo","new_word"} |
(3 rows) (3 rows)
...@@ -20,8 +20,8 @@ SELECT a[1:3], ...@@ -20,8 +20,8 @@ SELECT a[1:3],
d[1:1][1:2] d[1:1][1:2]
FROM arrtest; FROM arrtest;
-- returns three different results-- SELECT array_dims(a) AS a,array_dims(b) AS b,array_dims(c) AS c
SELECT array_dims(arrtest.b) AS x; FROM arrtest;
-- returns nothing -- returns nothing
SELECT * SELECT *
...@@ -30,9 +30,19 @@ SELECT * ...@@ -30,9 +30,19 @@ SELECT *
c = '{"foobar"}'::_name; c = '{"foobar"}'::_name;
UPDATE arrtest UPDATE arrtest
SET a[1:2] = '{16,25}', SET a[1:2] = '{16,25}'
b[1:1][1:1][1:2] = '{113, 117}', WHERE NOT a = '{}'::_int2;
c[1:1] = '{"new_word"}';
UPDATE arrtest
SET b[1:1][1:1][1:2] = '{113, 117}',
b[1:1][1:2][2:2] = '{142, 147}'
WHERE array_dims(b) = '[1:1][1:2][1:2]';
UPDATE arrtest
SET c[2:2] = '{"new_word"}'
WHERE array_dims(c) is not null;
SELECT a,b,c FROM arrtest;
SELECT a[1:3], SELECT a[1:3],
b[1:1][1:2][1:2], b[1:1][1:2][1:2],
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment