From 352a56ba68d00a4bce9944e1b0e6aeda8d3c021f Mon Sep 17 00:00:00 2001 From: Tom Lane <tgl@sss.pgh.pa.us> Date: Fri, 29 Sep 2006 21:22:21 +0000 Subject: [PATCH] Allow assignment to array elements not contiguous with those already present; intervening positions are filled with nulls. This behavior is required by SQL99 but was not implementable before 8.2 due to lack of support for nulls in arrays. I have only made it work for the one-dimensional case, which is all that SQL99 requires. It seems quite complex to get it right in higher dimensions, and since we never allowed extension at all in higher dimensions, I think that must count as a future feature addition not a bug fix. --- doc/src/sgml/array.sgml | 13 +- src/backend/utils/adt/arrayfuncs.c | 199 +++++++++++++++------------ src/test/regress/expected/arrays.out | 110 +++++++++++++++ src/test/regress/sql/arrays.sql | 36 +++++ 4 files changed, 267 insertions(+), 91 deletions(-) diff --git a/doc/src/sgml/array.sgml b/doc/src/sgml/array.sgml index 55e4085d0dd..3ed8ce9c043 100644 --- a/doc/src/sgml/array.sgml +++ b/doc/src/sgml/array.sgml @@ -1,4 +1,4 @@ -<!-- $PostgreSQL: pgsql/doc/src/sgml/array.sgml,v 1.51 2006/05/09 23:12:54 momjian Exp $ --> +<!-- $PostgreSQL: pgsql/doc/src/sgml/array.sgml,v 1.52 2006/09/29 21:22:21 tgl Exp $ --> <sect1 id="arrays"> <title>Arrays</title> @@ -350,11 +350,12 @@ UPDATE sal_emp SET pay_by_quarter[1:2] = '{27000,27000}' </para> <para> - A stored array value can be enlarged by assigning to an element adjacent to - those already present, or by assigning to a slice that is adjacent - to or overlaps the data already present. For example, if array - <literal>myarray</> currently has 4 elements, it will have five - elements after an update that assigns to <literal>myarray[5]</>. + A stored array value can be enlarged by assigning to element(s) not already + present. Any positions between those previously present and the newly + assigned element(s) will be filled with nulls. For example, if array + <literal>myarray</> currently has 4 elements, it will have six + elements after an update that assigns to <literal>myarray[6]</>, + and <literal>myarray[5]</> will contain a null. Currently, enlargement in this fashion is only allowed for one-dimensional arrays, not multidimensional arrays. </para> diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c index 8b0c11c163d..dd1f1649fad 100644 --- a/src/backend/utils/adt/arrayfuncs.c +++ b/src/backend/utils/adt/arrayfuncs.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.131 2006/09/10 20:14:20 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.132 2006/09/29 21:22:21 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1925,8 +1925,9 @@ array_get_slice(ArrayType *array, * modified entry. The original array object is not changed. * * For one-dimensional arrays only, we allow the array to be extended - * by assigning to the position one above or one below the existing range. - * (XXX we could be more flexible: perhaps allow NULL fill?) + * by assigning to a position outside the existing subscript range; any + * positions between the existing elements and the new one are set to NULLs. + * (XXX TODO: allow a corresponding behavior for multidimensional arrays) * * NOTE: For assignments, we throw an error for invalid subscripts etc, * rather than returning a NULL as the fetch operations do. @@ -1949,17 +1950,18 @@ array_set(ArrayType *array, lb[MAXDIM], offset; char *elt_ptr; - bool extendbefore = false; - bool extendafter = false; bool newhasnulls; bits8 *oldnullbitmap; int oldnitems, + newnitems, olddatasize, newsize, olditemlen, newitemlen, overheadlen, oldoverheadlen, + addedbefore, + addedafter, lenbefore, lenafter; @@ -1972,12 +1974,12 @@ array_set(ArrayType *array, if (nSubscripts != 1) ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), - errmsg("invalid array subscripts"))); + errmsg("wrong number of array subscripts"))); if (indx[0] < 0 || indx[0] * elmlen >= arraytyplen) ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), - errmsg("invalid array subscripts"))); + errmsg("array subscript out of range"))); if (isNull) ereport(ERROR, @@ -1994,7 +1996,7 @@ array_set(ArrayType *array, if (nSubscripts <= 0 || nSubscripts > MAXDIM) ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), - errmsg("invalid array subscripts"))); + errmsg("wrong number of array subscripts"))); /* make sure item to be inserted is not toasted */ if (elmlen == -1 && !isNull) @@ -2028,70 +2030,72 @@ array_set(ArrayType *array, if (ndim != nSubscripts) ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), - errmsg("invalid array subscripts"))); + errmsg("wrong number of array subscripts"))); /* copy dim/lb since we may modify them */ memcpy(dim, ARR_DIMS(array), ndim * sizeof(int)); memcpy(lb, ARR_LBOUND(array), ndim * sizeof(int)); + newhasnulls = (ARR_HASNULL(array) || isNull); + addedbefore = addedafter = 0; + /* * Check subscripts */ - for (i = 0; i < ndim; i++) + if (ndim == 1) { - if (indx[i] < lb[i]) + if (indx[0] < lb[0]) { - if (ndim == 1 && indx[i] == lb[i] - 1) - { - dim[i]++; - lb[i]--; - extendbefore = true; - } - else - ereport(ERROR, - (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), - errmsg("invalid array subscripts"))); + addedbefore = lb[0] - indx[0]; + dim[0] += addedbefore; + lb[0] = indx[0]; + if (addedbefore > 1) + newhasnulls = true; /* will insert nulls */ } - if (indx[i] >= (dim[i] + lb[i])) + if (indx[0] >= (dim[0] + lb[0])) { - if (ndim == 1 && indx[i] == (dim[i] + lb[i])) - { - dim[i]++; - extendafter = true; - } - else + addedafter = indx[0] - (dim[0] + lb[0]) + 1; + dim[0] += addedafter; + if (addedafter > 1) + newhasnulls = true; /* will insert nulls */ + } + } + else + { + /* + * XXX currently we do not support extending multi-dimensional + * arrays during assignment + */ + for (i = 0; i < ndim; i++) + { + if (indx[i] < lb[i] || + indx[i] >= (dim[i] + lb[i])) ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), - errmsg("invalid array subscripts"))); + errmsg("array subscript out of range"))); } } /* * Compute sizes of items and areas to copy */ - if (ARR_HASNULL(array) || isNull) - { - newhasnulls = true; - overheadlen = ARR_OVERHEAD_WITHNULLS(ndim, - ArrayGetNItems(ndim, dim)); - } + newnitems = ArrayGetNItems(ndim, dim); + if (newhasnulls) + overheadlen = ARR_OVERHEAD_WITHNULLS(ndim, newnitems); else - { - newhasnulls = false; overheadlen = ARR_OVERHEAD_NONULLS(ndim); - } oldnitems = ArrayGetNItems(ndim, ARR_DIMS(array)); oldnullbitmap = ARR_NULLBITMAP(array); oldoverheadlen = ARR_DATA_OFFSET(array); olddatasize = ARR_SIZE(array) - oldoverheadlen; - if (extendbefore) + if (addedbefore) { offset = 0; lenbefore = 0; olditemlen = 0; lenafter = olddatasize; } - else if (extendafter) + else if (addedafter) { offset = oldnitems; lenbefore = olddatasize; @@ -2158,9 +2162,16 @@ array_set(ArrayType *array, { bits8 *newnullbitmap = ARR_NULLBITMAP(newarray); - array_set_isnull(newnullbitmap, offset, isNull); - if (extendbefore) - array_bitmap_copy(newnullbitmap, 1, + /* Zero the bitmap to take care of marking inserted positions null */ + MemSet(newnullbitmap, 0, (newnitems + 7) / 8); + /* Fix the inserted value */ + if (addedafter) + array_set_isnull(newnullbitmap, newnitems - 1, isNull); + else + array_set_isnull(newnullbitmap, offset, isNull); + /* Fix the copied range(s) */ + if (addedbefore) + array_bitmap_copy(newnullbitmap, addedbefore, oldnullbitmap, 0, oldnitems); else @@ -2168,7 +2179,7 @@ array_set(ArrayType *array, array_bitmap_copy(newnullbitmap, 0, oldnullbitmap, 0, offset); - if (!extendafter) + if (addedafter == 0) array_bitmap_copy(newnullbitmap, offset + 1, oldnullbitmap, offset + 1, oldnitems - offset - 1); @@ -2202,6 +2213,11 @@ array_set(ArrayType *array, * A new array is returned, just like the old except for the * modified range. The original array object is not changed. * + * For one-dimensional arrays only, we allow the array to be extended + * by assigning to positions outside the existing subscript range; any + * positions between the existing elements and the new ones are set to NULLs. + * (XXX TODO: allow a corresponding behavior for multidimensional arrays) + * * NOTE: we assume it is OK to scribble on the provided index arrays * lowerIndx[] and upperIndx[]. These are generally just temporaries. * @@ -2235,6 +2251,8 @@ array_set_slice(ArrayType *array, newitemsize, overheadlen, oldoverheadlen, + addedbefore, + addedafter, lenbefore, lenafter, itemsbefore, @@ -2298,55 +2316,70 @@ array_set_slice(ArrayType *array, if (ndim < nSubscripts || ndim <= 0 || ndim > MAXDIM) ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), - errmsg("invalid array subscripts"))); + errmsg("wrong number of array subscripts"))); /* copy dim/lb since we may modify them */ memcpy(dim, ARR_DIMS(array), ndim * sizeof(int)); memcpy(lb, ARR_LBOUND(array), ndim * sizeof(int)); + newhasnulls = (ARR_HASNULL(array) || ARR_HASNULL(srcArray)); + addedbefore = addedafter = 0; + /* - * Check provided subscripts. A slice exceeding the current array limits - * throws an error, *except* in the 1-D case where we will extend the - * array as long as no hole is created. An empty slice is an error, too. + * Check subscripts */ - for (i = 0; i < nSubscripts; i++) + if (ndim == 1) { - if (lowerIndx[i] > upperIndx[i]) + Assert(nSubscripts == 1); + if (lowerIndx[0] > upperIndx[0]) ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), - errmsg("invalid array subscripts"))); - if (lowerIndx[i] < lb[i]) + errmsg("upper bound cannot be less than lower bound"))); + if (lowerIndx[0] < lb[0]) { - if (ndim == 1 && upperIndx[i] >= lb[i] - 1) - { - dim[i] += lb[i] - lowerIndx[i]; - lb[i] = lowerIndx[i]; - } - else + if (upperIndx[0] < lb[0] - 1) + newhasnulls = true; /* will insert nulls */ + addedbefore = lb[0] - lowerIndx[0]; + dim[0] += addedbefore; + lb[0] = lowerIndx[0]; + } + if (upperIndx[0] >= (dim[0] + lb[0])) + { + if (lowerIndx[0] > (dim[0] + lb[0])) + newhasnulls = true; /* will insert nulls */ + addedafter = upperIndx[0] - (dim[0] + lb[0]) + 1; + dim[0] += addedafter; + } + } + else + { + /* + * XXX currently we do not support extending multi-dimensional + * arrays during assignment + */ + for (i = 0; i < nSubscripts; i++) + { + if (lowerIndx[i] > upperIndx[i]) + ereport(ERROR, + (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), + errmsg("upper bound cannot be less than lower bound"))); + if (lowerIndx[i] < lb[i] || + upperIndx[i] >= (dim[i] + lb[i])) ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), - errmsg("invalid array subscripts"))); + errmsg("array subscript out of range"))); } - if (upperIndx[i] >= (dim[i] + lb[i])) + /* fill any missing subscript positions with full array range */ + for (; i < ndim; i++) { - if (ndim == 1 && lowerIndx[i] <= (dim[i] + lb[i])) - dim[i] = upperIndx[i] - lb[i] + 1; - else + lowerIndx[i] = lb[i]; + upperIndx[i] = dim[i] + lb[i] - 1; + if (lowerIndx[i] > upperIndx[i]) ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), - errmsg("invalid array subscripts"))); + errmsg("upper bound cannot be less than lower bound"))); } } - /* fill any missing subscript positions with full array range */ - for (; i < ndim; i++) - { - lowerIndx[i] = lb[i]; - upperIndx[i] = dim[i] + lb[i] - 1; - if (lowerIndx[i] > upperIndx[i]) - ereport(ERROR, - (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), - errmsg("invalid array subscripts"))); - } /* Do this mainly to check for overflow */ nitems = ArrayGetNItems(ndim, dim); @@ -2366,16 +2399,10 @@ array_set_slice(ArrayType *array, * Compute space occupied by new entries, space occupied by replaced * entries, and required space for new array. */ - if (ARR_HASNULL(array) || ARR_HASNULL(srcArray)) - { - newhasnulls = true; + if (newhasnulls) overheadlen = ARR_OVERHEAD_WITHNULLS(ndim, nitems); - } else - { - newhasnulls = false; overheadlen = ARR_OVERHEAD_NONULLS(ndim); - } newitemsize = array_nelems_size(ARR_DATA_PTR(srcArray), 0, ARR_NULLBITMAP(srcArray), nsrcitems, elmlen, elmbyval, elmalign); @@ -2407,7 +2434,7 @@ array_set_slice(ArrayType *array, char *oldarraydata = ARR_DATA_PTR(array); bits8 *oldarraybitmap = ARR_NULLBITMAP(array); - itemsbefore = slicelb - oldlb; + itemsbefore = Min(slicelb, oldub + 1) - oldlb; lenbefore = array_nelems_size(oldarraydata, 0, oldarraybitmap, itemsbefore, elmlen, elmbyval, elmalign); @@ -2467,13 +2494,15 @@ array_set_slice(ArrayType *array, bits8 *newnullbitmap = ARR_NULLBITMAP(newarray); bits8 *oldnullbitmap = ARR_NULLBITMAP(array); - array_bitmap_copy(newnullbitmap, 0, + /* Zero the bitmap to handle marking inserted positions null */ + MemSet(newnullbitmap, 0, (nitems + 7) / 8); + array_bitmap_copy(newnullbitmap, addedbefore, oldnullbitmap, 0, itemsbefore); - array_bitmap_copy(newnullbitmap, itemsbefore, + array_bitmap_copy(newnullbitmap, lowerIndx[0] - lb[0], ARR_NULLBITMAP(srcArray), 0, nsrcitems); - array_bitmap_copy(newnullbitmap, itemsbefore + nsrcitems, + array_bitmap_copy(newnullbitmap, addedbefore + itemsbefore + nolditems, oldnullbitmap, itemsbefore + nolditems, itemsafter); } diff --git a/src/test/regress/expected/arrays.out b/src/test/regress/expected/arrays.out index b0f9f69a57f..643ae7f39bd 100644 --- a/src/test/regress/expected/arrays.out +++ b/src/test/regress/expected/arrays.out @@ -143,6 +143,116 @@ SELECT a,b,c FROM arrtest; [4:4]={NULL} | {3,4} | {foo,new_word} (3 rows) +-- +-- test array extension +-- +CREATE TEMP TABLE arrtest1 (i int[], t text[]); +insert into arrtest1 values(array[1,2,null,4], array['one','two',null,'four']); +select * from arrtest1; + i | t +--------------+--------------------- + {1,2,NULL,4} | {one,two,NULL,four} +(1 row) + +update arrtest1 set i[2] = 22, t[2] = 'twenty-two'; +select * from arrtest1; + i | t +---------------+---------------------------- + {1,22,NULL,4} | {one,twenty-two,NULL,four} +(1 row) + +update arrtest1 set i[5] = 5, t[5] = 'five'; +select * from arrtest1; + i | t +-----------------+--------------------------------- + {1,22,NULL,4,5} | {one,twenty-two,NULL,four,five} +(1 row) + +update arrtest1 set i[8] = 8, t[8] = 'eight'; +select * from arrtest1; + i | t +-----------------------------+------------------------------------------------- + {1,22,NULL,4,5,NULL,NULL,8} | {one,twenty-two,NULL,four,five,NULL,NULL,eight} +(1 row) + +update arrtest1 set i[0] = 0, t[0] = 'zero'; +select * from arrtest1; + i | t +-------------------------------------+------------------------------------------------------------ + [0:8]={0,1,22,NULL,4,5,NULL,NULL,8} | [0:8]={zero,one,twenty-two,NULL,four,five,NULL,NULL,eight} +(1 row) + +update arrtest1 set i[-3] = -3, t[-3] = 'minus-three'; +select * from arrtest1; + i | t +---------------------------------------------------+----------------------------------------------------------------------------------- + [-3:8]={-3,NULL,NULL,0,1,22,NULL,4,5,NULL,NULL,8} | [-3:8]={minus-three,NULL,NULL,zero,one,twenty-two,NULL,four,five,NULL,NULL,eight} +(1 row) + +update arrtest1 set i[0:2] = array[10,11,12], t[0:2] = array['ten','eleven','twelve']; +select * from arrtest1; + i | t +-----------------------------------------------------+--------------------------------------------------------------------------------- + [-3:8]={-3,NULL,NULL,10,11,12,NULL,4,5,NULL,NULL,8} | [-3:8]={minus-three,NULL,NULL,ten,eleven,twelve,NULL,four,five,NULL,NULL,eight} +(1 row) + +update arrtest1 set i[8:10] = array[18,null,20], t[8:10] = array['p18',null,'p20']; +select * from arrtest1; + i | t +---------------------------------------------------------------+----------------------------------------------------------------------------------------- + [-3:10]={-3,NULL,NULL,10,11,12,NULL,4,5,NULL,NULL,18,NULL,20} | [-3:10]={minus-three,NULL,NULL,ten,eleven,twelve,NULL,four,five,NULL,NULL,p18,NULL,p20} +(1 row) + +update arrtest1 set i[11:12] = array[null,22], t[11:12] = array[null,'p22']; +select * from arrtest1; + i | t +-----------------------------------------------------------------------+-------------------------------------------------------------------------------------------------- + [-3:12]={-3,NULL,NULL,10,11,12,NULL,4,5,NULL,NULL,18,NULL,20,NULL,22} | [-3:12]={minus-three,NULL,NULL,ten,eleven,twelve,NULL,four,five,NULL,NULL,p18,NULL,p20,NULL,p22} +(1 row) + +update arrtest1 set i[15:16] = array[null,26], t[15:16] = array[null,'p26']; +select * from arrtest1; + i | t +-----------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------- + [-3:16]={-3,NULL,NULL,10,11,12,NULL,4,5,NULL,NULL,18,NULL,20,NULL,22,NULL,NULL,NULL,26} | [-3:16]={minus-three,NULL,NULL,ten,eleven,twelve,NULL,four,five,NULL,NULL,p18,NULL,p20,NULL,p22,NULL,NULL,NULL,p26} +(1 row) + +update arrtest1 set i[-5:-3] = array[-15,-14,-13], t[-5:-3] = array['m15','m14','m13']; +select * from arrtest1; + i | t +--------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------- + [-5:16]={-15,-14,-13,NULL,NULL,10,11,12,NULL,4,5,NULL,NULL,18,NULL,20,NULL,22,NULL,NULL,NULL,26} | [-5:16]={m15,m14,m13,NULL,NULL,ten,eleven,twelve,NULL,four,five,NULL,NULL,p18,NULL,p20,NULL,p22,NULL,NULL,NULL,p26} +(1 row) + +update arrtest1 set i[-7:-6] = array[-17,null], t[-7:-6] = array['m17',null]; +select * from arrtest1; + i | t +-----------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------ + [-7:16]={-17,NULL,-15,-14,-13,NULL,NULL,10,11,12,NULL,4,5,NULL,NULL,18,NULL,20,NULL,22,NULL,NULL,NULL,26} | [-7:16]={m17,NULL,m15,m14,m13,NULL,NULL,ten,eleven,twelve,NULL,four,five,NULL,NULL,p18,NULL,p20,NULL,p22,NULL,NULL,NULL,p26} +(1 row) + +update arrtest1 set i[-12:-10] = array[-22,null,-20], t[-12:-10] = array['m22',null,'m20']; +select * from arrtest1; + i | t +-----------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------ + [-12:16]={-22,NULL,-20,NULL,NULL,-17,NULL,-15,-14,-13,NULL,NULL,10,11,12,NULL,4,5,NULL,NULL,18,NULL,20,NULL,22,NULL,NULL,NULL,26} | [-12:16]={m22,NULL,m20,NULL,NULL,m17,NULL,m15,m14,m13,NULL,NULL,ten,eleven,twelve,NULL,four,five,NULL,NULL,p18,NULL,p20,NULL,p22,NULL,NULL,NULL,p26} +(1 row) + +delete from arrtest1; +insert into arrtest1 values(array[1,2,null,4], array['one','two',null,'four']); +select * from arrtest1; + i | t +--------------+--------------------- + {1,2,NULL,4} | {one,two,NULL,four} +(1 row) + +update arrtest1 set i[0:5] = array[0,1,2,null,4,5], t[0:5] = array['z','p1','p2',null,'p4','p5']; +select * from arrtest1; + i | t +------------------------+---------------------------- + [0:5]={0,1,2,NULL,4,5} | [0:5]={z,p1,p2,NULL,p4,p5} +(1 row) + -- -- array expressions and operators -- diff --git a/src/test/regress/sql/arrays.sql b/src/test/regress/sql/arrays.sql index ad5f455cf49..1f574a01848 100644 --- a/src/test/regress/sql/arrays.sql +++ b/src/test/regress/sql/arrays.sql @@ -90,6 +90,42 @@ SELECT a FROM arrtest WHERE a[2] IS NULL; DELETE FROM arrtest WHERE a[2] IS NULL AND b IS NULL; SELECT a,b,c FROM arrtest; +-- +-- test array extension +-- +CREATE TEMP TABLE arrtest1 (i int[], t text[]); +insert into arrtest1 values(array[1,2,null,4], array['one','two',null,'four']); +select * from arrtest1; +update arrtest1 set i[2] = 22, t[2] = 'twenty-two'; +select * from arrtest1; +update arrtest1 set i[5] = 5, t[5] = 'five'; +select * from arrtest1; +update arrtest1 set i[8] = 8, t[8] = 'eight'; +select * from arrtest1; +update arrtest1 set i[0] = 0, t[0] = 'zero'; +select * from arrtest1; +update arrtest1 set i[-3] = -3, t[-3] = 'minus-three'; +select * from arrtest1; +update arrtest1 set i[0:2] = array[10,11,12], t[0:2] = array['ten','eleven','twelve']; +select * from arrtest1; +update arrtest1 set i[8:10] = array[18,null,20], t[8:10] = array['p18',null,'p20']; +select * from arrtest1; +update arrtest1 set i[11:12] = array[null,22], t[11:12] = array[null,'p22']; +select * from arrtest1; +update arrtest1 set i[15:16] = array[null,26], t[15:16] = array[null,'p26']; +select * from arrtest1; +update arrtest1 set i[-5:-3] = array[-15,-14,-13], t[-5:-3] = array['m15','m14','m13']; +select * from arrtest1; +update arrtest1 set i[-7:-6] = array[-17,null], t[-7:-6] = array['m17',null]; +select * from arrtest1; +update arrtest1 set i[-12:-10] = array[-22,null,-20], t[-12:-10] = array['m22',null,'m20']; +select * from arrtest1; +delete from arrtest1; +insert into arrtest1 values(array[1,2,null,4], array['one','two',null,'four']); +select * from arrtest1; +update arrtest1 set i[0:5] = array[0,1,2,null,4,5], t[0:5] = array['z','p1','p2',null,'p4','p5']; +select * from arrtest1; + -- -- array expressions and operators -- -- GitLab