Thread: array concat, et al patch (was: [GENERAL] join of array)

array concat, et al patch (was: [GENERAL] join of array)

From
Joe Conway
Date:
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

Re: array concat, et al patch (was: [GENERAL] join of array)

From
Bruce Momjian
Date:
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

Re: array concat, et al patch (was: [GENERAL] join of array)

From
Tom Lane
Date:
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

Re: array concat, et al patch

From
Joe Conway
Date:
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


Re: array concat, et al patch

From
Joe Conway
Date:
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

Re: array concat, et al patch

From
Tom Lane
Date:
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

Re: array concat, et al patch (was: [GENERAL] join of array)

From
Bruce Momjian
Date:
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