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

Generated by: LCOV version 1.14