*
   * NOTE: if we get a NULL result from a subscript expression, we return NULL
   * when it's an array reference, or raise an error when it's an assignment.
 - *
 - * NOTE: we deliberately refrain from applying DatumGetArrayTypeP() here,
 - * even though that might seem natural, because this code needs to support
 - * both varlena arrays and fixed-length array types.  DatumGetArrayTypeP()
 - * only works for the varlena kind.  The routines we call in arrayfuncs.c
 - * have to know the difference (that's what they need refattrlength for).
   *----------
   */
  static Datum
                   ExprDoneCond *isDone)
  {
     ArrayRef   *arrayRef = (ArrayRef *) astate->xprstate.expr;
 -   ArrayType  *array_source;
 -   ArrayType  *resultArray;
 +   Datum       array_source;
     bool        isAssignment = (arrayRef->refassgnexpr != NULL);
     bool        eisnull;
     ListCell   *l;
                  lower;
     int        *lIndex;
  
 -   array_source = (ArrayType *)
 -       DatumGetPointer(ExecEvalExpr(astate->refexpr,
 -                                    econtext,
 -                                    isNull,
 -                                    isDone));
 +   array_source = ExecEvalExpr(astate->refexpr,
 +                               econtext,
 +                               isNull,
 +                               isDone);
  
     /*
      * If refexpr yields NULL, and it's a fetch, then result is NULL. In the
              }
             else if (lIndex == NULL)
             {
 -               econtext->caseValue_datum = array_ref(array_source, i,
 -                                                     upper.indx,
 -                                                     astate->refattrlength,
 -                                                     astate->refelemlength,
 -                                                     astate->refelembyval,
 -                                                     astate->refelemalign,
 -                                               &econtext->caseValue_isNull);
 +               econtext->caseValue_datum =
 +                   array_get_element(array_source, i,
 +                                     upper.indx,
 +                                     astate->refattrlength,
 +                                     astate->refelemlength,
 +                                     astate->refelembyval,
 +                                     astate->refelemalign,
 +                                     &econtext->caseValue_isNull);
             }
             else
             {
 -               resultArray = array_get_slice(array_source, i,
 -                                             upper.indx, lower.indx,
 -                                             astate->refattrlength,
 -                                             astate->refelemlength,
 -                                             astate->refelembyval,
 -                                             astate->refelemalign);
 -               econtext->caseValue_datum = PointerGetDatum(resultArray);
 +               econtext->caseValue_datum =
 +                   array_get_slice(array_source, i,
 +                                   upper.indx, lower.indx,
 +                                   astate->refattrlength,
 +                                   astate->refelemlength,
 +                                   astate->refelembyval,
 +                                   astate->refelemalign);
                 econtext->caseValue_isNull = false;
             }
         }
           */
         if (astate->refattrlength > 0)  /* fixed-length array? */
             if (eisnull || *isNull)
 -               return PointerGetDatum(array_source);
 +               return array_source;
  
         /*
          * For assignment to varlena arrays, we handle a NULL original array
           */
         if (*isNull)
         {
 -           array_source = construct_empty_array(arrayRef->refelemtype);
 +           array_source = PointerGetDatum(construct_empty_array(arrayRef->refelemtype));
             *isNull = false;
         }
  
         if (lIndex == NULL)
 -           resultArray = array_set(array_source, i,
 -                                   upper.indx,
 -                                   sourceData,
 -                                   eisnull,
 -                                   astate->refattrlength,
 -                                   astate->refelemlength,
 -                                   astate->refelembyval,
 -                                   astate->refelemalign);
 +           return array_set_element(array_source, i,
 +                                    upper.indx,
 +                                    sourceData,
 +                                    eisnull,
 +                                    astate->refattrlength,
 +                                    astate->refelemlength,
 +                                    astate->refelembyval,
 +                                    astate->refelemalign);
         else
 -           resultArray = array_set_slice(array_source, i,
 -                                         upper.indx, lower.indx,
 -                                  (ArrayType *) DatumGetPointer(sourceData),
 -                                         eisnull,
 -                                         astate->refattrlength,
 -                                         astate->refelemlength,
 -                                         astate->refelembyval,
 -                                         astate->refelemalign);
 -       return PointerGetDatum(resultArray);
 +           return array_set_slice(array_source, i,
 +                                  upper.indx, lower.indx,
 +                                  sourceData,
 +                                  eisnull,
 +                                  astate->refattrlength,
 +                                  astate->refelemlength,
 +                                  astate->refelembyval,
 +                                  astate->refelemalign);
     }
  
     if (lIndex == NULL)
 -       return array_ref(array_source, i, upper.indx,
 -                        astate->refattrlength,
 -                        astate->refelemlength,
 -                        astate->refelembyval,
 -                        astate->refelemalign,
 -                        isNull);
 +       return array_get_element(array_source, i,
 +                                upper.indx,
 +                                astate->refattrlength,
 +                                astate->refelemlength,
 +                                astate->refelembyval,
 +                                astate->refelemalign,
 +                                isNull);
     else
 -   {
 -       resultArray = array_get_slice(array_source, i,
 -                                     upper.indx, lower.indx,
 -                                     astate->refattrlength,
 -                                     astate->refelemlength,
 -                                     astate->refelembyval,
 -                                     astate->refelemalign);
 -       return PointerGetDatum(resultArray);
 -   }
 +       return array_get_slice(array_source, i,
 +                              upper.indx, lower.indx,
 +                              astate->refattrlength,
 +                              astate->refelemlength,
 +                              astate->refelembyval,
 +                              astate->refelemalign);
  }
  
  /*
          
  
  /*
 - * array_ref :
 - *   This routine takes an array pointer and a subscript array and returns
 + * array_get_element :
 + *   This routine takes an array datum and a subscript array and returns
   *   the referenced item as a Datum.  Note that for a pass-by-reference
   *   datatype, the returned Datum is a pointer into the array object.
   *
   * This handles both ordinary varlena arrays and fixed-length arrays.
   *
   * Inputs:
 - * array: the array object (mustn't be NULL)
 + * arraydatum: the array object (mustn't be NULL)
   * nSubscripts: number of subscripts supplied
   * indx[]: the subscript values
   * arraytyplen: pg_type.typlen for the array type
    * *isNull is set to indicate whether the element is NULL.
   */
  Datum
 -array_ref(ArrayType *array,
 -         int nSubscripts,
 -         int *indx,
 -         int arraytyplen,
 -         int elmlen,
 -         bool elmbyval,
 -         char elmalign,
 -         bool *isNull)
 +array_get_element(Datum arraydatum,
 +                 int nSubscripts,
 +                 int *indx,
 +                 int arraytyplen,
 +                 int elmlen,
 +                 bool elmbyval,
 +                 char elmalign,
 +                 bool *isNull)
  {
 +   ArrayType  *array;
     int         i,
                 ndim,
                *dim,
          fixedLb[0] = 0;
         dim = fixedDim;
         lb = fixedLb;
 -       arraydataptr = (char *) array;
 +       arraydataptr = (char *) DatumGetPointer(arraydatum);
         arraynullsptr = NULL;
     }
     else
     {
         /* detoast input array if necessary */
 -       array = DatumGetArrayTypeP(PointerGetDatum(array));
 +       array = DatumGetArrayTypeP(arraydatum);
  
         ndim = ARR_NDIM(array);
         dim = ARR_DIMS(array);
    * This handles both ordinary varlena arrays and fixed-length arrays.
   *
   * Inputs:
 - * array: the array object (mustn't be NULL)
 + * arraydatum: the array object (mustn't be NULL)
   * nSubscripts: number of subscripts supplied (must be same for upper/lower)
   * upperIndx[]: the upper subscript values
   * lowerIndx[]: the lower subscript values
    * NOTE: we assume it is OK to scribble on the provided subscript arrays
   * lowerIndx[] and upperIndx[].  These are generally just temporaries.
   */
 -ArrayType *
 -array_get_slice(ArrayType *array,
 +Datum
 +array_get_slice(Datum arraydatum,
                 int nSubscripts,
                 int *upperIndx,
                 int *lowerIndx,
                  bool elmbyval,
                 char elmalign)
  {
 +   ArrayType  *array;
     ArrayType  *newarray;
     int         i,
                 ndim,
          dim = fixedDim;
         lb = fixedLb;
         elemtype = InvalidOid;  /* XXX */
 -       arraydataptr = (char *) array;
 +       arraydataptr = (char *) DatumGetPointer(arraydatum);
         arraynullsptr = NULL;
     }
     else
     {
         /* detoast input array if necessary */
 -       array = DatumGetArrayTypeP(PointerGetDatum(array));
 +       array = DatumGetArrayTypeP(arraydatum);
  
         ndim = ARR_NDIM(array);
         dim = ARR_DIMS(array);
       * slice, return an empty array.
      */
     if (ndim < nSubscripts || ndim <= 0 || ndim > MAXDIM)
 -       return construct_empty_array(elemtype);
 +       return PointerGetDatum(construct_empty_array(elemtype));
  
     for (i = 0; i < nSubscripts; i++)
     {
          if (upperIndx[i] >= (dim[i] + lb[i]))
             upperIndx[i] = dim[i] + lb[i] - 1;
         if (lowerIndx[i] > upperIndx[i])
 -           return construct_empty_array(elemtype);
 +           return PointerGetDatum(construct_empty_array(elemtype));
     }
     /* fill any missing subscript positions with full array range */
     for (; i < ndim; i++)
          lowerIndx[i] = lb[i];
         upperIndx[i] = dim[i] + lb[i] - 1;
         if (lowerIndx[i] > upperIndx[i])
 -           return construct_empty_array(elemtype);
 +           return PointerGetDatum(construct_empty_array(elemtype));
     }
  
     mda_get_range(ndim, span, lowerIndx, upperIndx);
                          lowerIndx, upperIndx,
                         elmlen, elmbyval, elmalign);
  
 -   return newarray;
 +   return PointerGetDatum(newarray);
  }
  
  /*
 - * array_set :
 - *       This routine sets the value of an array element (specified by
 + * array_set_element :
 + *       This routine sets the value of one array element (specified by
   *       a subscript array) to a new value specified by "dataValue".
   *
   * This handles both ordinary varlena arrays and fixed-length arrays.
   *
   * Inputs:
 - * array: the initial array object (mustn't be NULL)
 + * arraydatum: the initial array object (mustn't be NULL)
   * nSubscripts: number of subscripts supplied
   * indx[]: the subscript values
   * dataValue: the datum to be inserted at the given position
    * NOTE: For assignments, we throw an error for invalid subscripts etc,
   * rather than returning a NULL as the fetch operations do.
   */
 -ArrayType *
 -array_set(ArrayType *array,
 -         int nSubscripts,
 -         int *indx,
 -         Datum dataValue,
 -         bool isNull,
 -         int arraytyplen,
 -         int elmlen,
 -         bool elmbyval,
 -         char elmalign)
 +Datum
 +array_set_element(Datum arraydatum,
 +                 int nSubscripts,
 +                 int *indx,
 +                 Datum dataValue,
 +                 bool isNull,
 +                 int arraytyplen,
 +                 int elmlen,
 +                 bool elmbyval,
 +                 char elmalign)
  {
 +   ArrayType  *array;
     ArrayType  *newarray;
     int         i,
                 ndim,
           * fixed-length arrays -- these are assumed to be 1-d, 0-based. We
          * cannot extend them, either.
          */
 +       char       *resultarray;
 +
         if (nSubscripts != 1)
             ereport(ERROR,
                     (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
                      (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
                      errmsg("cannot assign null value to an element of a fixed-length array")));
  
 -       newarray = (ArrayType *) palloc(arraytyplen);
 -       memcpy(newarray, array, arraytyplen);
 -       elt_ptr = (char *) newarray + indx[0] * elmlen;
 +       resultarray = (char *) palloc(arraytyplen);
 +       memcpy(resultarray, DatumGetPointer(arraydatum), arraytyplen);
 +       elt_ptr = (char *) resultarray + indx[0] * elmlen;
         ArrayCastAndSet(dataValue, elmlen, elmbyval, elmalign, elt_ptr);
 -       return newarray;
 +       return PointerGetDatum(resultarray);
     }
  
     if (nSubscripts <= 0 || nSubscripts > MAXDIM)
          dataValue = PointerGetDatum(PG_DETOAST_DATUM(dataValue));
  
     /* detoast input array if necessary */
 -   array = DatumGetArrayTypeP(PointerGetDatum(array));
 +   array = DatumGetArrayTypeP(arraydatum);
  
     ndim = ARR_NDIM(array);
  
              lb[i] = indx[i];
         }
  
 -       return construct_md_array(&dataValue, &isNull, nSubscripts,
 -                                 dim, lb, elmtype,
 -                                 elmlen, elmbyval, elmalign);
 +       return PointerGetDatum(construct_md_array(&dataValue, &isNull,
 +                                                 nSubscripts, dim, lb,
 +                                                 elmtype,
 +                                               elmlen, elmbyval, elmalign));
     }
  
     if (ndim != nSubscripts)
          }
     }
  
 -   return newarray;
 +   return PointerGetDatum(newarray);
  }
  
  /*
    * This handles both ordinary varlena arrays and fixed-length arrays.
   *
   * Inputs:
 - * array: the initial array object (mustn't be NULL)
 + * arraydatum: the initial array object (mustn't be NULL)
   * nSubscripts: number of subscripts supplied (must be same for upper/lower)
   * upperIndx[]: the upper subscript values
   * lowerIndx[]: the lower subscript values
 - * srcArray: the source for the inserted values
 - * isNull: indicates whether srcArray is NULL
 + * srcArrayDatum: the source for the inserted values
 + * isNull: indicates whether srcArrayDatum is NULL
   * arraytyplen: pg_type.typlen for the array type
   * elmlen: pg_type.typlen for the array's element type
   * elmbyval: pg_type.typbyval for the array's element type
    * NOTE: For assignments, we throw an error for silly subscripts etc,
   * rather than returning a NULL or empty array as the fetch operations do.
   */
 -ArrayType *
 -array_set_slice(ArrayType *array,
 +Datum
 +array_set_slice(Datum arraydatum,
                 int nSubscripts,
                 int *upperIndx,
                 int *lowerIndx,
 -               ArrayType *srcArray,
 +               Datum srcArrayDatum,
                 bool isNull,
                 int arraytyplen,
                 int elmlen,
                 bool elmbyval,
                 char elmalign)
  {
 +   ArrayType  *array;
 +   ArrayType  *srcArray;
     ArrayType  *newarray;
     int         i,
                 ndim,
   
     /* Currently, assignment from a NULL source array is a no-op */
     if (isNull)
 -       return array;
 +       return arraydatum;
  
     if (arraytyplen > 0)
     {
      }
  
     /* detoast arrays if necessary */
 -   array = DatumGetArrayTypeP(PointerGetDatum(array));
 -   srcArray = DatumGetArrayTypeP(PointerGetDatum(srcArray));
 +   array = DatumGetArrayTypeP(arraydatum);
 +   srcArray = DatumGetArrayTypeP(srcArrayDatum);
  
     /* note: we assume srcArray contains no toasted elements */
  
                      (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
                      errmsg("source array too small")));
  
 -       return construct_md_array(dvalues, dnulls, nSubscripts,
 -                                 dim, lb, elmtype,
 -                                 elmlen, elmbyval, elmalign);
 +       return PointerGetDatum(construct_md_array(dvalues, dnulls, nSubscripts,
 +                                                 dim, lb, elmtype,
 +                                               elmlen, elmbyval, elmalign));
     }
  
     if (ndim < nSubscripts || ndim <= 0 || ndim > MAXDIM)
          }
     }
  
 -   return newarray;
 +   return PointerGetDatum(newarray);
 +}
 +
 +/*
 + * array_ref : backwards compatibility wrapper for array_get_element
 + *
 + * This only works for detoasted/flattened varlena arrays, since the array
 + * argument is declared as "ArrayType *".  However there's enough code like
 + * that to justify preserving this API.
 + */
 +Datum
 +array_ref(ArrayType *array, int nSubscripts, int *indx,
 +         int arraytyplen, int elmlen, bool elmbyval, char elmalign,
 +         bool *isNull)
 +{
 +   return array_get_element(PointerGetDatum(array), nSubscripts, indx,
 +                            arraytyplen, elmlen, elmbyval, elmalign,
 +                            isNull);
 +}
 +
 +/*
 + * array_set : backwards compatibility wrapper for array_set_element
 + *
 + * This only works for detoasted/flattened varlena arrays, since the array
 + * argument and result are declared as "ArrayType *".  However there's enough
 + * code like that to justify preserving this API.
 + */
 +ArrayType *
 +array_set(ArrayType *array, int nSubscripts, int *indx,
 +         Datum dataValue, bool isNull,
 +         int arraytyplen, int elmlen, bool elmbyval, char elmalign)
 +{
 +   return DatumGetArrayTypeP(array_set_element(PointerGetDatum(array),
 +                                               nSubscripts, indx,
 +                                               dataValue, isNull,
 +                                               arraytyplen,
 +                                               elmlen, elmbyval, elmalign));
  }
  
  /*
          extern Datum array_replace(PG_FUNCTION_ARGS);
  extern Datum width_bucket_array(PG_FUNCTION_ARGS);
  
 +extern Datum array_get_element(Datum arraydatum, int nSubscripts, int *indx,
 +                 int arraytyplen, int elmlen, bool elmbyval, char elmalign,
 +                 bool *isNull);
 +extern Datum array_set_element(Datum arraydatum, int nSubscripts, int *indx,
 +                 Datum dataValue, bool isNull,
 +                 int arraytyplen, int elmlen, bool elmbyval, char elmalign);
 +extern Datum array_get_slice(Datum arraydatum, int nSubscripts,
 +               int *upperIndx, int *lowerIndx,
 +               int arraytyplen, int elmlen, bool elmbyval, char elmalign);
 +extern Datum array_set_slice(Datum arraydatum, int nSubscripts,
 +               int *upperIndx, int *lowerIndx,
 +               Datum srcArrayDatum, bool isNull,
 +               int arraytyplen, int elmlen, bool elmbyval, char elmalign);
 +
  extern Datum array_ref(ArrayType *array, int nSubscripts, int *indx,
           int arraytyplen, int elmlen, bool elmbyval, char elmalign,
           bool *isNull);
  extern ArrayType *array_set(ArrayType *array, int nSubscripts, int *indx,
           Datum dataValue, bool isNull,
           int arraytyplen, int elmlen, bool elmbyval, char elmalign);
 -extern ArrayType *array_get_slice(ArrayType *array, int nSubscripts,
 -               int *upperIndx, int *lowerIndx,
 -               int arraytyplen, int elmlen, bool elmbyval, char elmalign);
 -extern ArrayType *array_set_slice(ArrayType *array, int nSubscripts,
 -               int *upperIndx, int *lowerIndx,
 -               ArrayType *srcArray, bool isNull,
 -               int arraytyplen, int elmlen, bool elmbyval, char elmalign);
  
  extern Datum array_map(FunctionCallInfo fcinfo, Oid inpType, Oid retType,
           ArrayMapState *amstate);