PostgreSQL Source Code git master
arraysubs.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * arraysubs.c
4 * Subscripting support functions for arrays.
5 *
6 * Portions Copyright (c) 1996-2025, 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 */
29typedef 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 */
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 */
54static void
56 List *indirection,
57 ParseState *pstate,
58 bool isSlice,
59 bool isAssignment)
60{
61 List *upperIndexpr = NIL;
62 List *lowerIndexpr = NIL;
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)
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,
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)
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)
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}
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 */
179static bool
181 ExprEvalStep *op,
182 ExprContext *econtext)
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)
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)
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}
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 */
235static void
237 ExprEvalStep *op,
238 ExprContext *econtext)
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
247 sbsrefstate->numupper,
248 workspace->upperindex,
249 workspace->refattrlength,
250 workspace->refelemlength,
251 workspace->refelembyval,
252 workspace->refelemalign,
253 op->resnull);
254}
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 */
263static void
265 ExprEvalStep *op,
266 ExprContext *econtext)
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
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}
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 */
293static void
295 ExprEvalStep *op,
296 ExprContext *econtext)
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}
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 */
343static void
345 ExprEvalStep *op,
346 ExprContext *econtext)
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}
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 */
398static void
400 ExprEvalStep *op,
401 ExprContext *econtext)
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}
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 */
438static void
440 ExprEvalStep *op,
441 ExprContext *econtext)
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}
468
469/*
470 * Set up execution state for an array subscript operation.
471 */
472static void
474 SubscriptingRefState *sbsrefstate,
475 SubscriptExecSteps *methods)
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)
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 {
527 }
528}
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 */
538Datum
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}
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 */
565Datum
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}
Datum idx(PG_FUNCTION_ARGS)
Definition: _int_op.c:259
#define MAXDIM
Definition: array.h:75
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
Datum array_get_element(Datum arraydatum, int nSubscripts, int *indx, int arraytyplen, int elmlen, bool elmbyval, char elmalign, bool *isNull)
Definition: arrayfuncs.c:1820
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
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
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_exec_setup(const SubscriptingRef *sbsref, SubscriptingRefState *sbsrefstate, SubscriptExecSteps *methods)
Definition: arraysubs.c:473
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
Datum array_subscript_handler(PG_FUNCTION_ARGS)
Definition: arraysubs.c:539
static void array_subscript_transform(SubscriptingRef *sbsref, List *indirection, ParseState *pstate, bool isSlice, bool isAssignment)
Definition: arraysubs.c:55
Datum raw_array_subscript_handler(PG_FUNCTION_ARGS)
Definition: arraysubs.c:566
static bool array_subscript_check_subscripts(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
Definition: arraysubs.c:180
struct ArraySubWorkspace ArraySubWorkspace
#define Assert(condition)
Definition: c.h:815
int16_t int16
Definition: c.h:483
int32_t int32
Definition: c.h:484
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
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:361
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
for(;;)
int i
Definition: isn.c:72
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:76
List * lappend(List *list, void *datum)
Definition: list.c:339
void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, char *typalign)
Definition: lsyscache.c:2271
int16 get_typlen(Oid typid)
Definition: lsyscache.c:2197
Const * makeConst(Oid consttype, int32 consttypmod, Oid constcollid, int constlen, Datum constvalue, bool constisnull, bool constbyval)
Definition: makefuncs.c:303
void * palloc(Size size)
Definition: mcxt.c:1317
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 PointerGetDatum(const void *X)
Definition: postgres.h:327
uintptr_t Datum
Definition: postgres.h:69
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:217
static int32 DatumGetInt32(Datum X)
Definition: postgres.h:207
#define InvalidOid
Definition: postgres_ext.h:37
unsigned int Oid
Definition: postgres_ext.h:32
@ COERCE_IMPLICIT_CAST
Definition: primnodes.h:752
@ COERCION_ASSIGNMENT
Definition: primnodes.h:731
bool is_slice
Definition: parsenodes.h:470
Node * uidx
Definition: parsenodes.h:472
Node * lidx
Definition: parsenodes.h:471
int upperindex[MAXDIM]
Definition: arraysubs.c:43
int lowerindex[MAXDIM]
Definition: arraysubs.c:44
int16 refattrlength
Definition: arraysubs.c:33
int16 refelemlength
Definition: arraysubs.c:34
struct SubscriptingRefState * state
Definition: execExpr.h:561
struct ExprEvalStep::@55::@83 sbsref_subscript
struct ExprEvalStep::@55::@84 sbsref
Datum * resvalue
Definition: execExpr.h:302
union ExprEvalStep::@55 d
bool * resnull
Definition: execExpr.h:303
Definition: pg_list.h:54
Definition: nodes.h:129
ParseExprKind p_expr_kind
Definition: parse_node.h:230
ExecEvalSubroutine sbs_fetch_old
Definition: execExpr.h:808
ExecEvalBoolSubroutine sbs_check_subscripts
Definition: execExpr.h:805
ExecEvalSubroutine sbs_assign
Definition: execExpr.h:807
ExecEvalSubroutine sbs_fetch
Definition: execExpr.h:806
SubscriptTransform transform
Definition: subscripting.h:160
List * refupperindexpr
Definition: primnodes.h:709
List * reflowerindexpr
Definition: primnodes.h:715
Definition: regguts.h:323