LCOV - code coverage report
Current view: top level - src/backend/utils/adt - arraysubs.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 87.7 % 171 150
Test Date: 2026-04-07 14:16:30 Functions: 91.7 % 12 11
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-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         8742 : array_subscript_transform(SubscriptingRef *sbsref,
      58              :                           List *indirection,
      59              :                           ParseState *pstate,
      60              :                           bool isSlice,
      61              :                           bool isAssignment)
      62              : {
      63         8742 :     List       *upperIndexpr = NIL;
      64         8742 :     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        17682 :     foreach(idx, indirection)
      76              :     {
      77         8940 :         A_Indices  *ai = lfirst_node(A_Indices, idx);
      78              :         Node       *subexpr;
      79              : 
      80         8940 :         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         8940 :         if (ai->uidx)
     120              :         {
     121         8888 :             subexpr = transformExpr(pstate, ai->uidx, pstate->p_expr_kind);
     122              :             /* If it's not int4 already, try to coerce */
     123         8888 :             subexpr = coerce_to_target_type(pstate,
     124              :                                             subexpr, exprType(subexpr),
     125              :                                             INT4OID, -1,
     126              :                                             COERCION_ASSIGNMENT,
     127              :                                             COERCE_IMPLICIT_CAST,
     128              :                                             -1);
     129         8888 :             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         8940 :         upperIndexpr = lappend(upperIndexpr, subexpr);
     142              :     }
     143              : 
     144              :     /* ... and store the transformed lists into the SubscriptingRef node */
     145         8742 :     sbsref->refupperindexpr = upperIndexpr;
     146         8742 :     sbsref->reflowerindexpr = lowerIndexpr;
     147              : 
     148              :     /* Verify subscript list lengths are within implementation limit */
     149         8742 :     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         8738 :     if (isSlice)
     163          304 :         sbsref->refrestype = sbsref->refcontainertype;
     164              :     else
     165         8434 :         sbsref->refrestype = sbsref->refelemtype;
     166         8738 : }
     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       572656 : array_subscript_check_subscripts(ExprState *state,
     183              :                                  ExprEvalStep *op,
     184              :                                  ExprContext *econtext)
     185              : {
     186       572656 :     SubscriptingRefState *sbsrefstate = op->d.sbsref_subscript.state;
     187       572656 :     ArraySubWorkspace *workspace = (ArraySubWorkspace *) sbsrefstate->workspace;
     188              : 
     189              :     /* Process upper subscripts */
     190      1145625 :     for (int i = 0; i < sbsrefstate->numupper; i++)
     191              :     {
     192       572987 :         if (sbsrefstate->upperprovided[i])
     193              :         {
     194              :             /* If any index expr yields NULL, result is NULL or error */
     195       572891 :             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       572873 :             workspace->upperindex[i] = DatumGetInt32(sbsrefstate->upperindex[i]);
     205              :         }
     206              :     }
     207              : 
     208              :     /* Likewise for lower subscripts */
     209       573262 :     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       572629 :     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       571423 : array_subscript_fetch(ExprState *state,
     239              :                       ExprEvalStep *op,
     240              :                       ExprContext *econtext)
     241              : {
     242       571423 :     SubscriptingRefState *sbsrefstate = op->d.sbsref.state;
     243       571423 :     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      1142846 :     *op->resvalue = array_get_element(*op->resvalue,
     249              :                                       sbsrefstate->numupper,
     250       571423 :                                       workspace->upperindex,
     251       571423 :                                       workspace->refattrlength,
     252       571423 :                                       workspace->refelemlength,
     253       571423 :                                       workspace->refelembyval,
     254       571423 :                                       workspace->refelemalign,
     255              :                                       op->resnull);
     256       571423 : }
     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        19930 : array_exec_setup(const SubscriptingRef *sbsref,
     476              :                  SubscriptingRefState *sbsrefstate,
     477              :                  SubscriptExecSteps *methods)
     478              : {
     479        19930 :     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        19930 :     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        19930 :     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        19930 :     workspace = palloc_object(ArraySubWorkspace);
     502        19930 :     sbsrefstate->workspace = workspace;
     503              : 
     504              :     /*
     505              :      * Collect datatype details we'll need at execution.
     506              :      */
     507        19930 :     workspace->refelemtype = sbsref->refelemtype;
     508        19930 :     workspace->refattrlength = get_typlen(sbsref->refcontainertype);
     509        19930 :     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        19930 :     methods->sbs_check_subscripts = array_subscript_check_subscripts;
     518        19930 :     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        19623 :         methods->sbs_fetch = array_subscript_fetch;
     527        19623 :         methods->sbs_assign = array_subscript_assign;
     528        19623 :         methods->sbs_fetch_old = array_subscript_fetch_old;
     529              :     }
     530        19930 : }
     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        27617 : 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        27617 :     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         1055 : 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         1055 :     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