Thread: array concat, et al patch (was: [GENERAL] join of array)
Tom Lane wrote: > Could you look at how big a change it'd be, anyway? Offhand I think it > may just mean that the subscript-checking done in parse_expr.c needs to > be done at runtime instead. Remember parse_expr should only be > concerned about determining datatype, and for its purposes all arrays of > a given element type are the same --- subscript checking should happen > at runtime. (It seems likely that having an ndims field in ArrayExpr > is inappropriate.) The attached patch fixes code and regression tests for the following (docs to follow once applied): ======================================================================== 1) Array concatenation of equidimensional arrays: ======================================================================== regression=# select ARRAY[1,2] || ARRAY[3,4]; ?column? ----------- {1,2,3,4} (1 row) regression=# select ARRAY[[1],[2],[3]] || ARRAY[[4],[5]]; ?column? ----------------------- {{1},{2},{3},{4},{5}} (1 row) regression=# select ARRAY[[1,2],[2,3],[3,4]] || ARRAY[[4,5],[5,6]]; ?column? --------------------------------- {{1,2},{2,3},{3,4},{4,5},{5,6}} (1 row) ======================================================================== 2) Array literals or vars in ARRAY expressions: ======================================================================== regression=# create table arr(f1 int[], f2 int[]); CREATE TABLE regression=# insert into arr values (ARRAY[[1,2],[3,4]],ARRAY[[5,6],[7,8]]); INSERT 2635544 1 regression=# select ARRAY[f1,f2] from arr; array ------------------------------- {{{1,2},{3,4}},{{5,6},{7,8}}} (1 row) regression=# select ARRAY['{{1,2},{3,4}}'::int[],'{{5,6},{7,8}}'::int[]]; array ------------------------------- {{{1,2},{3,4}},{{5,6},{7,8}}} (1 row) ======================================================================== 3) Lower bound of outer array adjusted downward when an "element" (which could itself be an array) is concatenated onto the front of an array: ======================================================================== regression=# create table arr(f1 int[]); CREATE TABLE regression=# insert into arr values ('{}'); INSERT 2635538 1 regression=# update arr set f1[-2] = 1; UPDATE 1 regression=# select array_lower(f1,1) from arr; array_lower ------------- -2 (1 row) regression=# select array_lower(f1 || 2, 1) from arr; array_lower ------------- -2 (1 row) regression=# select array_lower(0 || f1, 1) from arr; array_lower ------------- -3 (1 row) regression=# update arr set f1 = ARRAY[[1,2],[3,4]]; UPDATE 1 regression=# select array_lower(f1,1) from arr; array_lower ------------- 1 (1 row) regression=# select array_lower(f1 || ARRAY[5,6], 1) from arr; array_lower ------------- 1 (1 row) regression=# select array_lower(ARRAY[-1,0] || f1, 1) from arr; array_lower ------------- 0 (1 row) Compiles without warnings and passes all regression tests. If there are no objections, please apply. As I mentioned above, docs to follow once I'm sure what actually ends up being committed. Joe Index: src/backend/executor/execQual.c =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/backend/executor/execQual.c,v retrieving revision 1.141 diff -c -r1.141 execQual.c *** src/backend/executor/execQual.c 8 Aug 2003 21:41:39 -0000 1.141 --- src/backend/executor/execQual.c 15 Aug 2003 21:52:30 -0000 *************** *** 1620,1635 **** ArrayType *result; List *element; Oid element_type = arrayExpr->element_typeid; ! int ndims = arrayExpr->ndims; int dims[MAXDIM]; int lbs[MAXDIM]; ! if (ndims == 1) { int nelems; Datum *dvalues; int i = 0; nelems = length(astate->elements); /* Shouldn't happen here, but if length is 0, return NULL */ --- 1620,1637 ---- ArrayType *result; List *element; Oid element_type = arrayExpr->element_typeid; ! int ndims = 0; int dims[MAXDIM]; int lbs[MAXDIM]; ! if (!arrayExpr->multidims) { + /* Elements are presumably of scalar type */ int nelems; Datum *dvalues; int i = 0; + ndims = 1; nelems = length(astate->elements); /* Shouldn't happen here, but if length is 0, return NULL */ *************** *** 1667,1672 **** --- 1669,1675 ---- } else { + /* Must be nested array expressions */ char *dat = NULL; Size ndatabytes = 0; int nbytes; *************** *** 1677,1688 **** bool firstone = true; int i; - if (ndims <= 0 || ndims > MAXDIM) - ereport(ERROR, - (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), - errmsg("number of array dimensions exceeds the maximum allowed, %d", - MAXDIM))); - /* loop through and get data area from each element */ foreach(element, astate->elements) { --- 1680,1685 ---- *************** *** 1705,1714 **** --- 1702,1719 ---- { /* Get sub-array details from first member */ elem_ndims = ARR_NDIM(array); + ndims = elem_ndims + 1; + if (ndims <= 0 || ndims > MAXDIM) + ereport(ERROR, + (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), + errmsg("number of array dimensions exceeds " \ + "the maximum allowed, %d", MAXDIM))); + elem_dims = (int *) palloc(elem_ndims * sizeof(int)); memcpy(elem_dims, ARR_DIMS(array), elem_ndims * sizeof(int)); elem_lbs = (int *) palloc(elem_ndims * sizeof(int)); memcpy(elem_lbs, ARR_LBOUND(array), elem_ndims * sizeof(int)); + firstone = false; } else Index: src/backend/nodes/copyfuncs.c =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/backend/nodes/copyfuncs.c,v retrieving revision 1.263 diff -c -r1.263 copyfuncs.c *** src/backend/nodes/copyfuncs.c 8 Aug 2003 21:41:43 -0000 1.263 --- src/backend/nodes/copyfuncs.c 15 Aug 2003 21:44:30 -0000 *************** *** 947,953 **** COPY_SCALAR_FIELD(array_typeid); COPY_SCALAR_FIELD(element_typeid); COPY_NODE_FIELD(elements); ! COPY_SCALAR_FIELD(ndims); return newnode; } --- 947,953 ---- COPY_SCALAR_FIELD(array_typeid); COPY_SCALAR_FIELD(element_typeid); COPY_NODE_FIELD(elements); ! COPY_SCALAR_FIELD(multidims); return newnode; } Index: src/backend/nodes/equalfuncs.c =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/backend/nodes/equalfuncs.c,v retrieving revision 1.207 diff -c -r1.207 equalfuncs.c *** src/backend/nodes/equalfuncs.c 8 Aug 2003 21:41:43 -0000 1.207 --- src/backend/nodes/equalfuncs.c 15 Aug 2003 21:44:44 -0000 *************** *** 409,415 **** COMPARE_SCALAR_FIELD(array_typeid); COMPARE_SCALAR_FIELD(element_typeid); COMPARE_NODE_FIELD(elements); ! COMPARE_SCALAR_FIELD(ndims); return true; } --- 409,415 ---- COMPARE_SCALAR_FIELD(array_typeid); COMPARE_SCALAR_FIELD(element_typeid); COMPARE_NODE_FIELD(elements); ! COMPARE_SCALAR_FIELD(multidims); return true; } Index: src/backend/nodes/outfuncs.c =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/backend/nodes/outfuncs.c,v retrieving revision 1.217 diff -c -r1.217 outfuncs.c *** src/backend/nodes/outfuncs.c 8 Aug 2003 21:41:44 -0000 1.217 --- src/backend/nodes/outfuncs.c 15 Aug 2003 21:45:34 -0000 *************** *** 785,791 **** WRITE_OID_FIELD(array_typeid); WRITE_OID_FIELD(element_typeid); WRITE_NODE_FIELD(elements); ! WRITE_INT_FIELD(ndims); } static void --- 785,791 ---- WRITE_OID_FIELD(array_typeid); WRITE_OID_FIELD(element_typeid); WRITE_NODE_FIELD(elements); ! WRITE_BOOL_FIELD(multidims); } static void Index: src/backend/nodes/readfuncs.c =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/backend/nodes/readfuncs.c,v retrieving revision 1.161 diff -c -r1.161 readfuncs.c *** src/backend/nodes/readfuncs.c 4 Aug 2003 02:39:59 -0000 1.161 --- src/backend/nodes/readfuncs.c 15 Aug 2003 21:46:05 -0000 *************** *** 659,665 **** READ_OID_FIELD(array_typeid); READ_OID_FIELD(element_typeid); READ_NODE_FIELD(elements); ! READ_INT_FIELD(ndims); READ_DONE(); } --- 659,665 ---- READ_OID_FIELD(array_typeid); READ_OID_FIELD(element_typeid); READ_NODE_FIELD(elements); ! READ_BOOL_FIELD(multidims); READ_DONE(); } Index: src/backend/optimizer/util/clauses.c =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/backend/optimizer/util/clauses.c,v retrieving revision 1.152 diff -c -r1.152 clauses.c *** src/backend/optimizer/util/clauses.c 8 Aug 2003 21:41:55 -0000 1.152 --- src/backend/optimizer/util/clauses.c 15 Aug 2003 21:48:03 -0000 *************** *** 1515,1521 **** newarray->array_typeid = arrayexpr->array_typeid; newarray->element_typeid = arrayexpr->element_typeid; newarray->elements = FastListValue(&newelems); ! newarray->ndims = arrayexpr->ndims; if (all_const) return (Node *) evaluate_expr((Expr *) newarray, --- 1515,1521 ---- newarray->array_typeid = arrayexpr->array_typeid; newarray->element_typeid = arrayexpr->element_typeid; newarray->elements = FastListValue(&newelems); ! newarray->multidims = arrayexpr->multidims; if (all_const) return (Node *) evaluate_expr((Expr *) newarray, Index: src/backend/parser/parse_expr.c =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/backend/parser/parse_expr.c,v retrieving revision 1.160 diff -c -r1.160 parse_expr.c *** src/backend/parser/parse_expr.c 4 Aug 2003 02:40:01 -0000 1.160 --- src/backend/parser/parse_expr.c 15 Aug 2003 21:38:10 -0000 *************** *** 748,754 **** List *element; Oid array_type; Oid element_type; - int ndims; /* Transform the element expressions */ foreach(element, a->elements) --- 748,753 ---- *************** *** 781,791 **** if (array_type != InvalidOid) { /* Elements are presumably of scalar type */ ! ndims = 1; } else { /* Must be nested array expressions */ array_type = element_type; element_type = get_element_type(array_type); if (!OidIsValid(element_type)) --- 780,792 ---- if (array_type != InvalidOid) { /* Elements are presumably of scalar type */ ! newa->multidims = false; } else { /* Must be nested array expressions */ + newa->multidims = true; + array_type = element_type; element_type = get_element_type(array_type); if (!OidIsValid(element_type)) *************** *** 793,839 **** (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("could not find array type for datatype %s", format_type_be(array_type)))); - - /* - * make sure the element expressions all have the same - * number of dimensions - */ - ndims = 0; - foreach(element, newcoercedelems) - { - ArrayExpr *e = (ArrayExpr *) lfirst(element); - - if (!IsA(e, ArrayExpr)) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("multidimensional ARRAY[] must be built from nested array expressions"))); - if (ndims == 0) - ndims = e->ndims; - else if (e->ndims != ndims) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("nested array expressions must have common number of dimensions"))); - if (e->element_typeid != element_type) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("nested array expressions must have common element type"))); - - } - /* increment the number of dimensions */ - ndims++; - - /* make sure we don't have too many dimensions now */ - if (ndims > MAXDIM) - ereport(ERROR, - (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), - errmsg("number of array dimensions exceeds the maximum allowed, %d", - MAXDIM))); } newa->array_typeid = array_type; newa->element_typeid = element_type; newa->elements = newcoercedelems; - newa->ndims = ndims; result = (Node *) newa; break; --- 794,804 ---- Index: src/backend/utils/adt/array_userfuncs.c =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/backend/utils/adt/array_userfuncs.c,v retrieving revision 1.7 diff -c -r1.7 array_userfuncs.c *** src/backend/utils/adt/array_userfuncs.c 4 Aug 2003 00:43:25 -0000 1.7 --- src/backend/utils/adt/array_userfuncs.c 15 Aug 2003 22:41:12 -0000 *************** *** 132,138 **** /*----------------------------------------------------------------------------- * array_cat : ! * concatenate two nD arrays to form an (n+1)D array, or * push an (n-1)D array onto the end of an nD array *---------------------------------------------------------------------------- */ --- 132,138 ---- /*----------------------------------------------------------------------------- * array_cat : ! * concatenate two nD arrays to form an nD array, or * push an (n-1)D array onto the end of an nD array *---------------------------------------------------------------------------- */ *************** *** 223,251 **** if (ndims1 == ndims2) { /* ! * resulting array has two element outer array made up of input ! * argument arrays */ int i; ! ndims = ndims1 + 1; dims = (int *) palloc(ndims * sizeof(int)); lbs = (int *) palloc(ndims * sizeof(int)); ! dims[0] = 2; /* outer array made up of two input arrays */ ! lbs[0] = 1; /* start lower bound at 1 */ ! for (i = 0; i < ndims1; i++) { if (dims1[i] != dims2[i] || lbs1[i] != lbs2[i]) ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("cannot concatenate incompatible arrays"), ! errdetail("Arrays with differing dimensions are not " ! "compatible for concatenation."))); ! dims[i + 1] = dims1[i]; ! lbs[i + 1] = lbs1[i]; } } else if (ndims1 == ndims2 - 1) --- 223,251 ---- if (ndims1 == ndims2) { /* ! * resulting array is made up of the elements (possibly arrays themselves) ! * of the input argument arrays */ int i; ! ndims = ndims1; dims = (int *) palloc(ndims * sizeof(int)); lbs = (int *) palloc(ndims * sizeof(int)); ! dims[0] = dims1[0] + dims2[0]; ! lbs[0] = lbs1[0]; ! for (i = 1; i < ndims; i++) { if (dims1[i] != dims2[i] || lbs1[i] != lbs2[i]) ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("cannot concatenate incompatible arrays"), ! errdetail("Arrays with differing element dimensions are " ! "not compatible for concatenation."))); ! dims[i] = dims1[i]; ! lbs[i] = lbs1[i]; } } else if (ndims1 == ndims2 - 1) *************** *** 264,269 **** --- 264,272 ---- /* increment number of elements in outer array */ dims[0] += 1; + /* decrement outer array lower bound */ + lbs[0] -= 1; + /* make sure the added element matches our existing elements */ for (i = 0; i < ndims1; i++) { *************** *** 276,284 **** } } else - /* (ndims1 == ndims2 + 1) */ { ! /* * resulting array has the first argument as the outer array, with * the second argument appended to the end of the outer dimension */ --- 279,287 ---- } } else { ! /* (ndims1 == ndims2 + 1) ! * * resulting array has the first argument as the outer array, with * the second argument appended to the end of the outer dimension */ Index: src/include/nodes/primnodes.h =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/include/nodes/primnodes.h,v retrieving revision 1.91 diff -c -r1.91 primnodes.h *** src/include/nodes/primnodes.h 11 Aug 2003 23:04:50 -0000 1.91 --- src/include/nodes/primnodes.h 15 Aug 2003 21:37:35 -0000 *************** *** 596,602 **** Oid array_typeid; /* type of expression result */ Oid element_typeid; /* common type of expression elements */ List *elements; /* the array elements */ ! int ndims; /* number of array dimensions */ } ArrayExpr; /* --- 596,602 ---- Oid array_typeid; /* type of expression result */ Oid element_typeid; /* common type of expression elements */ List *elements; /* the array elements */ ! bool multidims; /* true if elements are also ArrayExprs */ } ArrayExpr; /* Index: src/test/regress/expected/arrays.out =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/test/regress/expected/arrays.out,v retrieving revision 1.17 diff -c -r1.17 arrays.out *** src/test/regress/expected/arrays.out 21 Jul 2003 20:29:40 -0000 1.17 --- src/test/regress/expected/arrays.out 15 Aug 2003 23:09:19 -0000 *************** *** 190,199 **** {6,42} (1 row) ! SELECT array_cat(ARRAY[1,2], ARRAY[3,4]) AS "{{1,2},{3,4}}"; ! {{1,2},{3,4}} ! --------------- ! {{1,2},{3,4}} (1 row) SELECT array_cat(ARRAY[1,2], ARRAY[[3,4],[5,6]]) AS "{{1,2},{3,4},{5,6}}"; --- 190,199 ---- {6,42} (1 row) ! SELECT array_cat(ARRAY[1,2], ARRAY[3,4]) AS "{1,2,3,4}"; ! {1,2,3,4} ! ----------- ! {1,2,3,4} (1 row) SELECT array_cat(ARRAY[1,2], ARRAY[[3,4],[5,6]]) AS "{{1,2},{3,4},{5,6}}"; *************** *** 233,248 **** {0,1,2} (1 row) ! SELECT ARRAY[1,2] || ARRAY[3,4] AS "{{1,2},{3,4}}"; ! {{1,2},{3,4}} ! --------------- ! {{1,2},{3,4}} (1 row) SELECT ARRAY[[['hello','world']]] || ARRAY[[['happy','birthday']]] AS "ARRAY"; ! ARRAY ! ------------------------------------------ ! {{{{hello,world}}},{{{happy,birthday}}}} (1 row) SELECT ARRAY[[1,2],[3,4]] || ARRAY[5,6] AS "{{1,2},{3,4},{5,6}}"; --- 233,248 ---- {0,1,2} (1 row) ! SELECT ARRAY[1,2] || ARRAY[3,4] AS "{1,2,3,4}"; ! {1,2,3,4} ! ----------- ! {1,2,3,4} (1 row) SELECT ARRAY[[['hello','world']]] || ARRAY[[['happy','birthday']]] AS "ARRAY"; ! ARRAY ! -------------------------------------- ! {{{hello,world}},{{happy,birthday}}} (1 row) SELECT ARRAY[[1,2],[3,4]] || ARRAY[5,6] AS "{{1,2},{3,4},{5,6}}"; *************** *** 251,260 **** {{1,2},{3,4},{5,6}} (1 row) ! SELECT ARRAY[0,0] || ARRAY[1,1] || ARRAY[2,2] AS "{{0,0},{1,1},{2,2}}"; ! {{0,0},{1,1},{2,2}} ! --------------------- ! {{0,0},{1,1},{2,2}} (1 row) SELECT 0 || ARRAY[1,2] || 3 AS "{0,1,2,3}"; --- 251,260 ---- {{1,2},{3,4},{5,6}} (1 row) ! SELECT ARRAY[0,0] || ARRAY[1,1] || ARRAY[2,2] AS "{0,0,1,1,2,2}"; ! {0,0,1,1,2,2} ! --------------- ! {0,0,1,1,2,2} (1 row) SELECT 0 || ARRAY[1,2] || 3 AS "{0,1,2,3}"; Index: src/test/regress/sql/arrays.sql =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/test/regress/sql/arrays.sql,v retrieving revision 1.14 diff -c -r1.14 arrays.sql *** src/test/regress/sql/arrays.sql 29 Jun 2003 00:33:44 -0000 1.14 --- src/test/regress/sql/arrays.sql 15 Aug 2003 23:02:06 -0000 *************** *** 132,138 **** -- functions SELECT array_append(array[42], 6) AS "{42,6}"; SELECT array_prepend(6, array[42]) AS "{6,42}"; ! SELECT array_cat(ARRAY[1,2], ARRAY[3,4]) AS "{{1,2},{3,4}}"; SELECT array_cat(ARRAY[1,2], ARRAY[[3,4],[5,6]]) AS "{{1,2},{3,4},{5,6}}"; SELECT array_cat(ARRAY[[3,4],[5,6]], ARRAY[1,2]) AS "{{3,4},{5,6},{1,2}}"; --- 132,138 ---- -- functions SELECT array_append(array[42], 6) AS "{42,6}"; SELECT array_prepend(6, array[42]) AS "{6,42}"; ! SELECT array_cat(ARRAY[1,2], ARRAY[3,4]) AS "{1,2,3,4}"; SELECT array_cat(ARRAY[1,2], ARRAY[[3,4],[5,6]]) AS "{{1,2},{3,4},{5,6}}"; SELECT array_cat(ARRAY[[3,4],[5,6]], ARRAY[1,2]) AS "{{3,4},{5,6},{1,2}}"; *************** *** 141,150 **** SELECT NOT ARRAY[1.1,1.2,1.3] = ARRAY[1.1,1.2,1.3] AS "FALSE"; SELECT ARRAY[1,2] || 3 AS "{1,2,3}"; SELECT 0 || ARRAY[1,2] AS "{0,1,2}"; ! SELECT ARRAY[1,2] || ARRAY[3,4] AS "{{1,2},{3,4}}"; SELECT ARRAY[[['hello','world']]] || ARRAY[[['happy','birthday']]] AS "ARRAY"; SELECT ARRAY[[1,2],[3,4]] || ARRAY[5,6] AS "{{1,2},{3,4},{5,6}}"; ! SELECT ARRAY[0,0] || ARRAY[1,1] || ARRAY[2,2] AS "{{0,0},{1,1},{2,2}}"; SELECT 0 || ARRAY[1,2] || 3 AS "{0,1,2,3}"; -- array casts --- 141,150 ---- SELECT NOT ARRAY[1.1,1.2,1.3] = ARRAY[1.1,1.2,1.3] AS "FALSE"; SELECT ARRAY[1,2] || 3 AS "{1,2,3}"; SELECT 0 || ARRAY[1,2] AS "{0,1,2}"; ! SELECT ARRAY[1,2] || ARRAY[3,4] AS "{1,2,3,4}"; SELECT ARRAY[[['hello','world']]] || ARRAY[[['happy','birthday']]] AS "ARRAY"; SELECT ARRAY[[1,2],[3,4]] || ARRAY[5,6] AS "{{1,2},{3,4},{5,6}}"; ! SELECT ARRAY[0,0] || ARRAY[1,1] || ARRAY[2,2] AS "{0,0,1,1,2,2}"; SELECT 0 || ARRAY[1,2] || 3 AS "{0,1,2,3}"; -- array casts
Your patch has been added to the PostgreSQL unapplied patches list at: http://momjian.postgresql.org/cgi-bin/pgpatches I will try to apply it within the next 48 hours. --------------------------------------------------------------------------- Joe Conway wrote: > Tom Lane wrote: > > Could you look at how big a change it'd be, anyway? Offhand I think it > > may just mean that the subscript-checking done in parse_expr.c needs to > > be done at runtime instead. Remember parse_expr should only be > > concerned about determining datatype, and for its purposes all arrays of > > a given element type are the same --- subscript checking should happen > > at runtime. (It seems likely that having an ndims field in ArrayExpr > > is inappropriate.) > > The attached patch fixes code and regression tests for the following > (docs to follow once applied): > > ======================================================================== > 1) Array concatenation of equidimensional arrays: > ======================================================================== > regression=# select ARRAY[1,2] || ARRAY[3,4]; > ?column? > ----------- > {1,2,3,4} > (1 row) > > regression=# select ARRAY[[1],[2],[3]] || ARRAY[[4],[5]]; > ?column? > ----------------------- > {{1},{2},{3},{4},{5}} > (1 row) > > regression=# select ARRAY[[1,2],[2,3],[3,4]] || ARRAY[[4,5],[5,6]]; > ?column? > --------------------------------- > {{1,2},{2,3},{3,4},{4,5},{5,6}} > (1 row) > > > ======================================================================== > 2) Array literals or vars in ARRAY expressions: > ======================================================================== > regression=# create table arr(f1 int[], f2 int[]); > CREATE TABLE > regression=# insert into arr values (ARRAY[[1,2],[3,4]],ARRAY[[5,6],[7,8]]); > INSERT 2635544 1 > regression=# select ARRAY[f1,f2] from arr; > array > ------------------------------- > {{{1,2},{3,4}},{{5,6},{7,8}}} > (1 row) > > regression=# select ARRAY['{{1,2},{3,4}}'::int[],'{{5,6},{7,8}}'::int[]]; > array > ------------------------------- > {{{1,2},{3,4}},{{5,6},{7,8}}} > (1 row) > > > ======================================================================== > 3) Lower bound of outer array adjusted downward when an "element" (which > could itself be an array) is concatenated onto the front of an array: > ======================================================================== > regression=# create table arr(f1 int[]); > CREATE TABLE > regression=# insert into arr values ('{}'); > INSERT 2635538 1 > regression=# update arr set f1[-2] = 1; > UPDATE 1 > regression=# select array_lower(f1,1) from arr; > array_lower > ------------- > -2 > (1 row) > > regression=# select array_lower(f1 || 2, 1) from arr; > array_lower > ------------- > -2 > (1 row) > > regression=# select array_lower(0 || f1, 1) from arr; > array_lower > ------------- > -3 > (1 row) > > regression=# update arr set f1 = ARRAY[[1,2],[3,4]]; > UPDATE 1 > regression=# select array_lower(f1,1) from arr; > array_lower > ------------- > 1 > (1 row) > > regression=# select array_lower(f1 || ARRAY[5,6], 1) from arr; > array_lower > ------------- > 1 > (1 row) > > regression=# select array_lower(ARRAY[-1,0] || f1, 1) from arr; > array_lower > ------------- > 0 > (1 row) > > > Compiles without warnings and passes all regression tests. If there are > no objections, please apply. As I mentioned above, docs to follow once > I'm sure what actually ends up being committed. > > Joe > Index: src/backend/executor/execQual.c > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/backend/executor/execQual.c,v > retrieving revision 1.141 > diff -c -r1.141 execQual.c > *** src/backend/executor/execQual.c 8 Aug 2003 21:41:39 -0000 1.141 > --- src/backend/executor/execQual.c 15 Aug 2003 21:52:30 -0000 > *************** > *** 1620,1635 **** > ArrayType *result; > List *element; > Oid element_type = arrayExpr->element_typeid; > ! int ndims = arrayExpr->ndims; > int dims[MAXDIM]; > int lbs[MAXDIM]; > > ! if (ndims == 1) > { > int nelems; > Datum *dvalues; > int i = 0; > > nelems = length(astate->elements); > > /* Shouldn't happen here, but if length is 0, return NULL */ > --- 1620,1637 ---- > ArrayType *result; > List *element; > Oid element_type = arrayExpr->element_typeid; > ! int ndims = 0; > int dims[MAXDIM]; > int lbs[MAXDIM]; > > ! if (!arrayExpr->multidims) > { > + /* Elements are presumably of scalar type */ > int nelems; > Datum *dvalues; > int i = 0; > > + ndims = 1; > nelems = length(astate->elements); > > /* Shouldn't happen here, but if length is 0, return NULL */ > *************** > *** 1667,1672 **** > --- 1669,1675 ---- > } > else > { > + /* Must be nested array expressions */ > char *dat = NULL; > Size ndatabytes = 0; > int nbytes; > *************** > *** 1677,1688 **** > bool firstone = true; > int i; > > - if (ndims <= 0 || ndims > MAXDIM) > - ereport(ERROR, > - (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), > - errmsg("number of array dimensions exceeds the maximum allowed, %d", > - MAXDIM))); > - > /* loop through and get data area from each element */ > foreach(element, astate->elements) > { > --- 1680,1685 ---- > *************** > *** 1705,1714 **** > --- 1702,1719 ---- > { > /* Get sub-array details from first member */ > elem_ndims = ARR_NDIM(array); > + ndims = elem_ndims + 1; > + if (ndims <= 0 || ndims > MAXDIM) > + ereport(ERROR, > + (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), > + errmsg("number of array dimensions exceeds " \ > + "the maximum allowed, %d", MAXDIM))); > + > elem_dims = (int *) palloc(elem_ndims * sizeof(int)); > memcpy(elem_dims, ARR_DIMS(array), elem_ndims * sizeof(int)); > elem_lbs = (int *) palloc(elem_ndims * sizeof(int)); > memcpy(elem_lbs, ARR_LBOUND(array), elem_ndims * sizeof(int)); > + > firstone = false; > } > else > Index: src/backend/nodes/copyfuncs.c > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/backend/nodes/copyfuncs.c,v > retrieving revision 1.263 > diff -c -r1.263 copyfuncs.c > *** src/backend/nodes/copyfuncs.c 8 Aug 2003 21:41:43 -0000 1.263 > --- src/backend/nodes/copyfuncs.c 15 Aug 2003 21:44:30 -0000 > *************** > *** 947,953 **** > COPY_SCALAR_FIELD(array_typeid); > COPY_SCALAR_FIELD(element_typeid); > COPY_NODE_FIELD(elements); > ! COPY_SCALAR_FIELD(ndims); > > return newnode; > } > --- 947,953 ---- > COPY_SCALAR_FIELD(array_typeid); > COPY_SCALAR_FIELD(element_typeid); > COPY_NODE_FIELD(elements); > ! COPY_SCALAR_FIELD(multidims); > > return newnode; > } > Index: src/backend/nodes/equalfuncs.c > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/backend/nodes/equalfuncs.c,v > retrieving revision 1.207 > diff -c -r1.207 equalfuncs.c > *** src/backend/nodes/equalfuncs.c 8 Aug 2003 21:41:43 -0000 1.207 > --- src/backend/nodes/equalfuncs.c 15 Aug 2003 21:44:44 -0000 > *************** > *** 409,415 **** > COMPARE_SCALAR_FIELD(array_typeid); > COMPARE_SCALAR_FIELD(element_typeid); > COMPARE_NODE_FIELD(elements); > ! COMPARE_SCALAR_FIELD(ndims); > > return true; > } > --- 409,415 ---- > COMPARE_SCALAR_FIELD(array_typeid); > COMPARE_SCALAR_FIELD(element_typeid); > COMPARE_NODE_FIELD(elements); > ! COMPARE_SCALAR_FIELD(multidims); > > return true; > } > Index: src/backend/nodes/outfuncs.c > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/backend/nodes/outfuncs.c,v > retrieving revision 1.217 > diff -c -r1.217 outfuncs.c > *** src/backend/nodes/outfuncs.c 8 Aug 2003 21:41:44 -0000 1.217 > --- src/backend/nodes/outfuncs.c 15 Aug 2003 21:45:34 -0000 > *************** > *** 785,791 **** > WRITE_OID_FIELD(array_typeid); > WRITE_OID_FIELD(element_typeid); > WRITE_NODE_FIELD(elements); > ! WRITE_INT_FIELD(ndims); > } > > static void > --- 785,791 ---- > WRITE_OID_FIELD(array_typeid); > WRITE_OID_FIELD(element_typeid); > WRITE_NODE_FIELD(elements); > ! WRITE_BOOL_FIELD(multidims); > } > > static void > Index: src/backend/nodes/readfuncs.c > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/backend/nodes/readfuncs.c,v > retrieving revision 1.161 > diff -c -r1.161 readfuncs.c > *** src/backend/nodes/readfuncs.c 4 Aug 2003 02:39:59 -0000 1.161 > --- src/backend/nodes/readfuncs.c 15 Aug 2003 21:46:05 -0000 > *************** > *** 659,665 **** > READ_OID_FIELD(array_typeid); > READ_OID_FIELD(element_typeid); > READ_NODE_FIELD(elements); > ! READ_INT_FIELD(ndims); > > READ_DONE(); > } > --- 659,665 ---- > READ_OID_FIELD(array_typeid); > READ_OID_FIELD(element_typeid); > READ_NODE_FIELD(elements); > ! READ_BOOL_FIELD(multidims); > > READ_DONE(); > } > Index: src/backend/optimizer/util/clauses.c > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/backend/optimizer/util/clauses.c,v > retrieving revision 1.152 > diff -c -r1.152 clauses.c > *** src/backend/optimizer/util/clauses.c 8 Aug 2003 21:41:55 -0000 1.152 > --- src/backend/optimizer/util/clauses.c 15 Aug 2003 21:48:03 -0000 > *************** > *** 1515,1521 **** > newarray->array_typeid = arrayexpr->array_typeid; > newarray->element_typeid = arrayexpr->element_typeid; > newarray->elements = FastListValue(&newelems); > ! newarray->ndims = arrayexpr->ndims; > > if (all_const) > return (Node *) evaluate_expr((Expr *) newarray, > --- 1515,1521 ---- > newarray->array_typeid = arrayexpr->array_typeid; > newarray->element_typeid = arrayexpr->element_typeid; > newarray->elements = FastListValue(&newelems); > ! newarray->multidims = arrayexpr->multidims; > > if (all_const) > return (Node *) evaluate_expr((Expr *) newarray, > Index: src/backend/parser/parse_expr.c > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/backend/parser/parse_expr.c,v > retrieving revision 1.160 > diff -c -r1.160 parse_expr.c > *** src/backend/parser/parse_expr.c 4 Aug 2003 02:40:01 -0000 1.160 > --- src/backend/parser/parse_expr.c 15 Aug 2003 21:38:10 -0000 > *************** > *** 748,754 **** > List *element; > Oid array_type; > Oid element_type; > - int ndims; > > /* Transform the element expressions */ > foreach(element, a->elements) > --- 748,753 ---- > *************** > *** 781,791 **** > if (array_type != InvalidOid) > { > /* Elements are presumably of scalar type */ > ! ndims = 1; > } > else > { > /* Must be nested array expressions */ > array_type = element_type; > element_type = get_element_type(array_type); > if (!OidIsValid(element_type)) > --- 780,792 ---- > if (array_type != InvalidOid) > { > /* Elements are presumably of scalar type */ > ! newa->multidims = false; > } > else > { > /* Must be nested array expressions */ > + newa->multidims = true; > + > array_type = element_type; > element_type = get_element_type(array_type); > if (!OidIsValid(element_type)) > *************** > *** 793,839 **** > (errcode(ERRCODE_UNDEFINED_OBJECT), > errmsg("could not find array type for datatype %s", > format_type_be(array_type)))); > - > - /* > - * make sure the element expressions all have the same > - * number of dimensions > - */ > - ndims = 0; > - foreach(element, newcoercedelems) > - { > - ArrayExpr *e = (ArrayExpr *) lfirst(element); > - > - if (!IsA(e, ArrayExpr)) > - ereport(ERROR, > - (errcode(ERRCODE_SYNTAX_ERROR), > - errmsg("multidimensional ARRAY[] must be built from nested array expressions"))); > - if (ndims == 0) > - ndims = e->ndims; > - else if (e->ndims != ndims) > - ereport(ERROR, > - (errcode(ERRCODE_SYNTAX_ERROR), > - errmsg("nested array expressions must have common number of dimensions"))); > - if (e->element_typeid != element_type) > - ereport(ERROR, > - (errcode(ERRCODE_SYNTAX_ERROR), > - errmsg("nested array expressions must have common element type"))); > - > - } > - /* increment the number of dimensions */ > - ndims++; > - > - /* make sure we don't have too many dimensions now */ > - if (ndims > MAXDIM) > - ereport(ERROR, > - (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), > - errmsg("number of array dimensions exceeds the maximum allowed, %d", > - MAXDIM))); > } > > newa->array_typeid = array_type; > newa->element_typeid = element_type; > newa->elements = newcoercedelems; > - newa->ndims = ndims; > > result = (Node *) newa; > break; > --- 794,804 ---- > Index: src/backend/utils/adt/array_userfuncs.c > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/backend/utils/adt/array_userfuncs.c,v > retrieving revision 1.7 > diff -c -r1.7 array_userfuncs.c > *** src/backend/utils/adt/array_userfuncs.c 4 Aug 2003 00:43:25 -0000 1.7 > --- src/backend/utils/adt/array_userfuncs.c 15 Aug 2003 22:41:12 -0000 > *************** > *** 132,138 **** > > /*----------------------------------------------------------------------------- > * array_cat : > ! * concatenate two nD arrays to form an (n+1)D array, or > * push an (n-1)D array onto the end of an nD array > *---------------------------------------------------------------------------- > */ > --- 132,138 ---- > > /*----------------------------------------------------------------------------- > * array_cat : > ! * concatenate two nD arrays to form an nD array, or > * push an (n-1)D array onto the end of an nD array > *---------------------------------------------------------------------------- > */ > *************** > *** 223,251 **** > if (ndims1 == ndims2) > { > /* > ! * resulting array has two element outer array made up of input > ! * argument arrays > */ > int i; > > ! ndims = ndims1 + 1; > dims = (int *) palloc(ndims * sizeof(int)); > lbs = (int *) palloc(ndims * sizeof(int)); > > ! dims[0] = 2; /* outer array made up of two input arrays */ > ! lbs[0] = 1; /* start lower bound at 1 */ > > ! for (i = 0; i < ndims1; i++) > { > if (dims1[i] != dims2[i] || lbs1[i] != lbs2[i]) > ereport(ERROR, > (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), > errmsg("cannot concatenate incompatible arrays"), > ! errdetail("Arrays with differing dimensions are not " > ! "compatible for concatenation."))); > > ! dims[i + 1] = dims1[i]; > ! lbs[i + 1] = lbs1[i]; > } > } > else if (ndims1 == ndims2 - 1) > --- 223,251 ---- > if (ndims1 == ndims2) > { > /* > ! * resulting array is made up of the elements (possibly arrays themselves) > ! * of the input argument arrays > */ > int i; > > ! ndims = ndims1; > dims = (int *) palloc(ndims * sizeof(int)); > lbs = (int *) palloc(ndims * sizeof(int)); > > ! dims[0] = dims1[0] + dims2[0]; > ! lbs[0] = lbs1[0]; > > ! for (i = 1; i < ndims; i++) > { > if (dims1[i] != dims2[i] || lbs1[i] != lbs2[i]) > ereport(ERROR, > (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), > errmsg("cannot concatenate incompatible arrays"), > ! errdetail("Arrays with differing element dimensions are " > ! "not compatible for concatenation."))); > > ! dims[i] = dims1[i]; > ! lbs[i] = lbs1[i]; > } > } > else if (ndims1 == ndims2 - 1) > *************** > *** 264,269 **** > --- 264,272 ---- > /* increment number of elements in outer array */ > dims[0] += 1; > > + /* decrement outer array lower bound */ > + lbs[0] -= 1; > + > /* make sure the added element matches our existing elements */ > for (i = 0; i < ndims1; i++) > { > *************** > *** 276,284 **** > } > } > else > - /* (ndims1 == ndims2 + 1) */ > { > ! /* > * resulting array has the first argument as the outer array, with > * the second argument appended to the end of the outer dimension > */ > --- 279,287 ---- > } > } > else > { > ! /* (ndims1 == ndims2 + 1) > ! * > * resulting array has the first argument as the outer array, with > * the second argument appended to the end of the outer dimension > */ > Index: src/include/nodes/primnodes.h > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/include/nodes/primnodes.h,v > retrieving revision 1.91 > diff -c -r1.91 primnodes.h > *** src/include/nodes/primnodes.h 11 Aug 2003 23:04:50 -0000 1.91 > --- src/include/nodes/primnodes.h 15 Aug 2003 21:37:35 -0000 > *************** > *** 596,602 **** > Oid array_typeid; /* type of expression result */ > Oid element_typeid; /* common type of expression elements */ > List *elements; /* the array elements */ > ! int ndims; /* number of array dimensions */ > } ArrayExpr; > > /* > --- 596,602 ---- > Oid array_typeid; /* type of expression result */ > Oid element_typeid; /* common type of expression elements */ > List *elements; /* the array elements */ > ! bool multidims; /* true if elements are also ArrayExprs */ > } ArrayExpr; > > /* > Index: src/test/regress/expected/arrays.out > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/test/regress/expected/arrays.out,v > retrieving revision 1.17 > diff -c -r1.17 arrays.out > *** src/test/regress/expected/arrays.out 21 Jul 2003 20:29:40 -0000 1.17 > --- src/test/regress/expected/arrays.out 15 Aug 2003 23:09:19 -0000 > *************** > *** 190,199 **** > {6,42} > (1 row) > > ! SELECT array_cat(ARRAY[1,2], ARRAY[3,4]) AS "{{1,2},{3,4}}"; > ! {{1,2},{3,4}} > ! --------------- > ! {{1,2},{3,4}} > (1 row) > > SELECT array_cat(ARRAY[1,2], ARRAY[[3,4],[5,6]]) AS "{{1,2},{3,4},{5,6}}"; > --- 190,199 ---- > {6,42} > (1 row) > > ! SELECT array_cat(ARRAY[1,2], ARRAY[3,4]) AS "{1,2,3,4}"; > ! {1,2,3,4} > ! ----------- > ! {1,2,3,4} > (1 row) > > SELECT array_cat(ARRAY[1,2], ARRAY[[3,4],[5,6]]) AS "{{1,2},{3,4},{5,6}}"; > *************** > *** 233,248 **** > {0,1,2} > (1 row) > > ! SELECT ARRAY[1,2] || ARRAY[3,4] AS "{{1,2},{3,4}}"; > ! {{1,2},{3,4}} > ! --------------- > ! {{1,2},{3,4}} > (1 row) > > SELECT ARRAY[[['hello','world']]] || ARRAY[[['happy','birthday']]] AS "ARRAY"; > ! ARRAY > ! ------------------------------------------ > ! {{{{hello,world}}},{{{happy,birthday}}}} > (1 row) > > SELECT ARRAY[[1,2],[3,4]] || ARRAY[5,6] AS "{{1,2},{3,4},{5,6}}"; > --- 233,248 ---- > {0,1,2} > (1 row) > > ! SELECT ARRAY[1,2] || ARRAY[3,4] AS "{1,2,3,4}"; > ! {1,2,3,4} > ! ----------- > ! {1,2,3,4} > (1 row) > > SELECT ARRAY[[['hello','world']]] || ARRAY[[['happy','birthday']]] AS "ARRAY"; > ! ARRAY > ! -------------------------------------- > ! {{{hello,world}},{{happy,birthday}}} > (1 row) > > SELECT ARRAY[[1,2],[3,4]] || ARRAY[5,6] AS "{{1,2},{3,4},{5,6}}"; > *************** > *** 251,260 **** > {{1,2},{3,4},{5,6}} > (1 row) > > ! SELECT ARRAY[0,0] || ARRAY[1,1] || ARRAY[2,2] AS "{{0,0},{1,1},{2,2}}"; > ! {{0,0},{1,1},{2,2}} > ! --------------------- > ! {{0,0},{1,1},{2,2}} > (1 row) > > SELECT 0 || ARRAY[1,2] || 3 AS "{0,1,2,3}"; > --- 251,260 ---- > {{1,2},{3,4},{5,6}} > (1 row) > > ! SELECT ARRAY[0,0] || ARRAY[1,1] || ARRAY[2,2] AS "{0,0,1,1,2,2}"; > ! {0,0,1,1,2,2} > ! --------------- > ! {0,0,1,1,2,2} > (1 row) > > SELECT 0 || ARRAY[1,2] || 3 AS "{0,1,2,3}"; > Index: src/test/regress/sql/arrays.sql > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/test/regress/sql/arrays.sql,v > retrieving revision 1.14 > diff -c -r1.14 arrays.sql > *** src/test/regress/sql/arrays.sql 29 Jun 2003 00:33:44 -0000 1.14 > --- src/test/regress/sql/arrays.sql 15 Aug 2003 23:02:06 -0000 > *************** > *** 132,138 **** > -- functions > SELECT array_append(array[42], 6) AS "{42,6}"; > SELECT array_prepend(6, array[42]) AS "{6,42}"; > ! SELECT array_cat(ARRAY[1,2], ARRAY[3,4]) AS "{{1,2},{3,4}}"; > SELECT array_cat(ARRAY[1,2], ARRAY[[3,4],[5,6]]) AS "{{1,2},{3,4},{5,6}}"; > SELECT array_cat(ARRAY[[3,4],[5,6]], ARRAY[1,2]) AS "{{3,4},{5,6},{1,2}}"; > > --- 132,138 ---- > -- functions > SELECT array_append(array[42], 6) AS "{42,6}"; > SELECT array_prepend(6, array[42]) AS "{6,42}"; > ! SELECT array_cat(ARRAY[1,2], ARRAY[3,4]) AS "{1,2,3,4}"; > SELECT array_cat(ARRAY[1,2], ARRAY[[3,4],[5,6]]) AS "{{1,2},{3,4},{5,6}}"; > SELECT array_cat(ARRAY[[3,4],[5,6]], ARRAY[1,2]) AS "{{3,4},{5,6},{1,2}}"; > > *************** > *** 141,150 **** > SELECT NOT ARRAY[1.1,1.2,1.3] = ARRAY[1.1,1.2,1.3] AS "FALSE"; > SELECT ARRAY[1,2] || 3 AS "{1,2,3}"; > SELECT 0 || ARRAY[1,2] AS "{0,1,2}"; > ! SELECT ARRAY[1,2] || ARRAY[3,4] AS "{{1,2},{3,4}}"; > SELECT ARRAY[[['hello','world']]] || ARRAY[[['happy','birthday']]] AS "ARRAY"; > SELECT ARRAY[[1,2],[3,4]] || ARRAY[5,6] AS "{{1,2},{3,4},{5,6}}"; > ! SELECT ARRAY[0,0] || ARRAY[1,1] || ARRAY[2,2] AS "{{0,0},{1,1},{2,2}}"; > SELECT 0 || ARRAY[1,2] || 3 AS "{0,1,2,3}"; > > -- array casts > --- 141,150 ---- > SELECT NOT ARRAY[1.1,1.2,1.3] = ARRAY[1.1,1.2,1.3] AS "FALSE"; > SELECT ARRAY[1,2] || 3 AS "{1,2,3}"; > SELECT 0 || ARRAY[1,2] AS "{0,1,2}"; > ! SELECT ARRAY[1,2] || ARRAY[3,4] AS "{1,2,3,4}"; > SELECT ARRAY[[['hello','world']]] || ARRAY[[['happy','birthday']]] AS "ARRAY"; > SELECT ARRAY[[1,2],[3,4]] || ARRAY[5,6] AS "{{1,2},{3,4},{5,6}}"; > ! SELECT ARRAY[0,0] || ARRAY[1,1] || ARRAY[2,2] AS "{0,0,1,1,2,2}"; > SELECT 0 || ARRAY[1,2] || 3 AS "{0,1,2,3}"; > > -- array casts > > ---------------------------(end of broadcast)--------------------------- > TIP 2: you can get off all lists at once with the unregister command > (send "unregister YourEmailAddressHere" to majordomo@postgresql.org) -- Bruce Momjian | http://candle.pha.pa.us pgman@candle.pha.pa.us | (610) 359-1001 + If your life is a hard drive, | 13 Roberts Road + Christ can be your backup. | Newtown Square, Pennsylvania 19073
Joe Conway <mail@joeconway.com> writes: > The attached patch fixes code and regression tests for the following > 1) Array concatenation of equidimensional arrays: > 2) Array literals or vars in ARRAY expressions: > 3) Lower bound of outer array adjusted downward when an "element" (which > could itself be an array) is concatenated onto the front of an array: Applied with only marginal changes. (I thought the element-type checks removed from parse_expr.c had better be applied at runtime; and I noticed that array_cat scribbled on its inputs in some cases.) > docs to follow once > I'm sure what actually ends up being committed. You're on the hook for docs fixes... regards, tom lane
Tom Lane wrote: > Applied with only marginal changes. (I thought the element-type checks > removed from parse_expr.c had better be applied at runtime; and > I noticed that array_cat scribbled on its inputs in some cases.) Thanks! > You're on the hook for docs fixes... > I'm on it. Joe
Tom Lane wrote: > You're on the hook for docs fixes... Here's a patch for the documentation updates. Please apply. Thanks, Joe Index: doc/src/sgml/array.sgml =================================================================== RCS file: /opt/src/cvs/pgsql-server/doc/src/sgml/array.sgml,v retrieving revision 1.29 diff -c -r1.29 array.sgml *** doc/src/sgml/array.sgml 9 Aug 2003 22:50:21 -0000 1.29 --- doc/src/sgml/array.sgml 19 Aug 2003 05:31:16 -0000 *************** *** 162,168 **** expression syntax is discussed in more detail in <xref linkend="sql-syntax-array-constructors">. </para> - </sect2> <sect2> --- 162,167 ---- *************** *** 326,334 **** <literal>||</literal>. <programlisting> SELECT ARRAY[1,2] || ARRAY[3,4]; ! ?column? ! --------------- ! {{1,2},{3,4}} (1 row) SELECT ARRAY[5,6] || ARRAY[[1,2],[3,4]]; --- 325,333 ---- <literal>||</literal>. <programlisting> SELECT ARRAY[1,2] || ARRAY[3,4]; ! ?column? ! ----------- ! {1,2,3,4} (1 row) SELECT ARRAY[5,6] || ARRAY[[1,2],[3,4]]; *************** *** 337,363 **** {{5,6},{1,2},{3,4}} (1 row) </programlisting> The concatenation operator allows a single element to be pushed on to the beginning or end of a one-dimensional array. It also accepts two <replaceable>N</>-dimensional arrays, or an <replaceable>N</>-dimensional ! and an <replaceable>N+1</>-dimensional array. In the former case, the two ! <replaceable>N</>-dimension arrays become outer elements of an ! <replaceable>N+1</>-dimensional array. In the latter, the ! <replaceable>N</>-dimensional array is added as either the first or last ! outer element of the <replaceable>N+1</>-dimensional array. ! ! When extending an array by concatenation, the subscripts of its existing ! elements are preserved. For example, when pushing ! onto the beginning of an array with one-based subscripts, the resulting ! array has zero-based subscripts: <programlisting> SELECT array_dims(1 || ARRAY[2,3]); array_dims ------------ [0:2] (1 row) </programlisting> </para> --- 336,403 ---- {{5,6},{1,2},{3,4}} (1 row) </programlisting> + </para> + <para> The concatenation operator allows a single element to be pushed on to the beginning or end of a one-dimensional array. It also accepts two <replaceable>N</>-dimensional arrays, or an <replaceable>N</>-dimensional ! and an <replaceable>N+1</>-dimensional array. ! </para> + <para> + When a single element is pushed on to the beginning of a one-dimensional + array, the result is an array with a lower bound subscript equal to + the righthand operand's lower bound subscript, minus one. When a single + element is pushed on to the end of a one-dimensional array, the result is + an array retaining the lower bound of the lefthand operand. For example: <programlisting> SELECT array_dims(1 || ARRAY[2,3]); array_dims ------------ [0:2] (1 row) + + SELECT array_dims(ARRAY[1,2] || 3); + array_dims + ------------ + [1:3] + (1 row) + </programlisting> + </para> + + <para> + When two arrays with an equal number of dimensions are concatenated, the + result retains the lower bound subscript of the lefthand operand's outer + dimension. The result is an array comprising every element of the lefthand + operand followed by every element of the righthand operand. For example: + <programlisting> + SELECT array_dims(ARRAY[1,2] || ARRAY[3,4,5]); + array_dims + ------------ + [1:5] + (1 row) + + SELECT array_dims(ARRAY[[1,2],[3,4]] || ARRAY[[5,6],[7,8],[9,0]]); + array_dims + ------------ + [1:5][1:2] + (1 row) + </programlisting> + </para> + + <para> + When an <replaceable>N</>-dimensional array is pushed on to the beginning + or end of an <replaceable>N+1</>-dimensional array, the result is + analogous to the element-array case above. Each <replaceable>N</>-dimensional + sub-array is essentially an element of the <replaceable>N+1</>-dimensional + array's outer dimension. For example: + <programlisting> + SELECT array_dims(ARRAY[1,2] || ARRAY[[3,4],[5,6]]); + array_dims + ------------ + [0:2][1:2] + (1 row) </programlisting> </para> *************** *** 386,394 **** (1 row) SELECT array_cat(ARRAY[1,2], ARRAY[3,4]); ! array_cat ! --------------- ! {{1,2},{3,4}} (1 row) SELECT array_cat(ARRAY[[1,2],[3,4]], ARRAY[5,6]); --- 426,434 ---- (1 row) SELECT array_cat(ARRAY[1,2], ARRAY[3,4]); ! array_cat ! ----------- ! {1,2,3,4} (1 row) SELECT array_cat(ARRAY[[1,2],[3,4]], ARRAY[5,6]); Index: doc/src/sgml/func.sgml =================================================================== RCS file: /opt/src/cvs/pgsql-server/doc/src/sgml/func.sgml,v retrieving revision 1.167 diff -c -r1.167 func.sgml *** doc/src/sgml/func.sgml 17 Aug 2003 04:52:41 -0000 1.167 --- doc/src/sgml/func.sgml 19 Aug 2003 04:32:27 -0000 *************** *** 7093,7099 **** <entry> <literal>||</literal> </entry> <entry>array-to-array concatenation</entry> <entry><literal>ARRAY[1,2,3] || ARRAY[4,5,6]</literal></entry> ! <entry><literal>{{1,2,3},{4,5,6}}</literal></entry> </row> <row> --- 7093,7099 ---- <entry> <literal>||</literal> </entry> <entry>array-to-array concatenation</entry> <entry><literal>ARRAY[1,2,3] || ARRAY[4,5,6]</literal></entry> ! <entry><literal>{1,2,3,4,5,6}</literal></entry> </row> <row> *************** *** 7121,7126 **** --- 7121,7131 ---- </table> <para> + See <xref linkend="arrays"> for more details with regard to operator + behavior. + </para> + + <para> <xref linkend="array-functions-table"> shows the functions available for use with array types. See <xref linkend="arrays"> for more discussion and examples for the use of these functions. *************** *** 7167,7173 **** for <literal>NULL</literal> inputs </entry> <entry><literal>array_cat(ARRAY[1,2,3], ARRAY[4,5,6])</literal></entry> ! <entry><literal>{{1,2,3},{4,5,6}}</literal></entry> </row> <row> <entry> --- 7172,7178 ---- for <literal>NULL</literal> inputs </entry> <entry><literal>array_cat(ARRAY[1,2,3], ARRAY[4,5,6])</literal></entry> ! <entry><literal>{1,2,3,4,5,6}</literal></entry> </row> <row> <entry> Index: doc/src/sgml/syntax.sgml =================================================================== RCS file: /opt/src/cvs/pgsql-server/doc/src/sgml/syntax.sgml,v retrieving revision 1.82 diff -c -r1.82 syntax.sgml *** doc/src/sgml/syntax.sgml 14 Aug 2003 23:13:27 -0000 1.82 --- doc/src/sgml/syntax.sgml 19 Aug 2003 05:21:49 -0000 *************** *** 1271,1276 **** --- 1271,1298 ---- </para> <para> + Multidimensional array constructor elements can be anything yielding + an array of the proper kind, not only a sub-array construct. For example: + <programlisting> + create table arr(f1 int[], f2 int[]); + CREATE TABLE + insert into arr values (ARRAY[[1,2],[3,4]],ARRAY[[5,6],[7,8]]); + INSERT 2635544 1 + select ARRAY[f1,f2] from arr; + array + ------------------------------- + {{{1,2},{3,4}},{{5,6},{7,8}}} + (1 row) + + select ARRAY['{{1,2},{3,4}}'::int[],'{{5,6},{7,8}}'::int[]]; + array + ------------------------------- + {{{1,2},{3,4}},{{5,6},{7,8}}} + (1 row) + </programlisting> + </para> + + <para> It is also possible to construct an array from the results of a subquery. In this form, the array constructor is written with the keyword <literal>ARRAY</literal> followed by a parenthesized (not
Joe Conway <mail@joeconway.com> writes: > Here's a patch for the documentation updates. Please apply. Applied with one small change --- I thought the last example failed to make the point that the elements of an ARRAY[] construct could be dissimilar. regards, tom lane
Tom applied this patch. Thanks. --------------------------------------------------------------------------- Joe Conway wrote: > Tom Lane wrote: > > Could you look at how big a change it'd be, anyway? Offhand I think it > > may just mean that the subscript-checking done in parse_expr.c needs to > > be done at runtime instead. Remember parse_expr should only be > > concerned about determining datatype, and for its purposes all arrays of > > a given element type are the same --- subscript checking should happen > > at runtime. (It seems likely that having an ndims field in ArrayExpr > > is inappropriate.) > > The attached patch fixes code and regression tests for the following > (docs to follow once applied): > > ======================================================================== > 1) Array concatenation of equidimensional arrays: > ======================================================================== > regression=# select ARRAY[1,2] || ARRAY[3,4]; > ?column? > ----------- > {1,2,3,4} > (1 row) > > regression=# select ARRAY[[1],[2],[3]] || ARRAY[[4],[5]]; > ?column? > ----------------------- > {{1},{2},{3},{4},{5}} > (1 row) > > regression=# select ARRAY[[1,2],[2,3],[3,4]] || ARRAY[[4,5],[5,6]]; > ?column? > --------------------------------- > {{1,2},{2,3},{3,4},{4,5},{5,6}} > (1 row) > > > ======================================================================== > 2) Array literals or vars in ARRAY expressions: > ======================================================================== > regression=# create table arr(f1 int[], f2 int[]); > CREATE TABLE > regression=# insert into arr values (ARRAY[[1,2],[3,4]],ARRAY[[5,6],[7,8]]); > INSERT 2635544 1 > regression=# select ARRAY[f1,f2] from arr; > array > ------------------------------- > {{{1,2},{3,4}},{{5,6},{7,8}}} > (1 row) > > regression=# select ARRAY['{{1,2},{3,4}}'::int[],'{{5,6},{7,8}}'::int[]]; > array > ------------------------------- > {{{1,2},{3,4}},{{5,6},{7,8}}} > (1 row) > > > ======================================================================== > 3) Lower bound of outer array adjusted downward when an "element" (which > could itself be an array) is concatenated onto the front of an array: > ======================================================================== > regression=# create table arr(f1 int[]); > CREATE TABLE > regression=# insert into arr values ('{}'); > INSERT 2635538 1 > regression=# update arr set f1[-2] = 1; > UPDATE 1 > regression=# select array_lower(f1,1) from arr; > array_lower > ------------- > -2 > (1 row) > > regression=# select array_lower(f1 || 2, 1) from arr; > array_lower > ------------- > -2 > (1 row) > > regression=# select array_lower(0 || f1, 1) from arr; > array_lower > ------------- > -3 > (1 row) > > regression=# update arr set f1 = ARRAY[[1,2],[3,4]]; > UPDATE 1 > regression=# select array_lower(f1,1) from arr; > array_lower > ------------- > 1 > (1 row) > > regression=# select array_lower(f1 || ARRAY[5,6], 1) from arr; > array_lower > ------------- > 1 > (1 row) > > regression=# select array_lower(ARRAY[-1,0] || f1, 1) from arr; > array_lower > ------------- > 0 > (1 row) > > > Compiles without warnings and passes all regression tests. If there are > no objections, please apply. As I mentioned above, docs to follow once > I'm sure what actually ends up being committed. > > Joe > Index: src/backend/executor/execQual.c > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/backend/executor/execQual.c,v > retrieving revision 1.141 > diff -c -r1.141 execQual.c > *** src/backend/executor/execQual.c 8 Aug 2003 21:41:39 -0000 1.141 > --- src/backend/executor/execQual.c 15 Aug 2003 21:52:30 -0000 > *************** > *** 1620,1635 **** > ArrayType *result; > List *element; > Oid element_type = arrayExpr->element_typeid; > ! int ndims = arrayExpr->ndims; > int dims[MAXDIM]; > int lbs[MAXDIM]; > > ! if (ndims == 1) > { > int nelems; > Datum *dvalues; > int i = 0; > > nelems = length(astate->elements); > > /* Shouldn't happen here, but if length is 0, return NULL */ > --- 1620,1637 ---- > ArrayType *result; > List *element; > Oid element_type = arrayExpr->element_typeid; > ! int ndims = 0; > int dims[MAXDIM]; > int lbs[MAXDIM]; > > ! if (!arrayExpr->multidims) > { > + /* Elements are presumably of scalar type */ > int nelems; > Datum *dvalues; > int i = 0; > > + ndims = 1; > nelems = length(astate->elements); > > /* Shouldn't happen here, but if length is 0, return NULL */ > *************** > *** 1667,1672 **** > --- 1669,1675 ---- > } > else > { > + /* Must be nested array expressions */ > char *dat = NULL; > Size ndatabytes = 0; > int nbytes; > *************** > *** 1677,1688 **** > bool firstone = true; > int i; > > - if (ndims <= 0 || ndims > MAXDIM) > - ereport(ERROR, > - (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), > - errmsg("number of array dimensions exceeds the maximum allowed, %d", > - MAXDIM))); > - > /* loop through and get data area from each element */ > foreach(element, astate->elements) > { > --- 1680,1685 ---- > *************** > *** 1705,1714 **** > --- 1702,1719 ---- > { > /* Get sub-array details from first member */ > elem_ndims = ARR_NDIM(array); > + ndims = elem_ndims + 1; > + if (ndims <= 0 || ndims > MAXDIM) > + ereport(ERROR, > + (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), > + errmsg("number of array dimensions exceeds " \ > + "the maximum allowed, %d", MAXDIM))); > + > elem_dims = (int *) palloc(elem_ndims * sizeof(int)); > memcpy(elem_dims, ARR_DIMS(array), elem_ndims * sizeof(int)); > elem_lbs = (int *) palloc(elem_ndims * sizeof(int)); > memcpy(elem_lbs, ARR_LBOUND(array), elem_ndims * sizeof(int)); > + > firstone = false; > } > else > Index: src/backend/nodes/copyfuncs.c > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/backend/nodes/copyfuncs.c,v > retrieving revision 1.263 > diff -c -r1.263 copyfuncs.c > *** src/backend/nodes/copyfuncs.c 8 Aug 2003 21:41:43 -0000 1.263 > --- src/backend/nodes/copyfuncs.c 15 Aug 2003 21:44:30 -0000 > *************** > *** 947,953 **** > COPY_SCALAR_FIELD(array_typeid); > COPY_SCALAR_FIELD(element_typeid); > COPY_NODE_FIELD(elements); > ! COPY_SCALAR_FIELD(ndims); > > return newnode; > } > --- 947,953 ---- > COPY_SCALAR_FIELD(array_typeid); > COPY_SCALAR_FIELD(element_typeid); > COPY_NODE_FIELD(elements); > ! COPY_SCALAR_FIELD(multidims); > > return newnode; > } > Index: src/backend/nodes/equalfuncs.c > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/backend/nodes/equalfuncs.c,v > retrieving revision 1.207 > diff -c -r1.207 equalfuncs.c > *** src/backend/nodes/equalfuncs.c 8 Aug 2003 21:41:43 -0000 1.207 > --- src/backend/nodes/equalfuncs.c 15 Aug 2003 21:44:44 -0000 > *************** > *** 409,415 **** > COMPARE_SCALAR_FIELD(array_typeid); > COMPARE_SCALAR_FIELD(element_typeid); > COMPARE_NODE_FIELD(elements); > ! COMPARE_SCALAR_FIELD(ndims); > > return true; > } > --- 409,415 ---- > COMPARE_SCALAR_FIELD(array_typeid); > COMPARE_SCALAR_FIELD(element_typeid); > COMPARE_NODE_FIELD(elements); > ! COMPARE_SCALAR_FIELD(multidims); > > return true; > } > Index: src/backend/nodes/outfuncs.c > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/backend/nodes/outfuncs.c,v > retrieving revision 1.217 > diff -c -r1.217 outfuncs.c > *** src/backend/nodes/outfuncs.c 8 Aug 2003 21:41:44 -0000 1.217 > --- src/backend/nodes/outfuncs.c 15 Aug 2003 21:45:34 -0000 > *************** > *** 785,791 **** > WRITE_OID_FIELD(array_typeid); > WRITE_OID_FIELD(element_typeid); > WRITE_NODE_FIELD(elements); > ! WRITE_INT_FIELD(ndims); > } > > static void > --- 785,791 ---- > WRITE_OID_FIELD(array_typeid); > WRITE_OID_FIELD(element_typeid); > WRITE_NODE_FIELD(elements); > ! WRITE_BOOL_FIELD(multidims); > } > > static void > Index: src/backend/nodes/readfuncs.c > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/backend/nodes/readfuncs.c,v > retrieving revision 1.161 > diff -c -r1.161 readfuncs.c > *** src/backend/nodes/readfuncs.c 4 Aug 2003 02:39:59 -0000 1.161 > --- src/backend/nodes/readfuncs.c 15 Aug 2003 21:46:05 -0000 > *************** > *** 659,665 **** > READ_OID_FIELD(array_typeid); > READ_OID_FIELD(element_typeid); > READ_NODE_FIELD(elements); > ! READ_INT_FIELD(ndims); > > READ_DONE(); > } > --- 659,665 ---- > READ_OID_FIELD(array_typeid); > READ_OID_FIELD(element_typeid); > READ_NODE_FIELD(elements); > ! READ_BOOL_FIELD(multidims); > > READ_DONE(); > } > Index: src/backend/optimizer/util/clauses.c > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/backend/optimizer/util/clauses.c,v > retrieving revision 1.152 > diff -c -r1.152 clauses.c > *** src/backend/optimizer/util/clauses.c 8 Aug 2003 21:41:55 -0000 1.152 > --- src/backend/optimizer/util/clauses.c 15 Aug 2003 21:48:03 -0000 > *************** > *** 1515,1521 **** > newarray->array_typeid = arrayexpr->array_typeid; > newarray->element_typeid = arrayexpr->element_typeid; > newarray->elements = FastListValue(&newelems); > ! newarray->ndims = arrayexpr->ndims; > > if (all_const) > return (Node *) evaluate_expr((Expr *) newarray, > --- 1515,1521 ---- > newarray->array_typeid = arrayexpr->array_typeid; > newarray->element_typeid = arrayexpr->element_typeid; > newarray->elements = FastListValue(&newelems); > ! newarray->multidims = arrayexpr->multidims; > > if (all_const) > return (Node *) evaluate_expr((Expr *) newarray, > Index: src/backend/parser/parse_expr.c > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/backend/parser/parse_expr.c,v > retrieving revision 1.160 > diff -c -r1.160 parse_expr.c > *** src/backend/parser/parse_expr.c 4 Aug 2003 02:40:01 -0000 1.160 > --- src/backend/parser/parse_expr.c 15 Aug 2003 21:38:10 -0000 > *************** > *** 748,754 **** > List *element; > Oid array_type; > Oid element_type; > - int ndims; > > /* Transform the element expressions */ > foreach(element, a->elements) > --- 748,753 ---- > *************** > *** 781,791 **** > if (array_type != InvalidOid) > { > /* Elements are presumably of scalar type */ > ! ndims = 1; > } > else > { > /* Must be nested array expressions */ > array_type = element_type; > element_type = get_element_type(array_type); > if (!OidIsValid(element_type)) > --- 780,792 ---- > if (array_type != InvalidOid) > { > /* Elements are presumably of scalar type */ > ! newa->multidims = false; > } > else > { > /* Must be nested array expressions */ > + newa->multidims = true; > + > array_type = element_type; > element_type = get_element_type(array_type); > if (!OidIsValid(element_type)) > *************** > *** 793,839 **** > (errcode(ERRCODE_UNDEFINED_OBJECT), > errmsg("could not find array type for datatype %s", > format_type_be(array_type)))); > - > - /* > - * make sure the element expressions all have the same > - * number of dimensions > - */ > - ndims = 0; > - foreach(element, newcoercedelems) > - { > - ArrayExpr *e = (ArrayExpr *) lfirst(element); > - > - if (!IsA(e, ArrayExpr)) > - ereport(ERROR, > - (errcode(ERRCODE_SYNTAX_ERROR), > - errmsg("multidimensional ARRAY[] must be built from nested array expressions"))); > - if (ndims == 0) > - ndims = e->ndims; > - else if (e->ndims != ndims) > - ereport(ERROR, > - (errcode(ERRCODE_SYNTAX_ERROR), > - errmsg("nested array expressions must have common number of dimensions"))); > - if (e->element_typeid != element_type) > - ereport(ERROR, > - (errcode(ERRCODE_SYNTAX_ERROR), > - errmsg("nested array expressions must have common element type"))); > - > - } > - /* increment the number of dimensions */ > - ndims++; > - > - /* make sure we don't have too many dimensions now */ > - if (ndims > MAXDIM) > - ereport(ERROR, > - (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), > - errmsg("number of array dimensions exceeds the maximum allowed, %d", > - MAXDIM))); > } > > newa->array_typeid = array_type; > newa->element_typeid = element_type; > newa->elements = newcoercedelems; > - newa->ndims = ndims; > > result = (Node *) newa; > break; > --- 794,804 ---- > Index: src/backend/utils/adt/array_userfuncs.c > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/backend/utils/adt/array_userfuncs.c,v > retrieving revision 1.7 > diff -c -r1.7 array_userfuncs.c > *** src/backend/utils/adt/array_userfuncs.c 4 Aug 2003 00:43:25 -0000 1.7 > --- src/backend/utils/adt/array_userfuncs.c 15 Aug 2003 22:41:12 -0000 > *************** > *** 132,138 **** > > /*----------------------------------------------------------------------------- > * array_cat : > ! * concatenate two nD arrays to form an (n+1)D array, or > * push an (n-1)D array onto the end of an nD array > *---------------------------------------------------------------------------- > */ > --- 132,138 ---- > > /*----------------------------------------------------------------------------- > * array_cat : > ! * concatenate two nD arrays to form an nD array, or > * push an (n-1)D array onto the end of an nD array > *---------------------------------------------------------------------------- > */ > *************** > *** 223,251 **** > if (ndims1 == ndims2) > { > /* > ! * resulting array has two element outer array made up of input > ! * argument arrays > */ > int i; > > ! ndims = ndims1 + 1; > dims = (int *) palloc(ndims * sizeof(int)); > lbs = (int *) palloc(ndims * sizeof(int)); > > ! dims[0] = 2; /* outer array made up of two input arrays */ > ! lbs[0] = 1; /* start lower bound at 1 */ > > ! for (i = 0; i < ndims1; i++) > { > if (dims1[i] != dims2[i] || lbs1[i] != lbs2[i]) > ereport(ERROR, > (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), > errmsg("cannot concatenate incompatible arrays"), > ! errdetail("Arrays with differing dimensions are not " > ! "compatible for concatenation."))); > > ! dims[i + 1] = dims1[i]; > ! lbs[i + 1] = lbs1[i]; > } > } > else if (ndims1 == ndims2 - 1) > --- 223,251 ---- > if (ndims1 == ndims2) > { > /* > ! * resulting array is made up of the elements (possibly arrays themselves) > ! * of the input argument arrays > */ > int i; > > ! ndims = ndims1; > dims = (int *) palloc(ndims * sizeof(int)); > lbs = (int *) palloc(ndims * sizeof(int)); > > ! dims[0] = dims1[0] + dims2[0]; > ! lbs[0] = lbs1[0]; > > ! for (i = 1; i < ndims; i++) > { > if (dims1[i] != dims2[i] || lbs1[i] != lbs2[i]) > ereport(ERROR, > (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), > errmsg("cannot concatenate incompatible arrays"), > ! errdetail("Arrays with differing element dimensions are " > ! "not compatible for concatenation."))); > > ! dims[i] = dims1[i]; > ! lbs[i] = lbs1[i]; > } > } > else if (ndims1 == ndims2 - 1) > *************** > *** 264,269 **** > --- 264,272 ---- > /* increment number of elements in outer array */ > dims[0] += 1; > > + /* decrement outer array lower bound */ > + lbs[0] -= 1; > + > /* make sure the added element matches our existing elements */ > for (i = 0; i < ndims1; i++) > { > *************** > *** 276,284 **** > } > } > else > - /* (ndims1 == ndims2 + 1) */ > { > ! /* > * resulting array has the first argument as the outer array, with > * the second argument appended to the end of the outer dimension > */ > --- 279,287 ---- > } > } > else > { > ! /* (ndims1 == ndims2 + 1) > ! * > * resulting array has the first argument as the outer array, with > * the second argument appended to the end of the outer dimension > */ > Index: src/include/nodes/primnodes.h > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/include/nodes/primnodes.h,v > retrieving revision 1.91 > diff -c -r1.91 primnodes.h > *** src/include/nodes/primnodes.h 11 Aug 2003 23:04:50 -0000 1.91 > --- src/include/nodes/primnodes.h 15 Aug 2003 21:37:35 -0000 > *************** > *** 596,602 **** > Oid array_typeid; /* type of expression result */ > Oid element_typeid; /* common type of expression elements */ > List *elements; /* the array elements */ > ! int ndims; /* number of array dimensions */ > } ArrayExpr; > > /* > --- 596,602 ---- > Oid array_typeid; /* type of expression result */ > Oid element_typeid; /* common type of expression elements */ > List *elements; /* the array elements */ > ! bool multidims; /* true if elements are also ArrayExprs */ > } ArrayExpr; > > /* > Index: src/test/regress/expected/arrays.out > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/test/regress/expected/arrays.out,v > retrieving revision 1.17 > diff -c -r1.17 arrays.out > *** src/test/regress/expected/arrays.out 21 Jul 2003 20:29:40 -0000 1.17 > --- src/test/regress/expected/arrays.out 15 Aug 2003 23:09:19 -0000 > *************** > *** 190,199 **** > {6,42} > (1 row) > > ! SELECT array_cat(ARRAY[1,2], ARRAY[3,4]) AS "{{1,2},{3,4}}"; > ! {{1,2},{3,4}} > ! --------------- > ! {{1,2},{3,4}} > (1 row) > > SELECT array_cat(ARRAY[1,2], ARRAY[[3,4],[5,6]]) AS "{{1,2},{3,4},{5,6}}"; > --- 190,199 ---- > {6,42} > (1 row) > > ! SELECT array_cat(ARRAY[1,2], ARRAY[3,4]) AS "{1,2,3,4}"; > ! {1,2,3,4} > ! ----------- > ! {1,2,3,4} > (1 row) > > SELECT array_cat(ARRAY[1,2], ARRAY[[3,4],[5,6]]) AS "{{1,2},{3,4},{5,6}}"; > *************** > *** 233,248 **** > {0,1,2} > (1 row) > > ! SELECT ARRAY[1,2] || ARRAY[3,4] AS "{{1,2},{3,4}}"; > ! {{1,2},{3,4}} > ! --------------- > ! {{1,2},{3,4}} > (1 row) > > SELECT ARRAY[[['hello','world']]] || ARRAY[[['happy','birthday']]] AS "ARRAY"; > ! ARRAY > ! ------------------------------------------ > ! {{{{hello,world}}},{{{happy,birthday}}}} > (1 row) > > SELECT ARRAY[[1,2],[3,4]] || ARRAY[5,6] AS "{{1,2},{3,4},{5,6}}"; > --- 233,248 ---- > {0,1,2} > (1 row) > > ! SELECT ARRAY[1,2] || ARRAY[3,4] AS "{1,2,3,4}"; > ! {1,2,3,4} > ! ----------- > ! {1,2,3,4} > (1 row) > > SELECT ARRAY[[['hello','world']]] || ARRAY[[['happy','birthday']]] AS "ARRAY"; > ! ARRAY > ! -------------------------------------- > ! {{{hello,world}},{{happy,birthday}}} > (1 row) > > SELECT ARRAY[[1,2],[3,4]] || ARRAY[5,6] AS "{{1,2},{3,4},{5,6}}"; > *************** > *** 251,260 **** > {{1,2},{3,4},{5,6}} > (1 row) > > ! SELECT ARRAY[0,0] || ARRAY[1,1] || ARRAY[2,2] AS "{{0,0},{1,1},{2,2}}"; > ! {{0,0},{1,1},{2,2}} > ! --------------------- > ! {{0,0},{1,1},{2,2}} > (1 row) > > SELECT 0 || ARRAY[1,2] || 3 AS "{0,1,2,3}"; > --- 251,260 ---- > {{1,2},{3,4},{5,6}} > (1 row) > > ! SELECT ARRAY[0,0] || ARRAY[1,1] || ARRAY[2,2] AS "{0,0,1,1,2,2}"; > ! {0,0,1,1,2,2} > ! --------------- > ! {0,0,1,1,2,2} > (1 row) > > SELECT 0 || ARRAY[1,2] || 3 AS "{0,1,2,3}"; > Index: src/test/regress/sql/arrays.sql > =================================================================== > RCS file: /opt/src/cvs/pgsql-server/src/test/regress/sql/arrays.sql,v > retrieving revision 1.14 > diff -c -r1.14 arrays.sql > *** src/test/regress/sql/arrays.sql 29 Jun 2003 00:33:44 -0000 1.14 > --- src/test/regress/sql/arrays.sql 15 Aug 2003 23:02:06 -0000 > *************** > *** 132,138 **** > -- functions > SELECT array_append(array[42], 6) AS "{42,6}"; > SELECT array_prepend(6, array[42]) AS "{6,42}"; > ! SELECT array_cat(ARRAY[1,2], ARRAY[3,4]) AS "{{1,2},{3,4}}"; > SELECT array_cat(ARRAY[1,2], ARRAY[[3,4],[5,6]]) AS "{{1,2},{3,4},{5,6}}"; > SELECT array_cat(ARRAY[[3,4],[5,6]], ARRAY[1,2]) AS "{{3,4},{5,6},{1,2}}"; > > --- 132,138 ---- > -- functions > SELECT array_append(array[42], 6) AS "{42,6}"; > SELECT array_prepend(6, array[42]) AS "{6,42}"; > ! SELECT array_cat(ARRAY[1,2], ARRAY[3,4]) AS "{1,2,3,4}"; > SELECT array_cat(ARRAY[1,2], ARRAY[[3,4],[5,6]]) AS "{{1,2},{3,4},{5,6}}"; > SELECT array_cat(ARRAY[[3,4],[5,6]], ARRAY[1,2]) AS "{{3,4},{5,6},{1,2}}"; > > *************** > *** 141,150 **** > SELECT NOT ARRAY[1.1,1.2,1.3] = ARRAY[1.1,1.2,1.3] AS "FALSE"; > SELECT ARRAY[1,2] || 3 AS "{1,2,3}"; > SELECT 0 || ARRAY[1,2] AS "{0,1,2}"; > ! SELECT ARRAY[1,2] || ARRAY[3,4] AS "{{1,2},{3,4}}"; > SELECT ARRAY[[['hello','world']]] || ARRAY[[['happy','birthday']]] AS "ARRAY"; > SELECT ARRAY[[1,2],[3,4]] || ARRAY[5,6] AS "{{1,2},{3,4},{5,6}}"; > ! SELECT ARRAY[0,0] || ARRAY[1,1] || ARRAY[2,2] AS "{{0,0},{1,1},{2,2}}"; > SELECT 0 || ARRAY[1,2] || 3 AS "{0,1,2,3}"; > > -- array casts > --- 141,150 ---- > SELECT NOT ARRAY[1.1,1.2,1.3] = ARRAY[1.1,1.2,1.3] AS "FALSE"; > SELECT ARRAY[1,2] || 3 AS "{1,2,3}"; > SELECT 0 || ARRAY[1,2] AS "{0,1,2}"; > ! SELECT ARRAY[1,2] || ARRAY[3,4] AS "{1,2,3,4}"; > SELECT ARRAY[[['hello','world']]] || ARRAY[[['happy','birthday']]] AS "ARRAY"; > SELECT ARRAY[[1,2],[3,4]] || ARRAY[5,6] AS "{{1,2},{3,4},{5,6}}"; > ! SELECT ARRAY[0,0] || ARRAY[1,1] || ARRAY[2,2] AS "{0,0,1,1,2,2}"; > SELECT 0 || ARRAY[1,2] || 3 AS "{0,1,2,3}"; > > -- array casts > > ---------------------------(end of broadcast)--------------------------- > TIP 2: you can get off all lists at once with the unregister command > (send "unregister YourEmailAddressHere" to majordomo@postgresql.org) -- Bruce Momjian | http://candle.pha.pa.us pgman@candle.pha.pa.us | (610) 359-1001 + If your life is a hard drive, | 13 Roberts Road + Christ can be your backup. | Newtown Square, Pennsylvania 19073