Обсуждение: 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