PostgreSQL Source Code  git master
arraysubs.c File Reference
#include "postgres.h"
#include "executor/execExpr.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "nodes/subscripting.h"
#include "parser/parse_coerce.h"
#include "parser/parse_expr.h"
#include "utils/array.h"
#include "utils/fmgrprotos.h"
#include "utils/lsyscache.h"
Include dependency graph for arraysubs.c:

Go to the source code of this file.

Data Structures

struct  ArraySubWorkspace
 

Typedefs

typedef struct ArraySubWorkspace ArraySubWorkspace
 

Functions

static void array_subscript_transform (SubscriptingRef *sbsref, List *indirection, ParseState *pstate, bool isSlice, bool isAssignment)
 
static bool array_subscript_check_subscripts (ExprState *state, ExprEvalStep *op, ExprContext *econtext)
 
static void array_subscript_fetch (ExprState *state, ExprEvalStep *op, ExprContext *econtext)
 
static void array_subscript_fetch_slice (ExprState *state, ExprEvalStep *op, ExprContext *econtext)
 
static void array_subscript_assign (ExprState *state, ExprEvalStep *op, ExprContext *econtext)
 
static void array_subscript_assign_slice (ExprState *state, ExprEvalStep *op, ExprContext *econtext)
 
static void array_subscript_fetch_old (ExprState *state, ExprEvalStep *op, ExprContext *econtext)
 
static void array_subscript_fetch_old_slice (ExprState *state, ExprEvalStep *op, ExprContext *econtext)
 
static void array_exec_setup (const SubscriptingRef *sbsref, SubscriptingRefState *sbsrefstate, SubscriptExecSteps *methods)
 
Datum array_subscript_handler (PG_FUNCTION_ARGS)
 
Datum raw_array_subscript_handler (PG_FUNCTION_ARGS)
 

Typedef Documentation

◆ ArraySubWorkspace

Function Documentation

◆ array_exec_setup()

static void array_exec_setup ( const SubscriptingRef sbsref,
SubscriptingRefState sbsrefstate,
SubscriptExecSteps methods 
)
static

Definition at line 473 of file arraysubs.c.

476 {
477  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  if (sbsrefstate->numupper > MAXDIM)
486  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  if (sbsrefstate->numlower != 0 &&
493  sbsrefstate->numupper != sbsrefstate->numlower)
494  elog(ERROR, "upper and lower index lists are not same length");
495 
496  /*
497  * Allocate type-specific workspace.
498  */
499  workspace = (ArraySubWorkspace *) palloc(sizeof(ArraySubWorkspace));
500  sbsrefstate->workspace = workspace;
501 
502  /*
503  * Collect datatype details we'll need at execution.
504  */
505  workspace->refelemtype = sbsref->refelemtype;
506  workspace->refattrlength = get_typlen(sbsref->refcontainertype);
507  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  */
516  if (is_slice)
517  {
521  }
522  else
523  {
524  methods->sbs_fetch = array_subscript_fetch;
527  }
528 }
#define MAXDIM
Definition: array.h:75
static void array_subscript_assign_slice(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
Definition: arraysubs.c:344
static void array_subscript_fetch_old(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
Definition: arraysubs.c:399
static void array_subscript_assign(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
Definition: arraysubs.c:294
static void array_subscript_fetch(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
Definition: arraysubs.c:236
static void array_subscript_fetch_old_slice(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
Definition: arraysubs.c:439
static void array_subscript_fetch_slice(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
Definition: arraysubs.c:264
static bool array_subscript_check_subscripts(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
Definition: arraysubs.c:180
int errcode(int sqlerrcode)
Definition: elog.c:859
int errmsg(const char *fmt,...)
Definition: elog.c:1072
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
#define ereport(elevel,...)
Definition: elog.h:149
void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, char *typalign)
Definition: lsyscache.c:2271
int16 get_typlen(Oid typid)
Definition: lsyscache.c:2197
void * palloc(Size size)
Definition: mcxt.c:1316
int16 refattrlength
Definition: arraysubs.c:33
int16 refelemlength
Definition: arraysubs.c:34
ExecEvalSubroutine sbs_fetch_old
Definition: execExpr.h:758
ExecEvalBoolSubroutine sbs_check_subscripts
Definition: execExpr.h:755
ExecEvalSubroutine sbs_assign
Definition: execExpr.h:757
ExecEvalSubroutine sbs_fetch
Definition: execExpr.h:756

References array_subscript_assign(), array_subscript_assign_slice(), array_subscript_check_subscripts(), array_subscript_fetch(), array_subscript_fetch_old(), array_subscript_fetch_old_slice(), array_subscript_fetch_slice(), elog, ereport, errcode(), errmsg(), ERROR, get_typlen(), get_typlenbyvalalign(), MAXDIM, SubscriptingRefState::numlower, SubscriptingRefState::numupper, palloc(), ArraySubWorkspace::refattrlength, ArraySubWorkspace::refelemalign, ArraySubWorkspace::refelembyval, ArraySubWorkspace::refelemlength, ArraySubWorkspace::refelemtype, SubscriptExecSteps::sbs_assign, SubscriptExecSteps::sbs_check_subscripts, SubscriptExecSteps::sbs_fetch, SubscriptExecSteps::sbs_fetch_old, and SubscriptingRefState::workspace.

Referenced by array_subscript_handler(), and raw_array_subscript_handler().

◆ array_subscript_assign()

static void array_subscript_assign ( ExprState state,
ExprEvalStep op,
ExprContext econtext 
)
static

Definition at line 294 of file arraysubs.c.

297 {
298  SubscriptingRefState *sbsrefstate = op->d.sbsref.state;
299  ArraySubWorkspace *workspace = (ArraySubWorkspace *) sbsrefstate->workspace;
300  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  if (workspace->refattrlength > 0)
308  {
309  if (*op->resnull || sbsrefstate->replacenull)
310  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  if (*op->resnull)
320  {
321  arraySource = PointerGetDatum(construct_empty_array(workspace->refelemtype));
322  *op->resnull = false;
323  }
324 
325  *op->resvalue = array_set_element(arraySource,
326  sbsrefstate->numupper,
327  workspace->upperindex,
328  sbsrefstate->replacevalue,
329  sbsrefstate->replacenull,
330  workspace->refattrlength,
331  workspace->refelemlength,
332  workspace->refelembyval,
333  workspace->refelemalign);
334  /* The result is never NULL, so no need to change *op->resnull */
335 }
Datum array_set_element(Datum arraydatum, int nSubscripts, int *indx, Datum dataValue, bool isNull, int arraytyplen, int elmlen, bool elmbyval, char elmalign)
Definition: arrayfuncs.c:2201
ArrayType * construct_empty_array(Oid elmtype)
Definition: arrayfuncs.c:3561
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
uintptr_t Datum
Definition: postgres.h:64
int upperindex[MAXDIM]
Definition: arraysubs.c:43
union ExprEvalStep::@54 d
Datum * resvalue
Definition: execExpr.h:284
struct ExprEvalStep::@54::@82 sbsref
bool * resnull
Definition: execExpr.h:285

References array_set_element(), construct_empty_array(), ExprEvalStep::d, if(), SubscriptingRefState::numupper, PointerGetDatum(), ArraySubWorkspace::refattrlength, ArraySubWorkspace::refelemalign, ArraySubWorkspace::refelembyval, ArraySubWorkspace::refelemlength, ArraySubWorkspace::refelemtype, SubscriptingRefState::replacenull, SubscriptingRefState::replacevalue, ExprEvalStep::resnull, ExprEvalStep::resvalue, ExprEvalStep::sbsref, ArraySubWorkspace::upperindex, and SubscriptingRefState::workspace.

Referenced by array_exec_setup().

◆ array_subscript_assign_slice()

static void array_subscript_assign_slice ( ExprState state,
ExprEvalStep op,
ExprContext econtext 
)
static

Definition at line 344 of file arraysubs.c.

347 {
348  SubscriptingRefState *sbsrefstate = op->d.sbsref.state;
349  ArraySubWorkspace *workspace = (ArraySubWorkspace *) sbsrefstate->workspace;
350  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  if (workspace->refattrlength > 0)
358  {
359  if (*op->resnull || sbsrefstate->replacenull)
360  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  if (*op->resnull)
370  {
371  arraySource = PointerGetDatum(construct_empty_array(workspace->refelemtype));
372  *op->resnull = false;
373  }
374 
375  *op->resvalue = array_set_slice(arraySource,
376  sbsrefstate->numupper,
377  workspace->upperindex,
378  workspace->lowerindex,
379  sbsrefstate->upperprovided,
380  sbsrefstate->lowerprovided,
381  sbsrefstate->replacevalue,
382  sbsrefstate->replacenull,
383  workspace->refattrlength,
384  workspace->refelemlength,
385  workspace->refelembyval,
386  workspace->refelemalign);
387  /* The result is never NULL, so no need to change *op->resnull */
388 }
Datum array_set_slice(Datum arraydatum, int nSubscripts, int *upperIndx, int *lowerIndx, bool *upperProvided, bool *lowerProvided, Datum srcArrayDatum, bool isNull, int arraytyplen, int elmlen, bool elmbyval, char elmalign)
Definition: arrayfuncs.c:2806
int lowerindex[MAXDIM]
Definition: arraysubs.c:44

References array_set_slice(), construct_empty_array(), ExprEvalStep::d, if(), ArraySubWorkspace::lowerindex, SubscriptingRefState::lowerprovided, SubscriptingRefState::numupper, PointerGetDatum(), ArraySubWorkspace::refattrlength, ArraySubWorkspace::refelemalign, ArraySubWorkspace::refelembyval, ArraySubWorkspace::refelemlength, ArraySubWorkspace::refelemtype, SubscriptingRefState::replacenull, SubscriptingRefState::replacevalue, ExprEvalStep::resnull, ExprEvalStep::resvalue, ExprEvalStep::sbsref, ArraySubWorkspace::upperindex, SubscriptingRefState::upperprovided, and SubscriptingRefState::workspace.

Referenced by array_exec_setup().

◆ array_subscript_check_subscripts()

static bool array_subscript_check_subscripts ( ExprState state,
ExprEvalStep op,
ExprContext econtext 
)
static

Definition at line 180 of file arraysubs.c.

183 {
184  SubscriptingRefState *sbsrefstate = op->d.sbsref_subscript.state;
185  ArraySubWorkspace *workspace = (ArraySubWorkspace *) sbsrefstate->workspace;
186 
187  /* Process upper subscripts */
188  for (int i = 0; i < sbsrefstate->numupper; i++)
189  {
190  if (sbsrefstate->upperprovided[i])
191  {
192  /* If any index expr yields NULL, result is NULL or error */
193  if (sbsrefstate->upperindexnull[i])
194  {
195  if (sbsrefstate->isassignment)
196  ereport(ERROR,
197  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
198  errmsg("array subscript in assignment must not be null")));
199  *op->resnull = true;
200  return false;
201  }
202  workspace->upperindex[i] = DatumGetInt32(sbsrefstate->upperindex[i]);
203  }
204  }
205 
206  /* Likewise for lower subscripts */
207  for (int i = 0; i < sbsrefstate->numlower; i++)
208  {
209  if (sbsrefstate->lowerprovided[i])
210  {
211  /* If any index expr yields NULL, result is NULL or error */
212  if (sbsrefstate->lowerindexnull[i])
213  {
214  if (sbsrefstate->isassignment)
215  ereport(ERROR,
216  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
217  errmsg("array subscript in assignment must not be null")));
218  *op->resnull = true;
219  return false;
220  }
221  workspace->lowerindex[i] = DatumGetInt32(sbsrefstate->lowerindex[i]);
222  }
223  }
224 
225  return true;
226 }
for(;;)
int i
Definition: isn.c:73
static int32 DatumGetInt32(Datum X)
Definition: postgres.h:202
struct ExprEvalStep::@54::@81 sbsref_subscript

References ExprEvalStep::d, DatumGetInt32(), ereport, errcode(), errmsg(), ERROR, for(), i, SubscriptingRefState::isassignment, ArraySubWorkspace::lowerindex, SubscriptingRefState::lowerindex, SubscriptingRefState::lowerindexnull, SubscriptingRefState::lowerprovided, SubscriptingRefState::numlower, SubscriptingRefState::numupper, ExprEvalStep::resnull, ExprEvalStep::sbsref_subscript, ArraySubWorkspace::upperindex, SubscriptingRefState::upperindex, SubscriptingRefState::upperindexnull, SubscriptingRefState::upperprovided, and SubscriptingRefState::workspace.

Referenced by array_exec_setup().

◆ array_subscript_fetch()

static void array_subscript_fetch ( ExprState state,
ExprEvalStep op,
ExprContext econtext 
)
static

Definition at line 236 of file arraysubs.c.

239 {
240  SubscriptingRefState *sbsrefstate = op->d.sbsref.state;
241  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  *op->resvalue = array_get_element(*op->resvalue,
247  sbsrefstate->numupper,
248  workspace->upperindex,
249  workspace->refattrlength,
250  workspace->refelemlength,
251  workspace->refelembyval,
252  workspace->refelemalign,
253  op->resnull);
254 }
Datum array_get_element(Datum arraydatum, int nSubscripts, int *indx, int arraytyplen, int elmlen, bool elmbyval, char elmalign, bool *isNull)
Definition: arrayfuncs.c:1820
#define Assert(condition)
Definition: c.h:858

References array_get_element(), Assert, ExprEvalStep::d, SubscriptingRefState::numupper, ArraySubWorkspace::refattrlength, ArraySubWorkspace::refelemalign, ArraySubWorkspace::refelembyval, ArraySubWorkspace::refelemlength, ExprEvalStep::resnull, ExprEvalStep::resvalue, ExprEvalStep::sbsref, ArraySubWorkspace::upperindex, and SubscriptingRefState::workspace.

Referenced by array_exec_setup().

◆ array_subscript_fetch_old()

static void array_subscript_fetch_old ( ExprState state,
ExprEvalStep op,
ExprContext econtext 
)
static

Definition at line 399 of file arraysubs.c.

402 {
403  SubscriptingRefState *sbsrefstate = op->d.sbsref.state;
404  ArraySubWorkspace *workspace = (ArraySubWorkspace *) sbsrefstate->workspace;
405 
406  if (*op->resnull)
407  {
408  /* whole array is null, so any element is too */
409  sbsrefstate->prevvalue = (Datum) 0;
410  sbsrefstate->prevnull = true;
411  }
412  else
413  sbsrefstate->prevvalue = array_get_element(*op->resvalue,
414  sbsrefstate->numupper,
415  workspace->upperindex,
416  workspace->refattrlength,
417  workspace->refelemlength,
418  workspace->refelembyval,
419  workspace->refelemalign,
420  &sbsrefstate->prevnull);
421 }

References array_get_element(), ExprEvalStep::d, if(), SubscriptingRefState::numupper, SubscriptingRefState::prevnull, SubscriptingRefState::prevvalue, ArraySubWorkspace::refattrlength, ArraySubWorkspace::refelemalign, ArraySubWorkspace::refelembyval, ArraySubWorkspace::refelemlength, ExprEvalStep::resnull, ExprEvalStep::resvalue, ExprEvalStep::sbsref, ArraySubWorkspace::upperindex, and SubscriptingRefState::workspace.

Referenced by array_exec_setup().

◆ array_subscript_fetch_old_slice()

static void array_subscript_fetch_old_slice ( ExprState state,
ExprEvalStep op,
ExprContext econtext 
)
static

Definition at line 439 of file arraysubs.c.

442 {
443  SubscriptingRefState *sbsrefstate = op->d.sbsref.state;
444  ArraySubWorkspace *workspace = (ArraySubWorkspace *) sbsrefstate->workspace;
445 
446  if (*op->resnull)
447  {
448  /* whole array is null, so any slice is too */
449  sbsrefstate->prevvalue = (Datum) 0;
450  sbsrefstate->prevnull = true;
451  }
452  else
453  {
454  sbsrefstate->prevvalue = array_get_slice(*op->resvalue,
455  sbsrefstate->numupper,
456  workspace->upperindex,
457  workspace->lowerindex,
458  sbsrefstate->upperprovided,
459  sbsrefstate->lowerprovided,
460  workspace->refattrlength,
461  workspace->refelemlength,
462  workspace->refelembyval,
463  workspace->refelemalign);
464  /* slices of non-null arrays are never null */
465  sbsrefstate->prevnull = false;
466  }
467 }
Datum array_get_slice(Datum arraydatum, int nSubscripts, int *upperIndx, int *lowerIndx, bool *upperProvided, bool *lowerProvided, int arraytyplen, int elmlen, bool elmbyval, char elmalign)
Definition: arrayfuncs.c:2030

References array_get_slice(), ExprEvalStep::d, if(), ArraySubWorkspace::lowerindex, SubscriptingRefState::lowerprovided, SubscriptingRefState::numupper, SubscriptingRefState::prevnull, SubscriptingRefState::prevvalue, ArraySubWorkspace::refattrlength, ArraySubWorkspace::refelemalign, ArraySubWorkspace::refelembyval, ArraySubWorkspace::refelemlength, ExprEvalStep::resnull, ExprEvalStep::resvalue, ExprEvalStep::sbsref, ArraySubWorkspace::upperindex, SubscriptingRefState::upperprovided, and SubscriptingRefState::workspace.

Referenced by array_exec_setup().

◆ array_subscript_fetch_slice()

static void array_subscript_fetch_slice ( ExprState state,
ExprEvalStep op,
ExprContext econtext 
)
static

Definition at line 264 of file arraysubs.c.

267 {
268  SubscriptingRefState *sbsrefstate = op->d.sbsref.state;
269  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  *op->resvalue = array_get_slice(*op->resvalue,
275  sbsrefstate->numupper,
276  workspace->upperindex,
277  workspace->lowerindex,
278  sbsrefstate->upperprovided,
279  sbsrefstate->lowerprovided,
280  workspace->refattrlength,
281  workspace->refelemlength,
282  workspace->refelembyval,
283  workspace->refelemalign);
284  /* The slice is never NULL, so no need to change *op->resnull */
285 }

References array_get_slice(), Assert, ExprEvalStep::d, ArraySubWorkspace::lowerindex, SubscriptingRefState::lowerprovided, SubscriptingRefState::numupper, ArraySubWorkspace::refattrlength, ArraySubWorkspace::refelemalign, ArraySubWorkspace::refelembyval, ArraySubWorkspace::refelemlength, ExprEvalStep::resnull, ExprEvalStep::resvalue, ExprEvalStep::sbsref, ArraySubWorkspace::upperindex, SubscriptingRefState::upperprovided, and SubscriptingRefState::workspace.

Referenced by array_exec_setup().

◆ array_subscript_handler()

Datum array_subscript_handler ( PG_FUNCTION_ARGS  )

Definition at line 539 of file arraysubs.c.

540 {
541  static const SubscriptRoutines sbsroutines = {
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  PG_RETURN_POINTER(&sbsroutines);
550 }
static void array_exec_setup(const SubscriptingRef *sbsref, SubscriptingRefState *sbsrefstate, SubscriptExecSteps *methods)
Definition: arraysubs.c:473
static void array_subscript_transform(SubscriptingRef *sbsref, List *indirection, ParseState *pstate, bool isSlice, bool isAssignment)
Definition: arraysubs.c:55
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:361
SubscriptTransform transform
Definition: subscripting.h:160

References array_exec_setup(), array_subscript_transform(), PG_RETURN_POINTER, and SubscriptRoutines::transform.

◆ array_subscript_transform()

static void array_subscript_transform ( SubscriptingRef sbsref,
List indirection,
ParseState pstate,
bool  isSlice,
bool  isAssignment 
)
static

Definition at line 55 of file arraysubs.c.

60 {
61  List *upperIndexpr = NIL;
62  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  foreach(idx, indirection)
74  {
76  Node *subexpr;
77 
78  if (isSlice)
79  {
80  if (ai->lidx)
81  {
82  subexpr = transformExpr(pstate, ai->lidx, pstate->p_expr_kind);
83  /* If it's not int4 already, try to coerce */
84  subexpr = coerce_to_target_type(pstate,
85  subexpr, exprType(subexpr),
86  INT4OID, -1,
89  -1);
90  if (subexpr == NULL)
91  ereport(ERROR,
92  (errcode(ERRCODE_DATATYPE_MISMATCH),
93  errmsg("array subscript must have type integer"),
94  parser_errposition(pstate, exprLocation(ai->lidx))));
95  }
96  else if (!ai->is_slice)
97  {
98  /* Make a constant 1 */
99  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  subexpr = NULL;
111  }
112  lowerIndexpr = lappend(lowerIndexpr, subexpr);
113  }
114  else
115  Assert(ai->lidx == NULL && !ai->is_slice);
116 
117  if (ai->uidx)
118  {
119  subexpr = transformExpr(pstate, ai->uidx, pstate->p_expr_kind);
120  /* If it's not int4 already, try to coerce */
121  subexpr = coerce_to_target_type(pstate,
122  subexpr, exprType(subexpr),
123  INT4OID, -1,
126  -1);
127  if (subexpr == NULL)
128  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  subexpr = NULL;
138  }
139  upperIndexpr = lappend(upperIndexpr, subexpr);
140  }
141 
142  /* ... and store the transformed lists into the SubscriptRef node */
143  sbsref->refupperindexpr = upperIndexpr;
144  sbsref->reflowerindexpr = lowerIndexpr;
145 
146  /* Verify subscript list lengths are within implementation limit */
147  if (list_length(upperIndexpr) > MAXDIM)
148  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  if (isSlice)
161  sbsref->refrestype = sbsref->refcontainertype;
162  else
163  sbsref->refrestype = sbsref->refelemtype;
164 }
Datum idx(PG_FUNCTION_ARGS)
Definition: _int_op.c:259
signed int int32
Definition: c.h:494
List * lappend(List *list, void *datum)
Definition: list.c:339
Const * makeConst(Oid consttype, int32 consttypmod, Oid constcollid, int constlen, Datum constvalue, bool constisnull, bool constbyval)
Definition: makefuncs.c:301
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
int exprLocation(const Node *expr)
Definition: nodeFuncs.c:1386
Node * coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype, Oid targettype, int32 targettypmod, CoercionContext ccontext, CoercionForm cformat, int location)
Definition: parse_coerce.c:78
Node * transformExpr(ParseState *pstate, Node *expr, ParseExprKind exprKind)
Definition: parse_expr.c:121
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:106
#define lfirst_node(type, lc)
Definition: pg_list.h:176
static int list_length(const List *l)
Definition: pg_list.h:152
#define NIL
Definition: pg_list.h:68
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:212
#define InvalidOid
Definition: postgres_ext.h:36
@ COERCE_IMPLICIT_CAST
Definition: primnodes.h:706
@ COERCION_ASSIGNMENT
Definition: primnodes.h:685
bool is_slice
Definition: parsenodes.h:459
Node * uidx
Definition: parsenodes.h:461
Node * lidx
Definition: parsenodes.h:460
Definition: pg_list.h:54
Definition: nodes.h:129
ParseExprKind p_expr_kind
Definition: parse_node.h:211
List * refupperindexpr
Definition: primnodes.h:663
List * reflowerindexpr
Definition: primnodes.h:669

References Assert, COERCE_IMPLICIT_CAST, coerce_to_target_type(), COERCION_ASSIGNMENT, ereport, errcode(), errmsg(), ERROR, exprLocation(), exprType(), idx(), Int32GetDatum(), InvalidOid, A_Indices::is_slice, lappend(), lfirst_node, A_Indices::lidx, list_length(), makeConst(), MAXDIM, NIL, ParseState::p_expr_kind, parser_errposition(), SubscriptingRef::reflowerindexpr, SubscriptingRef::refupperindexpr, transformExpr(), and A_Indices::uidx.

Referenced by array_subscript_handler(), and raw_array_subscript_handler().

◆ raw_array_subscript_handler()

Datum raw_array_subscript_handler ( PG_FUNCTION_ARGS  )

Definition at line 566 of file arraysubs.c.

567 {
568  static const SubscriptRoutines sbsroutines = {
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  PG_RETURN_POINTER(&sbsroutines);
577 }

References array_exec_setup(), array_subscript_transform(), PG_RETURN_POINTER, and SubscriptRoutines::transform.