LCOV - differential code coverage report
Current view: top level - src/backend/utils/adt - arraysubs.c (source / functions) Coverage Total Hit UBC CBC
Current: Differential Code Coverage HEAD vs 15 Lines: 87.1 % 163 142 21 142
Current Date: 2023-04-08 15:15:32 Functions: 90.9 % 11 10 1 10
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  Line data    Source code
       1                 : /*-------------------------------------------------------------------------
       2                 :  *
       3                 :  * arraysubs.c
       4                 :  *    Subscripting support functions for arrays.
       5                 :  *
       6                 :  * Portions Copyright (c) 1996-2023, 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/builtins.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 CBC        9096 : array_subscript_transform(SubscriptingRef *sbsref,
      56                 :                           List *indirection,
      57                 :                           ParseState *pstate,
      58                 :                           bool isSlice,
      59                 :                           bool isAssignment)
      60                 : {
      61            9096 :     List       *upperIndexpr = NIL;
      62            9096 :     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           18337 :     foreach(idx, indirection)
      74                 :     {
      75            9241 :         A_Indices  *ai = lfirst_node(A_Indices, idx);
      76                 :         Node       *subexpr;
      77                 : 
      78            9241 :         if (isSlice)
      79                 :         {
      80             283 :             if (ai->lidx)
      81                 :             {
      82             217 :                 subexpr = transformExpr(pstate, ai->lidx, pstate->p_expr_kind);
      83                 :                 /* If it's not int4 already, try to coerce */
      84             217 :                 subexpr = coerce_to_target_type(pstate,
      85                 :                                                 subexpr, exprType(subexpr),
      86                 :                                                 INT4OID, -1,
      87                 :                                                 COERCION_ASSIGNMENT,
      88                 :                                                 COERCE_IMPLICIT_CAST,
      89                 :                                                 -1);
      90             217 :                 if (subexpr == NULL)
      91 UBC           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 CBC          66 :             else if (!ai->is_slice)
      97                 :             {
      98                 :                 /* Make a constant 1 */
      99              27 :                 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              39 :                 subexpr = NULL;
     111                 :             }
     112             283 :             lowerIndexpr = lappend(lowerIndexpr, subexpr);
     113                 :         }
     114                 :         else
     115            8958 :             Assert(ai->lidx == NULL && !ai->is_slice);
     116                 : 
     117            9241 :         if (ai->uidx)
     118                 :         {
     119            9202 :             subexpr = transformExpr(pstate, ai->uidx, pstate->p_expr_kind);
     120                 :             /* If it's not int4 already, try to coerce */
     121            9202 :             subexpr = coerce_to_target_type(pstate,
     122                 :                                             subexpr, exprType(subexpr),
     123                 :                                             INT4OID, -1,
     124                 :                                             COERCION_ASSIGNMENT,
     125                 :                                             COERCE_IMPLICIT_CAST,
     126                 :                                             -1);
     127            9202 :             if (subexpr == NULL)
     128 UBC           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 CBC          39 :             Assert(isSlice && ai->is_slice);
     137              39 :             subexpr = NULL;
     138                 :         }
     139            9241 :         upperIndexpr = lappend(upperIndexpr, subexpr);
     140                 :     }
     141                 : 
     142                 :     /* ... and store the transformed lists into the SubscriptRef node */
     143            9096 :     sbsref->refupperindexpr = upperIndexpr;
     144            9096 :     sbsref->reflowerindexpr = lowerIndexpr;
     145                 : 
     146                 :     /* Verify subscript list lengths are within implementation limit */
     147            9096 :     if (list_length(upperIndexpr) > MAXDIM)
     148               3 :         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            9093 :     if (isSlice)
     161             205 :         sbsref->refrestype = sbsref->refcontainertype;
     162                 :     else
     163            8888 :         sbsref->refrestype = sbsref->refelemtype;
     164            9093 : }
     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          331419 : array_subscript_check_subscripts(ExprState *state,
     181                 :                                  ExprEvalStep *op,
     182                 :                                  ExprContext *econtext)
     183                 : {
     184          331419 :     SubscriptingRefState *sbsrefstate = op->d.sbsref_subscript.state;
     185          331419 :     ArraySubWorkspace *workspace = (ArraySubWorkspace *) sbsrefstate->workspace;
     186                 : 
     187                 :     /* Process upper subscripts */
     188          663061 :     for (int i = 0; i < sbsrefstate->numupper; i++)
     189                 :     {
     190          331654 :         if (sbsrefstate->upperprovided[i])
     191                 :         {
     192                 :             /* If any index expr yields NULL, result is NULL or error */
     193          331582 :             if (sbsrefstate->upperindexnull[i])
     194                 :             {
     195              12 :                 if (sbsrefstate->isassignment)
     196               6 :                     ereport(ERROR,
     197                 :                             (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
     198                 :                              errmsg("array subscript in assignment must not be null")));
     199               6 :                 *op->resnull = true;
     200               6 :                 return false;
     201                 :             }
     202          331570 :             workspace->upperindex[i] = DatumGetInt32(sbsrefstate->upperindex[i]);
     203                 :         }
     204                 :     }
     205                 : 
     206                 :     /* Likewise for lower subscripts */
     207          331839 :     for (int i = 0; i < sbsrefstate->numlower; i++)
     208                 :     {
     209             438 :         if (sbsrefstate->lowerprovided[i])
     210                 :         {
     211                 :             /* If any index expr yields NULL, result is NULL or error */
     212             375 :             if (sbsrefstate->lowerindexnull[i])
     213                 :             {
     214               6 :                 if (sbsrefstate->isassignment)
     215               3 :                     ereport(ERROR,
     216                 :                             (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
     217                 :                              errmsg("array subscript in assignment must not be null")));
     218               3 :                 *op->resnull = true;
     219               3 :                 return false;
     220                 :             }
     221             369 :             workspace->lowerindex[i] = DatumGetInt32(sbsrefstate->lowerindex[i]);
     222                 :         }
     223                 :     }
     224                 : 
     225          331401 :     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          330678 : array_subscript_fetch(ExprState *state,
     237                 :                       ExprEvalStep *op,
     238                 :                       ExprContext *econtext)
     239                 : {
     240          330678 :     SubscriptingRefState *sbsrefstate = op->d.sbsref.state;
     241          330678 :     ArraySubWorkspace *workspace = (ArraySubWorkspace *) sbsrefstate->workspace;
     242                 : 
     243                 :     /* Should not get here if source array (or any subscript) is null */
     244          330678 :     Assert(!(*op->resnull));
     245                 : 
     246          661356 :     *op->resvalue = array_get_element(*op->resvalue,
     247                 :                                       sbsrefstate->numupper,
     248          330678 :                                       workspace->upperindex,
     249          330678 :                                       workspace->refattrlength,
     250          330678 :                                       workspace->refelemlength,
     251          330678 :                                       workspace->refelembyval,
     252          330678 :                                       workspace->refelemalign,
     253                 :                                       op->resnull);
     254          330678 : }
     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             177 : array_subscript_fetch_slice(ExprState *state,
     265                 :                             ExprEvalStep *op,
     266                 :                             ExprContext *econtext)
     267                 : {
     268             177 :     SubscriptingRefState *sbsrefstate = op->d.sbsref.state;
     269             177 :     ArraySubWorkspace *workspace = (ArraySubWorkspace *) sbsrefstate->workspace;
     270                 : 
     271                 :     /* Should not get here if source array (or any subscript) is null */
     272             177 :     Assert(!(*op->resnull));
     273                 : 
     274             342 :     *op->resvalue = array_get_slice(*op->resvalue,
     275                 :                                     sbsrefstate->numupper,
     276             177 :                                     workspace->upperindex,
     277             177 :                                     workspace->lowerindex,
     278                 :                                     sbsrefstate->upperprovided,
     279                 :                                     sbsrefstate->lowerprovided,
     280             177 :                                     workspace->refattrlength,
     281             177 :                                     workspace->refelemlength,
     282             177 :                                     workspace->refelembyval,
     283             177 :                                     workspace->refelemalign);
     284                 :     /* The slice is never NULL, so no need to change *op->resnull */
     285             165 : }
     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             408 : array_subscript_assign(ExprState *state,
     295                 :                        ExprEvalStep *op,
     296                 :                        ExprContext *econtext)
     297                 : {
     298             408 :     SubscriptingRefState *sbsrefstate = op->d.sbsref.state;
     299             408 :     ArraySubWorkspace *workspace = (ArraySubWorkspace *) sbsrefstate->workspace;
     300             408 :     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             408 :     if (workspace->refattrlength > 0)
     308                 :     {
     309              18 :         if (*op->resnull || sbsrefstate->replacenull)
     310               9 :             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             399 :     if (*op->resnull)
     320                 :     {
     321             105 :         arraySource = PointerGetDatum(construct_empty_array(workspace->refelemtype));
     322             105 :         *op->resnull = false;
     323                 :     }
     324                 : 
     325             393 :     *op->resvalue = array_set_element(arraySource,
     326                 :                                       sbsrefstate->numupper,
     327             399 :                                       workspace->upperindex,
     328                 :                                       sbsrefstate->replacevalue,
     329             399 :                                       sbsrefstate->replacenull,
     330             399 :                                       workspace->refattrlength,
     331             399 :                                       workspace->refelemlength,
     332             399 :                                       workspace->refelembyval,
     333             399 :                                       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             122 : array_subscript_assign_slice(ExprState *state,
     345                 :                              ExprEvalStep *op,
     346                 :                              ExprContext *econtext)
     347                 : {
     348             122 :     SubscriptingRefState *sbsrefstate = op->d.sbsref.state;
     349             122 :     ArraySubWorkspace *workspace = (ArraySubWorkspace *) sbsrefstate->workspace;
     350             122 :     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             122 :     if (workspace->refattrlength > 0)
     358                 :     {
     359 UBC           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 CBC         122 :     if (*op->resnull)
     370                 :     {
     371              22 :         arraySource = PointerGetDatum(construct_empty_array(workspace->refelemtype));
     372              22 :         *op->resnull = false;
     373                 :     }
     374                 : 
     375             116 :     *op->resvalue = array_set_slice(arraySource,
     376                 :                                     sbsrefstate->numupper,
     377             122 :                                     workspace->upperindex,
     378             122 :                                     workspace->lowerindex,
     379                 :                                     sbsrefstate->upperprovided,
     380                 :                                     sbsrefstate->lowerprovided,
     381                 :                                     sbsrefstate->replacevalue,
     382             122 :                                     sbsrefstate->replacenull,
     383             122 :                                     workspace->refattrlength,
     384             122 :                                     workspace->refelemlength,
     385             122 :                                     workspace->refelembyval,
     386             122 :                                     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             111 : array_subscript_fetch_old(ExprState *state,
     400                 :                           ExprEvalStep *op,
     401                 :                           ExprContext *econtext)
     402                 : {
     403             111 :     SubscriptingRefState *sbsrefstate = op->d.sbsref.state;
     404             111 :     ArraySubWorkspace *workspace = (ArraySubWorkspace *) sbsrefstate->workspace;
     405                 : 
     406             111 :     if (*op->resnull)
     407                 :     {
     408                 :         /* whole array is null, so any element is too */
     409              32 :         sbsrefstate->prevvalue = (Datum) 0;
     410              32 :         sbsrefstate->prevnull = true;
     411                 :     }
     412                 :     else
     413              79 :         sbsrefstate->prevvalue = array_get_element(*op->resvalue,
     414                 :                                                    sbsrefstate->numupper,
     415              79 :                                                    workspace->upperindex,
     416              79 :                                                    workspace->refattrlength,
     417              79 :                                                    workspace->refelemlength,
     418              79 :                                                    workspace->refelembyval,
     419              79 :                                                    workspace->refelemalign,
     420                 :                                                    &sbsrefstate->prevnull);
     421             111 : }
     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 UBC           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 CBC        9257 : array_exec_setup(const SubscriptingRef *sbsref,
     474                 :                  SubscriptingRefState *sbsrefstate,
     475                 :                  SubscriptExecSteps *methods)
     476                 : {
     477            9257 :     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            9257 :     if (sbsrefstate->numupper > MAXDIM)
     486 UBC           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 CBC        9257 :     if (sbsrefstate->numlower != 0 &&
     493             201 :         sbsrefstate->numupper != sbsrefstate->numlower)
     494 UBC           0 :         elog(ERROR, "upper and lower index lists are not same length");
     495                 : 
     496                 :     /*
     497                 :      * Allocate type-specific workspace.
     498                 :      */
     499 CBC        9257 :     workspace = (ArraySubWorkspace *) palloc(sizeof(ArraySubWorkspace));
     500            9257 :     sbsrefstate->workspace = workspace;
     501                 : 
     502                 :     /*
     503                 :      * Collect datatype details we'll need at execution.
     504                 :      */
     505            9257 :     workspace->refelemtype = sbsref->refelemtype;
     506            9257 :     workspace->refattrlength = get_typlen(sbsref->refcontainertype);
     507            9257 :     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            9257 :     methods->sbs_check_subscripts = array_subscript_check_subscripts;
     516            9257 :     if (is_slice)
     517                 :     {
     518             201 :         methods->sbs_fetch = array_subscript_fetch_slice;
     519             201 :         methods->sbs_assign = array_subscript_assign_slice;
     520             201 :         methods->sbs_fetch_old = array_subscript_fetch_old_slice;
     521                 :     }
     522                 :     else
     523                 :     {
     524            9056 :         methods->sbs_fetch = array_subscript_fetch;
     525            9056 :         methods->sbs_assign = array_subscript_assign;
     526            9056 :         methods->sbs_fetch_old = array_subscript_fetch_old;
     527                 :     }
     528            9257 : }
     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           17678 : 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           17678 :     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             675 : 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             675 :     PG_RETURN_POINTER(&sbsroutines);
     577                 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a