Repair bug #2694 concerning an ARRAY[] construct whose inputs are empty
authorTom Lane
Mon, 6 Nov 2006 18:21:31 +0000 (18:21 +0000)
committerTom Lane
Mon, 6 Nov 2006 18:21:31 +0000 (18:21 +0000)
sub-arrays.  Per discussion, if all inputs are empty arrays then result
must be an empty array too, whereas a mix of empty and nonempty arrays
should (and already did) draw an error.  In the back branches, the
construct was strict: any NULL input immediately yielded a NULL output;
so I left that behavior alone.  HEAD was simply ignoring NULL sub-arrays,
which doesn't seem very sensible.  For lack of a better idea it now
treats NULL sub-arrays the same as empty ones.

src/backend/executor/execQual.c

index 943ae62d3d439e7f4232c35f95db99d9d50cfe26..6559947bf1eff7b6dfd22e5da565d32799763ded 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.196 2006/10/06 17:13:59 petere Exp $
+ *   $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.197 2006/11/06 18:21:31 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -2280,6 +2280,7 @@ ExecEvalArray(ArrayExprState *astate, ExprContext *econtext,
        int        *elem_lbs = NULL;
        bool        firstone = true;
        bool        havenulls = false;
+       bool        haveempty = false;
        char      **subdata;
        bits8     **subbitmaps;
        int        *subbytes;
@@ -2302,11 +2303,15 @@ ExecEvalArray(ArrayExprState *astate, ExprContext *econtext,
            bool        eisnull;
            Datum       arraydatum;
            ArrayType  *array;
+           int         this_ndims;
 
            arraydatum = ExecEvalExpr(e, econtext, &eisnull, NULL);
-           /* ignore null subarrays */
+           /* temporarily ignore null subarrays */
            if (eisnull)
+           {
+               haveempty = true;
                continue;
+           }
 
            array = DatumGetArrayTypeP(arraydatum);
 
@@ -2320,10 +2325,18 @@ ExecEvalArray(ArrayExprState *astate, ExprContext *econtext,
                                   format_type_be(ARR_ELEMTYPE(array)),
                                   format_type_be(element_type))));
 
+           this_ndims = ARR_NDIM(array);
+           /* temporarily ignore zero-dimensional subarrays */
+           if (this_ndims <= 0)
+           {
+               haveempty = true;
+               continue;
+           }
+
            if (firstone)
            {
                /* Get sub-array details from first member */
-               elem_ndims = ARR_NDIM(array);
+               elem_ndims = this_ndims;
                ndims = elem_ndims + 1;
                if (ndims <= 0 || ndims > MAXDIM)
                    ereport(ERROR,
@@ -2341,7 +2354,7 @@ ExecEvalArray(ArrayExprState *astate, ExprContext *econtext,
            else
            {
                /* Check other sub-arrays are compatible */
-               if (elem_ndims != ARR_NDIM(array) ||
+               if (elem_ndims != this_ndims ||
                    memcmp(elem_dims, ARR_DIMS(array),
                           elem_ndims * sizeof(int)) != 0 ||
                    memcmp(elem_lbs, ARR_LBOUND(array),
@@ -2356,13 +2369,29 @@ ExecEvalArray(ArrayExprState *astate, ExprContext *econtext,
            subbitmaps[outer_nelems] = ARR_NULLBITMAP(array);
            subbytes[outer_nelems] = ARR_SIZE(array) - ARR_DATA_OFFSET(array);
            nbytes += subbytes[outer_nelems];
-           subnitems[outer_nelems] = ArrayGetNItems(ARR_NDIM(array),
+           subnitems[outer_nelems] = ArrayGetNItems(this_ndims,
                                                     ARR_DIMS(array));
            nitems += subnitems[outer_nelems];
            havenulls |= ARR_HASNULL(array);
            outer_nelems++;
        }
 
+       /*
+        * If all items were null or empty arrays, return an empty array;
+        * otherwise, if some were and some weren't, raise error.  (Note:
+        * we must special-case this somehow to avoid trying to generate
+        * a 1-D array formed from empty arrays.  It's not ideal...)
+        */
+       if (haveempty)
+       {
+           if (ndims == 0)     /* didn't find any nonempty array */
+               return PointerGetDatum(construct_empty_array(element_type));
+           ereport(ERROR,
+                   (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
+                    errmsg("multidimensional arrays must have array "
+                           "expressions with matching dimensions")));
+       }
+
        /* setup for multi-D array */
        dims[0] = outer_nelems;
        lbs[0] = 1;