LCOV - code coverage report
Current view: top level - src/backend/utils/adt - arraysubs.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 87.7 % 171 150
Test Date: 2026-07-22 12:15:41 Functions: 91.7 % 12 11
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 68.5 % 92 63

             Branch data     Line data    Source code
       1                 :             : /*-------------------------------------------------------------------------
       2                 :             :  *
       3                 :             :  * arraysubs.c
       4                 :             :  *    Subscripting support functions for arrays.
       5                 :             :  *
       6                 :             :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
       7                 :             :  * Portions Copyright (c) 1994, Regents of the University of California
       8                 :             :  *
       9                 :             :  *
      10                 :             :  * IDENTIFICATION
      11                 :             :  *    src/backend/utils/adt/arraysubs.c
      12                 :             :  *
      13                 :             :  *-------------------------------------------------------------------------
      14                 :             :  */
      15                 :             : #include "postgres.h"
      16                 :             : 
      17                 :             : #include "catalog/pg_type_d.h"
      18                 :             : #include "executor/execExpr.h"
      19                 :             : #include "nodes/makefuncs.h"
      20                 :             : #include "nodes/nodeFuncs.h"
      21                 :             : #include "nodes/subscripting.h"
      22                 :             : #include "nodes/supportnodes.h"
      23                 :             : #include "parser/parse_coerce.h"
      24                 :             : #include "parser/parse_expr.h"
      25                 :             : #include "utils/array.h"
      26                 :             : #include "utils/fmgrprotos.h"
      27                 :             : #include "utils/lsyscache.h"
      28                 :             : 
      29                 :             : 
      30                 :             : /* SubscriptingRefState.workspace for array subscripting execution */
      31                 :             : typedef struct ArraySubWorkspace
      32                 :             : {
      33                 :             :     /* Values determined during expression compilation */
      34                 :             :     Oid         refelemtype;    /* OID of the array element type */
      35                 :             :     int16       refattrlength;  /* typlen of array type */
      36                 :             :     int16       refelemlength;  /* typlen of the array element type */
      37                 :             :     bool        refelembyval;   /* is the element type pass-by-value? */
      38                 :             :     char        refelemalign;   /* typalign of the element type */
      39                 :             : 
      40                 :             :     /*
      41                 :             :      * Subscript values converted to integers.  Note that these arrays must be
      42                 :             :      * of length MAXDIM even when dealing with fewer subscripts, because
      43                 :             :      * array_get/set_slice may scribble on the extra entries.
      44                 :             :      */
      45                 :             :     int         upperindex[MAXDIM];
      46                 :             :     int         lowerindex[MAXDIM];
      47                 :             : } ArraySubWorkspace;
      48                 :             : 
      49                 :             : 
      50                 :             : /*
      51                 :             :  * Finish parse analysis of a SubscriptingRef expression for an array.
      52                 :             :  *
      53                 :             :  * Transform the subscript expressions, coerce them to integers,
      54                 :             :  * and determine the result type of the SubscriptingRef node.
      55                 :             :  */
      56                 :             : static void
      57                 :        8682 : array_subscript_transform(SubscriptingRef *sbsref,
      58                 :             :                           List *indirection,
      59                 :             :                           ParseState *pstate,
      60                 :             :                           bool isSlice,
      61                 :             :                           bool isAssignment)
      62                 :             : {
      63                 :        8682 :     List       *upperIndexpr = NIL;
      64                 :        8682 :     List       *lowerIndexpr = NIL;
      65                 :             :     ListCell   *idx;
      66                 :             : 
      67                 :             :     /*
      68                 :             :      * Transform the subscript expressions, and separate upper and lower
      69                 :             :      * bounds into two lists.
      70                 :             :      *
      71                 :             :      * If we have a container slice expression, we convert any non-slice
      72                 :             :      * indirection items to slices by treating the single subscript as the
      73                 :             :      * upper bound and supplying an assumed lower bound of 1.
      74                 :             :      */
      75   [ +  -  +  +  :       17562 :     foreach(idx, indirection)
                   +  + ]
      76                 :             :     {
      77                 :        8880 :         A_Indices  *ai = lfirst_node(A_Indices, idx);
      78                 :             :         Node       *subexpr;
      79                 :             : 
      80         [ +  + ]:        8880 :         if (isSlice)
      81                 :             :         {
      82         [ +  + ]:         412 :             if (ai->lidx)
      83                 :             :             {
      84                 :         324 :                 subexpr = transformExpr(pstate, ai->lidx, pstate->p_expr_kind);
      85                 :             :                 /* If it's not int4 already, try to coerce */
      86                 :         324 :                 subexpr = coerce_to_target_type(pstate,
      87                 :             :                                                 subexpr, exprType(subexpr),
      88                 :             :                                                 INT4OID, -1,
      89                 :             :                                                 COERCION_ASSIGNMENT,
      90                 :             :                                                 COERCE_IMPLICIT_CAST,
      91                 :             :                                                 -1);
      92         [ -  + ]:         324 :                 if (subexpr == NULL)
      93         [ #  # ]:           0 :                     ereport(ERROR,
      94                 :             :                             (errcode(ERRCODE_DATATYPE_MISMATCH),
      95                 :             :                              errmsg("array subscript must have type integer"),
      96                 :             :                              parser_errposition(pstate, exprLocation(ai->lidx))));
      97                 :             :             }
      98         [ +  + ]:          88 :             else if (!ai->is_slice)
      99                 :             :             {
     100                 :             :                 /* Make a constant 1 */
     101                 :          36 :                 subexpr = (Node *) makeConst(INT4OID,
     102                 :             :                                              -1,
     103                 :             :                                              InvalidOid,
     104                 :             :                                              sizeof(int32),
     105                 :             :                                              Int32GetDatum(1),
     106                 :             :                                              false,
     107                 :             :                                              true); /* pass by value */
     108                 :             :             }
     109                 :             :             else
     110                 :             :             {
     111                 :             :                 /* Slice with omitted lower bound, put NULL into the list */
     112                 :          52 :                 subexpr = NULL;
     113                 :             :             }
     114                 :         412 :             lowerIndexpr = lappend(lowerIndexpr, subexpr);
     115                 :             :         }
     116                 :             :         else
     117                 :             :             Assert(ai->lidx == NULL && !ai->is_slice);
     118                 :             : 
     119         [ +  + ]:        8880 :         if (ai->uidx)
     120                 :             :         {
     121                 :        8828 :             subexpr = transformExpr(pstate, ai->uidx, pstate->p_expr_kind);
     122                 :             :             /* If it's not int4 already, try to coerce */
     123                 :        8828 :             subexpr = coerce_to_target_type(pstate,
     124                 :             :                                             subexpr, exprType(subexpr),
     125                 :             :                                             INT4OID, -1,
     126                 :             :                                             COERCION_ASSIGNMENT,
     127                 :             :                                             COERCE_IMPLICIT_CAST,
     128                 :             :                                             -1);
     129         [ -  + ]:        8828 :             if (subexpr == NULL)
     130         [ #  # ]:           0 :                 ereport(ERROR,
     131                 :             :                         (errcode(ERRCODE_DATATYPE_MISMATCH),
     132                 :             :                          errmsg("array subscript must have type integer"),
     133                 :             :                          parser_errposition(pstate, exprLocation(ai->uidx))));
     134                 :             :         }
     135                 :             :         else
     136                 :             :         {
     137                 :             :             /* Slice with omitted upper bound, put NULL into the list */
     138                 :             :             Assert(isSlice && ai->is_slice);
     139                 :          52 :             subexpr = NULL;
     140                 :             :         }
     141                 :        8880 :         upperIndexpr = lappend(upperIndexpr, subexpr);
     142                 :             :     }
     143                 :             : 
     144                 :             :     /* ... and store the transformed lists into the SubscriptingRef node */
     145                 :        8682 :     sbsref->refupperindexpr = upperIndexpr;
     146                 :        8682 :     sbsref->reflowerindexpr = lowerIndexpr;
     147                 :             : 
     148                 :             :     /* Verify subscript list lengths are within implementation limit */
     149         [ +  + ]:        8682 :     if (list_length(upperIndexpr) > MAXDIM)
     150         [ +  - ]:           4 :         ereport(ERROR,
     151                 :             :                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     152                 :             :                  errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
     153                 :             :                         list_length(upperIndexpr), MAXDIM)));
     154                 :             :     /* We need not check lowerIndexpr separately */
     155                 :             : 
     156                 :             :     /*
     157                 :             :      * Determine the result type of the subscripting operation.  It's the same
     158                 :             :      * as the array type if we're slicing, else it's the element type.  In
     159                 :             :      * either case, the typmod is the same as the array's, so we need not
     160                 :             :      * change reftypmod.
     161                 :             :      */
     162         [ +  + ]:        8678 :     if (isSlice)
     163                 :         304 :         sbsref->refrestype = sbsref->refcontainertype;
     164                 :             :     else
     165                 :        8374 :         sbsref->refrestype = sbsref->refelemtype;
     166                 :        8678 : }
     167                 :             : 
     168                 :             : /*
     169                 :             :  * During execution, process the subscripts in a SubscriptingRef expression.
     170                 :             :  *
     171                 :             :  * The subscript expressions are already evaluated in Datum form in the
     172                 :             :  * SubscriptingRefState's arrays.  Check and convert them as necessary.
     173                 :             :  *
     174                 :             :  * If any subscript is NULL, we throw error in assignment cases, or in fetch
     175                 :             :  * cases set result to NULL and return false (instructing caller to skip the
     176                 :             :  * rest of the SubscriptingRef sequence).
     177                 :             :  *
     178                 :             :  * We convert all the subscripts to plain integers and save them in the
     179                 :             :  * sbsrefstate->workspace arrays.
     180                 :             :  */
     181                 :             : static bool
     182                 :      515471 : array_subscript_check_subscripts(ExprState *state,
     183                 :             :                                  ExprEvalStep *op,
     184                 :             :                                  ExprContext *econtext)
     185                 :             : {
     186                 :      515471 :     SubscriptingRefState *sbsrefstate = op->d.sbsref_subscript.state;
     187                 :      515471 :     ArraySubWorkspace *workspace = (ArraySubWorkspace *) sbsrefstate->workspace;
     188                 :             : 
     189                 :             :     /* Process upper subscripts */
     190         [ +  + ]:     1031255 :     for (int i = 0; i < sbsrefstate->numupper; i++)
     191                 :             :     {
     192         [ +  + ]:      515802 :         if (sbsrefstate->upperprovided[i])
     193                 :             :         {
     194                 :             :             /* If any index expr yields NULL, result is NULL or error */
     195         [ +  + ]:      515706 :             if (sbsrefstate->upperindexnull[i])
     196                 :             :             {
     197         [ +  + ]:          18 :                 if (sbsrefstate->isassignment)
     198         [ +  - ]:           8 :                     ereport(ERROR,
     199                 :             :                             (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
     200                 :             :                              errmsg("array subscript in assignment must not be null")));
     201                 :          10 :                 *op->resnull = true;
     202                 :          10 :                 return false;
     203                 :             :             }
     204                 :      515688 :             workspace->upperindex[i] = DatumGetInt32(sbsrefstate->upperindex[i]);
     205                 :             :         }
     206                 :             :     }
     207                 :             : 
     208                 :             :     /* Likewise for lower subscripts */
     209         [ +  + ]:      516077 :     for (int i = 0; i < sbsrefstate->numlower; i++)
     210                 :             :     {
     211         [ +  + ]:         633 :         if (sbsrefstate->lowerprovided[i])
     212                 :             :         {
     213                 :             :             /* If any index expr yields NULL, result is NULL or error */
     214         [ +  + ]:         549 :             if (sbsrefstate->lowerindexnull[i])
     215                 :             :             {
     216         [ +  + ]:           9 :                 if (sbsrefstate->isassignment)
     217         [ +  - ]:           4 :                     ereport(ERROR,
     218                 :             :                             (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
     219                 :             :                              errmsg("array subscript in assignment must not be null")));
     220                 :           5 :                 *op->resnull = true;
     221                 :           5 :                 return false;
     222                 :             :             }
     223                 :         540 :             workspace->lowerindex[i] = DatumGetInt32(sbsrefstate->lowerindex[i]);
     224                 :             :         }
     225                 :             :     }
     226                 :             : 
     227                 :      515444 :     return true;
     228                 :             : }
     229                 :             : 
     230                 :             : /*
     231                 :             :  * Evaluate SubscriptingRef fetch for an array element.
     232                 :             :  *
     233                 :             :  * Source container is in step's result variable (it's known not NULL, since
     234                 :             :  * we set fetch_strict to true), and indexes have already been evaluated into
     235                 :             :  * workspace array.
     236                 :             :  */
     237                 :             : static void
     238                 :      514238 : array_subscript_fetch(ExprState *state,
     239                 :             :                       ExprEvalStep *op,
     240                 :             :                       ExprContext *econtext)
     241                 :             : {
     242                 :      514238 :     SubscriptingRefState *sbsrefstate = op->d.sbsref.state;
     243                 :      514238 :     ArraySubWorkspace *workspace = (ArraySubWorkspace *) sbsrefstate->workspace;
     244                 :             : 
     245                 :             :     /* Should not get here if source array (or any subscript) is null */
     246                 :             :     Assert(!(*op->resnull));
     247                 :             : 
     248                 :     1028476 :     *op->resvalue = array_get_element(*op->resvalue,
     249                 :             :                                       sbsrefstate->numupper,
     250                 :      514238 :                                       workspace->upperindex,
     251                 :      514238 :                                       workspace->refattrlength,
     252                 :      514238 :                                       workspace->refelemlength,
     253                 :      514238 :                                       workspace->refelembyval,
     254                 :      514238 :                                       workspace->refelemalign,
     255                 :             :                                       op->resnull);
     256                 :      514238 : }
     257                 :             : 
     258                 :             : /*
     259                 :             :  * Evaluate SubscriptingRef fetch for an array slice.
     260                 :             :  *
     261                 :             :  * Source container is in step's result variable (it's known not NULL, since
     262                 :             :  * we set fetch_strict to true), and indexes have already been evaluated into
     263                 :             :  * workspace array.
     264                 :             :  */
     265                 :             : static void
     266                 :         256 : array_subscript_fetch_slice(ExprState *state,
     267                 :             :                             ExprEvalStep *op,
     268                 :             :                             ExprContext *econtext)
     269                 :             : {
     270                 :         256 :     SubscriptingRefState *sbsrefstate = op->d.sbsref.state;
     271                 :         256 :     ArraySubWorkspace *workspace = (ArraySubWorkspace *) sbsrefstate->workspace;
     272                 :             : 
     273                 :             :     /* Should not get here if source array (or any subscript) is null */
     274                 :             :     Assert(!(*op->resnull));
     275                 :             : 
     276                 :         496 :     *op->resvalue = array_get_slice(*op->resvalue,
     277                 :             :                                     sbsrefstate->numupper,
     278                 :         256 :                                     workspace->upperindex,
     279                 :         256 :                                     workspace->lowerindex,
     280                 :             :                                     sbsrefstate->upperprovided,
     281                 :             :                                     sbsrefstate->lowerprovided,
     282                 :         256 :                                     workspace->refattrlength,
     283                 :         256 :                                     workspace->refelemlength,
     284                 :         256 :                                     workspace->refelembyval,
     285                 :         256 :                                     workspace->refelemalign);
     286                 :             :     /* The slice is never NULL, so no need to change *op->resnull */
     287                 :         240 : }
     288                 :             : 
     289                 :             : /*
     290                 :             :  * Evaluate SubscriptingRef assignment for an array element assignment.
     291                 :             :  *
     292                 :             :  * Input container (possibly null) is in result area, replacement value is in
     293                 :             :  * SubscriptingRefState's replacevalue/replacenull.
     294                 :             :  */
     295                 :             : static void
     296                 :         749 : array_subscript_assign(ExprState *state,
     297                 :             :                        ExprEvalStep *op,
     298                 :             :                        ExprContext *econtext)
     299                 :             : {
     300                 :         749 :     SubscriptingRefState *sbsrefstate = op->d.sbsref.state;
     301                 :         749 :     ArraySubWorkspace *workspace = (ArraySubWorkspace *) sbsrefstate->workspace;
     302                 :         749 :     Datum       arraySource = *op->resvalue;
     303                 :             : 
     304                 :             :     /*
     305                 :             :      * For an assignment to a fixed-length array type, both the original array
     306                 :             :      * and the value to be assigned into it must be non-NULL, else we punt and
     307                 :             :      * return the original array.
     308                 :             :      */
     309         [ +  + ]:         749 :     if (workspace->refattrlength > 0)
     310                 :             :     {
     311   [ +  +  +  + ]:          25 :         if (*op->resnull || sbsrefstate->replacenull)
     312                 :          13 :             return;
     313                 :             :     }
     314                 :             : 
     315                 :             :     /*
     316                 :             :      * For assignment to varlena arrays, we handle a NULL original array by
     317                 :             :      * substituting an empty (zero-dimensional) array; insertion of the new
     318                 :             :      * element will result in a singleton array value.  It does not matter
     319                 :             :      * whether the new element is NULL.
     320                 :             :      */
     321         [ +  + ]:         736 :     if (*op->resnull)
     322                 :             :     {
     323                 :         236 :         arraySource = PointerGetDatum(construct_empty_array(workspace->refelemtype));
     324                 :         236 :         *op->resnull = false;
     325                 :             :     }
     326                 :             : 
     327                 :         720 :     *op->resvalue = array_set_element(arraySource,
     328                 :             :                                       sbsrefstate->numupper,
     329                 :         736 :                                       workspace->upperindex,
     330                 :             :                                       sbsrefstate->replacevalue,
     331                 :         736 :                                       sbsrefstate->replacenull,
     332                 :         736 :                                       workspace->refattrlength,
     333                 :         736 :                                       workspace->refelemlength,
     334                 :         736 :                                       workspace->refelembyval,
     335                 :         736 :                                       workspace->refelemalign);
     336                 :             :     /* The result is never NULL, so no need to change *op->resnull */
     337                 :             : }
     338                 :             : 
     339                 :             : /*
     340                 :             :  * Evaluate SubscriptingRef assignment for an array slice assignment.
     341                 :             :  *
     342                 :             :  * Input container (possibly null) is in result area, replacement value is in
     343                 :             :  * SubscriptingRefState's replacevalue/replacenull.
     344                 :             :  */
     345                 :             : static void
     346                 :         180 : array_subscript_assign_slice(ExprState *state,
     347                 :             :                              ExprEvalStep *op,
     348                 :             :                              ExprContext *econtext)
     349                 :             : {
     350                 :         180 :     SubscriptingRefState *sbsrefstate = op->d.sbsref.state;
     351                 :         180 :     ArraySubWorkspace *workspace = (ArraySubWorkspace *) sbsrefstate->workspace;
     352                 :         180 :     Datum       arraySource = *op->resvalue;
     353                 :             : 
     354                 :             :     /*
     355                 :             :      * For an assignment to a fixed-length array type, both the original array
     356                 :             :      * and the value to be assigned into it must be non-NULL, else we punt and
     357                 :             :      * return the original array.
     358                 :             :      */
     359         [ -  + ]:         180 :     if (workspace->refattrlength > 0)
     360                 :             :     {
     361   [ #  #  #  # ]:           0 :         if (*op->resnull || sbsrefstate->replacenull)
     362                 :           0 :             return;
     363                 :             :     }
     364                 :             : 
     365                 :             :     /*
     366                 :             :      * For assignment to varlena arrays, we handle a NULL original array by
     367                 :             :      * substituting an empty (zero-dimensional) array; insertion of the new
     368                 :             :      * element will result in a singleton array value.  It does not matter
     369                 :             :      * whether the new element is NULL.
     370                 :             :      */
     371         [ +  + ]:         180 :     if (*op->resnull)
     372                 :             :     {
     373                 :          43 :         arraySource = PointerGetDatum(construct_empty_array(workspace->refelemtype));
     374                 :          43 :         *op->resnull = false;
     375                 :             :     }
     376                 :             : 
     377                 :         160 :     *op->resvalue = array_set_slice(arraySource,
     378                 :             :                                     sbsrefstate->numupper,
     379                 :         180 :                                     workspace->upperindex,
     380                 :         180 :                                     workspace->lowerindex,
     381                 :             :                                     sbsrefstate->upperprovided,
     382                 :             :                                     sbsrefstate->lowerprovided,
     383                 :             :                                     sbsrefstate->replacevalue,
     384                 :         180 :                                     sbsrefstate->replacenull,
     385                 :         180 :                                     workspace->refattrlength,
     386                 :         180 :                                     workspace->refelemlength,
     387                 :         180 :                                     workspace->refelembyval,
     388                 :         180 :                                     workspace->refelemalign);
     389                 :             :     /* The result is never NULL, so no need to change *op->resnull */
     390                 :             : }
     391                 :             : 
     392                 :             : /*
     393                 :             :  * Compute old array element value for a SubscriptingRef assignment
     394                 :             :  * expression.  Will only be called if the new-value subexpression
     395                 :             :  * contains SubscriptingRef or FieldStore.  This is the same as the
     396                 :             :  * regular fetch case, except that we have to handle a null array,
     397                 :             :  * and the value should be stored into the SubscriptingRefState's
     398                 :             :  * prevvalue/prevnull fields.
     399                 :             :  */
     400                 :             : static void
     401                 :         183 : array_subscript_fetch_old(ExprState *state,
     402                 :             :                           ExprEvalStep *op,
     403                 :             :                           ExprContext *econtext)
     404                 :             : {
     405                 :         183 :     SubscriptingRefState *sbsrefstate = op->d.sbsref.state;
     406                 :         183 :     ArraySubWorkspace *workspace = (ArraySubWorkspace *) sbsrefstate->workspace;
     407                 :             : 
     408         [ +  + ]:         183 :     if (*op->resnull)
     409                 :             :     {
     410                 :             :         /* whole array is null, so any element is too */
     411                 :          58 :         sbsrefstate->prevvalue = (Datum) 0;
     412                 :          58 :         sbsrefstate->prevnull = true;
     413                 :             :     }
     414                 :             :     else
     415                 :         125 :         sbsrefstate->prevvalue = array_get_element(*op->resvalue,
     416                 :             :                                                    sbsrefstate->numupper,
     417                 :         125 :                                                    workspace->upperindex,
     418                 :         125 :                                                    workspace->refattrlength,
     419                 :         125 :                                                    workspace->refelemlength,
     420                 :         125 :                                                    workspace->refelembyval,
     421                 :         125 :                                                    workspace->refelemalign,
     422                 :             :                                                    &sbsrefstate->prevnull);
     423                 :         183 : }
     424                 :             : 
     425                 :             : /*
     426                 :             :  * Compute old array slice value for a SubscriptingRef assignment
     427                 :             :  * expression.  Will only be called if the new-value subexpression
     428                 :             :  * contains SubscriptingRef or FieldStore.  This is the same as the
     429                 :             :  * regular fetch case, except that we have to handle a null array,
     430                 :             :  * and the value should be stored into the SubscriptingRefState's
     431                 :             :  * prevvalue/prevnull fields.
     432                 :             :  *
     433                 :             :  * Note: this is presently dead code, because the new value for a
     434                 :             :  * slice would have to be an array, so it couldn't directly contain a
     435                 :             :  * FieldStore; nor could it contain a SubscriptingRef assignment, since
     436                 :             :  * we consider adjacent subscripts to index one multidimensional array
     437                 :             :  * not nested array types.  Future generalizations might make this
     438                 :             :  * reachable, however.
     439                 :             :  */
     440                 :             : static void
     441                 :           0 : array_subscript_fetch_old_slice(ExprState *state,
     442                 :             :                                 ExprEvalStep *op,
     443                 :             :                                 ExprContext *econtext)
     444                 :             : {
     445                 :           0 :     SubscriptingRefState *sbsrefstate = op->d.sbsref.state;
     446                 :           0 :     ArraySubWorkspace *workspace = (ArraySubWorkspace *) sbsrefstate->workspace;
     447                 :             : 
     448         [ #  # ]:           0 :     if (*op->resnull)
     449                 :             :     {
     450                 :             :         /* whole array is null, so any slice is too */
     451                 :           0 :         sbsrefstate->prevvalue = (Datum) 0;
     452                 :           0 :         sbsrefstate->prevnull = true;
     453                 :             :     }
     454                 :             :     else
     455                 :             :     {
     456                 :           0 :         sbsrefstate->prevvalue = array_get_slice(*op->resvalue,
     457                 :             :                                                  sbsrefstate->numupper,
     458                 :           0 :                                                  workspace->upperindex,
     459                 :           0 :                                                  workspace->lowerindex,
     460                 :             :                                                  sbsrefstate->upperprovided,
     461                 :             :                                                  sbsrefstate->lowerprovided,
     462                 :           0 :                                                  workspace->refattrlength,
     463                 :           0 :                                                  workspace->refelemlength,
     464                 :           0 :                                                  workspace->refelembyval,
     465                 :           0 :                                                  workspace->refelemalign);
     466                 :             :         /* slices of non-null arrays are never null */
     467                 :           0 :         sbsrefstate->prevnull = false;
     468                 :             :     }
     469                 :           0 : }
     470                 :             : 
     471                 :             : /*
     472                 :             :  * Set up execution state for an array subscript operation.
     473                 :             :  */
     474                 :             : static void
     475                 :       20176 : array_exec_setup(const SubscriptingRef *sbsref,
     476                 :             :                  SubscriptingRefState *sbsrefstate,
     477                 :             :                  SubscriptExecSteps *methods)
     478                 :             : {
     479                 :       20176 :     bool        is_slice = (sbsrefstate->numlower != 0);
     480                 :             :     ArraySubWorkspace *workspace;
     481                 :             : 
     482                 :             :     /*
     483                 :             :      * Enforce the implementation limit on number of array subscripts.  This
     484                 :             :      * check isn't entirely redundant with checking at parse time; conceivably
     485                 :             :      * the expression was stored by a backend with a different MAXDIM value.
     486                 :             :      */
     487         [ -  + ]:       20176 :     if (sbsrefstate->numupper > MAXDIM)
     488         [ #  # ]:           0 :         ereport(ERROR,
     489                 :             :                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
     490                 :             :                  errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
     491                 :             :                         sbsrefstate->numupper, MAXDIM)));
     492                 :             : 
     493                 :             :     /* Should be impossible if parser is sane, but check anyway: */
     494         [ +  + ]:       20176 :     if (sbsrefstate->numlower != 0 &&
     495         [ -  + ]:         307 :         sbsrefstate->numupper != sbsrefstate->numlower)
     496         [ #  # ]:           0 :         elog(ERROR, "upper and lower index lists are not same length");
     497                 :             : 
     498                 :             :     /*
     499                 :             :      * Allocate type-specific workspace.
     500                 :             :      */
     501                 :       20176 :     workspace = palloc_object(ArraySubWorkspace);
     502                 :       20176 :     sbsrefstate->workspace = workspace;
     503                 :             : 
     504                 :             :     /*
     505                 :             :      * Collect datatype details we'll need at execution.
     506                 :             :      */
     507                 :       20176 :     workspace->refelemtype = sbsref->refelemtype;
     508                 :       20176 :     workspace->refattrlength = get_typlen(sbsref->refcontainertype);
     509                 :       20176 :     get_typlenbyvalalign(sbsref->refelemtype,
     510                 :             :                          &workspace->refelemlength,
     511                 :             :                          &workspace->refelembyval,
     512                 :             :                          &workspace->refelemalign);
     513                 :             : 
     514                 :             :     /*
     515                 :             :      * Pass back pointers to appropriate step execution functions.
     516                 :             :      */
     517                 :       20176 :     methods->sbs_check_subscripts = array_subscript_check_subscripts;
     518         [ +  + ]:       20176 :     if (is_slice)
     519                 :             :     {
     520                 :         307 :         methods->sbs_fetch = array_subscript_fetch_slice;
     521                 :         307 :         methods->sbs_assign = array_subscript_assign_slice;
     522                 :         307 :         methods->sbs_fetch_old = array_subscript_fetch_old_slice;
     523                 :             :     }
     524                 :             :     else
     525                 :             :     {
     526                 :       19869 :         methods->sbs_fetch = array_subscript_fetch;
     527                 :       19869 :         methods->sbs_assign = array_subscript_assign;
     528                 :       19869 :         methods->sbs_fetch_old = array_subscript_fetch_old;
     529                 :             :     }
     530                 :       20176 : }
     531                 :             : 
     532                 :             : /*
     533                 :             :  * array_subscript_handler
     534                 :             :  *      Subscripting handler for standard varlena arrays.
     535                 :             :  *
     536                 :             :  * This should be used only for "true" array types, which have array headers
     537                 :             :  * as understood by the varlena array routines, and are referenced by the
     538                 :             :  * element type's pg_type.typarray field.
     539                 :             :  */
     540                 :             : Datum
     541                 :       27931 : array_subscript_handler(PG_FUNCTION_ARGS)
     542                 :             : {
     543                 :             :     static const SubscriptRoutines sbsroutines = {
     544                 :             :         .transform = array_subscript_transform,
     545                 :             :         .exec_setup = array_exec_setup,
     546                 :             :         .fetch_strict = true,   /* fetch returns NULL for NULL inputs */
     547                 :             :         .fetch_leakproof = true,    /* fetch returns NULL for bad subscript */
     548                 :             :         .store_leakproof = false    /* ... but assignment throws error */
     549                 :             :     };
     550                 :             : 
     551                 :       27931 :     PG_RETURN_POINTER(&sbsroutines);
     552                 :             : }
     553                 :             : 
     554                 :             : /*
     555                 :             :  * raw_array_subscript_handler
     556                 :             :  *      Subscripting handler for "raw" arrays.
     557                 :             :  *
     558                 :             :  * A "raw" array just contains N independent instances of the element type.
     559                 :             :  * Currently we require both the element type and the array type to be fixed
     560                 :             :  * length, but it wouldn't be too hard to relax that for the array type.
     561                 :             :  *
     562                 :             :  * As of now, all the support code is shared with standard varlena arrays.
     563                 :             :  * We may split those into separate code paths, but probably that would yield
     564                 :             :  * only marginal speedups.  The main point of having a separate handler is
     565                 :             :  * so that pg_type.typsubscript clearly indicates the type's semantics.
     566                 :             :  */
     567                 :             : Datum
     568                 :         927 : raw_array_subscript_handler(PG_FUNCTION_ARGS)
     569                 :             : {
     570                 :             :     static const SubscriptRoutines sbsroutines = {
     571                 :             :         .transform = array_subscript_transform,
     572                 :             :         .exec_setup = array_exec_setup,
     573                 :             :         .fetch_strict = true,   /* fetch returns NULL for NULL inputs */
     574                 :             :         .fetch_leakproof = true,    /* fetch returns NULL for bad subscript */
     575                 :             :         .store_leakproof = false    /* ... but assignment throws error */
     576                 :             :     };
     577                 :             : 
     578                 :         927 :     PG_RETURN_POINTER(&sbsroutines);
     579                 :             : }
     580                 :             : 
     581                 :             : /*
     582                 :             :  * array_subscript_handler_support()
     583                 :             :  *
     584                 :             :  * Planner support function for array_subscript_handler()
     585                 :             :  */
     586                 :             : Datum
     587                 :           1 : array_subscript_handler_support(PG_FUNCTION_ARGS)
     588                 :             : {
     589                 :           1 :     Node       *rawreq = (Node *) PG_GETARG_POINTER(0);
     590                 :           1 :     Node       *ret = NULL;
     591                 :             : 
     592         [ +  - ]:           1 :     if (IsA(rawreq, SupportRequestModifyInPlace))
     593                 :             :     {
     594                 :             :         /*
     595                 :             :          * We can optimize in-place subscripted assignment if the refexpr is
     596                 :             :          * the array being assigned to.  We don't need to worry about array
     597                 :             :          * references within the refassgnexpr or the subscripts; however, if
     598                 :             :          * there's no refassgnexpr then it's a fetch which there's no need to
     599                 :             :          * optimize.
     600                 :             :          */
     601                 :           1 :         SupportRequestModifyInPlace *req = (SupportRequestModifyInPlace *) rawreq;
     602                 :           1 :         Param      *refexpr = (Param *) linitial(req->args);
     603                 :             : 
     604   [ +  -  +  - ]:           1 :         if (refexpr && IsA(refexpr, Param) &&
     605         [ +  - ]:           1 :             refexpr->paramkind == PARAM_EXTERN &&
     606         [ +  - ]:           1 :             refexpr->paramid == req->paramid &&
     607         [ +  - ]:           1 :             lsecond(req->args) != NULL)
     608                 :           1 :             ret = (Node *) refexpr;
     609                 :             :     }
     610                 :             : 
     611                 :           1 :     PG_RETURN_POINTER(ret);
     612                 :             : }
        

Generated by: LCOV version 2.0-1