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-03-02 04:14:39 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 "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         6845 : array_subscript_transform(SubscriptingRef *sbsref,
      57              :                           List *indirection,
      58              :                           ParseState *pstate,
      59              :                           bool isSlice,
      60              :                           bool isAssignment)
      61              : {
      62         6845 :     List       *upperIndexpr = NIL;
      63         6845 :     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        13838 :     foreach(idx, indirection)
      75              :     {
      76         6993 :         A_Indices  *ai = lfirst_node(A_Indices, idx);
      77              :         Node       *subexpr;
      78              : 
      79         6993 :         if (isSlice)
      80              :         {
      81          310 :             if (ai->lidx)
      82              :             {
      83          244 :                 subexpr = transformExpr(pstate, ai->lidx, pstate->p_expr_kind);
      84              :                 /* If it's not int4 already, try to coerce */
      85          244 :                 subexpr = coerce_to_target_type(pstate,
      86              :                                                 subexpr, exprType(subexpr),
      87              :                                                 INT4OID, -1,
      88              :                                                 COERCION_ASSIGNMENT,
      89              :                                                 COERCE_IMPLICIT_CAST,
      90              :                                                 -1);
      91          244 :                 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           66 :             else if (!ai->is_slice)
      98              :             {
      99              :                 /* Make a constant 1 */
     100           27 :                 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           39 :                 subexpr = NULL;
     112              :             }
     113          310 :             lowerIndexpr = lappend(lowerIndexpr, subexpr);
     114              :         }
     115              :         else
     116              :             Assert(ai->lidx == NULL && !ai->is_slice);
     117              : 
     118         6993 :         if (ai->uidx)
     119              :         {
     120         6954 :             subexpr = transformExpr(pstate, ai->uidx, pstate->p_expr_kind);
     121              :             /* If it's not int4 already, try to coerce */
     122         6954 :             subexpr = coerce_to_target_type(pstate,
     123              :                                             subexpr, exprType(subexpr),
     124              :                                             INT4OID, -1,
     125              :                                             COERCION_ASSIGNMENT,
     126              :                                             COERCE_IMPLICIT_CAST,
     127              :                                             -1);
     128         6954 :             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           39 :             subexpr = NULL;
     139              :         }
     140         6993 :         upperIndexpr = lappend(upperIndexpr, subexpr);
     141              :     }
     142              : 
     143              :     /* ... and store the transformed lists into the SubscriptingRef node */
     144         6845 :     sbsref->refupperindexpr = upperIndexpr;
     145         6845 :     sbsref->reflowerindexpr = lowerIndexpr;
     146              : 
     147              :     /* Verify subscript list lengths are within implementation limit */
     148         6845 :     if (list_length(upperIndexpr) > MAXDIM)
     149            3 :         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         6842 :     if (isSlice)
     162          229 :         sbsref->refrestype = sbsref->refcontainertype;
     163              :     else
     164         6613 :         sbsref->refrestype = sbsref->refelemtype;
     165         6842 : }
     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       444580 : array_subscript_check_subscripts(ExprState *state,
     182              :                                  ExprEvalStep *op,
     183              :                                  ExprContext *econtext)
     184              : {
     185       444580 :     SubscriptingRefState *sbsrefstate = op->d.sbsref_subscript.state;
     186       444580 :     ArraySubWorkspace *workspace = (ArraySubWorkspace *) sbsrefstate->workspace;
     187              : 
     188              :     /* Process upper subscripts */
     189       889386 :     for (int i = 0; i < sbsrefstate->numupper; i++)
     190              :     {
     191       444818 :         if (sbsrefstate->upperprovided[i])
     192              :         {
     193              :             /* If any index expr yields NULL, result is NULL or error */
     194       444746 :             if (sbsrefstate->upperindexnull[i])
     195              :             {
     196           12 :                 if (sbsrefstate->isassignment)
     197            6 :                     ereport(ERROR,
     198              :                             (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
     199              :                              errmsg("array subscript in assignment must not be null")));
     200            6 :                 *op->resnull = true;
     201            6 :                 return false;
     202              :             }
     203       444734 :             workspace->upperindex[i] = DatumGetInt32(sbsrefstate->upperindex[i]);
     204              :         }
     205              :     }
     206              : 
     207              :     /* Likewise for lower subscripts */
     208       445024 :     for (int i = 0; i < sbsrefstate->numlower; i++)
     209              :     {
     210          462 :         if (sbsrefstate->lowerprovided[i])
     211              :         {
     212              :             /* If any index expr yields NULL, result is NULL or error */
     213          399 :             if (sbsrefstate->lowerindexnull[i])
     214              :             {
     215            6 :                 if (sbsrefstate->isassignment)
     216            3 :                     ereport(ERROR,
     217              :                             (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
     218              :                              errmsg("array subscript in assignment must not be null")));
     219            3 :                 *op->resnull = true;
     220            3 :                 return false;
     221              :             }
     222          393 :             workspace->lowerindex[i] = DatumGetInt32(sbsrefstate->lowerindex[i]);
     223              :         }
     224              :     }
     225              : 
     226       444562 :     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       443674 : array_subscript_fetch(ExprState *state,
     238              :                       ExprEvalStep *op,
     239              :                       ExprContext *econtext)
     240              : {
     241       443674 :     SubscriptingRefState *sbsrefstate = op->d.sbsref.state;
     242       443674 :     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       887348 :     *op->resvalue = array_get_element(*op->resvalue,
     248              :                                       sbsrefstate->numupper,
     249       443674 :                                       workspace->upperindex,
     250       443674 :                                       workspace->refattrlength,
     251       443674 :                                       workspace->refelemlength,
     252       443674 :                                       workspace->refelembyval,
     253       443674 :                                       workspace->refelemalign,
     254              :                                       op->resnull);
     255       443674 : }
     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          189 : array_subscript_fetch_slice(ExprState *state,
     266              :                             ExprEvalStep *op,
     267              :                             ExprContext *econtext)
     268              : {
     269          189 :     SubscriptingRefState *sbsrefstate = op->d.sbsref.state;
     270          189 :     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          366 :     *op->resvalue = array_get_slice(*op->resvalue,
     276              :                                     sbsrefstate->numupper,
     277          189 :                                     workspace->upperindex,
     278          189 :                                     workspace->lowerindex,
     279              :                                     sbsrefstate->upperprovided,
     280              :                                     sbsrefstate->lowerprovided,
     281          189 :                                     workspace->refattrlength,
     282          189 :                                     workspace->refelemlength,
     283          189 :                                     workspace->refelembyval,
     284          189 :                                     workspace->refelemalign);
     285              :     /* The slice is never NULL, so no need to change *op->resnull */
     286          177 : }
     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          552 : array_subscript_assign(ExprState *state,
     296              :                        ExprEvalStep *op,
     297              :                        ExprContext *econtext)
     298              : {
     299          552 :     SubscriptingRefState *sbsrefstate = op->d.sbsref.state;
     300          552 :     ArraySubWorkspace *workspace = (ArraySubWorkspace *) sbsrefstate->workspace;
     301          552 :     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          552 :     if (workspace->refattrlength > 0)
     309              :     {
     310           18 :         if (*op->resnull || sbsrefstate->replacenull)
     311            9 :             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          543 :     if (*op->resnull)
     321              :     {
     322          171 :         arraySource = PointerGetDatum(construct_empty_array(workspace->refelemtype));
     323          171 :         *op->resnull = false;
     324              :     }
     325              : 
     326          531 :     *op->resvalue = array_set_element(arraySource,
     327              :                                       sbsrefstate->numupper,
     328          543 :                                       workspace->upperindex,
     329              :                                       sbsrefstate->replacevalue,
     330          543 :                                       sbsrefstate->replacenull,
     331          543 :                                       workspace->refattrlength,
     332          543 :                                       workspace->refelemlength,
     333          543 :                                       workspace->refelembyval,
     334          543 :                                       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          131 : array_subscript_assign_slice(ExprState *state,
     346              :                              ExprEvalStep *op,
     347              :                              ExprContext *econtext)
     348              : {
     349          131 :     SubscriptingRefState *sbsrefstate = op->d.sbsref.state;
     350          131 :     ArraySubWorkspace *workspace = (ArraySubWorkspace *) sbsrefstate->workspace;
     351          131 :     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          131 :     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          131 :     if (*op->resnull)
     371              :     {
     372           28 :         arraySource = PointerGetDatum(construct_empty_array(workspace->refelemtype));
     373           28 :         *op->resnull = false;
     374              :     }
     375              : 
     376          116 :     *op->resvalue = array_set_slice(arraySource,
     377              :                                     sbsrefstate->numupper,
     378          131 :                                     workspace->upperindex,
     379          131 :                                     workspace->lowerindex,
     380              :                                     sbsrefstate->upperprovided,
     381              :                                     sbsrefstate->lowerprovided,
     382              :                                     sbsrefstate->replacevalue,
     383          131 :                                     sbsrefstate->replacenull,
     384          131 :                                     workspace->refattrlength,
     385          131 :                                     workspace->refelemlength,
     386          131 :                                     workspace->refelembyval,
     387          131 :                                     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          138 : array_subscript_fetch_old(ExprState *state,
     401              :                           ExprEvalStep *op,
     402              :                           ExprContext *econtext)
     403              : {
     404          138 :     SubscriptingRefState *sbsrefstate = op->d.sbsref.state;
     405          138 :     ArraySubWorkspace *workspace = (ArraySubWorkspace *) sbsrefstate->workspace;
     406              : 
     407          138 :     if (*op->resnull)
     408              :     {
     409              :         /* whole array is null, so any element is too */
     410           44 :         sbsrefstate->prevvalue = (Datum) 0;
     411           44 :         sbsrefstate->prevnull = true;
     412              :     }
     413              :     else
     414           94 :         sbsrefstate->prevvalue = array_get_element(*op->resvalue,
     415              :                                                    sbsrefstate->numupper,
     416           94 :                                                    workspace->upperindex,
     417           94 :                                                    workspace->refattrlength,
     418           94 :                                                    workspace->refelemlength,
     419           94 :                                                    workspace->refelembyval,
     420           94 :                                                    workspace->refelemalign,
     421              :                                                    &sbsrefstate->prevnull);
     422          138 : }
     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        14046 : array_exec_setup(const SubscriptingRef *sbsref,
     475              :                  SubscriptingRefState *sbsrefstate,
     476              :                  SubscriptExecSteps *methods)
     477              : {
     478        14046 :     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        14046 :     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        14046 :     if (sbsrefstate->numlower != 0 &&
     494          222 :         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        14046 :     workspace = palloc_object(ArraySubWorkspace);
     501        14046 :     sbsrefstate->workspace = workspace;
     502              : 
     503              :     /*
     504              :      * Collect datatype details we'll need at execution.
     505              :      */
     506        14046 :     workspace->refelemtype = sbsref->refelemtype;
     507        14046 :     workspace->refattrlength = get_typlen(sbsref->refcontainertype);
     508        14046 :     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        14046 :     methods->sbs_check_subscripts = array_subscript_check_subscripts;
     517        14046 :     if (is_slice)
     518              :     {
     519          222 :         methods->sbs_fetch = array_subscript_fetch_slice;
     520          222 :         methods->sbs_assign = array_subscript_assign_slice;
     521          222 :         methods->sbs_fetch_old = array_subscript_fetch_old_slice;
     522              :     }
     523              :     else
     524              :     {
     525        13824 :         methods->sbs_fetch = array_subscript_fetch;
     526        13824 :         methods->sbs_assign = array_subscript_assign;
     527        13824 :         methods->sbs_fetch_old = array_subscript_fetch_old;
     528              :     }
     529        14046 : }
     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        19952 : 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        19952 :     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          939 : 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          939 :     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            1 : array_subscript_handler_support(PG_FUNCTION_ARGS)
     587              : {
     588            1 :     Node       *rawreq = (Node *) PG_GETARG_POINTER(0);
     589            1 :     Node       *ret = NULL;
     590              : 
     591            1 :     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            1 :         SupportRequestModifyInPlace *req = (SupportRequestModifyInPlace *) rawreq;
     601            1 :         Param      *refexpr = (Param *) linitial(req->args);
     602              : 
     603            1 :         if (refexpr && IsA(refexpr, Param) &&
     604            1 :             refexpr->paramkind == PARAM_EXTERN &&
     605            1 :             refexpr->paramid == req->paramid &&
     606            1 :             lsecond(req->args) != NULL)
     607            1 :             ret = (Node *) refexpr;
     608              :     }
     609              : 
     610            1 :     PG_RETURN_POINTER(ret);
     611              : }
        

Generated by: LCOV version 2.0-1