LCOV - code coverage report
Current view: top level - src/backend/utils/adt - arraysubs.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 150 171 87.7 %
Date: 2025-02-21 16:15:14 Functions: 11 12 91.7 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14