PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
arraysubs.c File Reference
#include "postgres.h"
#include "executor/execExpr.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "nodes/subscripting.h"
#include "nodes/supportnodes.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)
 
Datum array_subscript_handler_support (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 474 of file arraysubs.c.

477{
478 bool is_slice = (sbsrefstate->numlower != 0);
479 ArraySubWorkspace *workspace;
480
481 /*
482 * Enforce the implementation limit on number of array subscripts. This
483 * check isn't entirely redundant with checking at parse time; conceivably
484 * the expression was stored by a backend with a different MAXDIM value.
485 */
486 if (sbsrefstate->numupper > MAXDIM)
488 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
489 errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
490 sbsrefstate->numupper, MAXDIM)));
491
492 /* Should be impossible if parser is sane, but check anyway: */
493 if (sbsrefstate->numlower != 0 &&
494 sbsrefstate->numupper != sbsrefstate->numlower)
495 elog(ERROR, "upper and lower index lists are not same length");
496
497 /*
498 * Allocate type-specific workspace.
499 */
500 workspace = (ArraySubWorkspace *) palloc(sizeof(ArraySubWorkspace));
501 sbsrefstate->workspace = workspace;
502
503 /*
504 * Collect datatype details we'll need at execution.
505 */
506 workspace->refelemtype = sbsref->refelemtype;
507 workspace->refattrlength = get_typlen(sbsref->refcontainertype);
508 get_typlenbyvalalign(sbsref->refelemtype,
509 &workspace->refelemlength,
510 &workspace->refelembyval,
511 &workspace->refelemalign);
512
513 /*
514 * Pass back pointers to appropriate step execution functions.
515 */
517 if (is_slice)
518 {
522 }
523 else
524 {
528 }
529}
#define MAXDIM
Definition: array.h:75
static void array_subscript_assign_slice(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
Definition: arraysubs.c:345
static void array_subscript_fetch_old(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
Definition: arraysubs.c:400
static void array_subscript_assign(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
Definition: arraysubs.c:295
static void array_subscript_fetch(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
Definition: arraysubs.c:237
static void array_subscript_fetch_old_slice(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
Definition: arraysubs.c:440
static void array_subscript_fetch_slice(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
Definition: arraysubs.c:265
static bool array_subscript_check_subscripts(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
Definition: arraysubs.c:181
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#define ereport(elevel,...)
Definition: elog.h:149
void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, char *typalign)
Definition: lsyscache.c:2354
int16 get_typlen(Oid typid)
Definition: lsyscache.c:2280
void * palloc(Size size)
Definition: mcxt.c:1317
int16 refattrlength
Definition: arraysubs.c:34
int16 refelemlength
Definition: arraysubs.c:35
ExecEvalSubroutine sbs_fetch_old
Definition: execExpr.h:817
ExecEvalBoolSubroutine sbs_check_subscripts
Definition: execExpr.h:814
ExecEvalSubroutine sbs_assign
Definition: execExpr.h:816
ExecEvalSubroutine sbs_fetch
Definition: execExpr.h:815

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 295 of file arraysubs.c.

298{
299 SubscriptingRefState *sbsrefstate = op->d.sbsref.state;
300 ArraySubWorkspace *workspace = (ArraySubWorkspace *) sbsrefstate->workspace;
301 Datum arraySource = *op->resvalue;
302
303 /*
304 * For an assignment to a fixed-length array type, both the original array
305 * and the value to be assigned into it must be non-NULL, else we punt and
306 * return the original array.
307 */
308 if (workspace->refattrlength > 0)
309 {
310 if (*op->resnull || sbsrefstate->replacenull)
311 return;
312 }
313
314 /*
315 * For assignment to varlena arrays, we handle a NULL original array by
316 * substituting an empty (zero-dimensional) array; insertion of the new
317 * element will result in a singleton array value. It does not matter
318 * whether the new element is NULL.
319 */
320 if (*op->resnull)
321 {
322 arraySource = PointerGetDatum(construct_empty_array(workspace->refelemtype));
323 *op->resnull = false;
324 }
325
326 *op->resvalue = array_set_element(arraySource,
327 sbsrefstate->numupper,
328 workspace->upperindex,
329 sbsrefstate->replacevalue,
330 sbsrefstate->replacenull,
331 workspace->refattrlength,
332 workspace->refelemlength,
333 workspace->refelembyval,
334 workspace->refelemalign);
335 /* The result is never NULL, so no need to change *op->resnull */
336}
ArrayType * construct_empty_array(Oid elmtype)
Definition: arrayfuncs.c:3580
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
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:78
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:327
uintptr_t Datum
Definition: postgres.h:69
int upperindex[MAXDIM]
Definition: arraysubs.c:44
struct SubscriptingRefState * state
Definition: execExpr.h:570
struct ExprEvalStep::@55::@84 sbsref
Datum * resvalue
Definition: execExpr.h:310
union ExprEvalStep::@55 d
bool * resnull
Definition: execExpr.h:311

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, ExprEvalStep::state, 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 345 of file arraysubs.c.

348{
349 SubscriptingRefState *sbsrefstate = op->d.sbsref.state;
350 ArraySubWorkspace *workspace = (ArraySubWorkspace *) sbsrefstate->workspace;
351 Datum arraySource = *op->resvalue;
352
353 /*
354 * For an assignment to a fixed-length array type, both the original array
355 * and the value to be assigned into it must be non-NULL, else we punt and
356 * return the original array.
357 */
358 if (workspace->refattrlength > 0)
359 {
360 if (*op->resnull || sbsrefstate->replacenull)
361 return;
362 }
363
364 /*
365 * For assignment to varlena arrays, we handle a NULL original array by
366 * substituting an empty (zero-dimensional) array; insertion of the new
367 * element will result in a singleton array value. It does not matter
368 * whether the new element is NULL.
369 */
370 if (*op->resnull)
371 {
372 arraySource = PointerGetDatum(construct_empty_array(workspace->refelemtype));
373 *op->resnull = false;
374 }
375
376 *op->resvalue = array_set_slice(arraySource,
377 sbsrefstate->numupper,
378 workspace->upperindex,
379 workspace->lowerindex,
380 sbsrefstate->upperprovided,
381 sbsrefstate->lowerprovided,
382 sbsrefstate->replacevalue,
383 sbsrefstate->replacenull,
384 workspace->refattrlength,
385 workspace->refelemlength,
386 workspace->refelembyval,
387 workspace->refelemalign);
388 /* The result is never NULL, so no need to change *op->resnull */
389}
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:45

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, ExprEvalStep::state, 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 181 of file arraysubs.c.

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

240{
241 SubscriptingRefState *sbsrefstate = op->d.sbsref.state;
242 ArraySubWorkspace *workspace = (ArraySubWorkspace *) sbsrefstate->workspace;
243
244 /* Should not get here if source array (or any subscript) is null */
245 Assert(!(*op->resnull));
246
248 sbsrefstate->numupper,
249 workspace->upperindex,
250 workspace->refattrlength,
251 workspace->refelemlength,
252 workspace->refelembyval,
253 workspace->refelemalign,
254 op->resnull);
255}
Datum array_get_element(Datum arraydatum, int nSubscripts, int *indx, int arraytyplen, int elmlen, bool elmbyval, char elmalign, bool *isNull)
Definition: arrayfuncs.c:1820
Assert(PointerIsAligned(start, uint64))

References array_get_element(), Assert(), ExprEvalStep::d, SubscriptingRefState::numupper, ArraySubWorkspace::refattrlength, ArraySubWorkspace::refelemalign, ArraySubWorkspace::refelembyval, ArraySubWorkspace::refelemlength, ExprEvalStep::resnull, ExprEvalStep::resvalue, ExprEvalStep::sbsref, ExprEvalStep::state, 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 400 of file arraysubs.c.

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

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, ExprEvalStep::state, 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 440 of file arraysubs.c.

443{
444 SubscriptingRefState *sbsrefstate = op->d.sbsref.state;
445 ArraySubWorkspace *workspace = (ArraySubWorkspace *) sbsrefstate->workspace;
446
447 if (*op->resnull)
448 {
449 /* whole array is null, so any slice is too */
450 sbsrefstate->prevvalue = (Datum) 0;
451 sbsrefstate->prevnull = true;
452 }
453 else
454 {
455 sbsrefstate->prevvalue = array_get_slice(*op->resvalue,
456 sbsrefstate->numupper,
457 workspace->upperindex,
458 workspace->lowerindex,
459 sbsrefstate->upperprovided,
460 sbsrefstate->lowerprovided,
461 workspace->refattrlength,
462 workspace->refelemlength,
463 workspace->refelembyval,
464 workspace->refelemalign);
465 /* slices of non-null arrays are never null */
466 sbsrefstate->prevnull = false;
467 }
468}
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, ExprEvalStep::state, 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 265 of file arraysubs.c.

268{
269 SubscriptingRefState *sbsrefstate = op->d.sbsref.state;
270 ArraySubWorkspace *workspace = (ArraySubWorkspace *) sbsrefstate->workspace;
271
272 /* Should not get here if source array (or any subscript) is null */
273 Assert(!(*op->resnull));
274
276 sbsrefstate->numupper,
277 workspace->upperindex,
278 workspace->lowerindex,
279 sbsrefstate->upperprovided,
280 sbsrefstate->lowerprovided,
281 workspace->refattrlength,
282 workspace->refelemlength,
283 workspace->refelembyval,
284 workspace->refelemalign);
285 /* The slice is never NULL, so no need to change *op->resnull */
286}

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, ExprEvalStep::state, 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 540 of file arraysubs.c.

541{
542 static const SubscriptRoutines sbsroutines = {
544 .exec_setup = array_exec_setup,
545 .fetch_strict = true, /* fetch returns NULL for NULL inputs */
546 .fetch_leakproof = true, /* fetch returns NULL for bad subscript */
547 .store_leakproof = false /* ... but assignment throws error */
548 };
549
550 PG_RETURN_POINTER(&sbsroutines);
551}
static void array_exec_setup(const SubscriptingRef *sbsref, SubscriptingRefState *sbsrefstate, SubscriptExecSteps *methods)
Definition: arraysubs.c:474
static void array_subscript_transform(SubscriptingRef *sbsref, List *indirection, ParseState *pstate, bool isSlice, bool isAssignment)
Definition: arraysubs.c:56
#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_handler_support()

Datum array_subscript_handler_support ( PG_FUNCTION_ARGS  )

Definition at line 586 of file arraysubs.c.

587{
588 Node *rawreq = (Node *) PG_GETARG_POINTER(0);
589 Node *ret = NULL;
590
591 if (IsA(rawreq, SupportRequestModifyInPlace))
592 {
593 /*
594 * We can optimize in-place subscripted assignment if the refexpr is
595 * the array being assigned to. We don't need to worry about array
596 * references within the refassgnexpr or the subscripts; however, if
597 * there's no refassgnexpr then it's a fetch which there's no need to
598 * optimize.
599 */
601 Param *refexpr = (Param *) linitial(req->args);
602
603 if (refexpr && IsA(refexpr, Param) &&
604 refexpr->paramkind == PARAM_EXTERN &&
605 refexpr->paramid == req->paramid &&
606 lsecond(req->args) != NULL)
607 ret = (Node *) refexpr;
608 }
609
611}
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:276
#define IsA(nodeptr, _type_)
Definition: nodes.h:164
#define linitial(l)
Definition: pg_list.h:178
#define lsecond(l)
Definition: pg_list.h:183
@ PARAM_EXTERN
Definition: primnodes.h:384
Definition: nodes.h:135
int paramid
Definition: primnodes.h:394
ParamKind paramkind
Definition: primnodes.h:393

References SupportRequestModifyInPlace::args, IsA, linitial, lsecond, PARAM_EXTERN, Param::paramid, SupportRequestModifyInPlace::paramid, Param::paramkind, PG_GETARG_POINTER, and PG_RETURN_POINTER.

◆ array_subscript_transform()

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

Definition at line 56 of file arraysubs.c.

61{
62 List *upperIndexpr = NIL;
63 List *lowerIndexpr = NIL;
65
66 /*
67 * Transform the subscript expressions, and separate upper and lower
68 * bounds into two lists.
69 *
70 * If we have a container slice expression, we convert any non-slice
71 * indirection items to slices by treating the single subscript as the
72 * upper bound and supplying an assumed lower bound of 1.
73 */
74 foreach(idx, indirection)
75 {
77 Node *subexpr;
78
79 if (isSlice)
80 {
81 if (ai->lidx)
82 {
83 subexpr = transformExpr(pstate, ai->lidx, pstate->p_expr_kind);
84 /* If it's not int4 already, try to coerce */
85 subexpr = coerce_to_target_type(pstate,
86 subexpr, exprType(subexpr),
87 INT4OID, -1,
90 -1);
91 if (subexpr == NULL)
93 (errcode(ERRCODE_DATATYPE_MISMATCH),
94 errmsg("array subscript must have type integer"),
95 parser_errposition(pstate, exprLocation(ai->lidx))));
96 }
97 else if (!ai->is_slice)
98 {
99 /* Make a constant 1 */
100 subexpr = (Node *) makeConst(INT4OID,
101 -1,
103 sizeof(int32),
104 Int32GetDatum(1),
105 false,
106 true); /* pass by value */
107 }
108 else
109 {
110 /* Slice with omitted lower bound, put NULL into the list */
111 subexpr = NULL;
112 }
113 lowerIndexpr = lappend(lowerIndexpr, subexpr);
114 }
115 else
116 Assert(ai->lidx == NULL && !ai->is_slice);
117
118 if (ai->uidx)
119 {
120 subexpr = transformExpr(pstate, ai->uidx, pstate->p_expr_kind);
121 /* If it's not int4 already, try to coerce */
122 subexpr = coerce_to_target_type(pstate,
123 subexpr, exprType(subexpr),
124 INT4OID, -1,
127 -1);
128 if (subexpr == NULL)
130 (errcode(ERRCODE_DATATYPE_MISMATCH),
131 errmsg("array subscript must have type integer"),
132 parser_errposition(pstate, exprLocation(ai->uidx))));
133 }
134 else
135 {
136 /* Slice with omitted upper bound, put NULL into the list */
137 Assert(isSlice && ai->is_slice);
138 subexpr = NULL;
139 }
140 upperIndexpr = lappend(upperIndexpr, subexpr);
141 }
142
143 /* ... and store the transformed lists into the SubscriptRef node */
144 sbsref->refupperindexpr = upperIndexpr;
145 sbsref->reflowerindexpr = lowerIndexpr;
146
147 /* Verify subscript list lengths are within implementation limit */
148 if (list_length(upperIndexpr) > MAXDIM)
150 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
151 errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
152 list_length(upperIndexpr), MAXDIM)));
153 /* We need not check lowerIndexpr separately */
154
155 /*
156 * Determine the result type of the subscripting operation. It's the same
157 * as the array type if we're slicing, else it's the element type. In
158 * either case, the typmod is the same as the array's, so we need not
159 * change reftypmod.
160 */
161 if (isSlice)
162 sbsref->refrestype = sbsref->refcontainertype;
163 else
164 sbsref->refrestype = sbsref->refelemtype;
165}
Datum idx(PG_FUNCTION_ARGS)
Definition: _int_op.c:259
int32_t int32
Definition: c.h:498
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:350
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
int exprLocation(const Node *expr)
Definition: nodeFuncs.c:1388
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:118
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:217
#define InvalidOid
Definition: postgres_ext.h:35
@ COERCE_IMPLICIT_CAST
Definition: primnodes.h:753
@ COERCION_ASSIGNMENT
Definition: primnodes.h:732
bool is_slice
Definition: parsenodes.h:470
Node * uidx
Definition: parsenodes.h:472
Node * lidx
Definition: parsenodes.h:471
Definition: pg_list.h:54
ParseExprKind p_expr_kind
Definition: parse_node.h:230
List * refupperindexpr
Definition: primnodes.h:710
List * reflowerindexpr
Definition: primnodes.h:716

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 567 of file arraysubs.c.

568{
569 static const SubscriptRoutines sbsroutines = {
571 .exec_setup = array_exec_setup,
572 .fetch_strict = true, /* fetch returns NULL for NULL inputs */
573 .fetch_leakproof = true, /* fetch returns NULL for bad subscript */
574 .store_leakproof = false /* ... but assignment throws error */
575 };
576
577 PG_RETURN_POINTER(&sbsroutines);
578}

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