Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * execExpr.c
4 : * Expression evaluation infrastructure.
5 : *
6 : * During executor startup, we compile each expression tree (which has
7 : * previously been processed by the parser and planner) into an ExprState,
8 : * using ExecInitExpr() et al. This converts the tree into a flat array
9 : * of ExprEvalSteps, which may be thought of as instructions in a program.
10 : * At runtime, we'll execute steps, starting with the first, until we reach
11 : * an EEOP_DONE opcode.
12 : *
13 : * This file contains the "compilation" logic. It is independent of the
14 : * specific execution technology we use (switch statement, computed goto,
15 : * JIT compilation, etc).
16 : *
17 : * See src/backend/executor/README for some background, specifically the
18 : * "Expression Trees and ExprState nodes", "Expression Initialization",
19 : * and "Expression Evaluation" sections.
20 : *
21 : *
22 : * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
23 : * Portions Copyright (c) 1994, Regents of the University of California
24 : *
25 : *
26 : * IDENTIFICATION
27 : * src/backend/executor/execExpr.c
28 : *
29 : *-------------------------------------------------------------------------
30 : */
31 : #include "postgres.h"
32 :
33 : #include "access/nbtree.h"
34 : #include "catalog/objectaccess.h"
35 : #include "catalog/pg_type.h"
36 : #include "executor/execExpr.h"
37 : #include "executor/nodeSubplan.h"
38 : #include "funcapi.h"
39 : #include "miscadmin.h"
40 : #include "nodes/makefuncs.h"
41 : #include "nodes/nodeFuncs.h"
42 : #include "optimizer/clauses.h"
43 : #include "optimizer/planner.h"
44 : #include "pgstat.h"
45 : #include "utils/builtins.h"
46 : #include "utils/lsyscache.h"
47 : #include "utils/typcache.h"
48 :
49 :
50 : typedef struct LastAttnumInfo
51 : {
52 : AttrNumber last_inner;
53 : AttrNumber last_outer;
54 : AttrNumber last_scan;
55 : } LastAttnumInfo;
56 :
57 : static void ExecReadyExpr(ExprState *state);
58 : static void ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state,
59 : Datum *resv, bool *resnull);
60 : static void ExprEvalPushStep(ExprState *es, const ExprEvalStep *s);
61 : static void ExecInitFunc(ExprEvalStep *scratch, Expr *node, List *args,
62 : Oid funcid, Oid inputcollid, PlanState *parent,
63 : ExprState *state);
64 : static void ExecInitExprSlots(ExprState *state, Node *node);
65 : static bool get_last_attnums_walker(Node *node, LastAttnumInfo *info);
66 : static void ExecInitWholeRowVar(ExprEvalStep *scratch, Var *variable,
67 : PlanState *parent);
68 : static void ExecInitArrayRef(ExprEvalStep *scratch, ArrayRef *aref,
69 : PlanState *parent, ExprState *state,
70 : Datum *resv, bool *resnull);
71 : static bool isAssignmentIndirectionExpr(Expr *expr);
72 : static void ExecInitCoerceToDomain(ExprEvalStep *scratch, CoerceToDomain *ctest,
73 : PlanState *parent, ExprState *state,
74 : Datum *resv, bool *resnull);
75 :
76 :
77 : /*
78 : * ExecInitExpr: prepare an expression tree for execution
79 : *
80 : * This function builds and returns an ExprState implementing the given
81 : * Expr node tree. The return ExprState can then be handed to ExecEvalExpr
82 : * for execution. Because the Expr tree itself is read-only as far as
83 : * ExecInitExpr and ExecEvalExpr are concerned, several different executions
84 : * of the same plan tree can occur concurrently. (But note that an ExprState
85 : * does mutate at runtime, so it can't be re-used concurrently.)
86 : *
87 : * This must be called in a memory context that will last as long as repeated
88 : * executions of the expression are needed. Typically the context will be
89 : * the same as the per-query context of the associated ExprContext.
90 : *
91 : * Any Aggref, WindowFunc, or SubPlan nodes found in the tree are added to
92 : * the lists of such nodes held by the parent PlanState (or more accurately,
93 : * the AggrefExprState etc. nodes created for them are added).
94 : *
95 : * Note: there is no ExecEndExpr function; we assume that any resource
96 : * cleanup needed will be handled by just releasing the memory context
97 : * in which the state tree is built. Functions that require additional
98 : * cleanup work can register a shutdown callback in the ExprContext.
99 : *
100 : * 'node' is the root of the expression tree to compile.
101 : * 'parent' is the PlanState node that owns the expression.
102 : *
103 : * 'parent' may be NULL if we are preparing an expression that is not
104 : * associated with a plan tree. (If so, it can't have aggs or subplans.)
105 : * Such cases should usually come through ExecPrepareExpr, not directly here.
106 : *
107 : * Also, if 'node' is NULL, we just return NULL. This is convenient for some
108 : * callers that may or may not have an expression that needs to be compiled.
109 : * Note that a NULL ExprState pointer *cannot* be handed to ExecEvalExpr,
110 : * although ExecQual and ExecCheck will accept one (and treat it as "true").
111 : */
112 : ExprState *
113 60854 : ExecInitExpr(Expr *node, PlanState *parent)
114 : {
115 : ExprState *state;
116 : ExprEvalStep scratch;
117 :
118 : /* Special case: NULL expression produces a NULL ExprState pointer */
119 60854 : if (node == NULL)
120 6664 : return NULL;
121 :
122 : /* Initialize ExprState with empty step list */
123 54190 : state = makeNode(ExprState);
124 54190 : state->expr = node;
125 :
126 : /* Insert EEOP_*_FETCHSOME steps as needed */
127 54190 : ExecInitExprSlots(state, (Node *) node);
128 :
129 : /* Compile the expression proper */
130 54190 : ExecInitExprRec(node, parent, state, &state->resvalue, &state->resnull);
131 :
132 : /* Finally, append a DONE step */
133 54189 : scratch.opcode = EEOP_DONE;
134 54189 : ExprEvalPushStep(state, &scratch);
135 :
136 54189 : ExecReadyExpr(state);
137 :
138 54189 : return state;
139 : }
140 :
141 : /*
142 : * ExecInitQual: prepare a qual for execution by ExecQual
143 : *
144 : * Prepares for the evaluation of a conjunctive boolean expression (qual list
145 : * with implicit AND semantics) that returns true if none of the
146 : * subexpressions are false.
147 : *
148 : * We must return true if the list is empty. Since that's a very common case,
149 : * we optimize it a bit further by translating to a NULL ExprState pointer
150 : * rather than setting up an ExprState that computes constant TRUE. (Some
151 : * especially hot-spot callers of ExecQual detect this and avoid calling
152 : * ExecQual at all.)
153 : *
154 : * If any of the subexpressions yield NULL, then the result of the conjunction
155 : * is false. This makes ExecQual primarily useful for evaluating WHERE
156 : * clauses, since SQL specifies that tuples with null WHERE results do not
157 : * get selected.
158 : */
159 : ExprState *
160 68876 : ExecInitQual(List *qual, PlanState *parent)
161 : {
162 : ExprState *state;
163 : ExprEvalStep scratch;
164 68876 : List *adjust_jumps = NIL;
165 : ListCell *lc;
166 :
167 : /* short-circuit (here and in ExecQual) for empty restriction list */
168 68876 : if (qual == NIL)
169 50018 : return NULL;
170 :
171 18858 : Assert(IsA(qual, List));
172 :
173 18858 : state = makeNode(ExprState);
174 18858 : state->expr = (Expr *) qual;
175 : /* mark expression as to be used with ExecQual() */
176 18858 : state->flags = EEO_FLAG_IS_QUAL;
177 :
178 : /* Insert EEOP_*_FETCHSOME steps as needed */
179 18858 : ExecInitExprSlots(state, (Node *) qual);
180 :
181 : /*
182 : * ExecQual() needs to return false for an expression returning NULL. That
183 : * allows us to short-circuit the evaluation the first time a NULL is
184 : * encountered. As qual evaluation is a hot-path this warrants using a
185 : * special opcode for qual evaluation that's simpler than BOOL_AND (which
186 : * has more complex NULL handling).
187 : */
188 18858 : scratch.opcode = EEOP_QUAL;
189 :
190 : /*
191 : * We can use ExprState's resvalue/resnull as target for each qual expr.
192 : */
193 18858 : scratch.resvalue = &state->resvalue;
194 18858 : scratch.resnull = &state->resnull;
195 :
196 45089 : foreach(lc, qual)
197 : {
198 26231 : Expr *node = (Expr *) lfirst(lc);
199 :
200 : /* first evaluate expression */
201 26231 : ExecInitExprRec(node, parent, state, &state->resvalue, &state->resnull);
202 :
203 : /* then emit EEOP_QUAL to detect if it's false (or null) */
204 26231 : scratch.d.qualexpr.jumpdone = -1;
205 26231 : ExprEvalPushStep(state, &scratch);
206 26231 : adjust_jumps = lappend_int(adjust_jumps,
207 26231 : state->steps_len - 1);
208 : }
209 :
210 : /* adjust jump targets */
211 45089 : foreach(lc, adjust_jumps)
212 : {
213 26231 : ExprEvalStep *as = &state->steps[lfirst_int(lc)];
214 :
215 26231 : Assert(as->opcode == EEOP_QUAL);
216 26231 : Assert(as->d.qualexpr.jumpdone == -1);
217 26231 : as->d.qualexpr.jumpdone = state->steps_len;
218 : }
219 :
220 : /*
221 : * At the end, we don't need to do anything more. The last qual expr must
222 : * have yielded TRUE, and since its result is stored in the desired output
223 : * location, we're done.
224 : */
225 18858 : scratch.opcode = EEOP_DONE;
226 18858 : ExprEvalPushStep(state, &scratch);
227 :
228 18858 : ExecReadyExpr(state);
229 :
230 18858 : return state;
231 : }
232 :
233 : /*
234 : * ExecInitCheck: prepare a check constraint for execution by ExecCheck
235 : *
236 : * This is much like ExecInitQual/ExecQual, except that a null result from
237 : * the conjunction is treated as TRUE. This behavior is appropriate for
238 : * evaluating CHECK constraints, since SQL specifies that NULL constraint
239 : * conditions are not failures.
240 : *
241 : * Note that like ExecInitQual, this expects input in implicit-AND format.
242 : * Users of ExecCheck that have expressions in normal explicit-AND format
243 : * can just apply ExecInitExpr to produce suitable input for ExecCheck.
244 : */
245 : ExprState *
246 72 : ExecInitCheck(List *qual, PlanState *parent)
247 : {
248 : /* short-circuit (here and in ExecCheck) for empty restriction list */
249 72 : if (qual == NIL)
250 0 : return NULL;
251 :
252 72 : Assert(IsA(qual, List));
253 :
254 : /*
255 : * Just convert the implicit-AND list to an explicit AND (if there's more
256 : * than one entry), and compile normally. Unlike ExecQual, we can't
257 : * short-circuit on NULL results, so the regular AND behavior is needed.
258 : */
259 72 : return ExecInitExpr(make_ands_explicit(qual), parent);
260 : }
261 :
262 : /*
263 : * Call ExecInitExpr() on a list of expressions, return a list of ExprStates.
264 : */
265 : List *
266 36603 : ExecInitExprList(List *nodes, PlanState *parent)
267 : {
268 36603 : List *result = NIL;
269 : ListCell *lc;
270 :
271 65696 : foreach(lc, nodes)
272 : {
273 29093 : Expr *e = lfirst(lc);
274 :
275 29093 : result = lappend(result, ExecInitExpr(e, parent));
276 : }
277 :
278 36603 : return result;
279 : }
280 :
281 : /*
282 : * ExecBuildProjectionInfo
283 : *
284 : * Build a ProjectionInfo node for evaluating the given tlist in the given
285 : * econtext, and storing the result into the tuple slot. (Caller must have
286 : * ensured that tuple slot has a descriptor matching the tlist!)
287 : *
288 : * inputDesc can be NULL, but if it is not, we check to see whether simple
289 : * Vars in the tlist match the descriptor. It is important to provide
290 : * inputDesc for relation-scan plan nodes, as a cross check that the relation
291 : * hasn't been changed since the plan was made. At higher levels of a plan,
292 : * there is no need to recheck.
293 : *
294 : * This is implemented by internally building an ExprState that performs the
295 : * whole projection in one go.
296 : *
297 : * Caution: before PG v10, the targetList was a list of ExprStates; now it
298 : * should be the planner-created targetlist, since we do the compilation here.
299 : */
300 : ProjectionInfo *
301 35062 : ExecBuildProjectionInfo(List *targetList,
302 : ExprContext *econtext,
303 : TupleTableSlot *slot,
304 : PlanState *parent,
305 : TupleDesc inputDesc)
306 : {
307 35062 : ProjectionInfo *projInfo = makeNode(ProjectionInfo);
308 : ExprState *state;
309 : ExprEvalStep scratch;
310 : ListCell *lc;
311 :
312 35062 : projInfo->pi_exprContext = econtext;
313 : /* We embed ExprState into ProjectionInfo instead of doing extra palloc */
314 35062 : projInfo->pi_state.tag.type = T_ExprState;
315 35062 : state = &projInfo->pi_state;
316 35062 : state->expr = (Expr *) targetList;
317 35062 : state->resultslot = slot;
318 :
319 : /* Insert EEOP_*_FETCHSOME steps as needed */
320 35062 : ExecInitExprSlots(state, (Node *) targetList);
321 :
322 : /* Now compile each tlist column */
323 102783 : foreach(lc, targetList)
324 : {
325 67723 : TargetEntry *tle = lfirst_node(TargetEntry, lc);
326 67723 : Var *variable = NULL;
327 67723 : AttrNumber attnum = 0;
328 67723 : bool isSafeVar = false;
329 :
330 : /*
331 : * If tlist expression is a safe non-system Var, use the fast-path
332 : * ASSIGN_*_VAR opcodes. "Safe" means that we don't need to apply
333 : * CheckVarSlotCompatibility() during plan startup. If a source slot
334 : * was provided, we make the equivalent tests here; if a slot was not
335 : * provided, we assume that no check is needed because we're dealing
336 : * with a non-relation-scan-level expression.
337 : */
338 135446 : if (tle->expr != NULL &&
339 104192 : IsA(tle->expr, Var) &&
340 36469 : ((Var *) tle->expr)->varattno > 0)
341 : {
342 : /* Non-system Var, but how safe is it? */
343 29600 : variable = (Var *) tle->expr;
344 29600 : attnum = variable->varattno;
345 :
346 29600 : if (inputDesc == NULL)
347 14498 : isSafeVar = true; /* can't check, just assume OK */
348 15102 : else if (attnum <= inputDesc->natts)
349 : {
350 15066 : Form_pg_attribute attr = TupleDescAttr(inputDesc, attnum - 1);
351 :
352 : /*
353 : * If user attribute is dropped or has a type mismatch, don't
354 : * use ASSIGN_*_VAR. Instead let the normal expression
355 : * machinery handle it (which'll possibly error out).
356 : */
357 15066 : if (!attr->attisdropped && variable->vartype == attr->atttypid)
358 : {
359 15059 : isSafeVar = true;
360 : }
361 : }
362 : }
363 :
364 67723 : if (isSafeVar)
365 : {
366 : /* Fast-path: just generate an EEOP_ASSIGN_*_VAR step */
367 29557 : switch (variable->varno)
368 : {
369 : case INNER_VAR:
370 : /* get the tuple from the inner node */
371 3861 : scratch.opcode = EEOP_ASSIGN_INNER_VAR;
372 3861 : break;
373 :
374 : case OUTER_VAR:
375 : /* get the tuple from the outer node */
376 10626 : scratch.opcode = EEOP_ASSIGN_OUTER_VAR;
377 10626 : break;
378 :
379 : /* INDEX_VAR is handled by default case */
380 :
381 : default:
382 : /* get the tuple from the relation being scanned */
383 15070 : scratch.opcode = EEOP_ASSIGN_SCAN_VAR;
384 15070 : break;
385 : }
386 :
387 29557 : scratch.d.assign_var.attnum = attnum - 1;
388 29557 : scratch.d.assign_var.resultnum = tle->resno - 1;
389 29557 : ExprEvalPushStep(state, &scratch);
390 : }
391 : else
392 : {
393 : /*
394 : * Otherwise, compile the column expression normally.
395 : *
396 : * We can't tell the expression to evaluate directly into the
397 : * result slot, as the result slot (and the exprstate for that
398 : * matter) can change between executions. We instead evaluate
399 : * into the ExprState's resvalue/resnull and then move.
400 : */
401 38166 : ExecInitExprRec(tle->expr, parent, state,
402 : &state->resvalue, &state->resnull);
403 :
404 : /*
405 : * Column might be referenced multiple times in upper nodes, so
406 : * force value to R/O - but only if it could be an expanded datum.
407 : */
408 38164 : if (get_typlen(exprType((Node *) tle->expr)) == -1)
409 14512 : scratch.opcode = EEOP_ASSIGN_TMP_MAKE_RO;
410 : else
411 23652 : scratch.opcode = EEOP_ASSIGN_TMP;
412 38164 : scratch.d.assign_tmp.resultnum = tle->resno - 1;
413 38164 : ExprEvalPushStep(state, &scratch);
414 : }
415 : }
416 :
417 35060 : scratch.opcode = EEOP_DONE;
418 35060 : ExprEvalPushStep(state, &scratch);
419 :
420 35060 : ExecReadyExpr(state);
421 :
422 35060 : return projInfo;
423 : }
424 :
425 : /*
426 : * ExecPrepareExpr --- initialize for expression execution outside a normal
427 : * Plan tree context.
428 : *
429 : * This differs from ExecInitExpr in that we don't assume the caller is
430 : * already running in the EState's per-query context. Also, we run the
431 : * passed expression tree through expression_planner() to prepare it for
432 : * execution. (In ordinary Plan trees the regular planning process will have
433 : * made the appropriate transformations on expressions, but for standalone
434 : * expressions this won't have happened.)
435 : */
436 : ExprState *
437 401 : ExecPrepareExpr(Expr *node, EState *estate)
438 : {
439 : ExprState *result;
440 : MemoryContext oldcontext;
441 :
442 401 : oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
443 :
444 401 : node = expression_planner(node);
445 :
446 401 : result = ExecInitExpr(node, NULL);
447 :
448 401 : MemoryContextSwitchTo(oldcontext);
449 :
450 401 : return result;
451 : }
452 :
453 : /*
454 : * ExecPrepareQual --- initialize for qual execution outside a normal
455 : * Plan tree context.
456 : *
457 : * This differs from ExecInitQual in that we don't assume the caller is
458 : * already running in the EState's per-query context. Also, we run the
459 : * passed expression tree through expression_planner() to prepare it for
460 : * execution. (In ordinary Plan trees the regular planning process will have
461 : * made the appropriate transformations on expressions, but for standalone
462 : * expressions this won't have happened.)
463 : */
464 : ExprState *
465 1563 : ExecPrepareQual(List *qual, EState *estate)
466 : {
467 : ExprState *result;
468 : MemoryContext oldcontext;
469 :
470 1563 : oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
471 :
472 1563 : qual = (List *) expression_planner((Expr *) qual);
473 :
474 1563 : result = ExecInitQual(qual, NULL);
475 :
476 1563 : MemoryContextSwitchTo(oldcontext);
477 :
478 1563 : return result;
479 : }
480 :
481 : /*
482 : * ExecPrepareCheck -- initialize check constraint for execution outside a
483 : * normal Plan tree context.
484 : *
485 : * See ExecPrepareExpr() and ExecInitCheck() for details.
486 : */
487 : ExprState *
488 72 : ExecPrepareCheck(List *qual, EState *estate)
489 : {
490 : ExprState *result;
491 : MemoryContext oldcontext;
492 :
493 72 : oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
494 :
495 72 : qual = (List *) expression_planner((Expr *) qual);
496 :
497 72 : result = ExecInitCheck(qual, NULL);
498 :
499 72 : MemoryContextSwitchTo(oldcontext);
500 :
501 72 : return result;
502 : }
503 :
504 : /*
505 : * Call ExecPrepareExpr() on each member of a list of Exprs, and return
506 : * a list of ExprStates.
507 : *
508 : * See ExecPrepareExpr() for details.
509 : */
510 : List *
511 114 : ExecPrepareExprList(List *nodes, EState *estate)
512 : {
513 114 : List *result = NIL;
514 : MemoryContext oldcontext;
515 : ListCell *lc;
516 :
517 : /* Ensure that the list cell nodes are in the right context too */
518 114 : oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
519 :
520 239 : foreach(lc, nodes)
521 : {
522 125 : Expr *e = (Expr *) lfirst(lc);
523 :
524 125 : result = lappend(result, ExecPrepareExpr(e, estate));
525 : }
526 :
527 114 : MemoryContextSwitchTo(oldcontext);
528 :
529 114 : return result;
530 : }
531 :
532 : /*
533 : * ExecCheck - evaluate a check constraint
534 : *
535 : * For check constraints, a null result is taken as TRUE, ie the constraint
536 : * passes.
537 : *
538 : * The check constraint may have been prepared with ExecInitCheck
539 : * (possibly via ExecPrepareCheck) if the caller had it in implicit-AND
540 : * format, but a regular boolean expression prepared with ExecInitExpr or
541 : * ExecPrepareExpr works too.
542 : */
543 : bool
544 2566 : ExecCheck(ExprState *state, ExprContext *econtext)
545 : {
546 : Datum ret;
547 : bool isnull;
548 :
549 : /* short-circuit (here and in ExecInitCheck) for empty restriction list */
550 2566 : if (state == NULL)
551 0 : return true;
552 :
553 : /* verify that expression was not compiled using ExecInitQual */
554 2566 : Assert(!(state->flags & EEO_FLAG_IS_QUAL));
555 :
556 2566 : ret = ExecEvalExprSwitchContext(state, econtext, &isnull);
557 :
558 2566 : if (isnull)
559 454 : return true;
560 :
561 2112 : return DatumGetBool(ret);
562 : }
563 :
564 : /*
565 : * Prepare a compiled expression for execution. This has to be called for
566 : * every ExprState before it can be executed.
567 : *
568 : * NB: While this currently only calls ExecReadyInterpretedExpr(),
569 : * this will likely get extended to further expression evaluation methods.
570 : * Therefore this should be used instead of directly calling
571 : * ExecReadyInterpretedExpr().
572 : */
573 : static void
574 108107 : ExecReadyExpr(ExprState *state)
575 : {
576 108107 : ExecReadyInterpretedExpr(state);
577 108107 : }
578 :
579 : /*
580 : * Append the steps necessary for the evaluation of node to ExprState->steps,
581 : * possibly recursing into sub-expressions of node.
582 : *
583 : * node - expression to evaluate
584 : * parent - parent executor node (or NULL if a standalone expression)
585 : * state - ExprState to whose ->steps to append the necessary operations
586 : * resv / resnull - where to store the result of the node into
587 : */
588 : static void
589 202328 : ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state,
590 : Datum *resv, bool *resnull)
591 : {
592 : ExprEvalStep scratch;
593 :
594 : /* Guard against stack overflow due to overly complex expressions */
595 202328 : check_stack_depth();
596 :
597 : /* Step's output location is always what the caller gave us */
598 202328 : Assert(resv != NULL && resnull != NULL);
599 202328 : scratch.resvalue = resv;
600 202328 : scratch.resnull = resnull;
601 :
602 : /* cases should be ordered as they are in enum NodeTag */
603 202328 : switch (nodeTag(node))
604 : {
605 : case T_Var:
606 : {
607 52910 : Var *variable = (Var *) node;
608 :
609 52910 : if (variable->varattno == InvalidAttrNumber)
610 : {
611 : /* whole-row Var */
612 304 : ExecInitWholeRowVar(&scratch, variable, parent);
613 : }
614 52606 : else if (variable->varattno <= 0)
615 : {
616 : /* system column */
617 9146 : scratch.d.var.attnum = variable->varattno;
618 9146 : scratch.d.var.vartype = variable->vartype;
619 9146 : switch (variable->varno)
620 : {
621 : case INNER_VAR:
622 0 : scratch.opcode = EEOP_INNER_SYSVAR;
623 0 : break;
624 : case OUTER_VAR:
625 0 : scratch.opcode = EEOP_OUTER_SYSVAR;
626 0 : break;
627 :
628 : /* INDEX_VAR is handled by default case */
629 :
630 : default:
631 9146 : scratch.opcode = EEOP_SCAN_SYSVAR;
632 9146 : break;
633 : }
634 : }
635 : else
636 : {
637 : /* regular user column */
638 43460 : scratch.d.var.attnum = variable->varattno - 1;
639 43460 : scratch.d.var.vartype = variable->vartype;
640 : /* select EEOP_*_FIRST opcode to force one-time checks */
641 43460 : switch (variable->varno)
642 : {
643 : case INNER_VAR:
644 5738 : scratch.opcode = EEOP_INNER_VAR_FIRST;
645 5738 : break;
646 : case OUTER_VAR:
647 7581 : scratch.opcode = EEOP_OUTER_VAR_FIRST;
648 7581 : break;
649 :
650 : /* INDEX_VAR is handled by default case */
651 :
652 : default:
653 30141 : scratch.opcode = EEOP_SCAN_VAR_FIRST;
654 30141 : break;
655 : }
656 : }
657 :
658 52910 : ExprEvalPushStep(state, &scratch);
659 52910 : break;
660 : }
661 :
662 : case T_Const:
663 : {
664 37967 : Const *con = (Const *) node;
665 :
666 37967 : scratch.opcode = EEOP_CONST;
667 37967 : scratch.d.constval.value = con->constvalue;
668 37967 : scratch.d.constval.isnull = con->constisnull;
669 :
670 37967 : ExprEvalPushStep(state, &scratch);
671 37967 : break;
672 : }
673 :
674 : case T_Param:
675 : {
676 36535 : Param *param = (Param *) node;
677 :
678 36535 : switch (param->paramkind)
679 : {
680 : case PARAM_EXEC:
681 18190 : scratch.opcode = EEOP_PARAM_EXEC;
682 18190 : scratch.d.param.paramid = param->paramid;
683 18190 : scratch.d.param.paramtype = param->paramtype;
684 18190 : break;
685 : case PARAM_EXTERN:
686 18345 : scratch.opcode = EEOP_PARAM_EXTERN;
687 18345 : scratch.d.param.paramid = param->paramid;
688 18345 : scratch.d.param.paramtype = param->paramtype;
689 18345 : break;
690 : default:
691 0 : elog(ERROR, "unrecognized paramkind: %d",
692 : (int) param->paramkind);
693 : break;
694 : }
695 :
696 36535 : ExprEvalPushStep(state, &scratch);
697 36535 : break;
698 : }
699 :
700 : case T_Aggref:
701 : {
702 2768 : Aggref *aggref = (Aggref *) node;
703 2768 : AggrefExprState *astate = makeNode(AggrefExprState);
704 :
705 2768 : scratch.opcode = EEOP_AGGREF;
706 2768 : scratch.d.aggref.astate = astate;
707 2768 : astate->aggref = aggref;
708 :
709 2768 : if (parent && IsA(parent, AggState))
710 2768 : {
711 2768 : AggState *aggstate = (AggState *) parent;
712 :
713 2768 : aggstate->aggs = lcons(astate, aggstate->aggs);
714 2768 : aggstate->numaggs++;
715 : }
716 : else
717 : {
718 : /* planner messed up */
719 0 : elog(ERROR, "Aggref found in non-Agg plan node");
720 : }
721 :
722 2768 : ExprEvalPushStep(state, &scratch);
723 2768 : break;
724 : }
725 :
726 : case T_GroupingFunc:
727 : {
728 39 : GroupingFunc *grp_node = (GroupingFunc *) node;
729 : Agg *agg;
730 :
731 78 : if (!parent || !IsA(parent, AggState) ||
732 39 : !IsA(parent->plan, Agg))
733 0 : elog(ERROR, "GroupingFunc found in non-Agg plan node");
734 :
735 39 : scratch.opcode = EEOP_GROUPING_FUNC;
736 39 : scratch.d.grouping_func.parent = (AggState *) parent;
737 :
738 39 : agg = (Agg *) (parent->plan);
739 :
740 39 : if (agg->groupingSets)
741 31 : scratch.d.grouping_func.clauses = grp_node->cols;
742 : else
743 8 : scratch.d.grouping_func.clauses = NIL;
744 :
745 39 : ExprEvalPushStep(state, &scratch);
746 39 : break;
747 : }
748 :
749 : case T_WindowFunc:
750 : {
751 166 : WindowFunc *wfunc = (WindowFunc *) node;
752 166 : WindowFuncExprState *wfstate = makeNode(WindowFuncExprState);
753 :
754 166 : wfstate->wfunc = wfunc;
755 :
756 166 : if (parent && IsA(parent, WindowAggState))
757 166 : {
758 166 : WindowAggState *winstate = (WindowAggState *) parent;
759 : int nfuncs;
760 :
761 166 : winstate->funcs = lcons(wfstate, winstate->funcs);
762 166 : nfuncs = ++winstate->numfuncs;
763 166 : if (wfunc->winagg)
764 116 : winstate->numaggs++;
765 :
766 : /* for now initialize agg using old style expressions */
767 166 : wfstate->args = ExecInitExprList(wfunc->args, parent);
768 166 : wfstate->aggfilter = ExecInitExpr(wfunc->aggfilter,
769 : parent);
770 :
771 : /*
772 : * Complain if the windowfunc's arguments contain any
773 : * windowfuncs; nested window functions are semantically
774 : * nonsensical. (This should have been caught earlier,
775 : * but we defend against it here anyway.)
776 : */
777 166 : if (nfuncs != winstate->numfuncs)
778 0 : ereport(ERROR,
779 : (errcode(ERRCODE_WINDOWING_ERROR),
780 : errmsg("window function calls cannot be nested")));
781 : }
782 : else
783 : {
784 : /* planner messed up */
785 0 : elog(ERROR, "WindowFunc found in non-WindowAgg plan node");
786 : }
787 :
788 166 : scratch.opcode = EEOP_WINDOW_FUNC;
789 166 : scratch.d.window_func.wfstate = wfstate;
790 166 : ExprEvalPushStep(state, &scratch);
791 166 : break;
792 : }
793 :
794 : case T_ArrayRef:
795 : {
796 728 : ArrayRef *aref = (ArrayRef *) node;
797 :
798 728 : ExecInitArrayRef(&scratch, aref, parent, state, resv, resnull);
799 727 : break;
800 : }
801 :
802 : case T_FuncExpr:
803 : {
804 20111 : FuncExpr *func = (FuncExpr *) node;
805 :
806 20111 : ExecInitFunc(&scratch, node,
807 : func->args, func->funcid, func->inputcollid,
808 : parent, state);
809 20110 : ExprEvalPushStep(state, &scratch);
810 20110 : break;
811 : }
812 :
813 : case T_OpExpr:
814 : {
815 34385 : OpExpr *op = (OpExpr *) node;
816 :
817 34385 : ExecInitFunc(&scratch, node,
818 : op->args, op->opfuncid, op->inputcollid,
819 : parent, state);
820 34385 : ExprEvalPushStep(state, &scratch);
821 34385 : break;
822 : }
823 :
824 : case T_DistinctExpr:
825 : {
826 39 : DistinctExpr *op = (DistinctExpr *) node;
827 :
828 39 : ExecInitFunc(&scratch, node,
829 : op->args, op->opfuncid, op->inputcollid,
830 : parent, state);
831 :
832 : /*
833 : * Change opcode of call instruction to EEOP_DISTINCT.
834 : *
835 : * XXX: historically we've not called the function usage
836 : * pgstat infrastructure - that seems inconsistent given that
837 : * we do so for normal function *and* operator evaluation. If
838 : * we decided to do that here, we'd probably want separate
839 : * opcodes for FUSAGE or not.
840 : */
841 39 : scratch.opcode = EEOP_DISTINCT;
842 39 : ExprEvalPushStep(state, &scratch);
843 39 : break;
844 : }
845 :
846 : case T_NullIfExpr:
847 : {
848 11 : NullIfExpr *op = (NullIfExpr *) node;
849 :
850 11 : ExecInitFunc(&scratch, node,
851 : op->args, op->opfuncid, op->inputcollid,
852 : parent, state);
853 :
854 : /*
855 : * Change opcode of call instruction to EEOP_NULLIF.
856 : *
857 : * XXX: historically we've not called the function usage
858 : * pgstat infrastructure - that seems inconsistent given that
859 : * we do so for normal function *and* operator evaluation. If
860 : * we decided to do that here, we'd probably want separate
861 : * opcodes for FUSAGE or not.
862 : */
863 11 : scratch.opcode = EEOP_NULLIF;
864 11 : ExprEvalPushStep(state, &scratch);
865 11 : break;
866 : }
867 :
868 : case T_ScalarArrayOpExpr:
869 : {
870 1031 : ScalarArrayOpExpr *opexpr = (ScalarArrayOpExpr *) node;
871 : Expr *scalararg;
872 : Expr *arrayarg;
873 : FmgrInfo *finfo;
874 : FunctionCallInfo fcinfo;
875 : AclResult aclresult;
876 :
877 1031 : Assert(list_length(opexpr->args) == 2);
878 1031 : scalararg = (Expr *) linitial(opexpr->args);
879 1031 : arrayarg = (Expr *) lsecond(opexpr->args);
880 :
881 : /* Check permission to call function */
882 1031 : aclresult = pg_proc_aclcheck(opexpr->opfuncid,
883 : GetUserId(),
884 : ACL_EXECUTE);
885 1031 : if (aclresult != ACLCHECK_OK)
886 0 : aclcheck_error(aclresult, ACL_KIND_PROC,
887 0 : get_func_name(opexpr->opfuncid));
888 1031 : InvokeFunctionExecuteHook(opexpr->opfuncid);
889 :
890 : /* Set up the primary fmgr lookup information */
891 1031 : finfo = palloc0(sizeof(FmgrInfo));
892 1031 : fcinfo = palloc0(sizeof(FunctionCallInfoData));
893 1031 : fmgr_info(opexpr->opfuncid, finfo);
894 1031 : fmgr_info_set_expr((Node *) node, finfo);
895 1031 : InitFunctionCallInfoData(*fcinfo, finfo, 2,
896 : opexpr->inputcollid, NULL, NULL);
897 :
898 : /* Evaluate scalar directly into left function argument */
899 1031 : ExecInitExprRec(scalararg, parent, state,
900 : &fcinfo->arg[0], &fcinfo->argnull[0]);
901 :
902 : /*
903 : * Evaluate array argument into our return value. There's no
904 : * danger in that, because the return value is guaranteed to
905 : * be overwritten by EEOP_SCALARARRAYOP, and will not be
906 : * passed to any other expression.
907 : */
908 1031 : ExecInitExprRec(arrayarg, parent, state, resv, resnull);
909 :
910 : /* And perform the operation */
911 1031 : scratch.opcode = EEOP_SCALARARRAYOP;
912 1031 : scratch.d.scalararrayop.element_type = InvalidOid;
913 1031 : scratch.d.scalararrayop.useOr = opexpr->useOr;
914 1031 : scratch.d.scalararrayop.finfo = finfo;
915 1031 : scratch.d.scalararrayop.fcinfo_data = fcinfo;
916 1031 : scratch.d.scalararrayop.fn_addr = finfo->fn_addr;
917 1031 : ExprEvalPushStep(state, &scratch);
918 1031 : break;
919 : }
920 :
921 : case T_BoolExpr:
922 : {
923 2048 : BoolExpr *boolexpr = (BoolExpr *) node;
924 2048 : int nargs = list_length(boolexpr->args);
925 2048 : List *adjust_jumps = NIL;
926 : int off;
927 : ListCell *lc;
928 :
929 : /* allocate scratch memory used by all steps of AND/OR */
930 2048 : if (boolexpr->boolop != NOT_EXPR)
931 959 : scratch.d.boolexpr.anynull = (bool *) palloc(sizeof(bool));
932 :
933 : /*
934 : * For each argument evaluate the argument itself, then
935 : * perform the bool operation's appropriate handling.
936 : *
937 : * We can evaluate each argument into our result area, since
938 : * the short-circuiting logic means we only need to remember
939 : * previous NULL values.
940 : *
941 : * AND/OR is split into separate STEP_FIRST (one) / STEP (zero
942 : * or more) / STEP_LAST (one) steps, as each of those has to
943 : * perform different work. The FIRST/LAST split is valid
944 : * because AND/OR have at least two arguments.
945 : */
946 2048 : off = 0;
947 5568 : foreach(lc, boolexpr->args)
948 : {
949 3520 : Expr *arg = (Expr *) lfirst(lc);
950 :
951 : /* Evaluate argument into our output variable */
952 3520 : ExecInitExprRec(arg, parent, state, resv, resnull);
953 :
954 : /* Perform the appropriate step type */
955 3520 : switch (boolexpr->boolop)
956 : {
957 : case AND_EXPR:
958 1178 : Assert(nargs >= 2);
959 :
960 1178 : if (off == 0)
961 482 : scratch.opcode = EEOP_BOOL_AND_STEP_FIRST;
962 696 : else if (off + 1 == nargs)
963 482 : scratch.opcode = EEOP_BOOL_AND_STEP_LAST;
964 : else
965 214 : scratch.opcode = EEOP_BOOL_AND_STEP;
966 1178 : break;
967 : case OR_EXPR:
968 1253 : Assert(nargs >= 2);
969 :
970 1253 : if (off == 0)
971 477 : scratch.opcode = EEOP_BOOL_OR_STEP_FIRST;
972 776 : else if (off + 1 == nargs)
973 477 : scratch.opcode = EEOP_BOOL_OR_STEP_LAST;
974 : else
975 299 : scratch.opcode = EEOP_BOOL_OR_STEP;
976 1253 : break;
977 : case NOT_EXPR:
978 1089 : Assert(nargs == 1);
979 :
980 1089 : scratch.opcode = EEOP_BOOL_NOT_STEP;
981 1089 : break;
982 : default:
983 0 : elog(ERROR, "unrecognized boolop: %d",
984 : (int) boolexpr->boolop);
985 : break;
986 : }
987 :
988 3520 : scratch.d.boolexpr.jumpdone = -1;
989 3520 : ExprEvalPushStep(state, &scratch);
990 3520 : adjust_jumps = lappend_int(adjust_jumps,
991 3520 : state->steps_len - 1);
992 3520 : off++;
993 : }
994 :
995 : /* adjust jump targets */
996 5568 : foreach(lc, adjust_jumps)
997 : {
998 3520 : ExprEvalStep *as = &state->steps[lfirst_int(lc)];
999 :
1000 3520 : Assert(as->d.boolexpr.jumpdone == -1);
1001 3520 : as->d.boolexpr.jumpdone = state->steps_len;
1002 : }
1003 :
1004 2048 : break;
1005 : }
1006 :
1007 : case T_SubPlan:
1008 : {
1009 1210 : SubPlan *subplan = (SubPlan *) node;
1010 : SubPlanState *sstate;
1011 :
1012 1210 : if (!parent)
1013 0 : elog(ERROR, "SubPlan found with no parent plan");
1014 :
1015 1210 : sstate = ExecInitSubPlan(subplan, parent);
1016 :
1017 : /* add SubPlanState nodes to parent->subPlan */
1018 1210 : parent->subPlan = lappend(parent->subPlan, sstate);
1019 :
1020 1210 : scratch.opcode = EEOP_SUBPLAN;
1021 1210 : scratch.d.subplan.sstate = sstate;
1022 :
1023 1210 : ExprEvalPushStep(state, &scratch);
1024 1210 : break;
1025 : }
1026 :
1027 : case T_AlternativeSubPlan:
1028 : {
1029 99 : AlternativeSubPlan *asplan = (AlternativeSubPlan *) node;
1030 : AlternativeSubPlanState *asstate;
1031 :
1032 99 : if (!parent)
1033 0 : elog(ERROR, "AlternativeSubPlan found with no parent plan");
1034 :
1035 99 : asstate = ExecInitAlternativeSubPlan(asplan, parent);
1036 :
1037 99 : scratch.opcode = EEOP_ALTERNATIVE_SUBPLAN;
1038 99 : scratch.d.alternative_subplan.asstate = asstate;
1039 :
1040 99 : ExprEvalPushStep(state, &scratch);
1041 99 : break;
1042 : }
1043 :
1044 : case T_FieldSelect:
1045 : {
1046 757 : FieldSelect *fselect = (FieldSelect *) node;
1047 :
1048 : /* evaluate row/record argument into result area */
1049 757 : ExecInitExprRec(fselect->arg, parent, state, resv, resnull);
1050 :
1051 : /* and extract field */
1052 757 : scratch.opcode = EEOP_FIELDSELECT;
1053 757 : scratch.d.fieldselect.fieldnum = fselect->fieldnum;
1054 757 : scratch.d.fieldselect.resulttype = fselect->resulttype;
1055 757 : scratch.d.fieldselect.argdesc = NULL;
1056 :
1057 757 : ExprEvalPushStep(state, &scratch);
1058 757 : break;
1059 : }
1060 :
1061 : case T_FieldStore:
1062 : {
1063 30 : FieldStore *fstore = (FieldStore *) node;
1064 : TupleDesc tupDesc;
1065 : TupleDesc *descp;
1066 : Datum *values;
1067 : bool *nulls;
1068 : int ncolumns;
1069 : ListCell *l1,
1070 : *l2;
1071 :
1072 : /* find out the number of columns in the composite type */
1073 30 : tupDesc = lookup_rowtype_tupdesc(fstore->resulttype, -1);
1074 30 : ncolumns = tupDesc->natts;
1075 30 : DecrTupleDescRefCount(tupDesc);
1076 :
1077 : /* create workspace for column values */
1078 30 : values = (Datum *) palloc(sizeof(Datum) * ncolumns);
1079 30 : nulls = (bool *) palloc(sizeof(bool) * ncolumns);
1080 :
1081 : /* create workspace for runtime tupdesc cache */
1082 30 : descp = (TupleDesc *) palloc(sizeof(TupleDesc));
1083 30 : *descp = NULL;
1084 :
1085 : /* emit code to evaluate the composite input value */
1086 30 : ExecInitExprRec(fstore->arg, parent, state, resv, resnull);
1087 :
1088 : /* next, deform the input tuple into our workspace */
1089 30 : scratch.opcode = EEOP_FIELDSTORE_DEFORM;
1090 30 : scratch.d.fieldstore.fstore = fstore;
1091 30 : scratch.d.fieldstore.argdesc = descp;
1092 30 : scratch.d.fieldstore.values = values;
1093 30 : scratch.d.fieldstore.nulls = nulls;
1094 30 : scratch.d.fieldstore.ncolumns = ncolumns;
1095 30 : ExprEvalPushStep(state, &scratch);
1096 :
1097 : /* evaluate new field values, store in workspace columns */
1098 67 : forboth(l1, fstore->newvals, l2, fstore->fieldnums)
1099 : {
1100 37 : Expr *e = (Expr *) lfirst(l1);
1101 37 : AttrNumber fieldnum = lfirst_int(l2);
1102 : Datum *save_innermost_caseval;
1103 : bool *save_innermost_casenull;
1104 :
1105 37 : if (fieldnum <= 0 || fieldnum > ncolumns)
1106 0 : elog(ERROR, "field number %d is out of range in FieldStore",
1107 : fieldnum);
1108 :
1109 : /*
1110 : * Use the CaseTestExpr mechanism to pass down the old
1111 : * value of the field being replaced; this is needed in
1112 : * case the newval is itself a FieldStore or ArrayRef that
1113 : * has to obtain and modify the old value. It's safe to
1114 : * reuse the CASE mechanism because there cannot be a CASE
1115 : * between here and where the value would be needed, and a
1116 : * field assignment can't be within a CASE either. (So
1117 : * saving and restoring innermost_caseval is just
1118 : * paranoia, but let's do it anyway.)
1119 : *
1120 : * Another non-obvious point is that it's safe to use the
1121 : * field's values[]/nulls[] entries as both the caseval
1122 : * source and the result address for this subexpression.
1123 : * That's okay only because (1) both FieldStore and
1124 : * ArrayRef evaluate their arg or refexpr inputs first,
1125 : * and (2) any such CaseTestExpr is directly the arg or
1126 : * refexpr input. So any read of the caseval will occur
1127 : * before there's a chance to overwrite it. Also, if
1128 : * multiple entries in the newvals/fieldnums lists target
1129 : * the same field, they'll effectively be applied
1130 : * left-to-right which is what we want.
1131 : */
1132 37 : save_innermost_caseval = state->innermost_caseval;
1133 37 : save_innermost_casenull = state->innermost_casenull;
1134 37 : state->innermost_caseval = &values[fieldnum - 1];
1135 37 : state->innermost_casenull = &nulls[fieldnum - 1];
1136 :
1137 74 : ExecInitExprRec(e, parent, state,
1138 37 : &values[fieldnum - 1],
1139 37 : &nulls[fieldnum - 1]);
1140 :
1141 37 : state->innermost_caseval = save_innermost_caseval;
1142 37 : state->innermost_casenull = save_innermost_casenull;
1143 : }
1144 :
1145 : /* finally, form result tuple */
1146 30 : scratch.opcode = EEOP_FIELDSTORE_FORM;
1147 30 : scratch.d.fieldstore.fstore = fstore;
1148 30 : scratch.d.fieldstore.argdesc = descp;
1149 30 : scratch.d.fieldstore.values = values;
1150 30 : scratch.d.fieldstore.nulls = nulls;
1151 30 : scratch.d.fieldstore.ncolumns = ncolumns;
1152 30 : ExprEvalPushStep(state, &scratch);
1153 30 : break;
1154 : }
1155 :
1156 : case T_RelabelType:
1157 : {
1158 : /* relabel doesn't need to do anything at runtime */
1159 2673 : RelabelType *relabel = (RelabelType *) node;
1160 :
1161 2673 : ExecInitExprRec(relabel->arg, parent, state, resv, resnull);
1162 2673 : break;
1163 : }
1164 :
1165 : case T_CoerceViaIO:
1166 : {
1167 770 : CoerceViaIO *iocoerce = (CoerceViaIO *) node;
1168 : Oid iofunc;
1169 : bool typisvarlena;
1170 : Oid typioparam;
1171 : FunctionCallInfo fcinfo_in;
1172 :
1173 : /* evaluate argument into step's result area */
1174 770 : ExecInitExprRec(iocoerce->arg, parent, state, resv, resnull);
1175 :
1176 : /*
1177 : * Prepare both output and input function calls, to be
1178 : * evaluated inside a single evaluation step for speed - this
1179 : * can be a very common operation.
1180 : *
1181 : * We don't check permissions here as a type's input/output
1182 : * function are assumed to be executable by everyone.
1183 : */
1184 770 : scratch.opcode = EEOP_IOCOERCE;
1185 :
1186 : /* lookup the source type's output function */
1187 770 : scratch.d.iocoerce.finfo_out = palloc0(sizeof(FmgrInfo));
1188 770 : scratch.d.iocoerce.fcinfo_data_out = palloc0(sizeof(FunctionCallInfoData));
1189 :
1190 770 : getTypeOutputInfo(exprType((Node *) iocoerce->arg),
1191 : &iofunc, &typisvarlena);
1192 770 : fmgr_info(iofunc, scratch.d.iocoerce.finfo_out);
1193 770 : fmgr_info_set_expr((Node *) node, scratch.d.iocoerce.finfo_out);
1194 770 : InitFunctionCallInfoData(*scratch.d.iocoerce.fcinfo_data_out,
1195 : scratch.d.iocoerce.finfo_out,
1196 : 1, InvalidOid, NULL, NULL);
1197 :
1198 : /* lookup the result type's input function */
1199 770 : scratch.d.iocoerce.finfo_in = palloc0(sizeof(FmgrInfo));
1200 770 : scratch.d.iocoerce.fcinfo_data_in = palloc0(sizeof(FunctionCallInfoData));
1201 :
1202 770 : getTypeInputInfo(iocoerce->resulttype,
1203 : &iofunc, &typioparam);
1204 770 : fmgr_info(iofunc, scratch.d.iocoerce.finfo_in);
1205 770 : fmgr_info_set_expr((Node *) node, scratch.d.iocoerce.finfo_in);
1206 770 : InitFunctionCallInfoData(*scratch.d.iocoerce.fcinfo_data_in,
1207 : scratch.d.iocoerce.finfo_in,
1208 : 3, InvalidOid, NULL, NULL);
1209 :
1210 : /*
1211 : * We can preload the second and third arguments for the input
1212 : * function, since they're constants.
1213 : */
1214 770 : fcinfo_in = scratch.d.iocoerce.fcinfo_data_in;
1215 770 : fcinfo_in->arg[1] = ObjectIdGetDatum(typioparam);
1216 770 : fcinfo_in->argnull[1] = false;
1217 770 : fcinfo_in->arg[2] = Int32GetDatum(-1);
1218 770 : fcinfo_in->argnull[2] = false;
1219 :
1220 770 : ExprEvalPushStep(state, &scratch);
1221 770 : break;
1222 : }
1223 :
1224 : case T_ArrayCoerceExpr:
1225 : {
1226 101 : ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node;
1227 : Oid resultelemtype;
1228 :
1229 : /* evaluate argument into step's result area */
1230 101 : ExecInitExprRec(acoerce->arg, parent, state, resv, resnull);
1231 :
1232 101 : resultelemtype = get_element_type(acoerce->resulttype);
1233 101 : if (!OidIsValid(resultelemtype))
1234 0 : ereport(ERROR,
1235 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1236 : errmsg("target type is not an array")));
1237 : /* Arrays over domains aren't supported yet */
1238 101 : Assert(getBaseType(resultelemtype) == resultelemtype);
1239 :
1240 101 : scratch.opcode = EEOP_ARRAYCOERCE;
1241 101 : scratch.d.arraycoerce.coerceexpr = acoerce;
1242 101 : scratch.d.arraycoerce.resultelemtype = resultelemtype;
1243 :
1244 101 : if (OidIsValid(acoerce->elemfuncid))
1245 : {
1246 : AclResult aclresult;
1247 :
1248 : /* Check permission to call function */
1249 28 : aclresult = pg_proc_aclcheck(acoerce->elemfuncid,
1250 : GetUserId(),
1251 : ACL_EXECUTE);
1252 28 : if (aclresult != ACLCHECK_OK)
1253 1 : aclcheck_error(aclresult, ACL_KIND_PROC,
1254 1 : get_func_name(acoerce->elemfuncid));
1255 27 : InvokeFunctionExecuteHook(acoerce->elemfuncid);
1256 :
1257 : /* Set up the primary fmgr lookup information */
1258 27 : scratch.d.arraycoerce.elemfunc =
1259 27 : (FmgrInfo *) palloc0(sizeof(FmgrInfo));
1260 27 : fmgr_info(acoerce->elemfuncid,
1261 : scratch.d.arraycoerce.elemfunc);
1262 27 : fmgr_info_set_expr((Node *) acoerce,
1263 : scratch.d.arraycoerce.elemfunc);
1264 :
1265 : /* Set up workspace for array_map */
1266 27 : scratch.d.arraycoerce.amstate =
1267 27 : (ArrayMapState *) palloc0(sizeof(ArrayMapState));
1268 : }
1269 : else
1270 : {
1271 : /* Don't need workspace if there's no conversion func */
1272 73 : scratch.d.arraycoerce.elemfunc = NULL;
1273 73 : scratch.d.arraycoerce.amstate = NULL;
1274 : }
1275 :
1276 100 : ExprEvalPushStep(state, &scratch);
1277 100 : break;
1278 : }
1279 :
1280 : case T_ConvertRowtypeExpr:
1281 : {
1282 53 : ConvertRowtypeExpr *convert = (ConvertRowtypeExpr *) node;
1283 :
1284 : /* evaluate argument into step's result area */
1285 53 : ExecInitExprRec(convert->arg, parent, state, resv, resnull);
1286 :
1287 : /* and push conversion step */
1288 53 : scratch.opcode = EEOP_CONVERT_ROWTYPE;
1289 53 : scratch.d.convert_rowtype.convert = convert;
1290 53 : scratch.d.convert_rowtype.indesc = NULL;
1291 53 : scratch.d.convert_rowtype.outdesc = NULL;
1292 53 : scratch.d.convert_rowtype.map = NULL;
1293 53 : scratch.d.convert_rowtype.initialized = false;
1294 :
1295 53 : ExprEvalPushStep(state, &scratch);
1296 53 : break;
1297 : }
1298 :
1299 : /* note that CaseWhen expressions are handled within this block */
1300 : case T_CaseExpr:
1301 : {
1302 1340 : CaseExpr *caseExpr = (CaseExpr *) node;
1303 1340 : List *adjust_jumps = NIL;
1304 1340 : Datum *caseval = NULL;
1305 1340 : bool *casenull = NULL;
1306 : ListCell *lc;
1307 :
1308 : /*
1309 : * If there's a test expression, we have to evaluate it and
1310 : * save the value where the CaseTestExpr placeholders can find
1311 : * it.
1312 : */
1313 1340 : if (caseExpr->arg != NULL)
1314 : {
1315 : /* Evaluate testexpr into caseval/casenull workspace */
1316 213 : caseval = palloc(sizeof(Datum));
1317 213 : casenull = palloc(sizeof(bool));
1318 :
1319 213 : ExecInitExprRec(caseExpr->arg, parent, state,
1320 : caseval, casenull);
1321 :
1322 : /*
1323 : * Since value might be read multiple times, force to R/O
1324 : * - but only if it could be an expanded datum.
1325 : */
1326 213 : if (get_typlen(exprType((Node *) caseExpr->arg)) == -1)
1327 : {
1328 : /* change caseval in-place */
1329 7 : scratch.opcode = EEOP_MAKE_READONLY;
1330 7 : scratch.resvalue = caseval;
1331 7 : scratch.resnull = casenull;
1332 7 : scratch.d.make_readonly.value = caseval;
1333 7 : scratch.d.make_readonly.isnull = casenull;
1334 7 : ExprEvalPushStep(state, &scratch);
1335 : /* restore normal settings of scratch fields */
1336 7 : scratch.resvalue = resv;
1337 7 : scratch.resnull = resnull;
1338 : }
1339 : }
1340 :
1341 : /*
1342 : * Prepare to evaluate each of the WHEN clauses in turn; as
1343 : * soon as one is true we return the value of the
1344 : * corresponding THEN clause. If none are true then we return
1345 : * the value of the ELSE clause, or NULL if there is none.
1346 : */
1347 3422 : foreach(lc, caseExpr->args)
1348 : {
1349 2082 : CaseWhen *when = (CaseWhen *) lfirst(lc);
1350 : Datum *save_innermost_caseval;
1351 : bool *save_innermost_casenull;
1352 : int whenstep;
1353 :
1354 : /*
1355 : * Make testexpr result available to CaseTestExpr nodes
1356 : * within the condition. We must save and restore prior
1357 : * setting of innermost_caseval fields, in case this node
1358 : * is itself within a larger CASE.
1359 : *
1360 : * If there's no test expression, we don't actually need
1361 : * to save and restore these fields; but it's less code to
1362 : * just do so unconditionally.
1363 : */
1364 2082 : save_innermost_caseval = state->innermost_caseval;
1365 2082 : save_innermost_casenull = state->innermost_casenull;
1366 2082 : state->innermost_caseval = caseval;
1367 2082 : state->innermost_casenull = casenull;
1368 :
1369 : /* evaluate condition into CASE's result variables */
1370 2082 : ExecInitExprRec(when->expr, parent, state, resv, resnull);
1371 :
1372 2082 : state->innermost_caseval = save_innermost_caseval;
1373 2082 : state->innermost_casenull = save_innermost_casenull;
1374 :
1375 : /* If WHEN result isn't true, jump to next CASE arm */
1376 2082 : scratch.opcode = EEOP_JUMP_IF_NOT_TRUE;
1377 2082 : scratch.d.jump.jumpdone = -1; /* computed later */
1378 2082 : ExprEvalPushStep(state, &scratch);
1379 2082 : whenstep = state->steps_len - 1;
1380 :
1381 : /*
1382 : * If WHEN result is true, evaluate THEN result, storing
1383 : * it into the CASE's result variables.
1384 : */
1385 2082 : ExecInitExprRec(when->result, parent, state, resv, resnull);
1386 :
1387 : /* Emit JUMP step to jump to end of CASE's code */
1388 2082 : scratch.opcode = EEOP_JUMP;
1389 2082 : scratch.d.jump.jumpdone = -1; /* computed later */
1390 2082 : ExprEvalPushStep(state, &scratch);
1391 :
1392 : /*
1393 : * Don't know address for that jump yet, compute once the
1394 : * whole CASE expression is built.
1395 : */
1396 2082 : adjust_jumps = lappend_int(adjust_jumps,
1397 2082 : state->steps_len - 1);
1398 :
1399 : /*
1400 : * But we can set WHEN test's jump target now, to make it
1401 : * jump to the next WHEN subexpression or the ELSE.
1402 : */
1403 2082 : state->steps[whenstep].d.jump.jumpdone = state->steps_len;
1404 : }
1405 :
1406 : /* transformCaseExpr always adds a default */
1407 1340 : Assert(caseExpr->defresult);
1408 :
1409 : /* evaluate ELSE expr into CASE's result variables */
1410 1340 : ExecInitExprRec(caseExpr->defresult, parent, state,
1411 : resv, resnull);
1412 :
1413 : /* adjust jump targets */
1414 3422 : foreach(lc, adjust_jumps)
1415 : {
1416 2082 : ExprEvalStep *as = &state->steps[lfirst_int(lc)];
1417 :
1418 2082 : Assert(as->opcode == EEOP_JUMP);
1419 2082 : Assert(as->d.jump.jumpdone == -1);
1420 2082 : as->d.jump.jumpdone = state->steps_len;
1421 : }
1422 :
1423 1340 : break;
1424 : }
1425 :
1426 : case T_CaseTestExpr:
1427 : {
1428 : /*
1429 : * Read from location identified by innermost_caseval. Note
1430 : * that innermost_caseval could be NULL, if this node isn't
1431 : * actually within a CASE structure; some parts of the system
1432 : * abuse CaseTestExpr to cause a read of a value externally
1433 : * supplied in econtext->caseValue_datum. We'll take care of
1434 : * that scenario at runtime.
1435 : */
1436 1156 : scratch.opcode = EEOP_CASE_TESTVAL;
1437 1156 : scratch.d.casetest.value = state->innermost_caseval;
1438 1156 : scratch.d.casetest.isnull = state->innermost_casenull;
1439 :
1440 1156 : ExprEvalPushStep(state, &scratch);
1441 1156 : break;
1442 : }
1443 :
1444 : case T_ArrayExpr:
1445 : {
1446 1288 : ArrayExpr *arrayexpr = (ArrayExpr *) node;
1447 1288 : int nelems = list_length(arrayexpr->elements);
1448 : ListCell *lc;
1449 : int elemoff;
1450 :
1451 : /*
1452 : * Evaluate by computing each element, and then forming the
1453 : * array. Elements are computed into scratch arrays
1454 : * associated with the ARRAYEXPR step.
1455 : */
1456 1288 : scratch.opcode = EEOP_ARRAYEXPR;
1457 1288 : scratch.d.arrayexpr.elemvalues =
1458 1288 : (Datum *) palloc(sizeof(Datum) * nelems);
1459 1288 : scratch.d.arrayexpr.elemnulls =
1460 1288 : (bool *) palloc(sizeof(bool) * nelems);
1461 1288 : scratch.d.arrayexpr.nelems = nelems;
1462 :
1463 : /* fill remaining fields of step */
1464 1288 : scratch.d.arrayexpr.multidims = arrayexpr->multidims;
1465 1288 : scratch.d.arrayexpr.elemtype = arrayexpr->element_typeid;
1466 :
1467 : /* do one-time catalog lookup for type info */
1468 1288 : get_typlenbyvalalign(arrayexpr->element_typeid,
1469 : &scratch.d.arrayexpr.elemlength,
1470 : &scratch.d.arrayexpr.elembyval,
1471 : &scratch.d.arrayexpr.elemalign);
1472 :
1473 : /* prepare to evaluate all arguments */
1474 1288 : elemoff = 0;
1475 4328 : foreach(lc, arrayexpr->elements)
1476 : {
1477 3040 : Expr *e = (Expr *) lfirst(lc);
1478 :
1479 9120 : ExecInitExprRec(e, parent, state,
1480 6080 : &scratch.d.arrayexpr.elemvalues[elemoff],
1481 3040 : &scratch.d.arrayexpr.elemnulls[elemoff]);
1482 3040 : elemoff++;
1483 : }
1484 :
1485 : /* and then collect all into an array */
1486 1288 : ExprEvalPushStep(state, &scratch);
1487 1288 : break;
1488 : }
1489 :
1490 : case T_RowExpr:
1491 : {
1492 342 : RowExpr *rowexpr = (RowExpr *) node;
1493 342 : int nelems = list_length(rowexpr->args);
1494 : TupleDesc tupdesc;
1495 : int i;
1496 : ListCell *l;
1497 :
1498 : /* Build tupdesc to describe result tuples */
1499 342 : if (rowexpr->row_typeid == RECORDOID)
1500 : {
1501 : /* generic record, use types of given expressions */
1502 146 : tupdesc = ExecTypeFromExprList(rowexpr->args);
1503 : }
1504 : else
1505 : {
1506 : /* it's been cast to a named type, use that */
1507 196 : tupdesc = lookup_rowtype_tupdesc_copy(rowexpr->row_typeid, -1);
1508 : }
1509 : /* In either case, adopt RowExpr's column aliases */
1510 342 : ExecTypeSetColNames(tupdesc, rowexpr->colnames);
1511 : /* Bless the tupdesc in case it's now of type RECORD */
1512 342 : BlessTupleDesc(tupdesc);
1513 :
1514 : /*
1515 : * In the named-type case, the tupdesc could have more columns
1516 : * than are in the args list, since the type might have had
1517 : * columns added since the ROW() was parsed. We want those
1518 : * extra columns to go to nulls, so we make sure that the
1519 : * workspace arrays are large enough and then initialize any
1520 : * extra columns to read as NULLs.
1521 : */
1522 342 : Assert(nelems <= tupdesc->natts);
1523 342 : nelems = Max(nelems, tupdesc->natts);
1524 :
1525 : /*
1526 : * Evaluate by first building datums for each field, and then
1527 : * a final step forming the composite datum.
1528 : */
1529 342 : scratch.opcode = EEOP_ROW;
1530 342 : scratch.d.row.tupdesc = tupdesc;
1531 :
1532 : /* space for the individual field datums */
1533 342 : scratch.d.row.elemvalues =
1534 342 : (Datum *) palloc(sizeof(Datum) * nelems);
1535 342 : scratch.d.row.elemnulls =
1536 342 : (bool *) palloc(sizeof(bool) * nelems);
1537 : /* as explained above, make sure any extra columns are null */
1538 342 : memset(scratch.d.row.elemnulls, true, sizeof(bool) * nelems);
1539 :
1540 : /* Set up evaluation, skipping any deleted columns */
1541 342 : i = 0;
1542 1163 : foreach(l, rowexpr->args)
1543 : {
1544 821 : Form_pg_attribute att = TupleDescAttr(tupdesc, i);
1545 821 : Expr *e = (Expr *) lfirst(l);
1546 :
1547 821 : if (!att->attisdropped)
1548 : {
1549 : /*
1550 : * Guard against ALTER COLUMN TYPE on rowtype since
1551 : * the RowExpr was created. XXX should we check
1552 : * typmod too? Not sure we can be sure it'll be the
1553 : * same.
1554 : */
1555 821 : if (exprType((Node *) e) != att->atttypid)
1556 0 : ereport(ERROR,
1557 : (errcode(ERRCODE_DATATYPE_MISMATCH),
1558 : errmsg("ROW() column has type %s instead of type %s",
1559 : format_type_be(exprType((Node *) e)),
1560 : format_type_be(att->atttypid))));
1561 : }
1562 : else
1563 : {
1564 : /*
1565 : * Ignore original expression and insert a NULL. We
1566 : * don't really care what type of NULL it is, so
1567 : * always make an int4 NULL.
1568 : */
1569 0 : e = (Expr *) makeNullConst(INT4OID, -1, InvalidOid);
1570 : }
1571 :
1572 : /* Evaluate column expr into appropriate workspace slot */
1573 2463 : ExecInitExprRec(e, parent, state,
1574 1642 : &scratch.d.row.elemvalues[i],
1575 821 : &scratch.d.row.elemnulls[i]);
1576 821 : i++;
1577 : }
1578 :
1579 : /* And finally build the row value */
1580 342 : ExprEvalPushStep(state, &scratch);
1581 342 : break;
1582 : }
1583 :
1584 : case T_RowCompareExpr:
1585 : {
1586 17 : RowCompareExpr *rcexpr = (RowCompareExpr *) node;
1587 17 : int nopers = list_length(rcexpr->opnos);
1588 17 : List *adjust_jumps = NIL;
1589 : ListCell *l_left_expr,
1590 : *l_right_expr,
1591 : *l_opno,
1592 : *l_opfamily,
1593 : *l_inputcollid;
1594 : ListCell *lc;
1595 : int off;
1596 :
1597 : /*
1598 : * Iterate over each field, prepare comparisons. To handle
1599 : * NULL results, prepare jumps to after the expression. If a
1600 : * comparison yields a != 0 result, jump to the final step.
1601 : */
1602 17 : Assert(list_length(rcexpr->largs) == nopers);
1603 17 : Assert(list_length(rcexpr->rargs) == nopers);
1604 17 : Assert(list_length(rcexpr->opfamilies) == nopers);
1605 17 : Assert(list_length(rcexpr->inputcollids) == nopers);
1606 :
1607 17 : off = 0;
1608 89 : for (off = 0,
1609 17 : l_left_expr = list_head(rcexpr->largs),
1610 17 : l_right_expr = list_head(rcexpr->rargs),
1611 17 : l_opno = list_head(rcexpr->opnos),
1612 17 : l_opfamily = list_head(rcexpr->opfamilies),
1613 17 : l_inputcollid = list_head(rcexpr->inputcollids);
1614 : off < nopers;
1615 38 : off++,
1616 38 : l_left_expr = lnext(l_left_expr),
1617 38 : l_right_expr = lnext(l_right_expr),
1618 38 : l_opno = lnext(l_opno),
1619 38 : l_opfamily = lnext(l_opfamily),
1620 38 : l_inputcollid = lnext(l_inputcollid))
1621 : {
1622 38 : Expr *left_expr = (Expr *) lfirst(l_left_expr);
1623 38 : Expr *right_expr = (Expr *) lfirst(l_right_expr);
1624 38 : Oid opno = lfirst_oid(l_opno);
1625 38 : Oid opfamily = lfirst_oid(l_opfamily);
1626 38 : Oid inputcollid = lfirst_oid(l_inputcollid);
1627 : int strategy;
1628 : Oid lefttype;
1629 : Oid righttype;
1630 : Oid proc;
1631 : FmgrInfo *finfo;
1632 : FunctionCallInfo fcinfo;
1633 :
1634 38 : get_op_opfamily_properties(opno, opfamily, false,
1635 : &strategy,
1636 : &lefttype,
1637 : &righttype);
1638 38 : proc = get_opfamily_proc(opfamily,
1639 : lefttype,
1640 : righttype,
1641 : BTORDER_PROC);
1642 38 : if (!OidIsValid(proc))
1643 0 : elog(ERROR, "missing support function %d(%u,%u) in opfamily %u",
1644 : BTORDER_PROC, lefttype, righttype, opfamily);
1645 :
1646 : /* Set up the primary fmgr lookup information */
1647 38 : finfo = palloc0(sizeof(FmgrInfo));
1648 38 : fcinfo = palloc0(sizeof(FunctionCallInfoData));
1649 38 : fmgr_info(proc, finfo);
1650 38 : fmgr_info_set_expr((Node *) node, finfo);
1651 38 : InitFunctionCallInfoData(*fcinfo, finfo, 2,
1652 : inputcollid, NULL, NULL);
1653 :
1654 : /*
1655 : * If we enforced permissions checks on index support
1656 : * functions, we'd need to make a check here. But the
1657 : * index support machinery doesn't do that, and thus
1658 : * neither does this code.
1659 : */
1660 :
1661 : /* evaluate left and right args directly into fcinfo */
1662 38 : ExecInitExprRec(left_expr, parent, state,
1663 : &fcinfo->arg[0], &fcinfo->argnull[0]);
1664 38 : ExecInitExprRec(right_expr, parent, state,
1665 : &fcinfo->arg[1], &fcinfo->argnull[1]);
1666 :
1667 38 : scratch.opcode = EEOP_ROWCOMPARE_STEP;
1668 38 : scratch.d.rowcompare_step.finfo = finfo;
1669 38 : scratch.d.rowcompare_step.fcinfo_data = fcinfo;
1670 38 : scratch.d.rowcompare_step.fn_addr = finfo->fn_addr;
1671 : /* jump targets filled below */
1672 38 : scratch.d.rowcompare_step.jumpnull = -1;
1673 38 : scratch.d.rowcompare_step.jumpdone = -1;
1674 :
1675 38 : ExprEvalPushStep(state, &scratch);
1676 38 : adjust_jumps = lappend_int(adjust_jumps,
1677 38 : state->steps_len - 1);
1678 : }
1679 :
1680 : /*
1681 : * We could have a zero-column rowtype, in which case the rows
1682 : * necessarily compare equal.
1683 : */
1684 17 : if (nopers == 0)
1685 : {
1686 0 : scratch.opcode = EEOP_CONST;
1687 0 : scratch.d.constval.value = Int32GetDatum(0);
1688 0 : scratch.d.constval.isnull = false;
1689 0 : ExprEvalPushStep(state, &scratch);
1690 : }
1691 :
1692 : /* Finally, examine the last comparison result */
1693 17 : scratch.opcode = EEOP_ROWCOMPARE_FINAL;
1694 17 : scratch.d.rowcompare_final.rctype = rcexpr->rctype;
1695 17 : ExprEvalPushStep(state, &scratch);
1696 :
1697 : /* adjust jump targetss */
1698 55 : foreach(lc, adjust_jumps)
1699 : {
1700 38 : ExprEvalStep *as = &state->steps[lfirst_int(lc)];
1701 :
1702 38 : Assert(as->opcode == EEOP_ROWCOMPARE_STEP);
1703 38 : Assert(as->d.rowcompare_step.jumpdone == -1);
1704 38 : Assert(as->d.rowcompare_step.jumpnull == -1);
1705 :
1706 : /* jump to comparison evaluation */
1707 38 : as->d.rowcompare_step.jumpdone = state->steps_len - 1;
1708 : /* jump to the following expression */
1709 38 : as->d.rowcompare_step.jumpnull = state->steps_len;
1710 : }
1711 :
1712 17 : break;
1713 : }
1714 :
1715 : case T_CoalesceExpr:
1716 : {
1717 275 : CoalesceExpr *coalesce = (CoalesceExpr *) node;
1718 275 : List *adjust_jumps = NIL;
1719 : ListCell *lc;
1720 :
1721 : /* We assume there's at least one arg */
1722 275 : Assert(coalesce->args != NIL);
1723 :
1724 : /*
1725 : * Prepare evaluation of all coalesced arguments, after each
1726 : * one push a step that short-circuits if not null.
1727 : */
1728 823 : foreach(lc, coalesce->args)
1729 : {
1730 548 : Expr *e = (Expr *) lfirst(lc);
1731 :
1732 : /* evaluate argument, directly into result datum */
1733 548 : ExecInitExprRec(e, parent, state, resv, resnull);
1734 :
1735 : /* if it's not null, skip to end of COALESCE expr */
1736 548 : scratch.opcode = EEOP_JUMP_IF_NOT_NULL;
1737 548 : scratch.d.jump.jumpdone = -1; /* adjust later */
1738 548 : ExprEvalPushStep(state, &scratch);
1739 :
1740 548 : adjust_jumps = lappend_int(adjust_jumps,
1741 548 : state->steps_len - 1);
1742 : }
1743 :
1744 : /*
1745 : * No need to add a constant NULL return - we only can get to
1746 : * the end of the expression if a NULL already is being
1747 : * returned.
1748 : */
1749 :
1750 : /* adjust jump targets */
1751 823 : foreach(lc, adjust_jumps)
1752 : {
1753 548 : ExprEvalStep *as = &state->steps[lfirst_int(lc)];
1754 :
1755 548 : Assert(as->opcode == EEOP_JUMP_IF_NOT_NULL);
1756 548 : Assert(as->d.jump.jumpdone == -1);
1757 548 : as->d.jump.jumpdone = state->steps_len;
1758 : }
1759 :
1760 275 : break;
1761 : }
1762 :
1763 : case T_MinMaxExpr:
1764 : {
1765 22 : MinMaxExpr *minmaxexpr = (MinMaxExpr *) node;
1766 22 : int nelems = list_length(minmaxexpr->args);
1767 : TypeCacheEntry *typentry;
1768 : FmgrInfo *finfo;
1769 : FunctionCallInfo fcinfo;
1770 : ListCell *lc;
1771 : int off;
1772 :
1773 : /* Look up the btree comparison function for the datatype */
1774 22 : typentry = lookup_type_cache(minmaxexpr->minmaxtype,
1775 : TYPECACHE_CMP_PROC);
1776 22 : if (!OidIsValid(typentry->cmp_proc))
1777 0 : ereport(ERROR,
1778 : (errcode(ERRCODE_UNDEFINED_FUNCTION),
1779 : errmsg("could not identify a comparison function for type %s",
1780 : format_type_be(minmaxexpr->minmaxtype))));
1781 :
1782 : /*
1783 : * If we enforced permissions checks on index support
1784 : * functions, we'd need to make a check here. But the index
1785 : * support machinery doesn't do that, and thus neither does
1786 : * this code.
1787 : */
1788 :
1789 : /* Perform function lookup */
1790 22 : finfo = palloc0(sizeof(FmgrInfo));
1791 22 : fcinfo = palloc0(sizeof(FunctionCallInfoData));
1792 22 : fmgr_info(typentry->cmp_proc, finfo);
1793 22 : fmgr_info_set_expr((Node *) node, finfo);
1794 22 : InitFunctionCallInfoData(*fcinfo, finfo, 2,
1795 : minmaxexpr->inputcollid, NULL, NULL);
1796 :
1797 22 : scratch.opcode = EEOP_MINMAX;
1798 : /* allocate space to store arguments */
1799 22 : scratch.d.minmax.values =
1800 22 : (Datum *) palloc(sizeof(Datum) * nelems);
1801 22 : scratch.d.minmax.nulls =
1802 22 : (bool *) palloc(sizeof(bool) * nelems);
1803 22 : scratch.d.minmax.nelems = nelems;
1804 :
1805 22 : scratch.d.minmax.op = minmaxexpr->op;
1806 22 : scratch.d.minmax.finfo = finfo;
1807 22 : scratch.d.minmax.fcinfo_data = fcinfo;
1808 :
1809 : /* evaluate expressions into minmax->values/nulls */
1810 22 : off = 0;
1811 68 : foreach(lc, minmaxexpr->args)
1812 : {
1813 46 : Expr *e = (Expr *) lfirst(lc);
1814 :
1815 138 : ExecInitExprRec(e, parent, state,
1816 92 : &scratch.d.minmax.values[off],
1817 46 : &scratch.d.minmax.nulls[off]);
1818 46 : off++;
1819 : }
1820 :
1821 : /* and push the final comparison */
1822 22 : ExprEvalPushStep(state, &scratch);
1823 22 : break;
1824 : }
1825 :
1826 : case T_SQLValueFunction:
1827 : {
1828 436 : SQLValueFunction *svf = (SQLValueFunction *) node;
1829 :
1830 436 : scratch.opcode = EEOP_SQLVALUEFUNCTION;
1831 436 : scratch.d.sqlvaluefunction.svf = svf;
1832 :
1833 436 : ExprEvalPushStep(state, &scratch);
1834 436 : break;
1835 : }
1836 :
1837 : case T_XmlExpr:
1838 : {
1839 25 : XmlExpr *xexpr = (XmlExpr *) node;
1840 25 : int nnamed = list_length(xexpr->named_args);
1841 25 : int nargs = list_length(xexpr->args);
1842 : int off;
1843 : ListCell *arg;
1844 :
1845 25 : scratch.opcode = EEOP_XMLEXPR;
1846 25 : scratch.d.xmlexpr.xexpr = xexpr;
1847 :
1848 : /* allocate space for storing all the arguments */
1849 25 : if (nnamed)
1850 : {
1851 0 : scratch.d.xmlexpr.named_argvalue =
1852 0 : (Datum *) palloc(sizeof(Datum) * nnamed);
1853 0 : scratch.d.xmlexpr.named_argnull =
1854 0 : (bool *) palloc(sizeof(bool) * nnamed);
1855 : }
1856 : else
1857 : {
1858 25 : scratch.d.xmlexpr.named_argvalue = NULL;
1859 25 : scratch.d.xmlexpr.named_argnull = NULL;
1860 : }
1861 :
1862 25 : if (nargs)
1863 : {
1864 25 : scratch.d.xmlexpr.argvalue =
1865 25 : (Datum *) palloc(sizeof(Datum) * nargs);
1866 25 : scratch.d.xmlexpr.argnull =
1867 25 : (bool *) palloc(sizeof(bool) * nargs);
1868 : }
1869 : else
1870 : {
1871 0 : scratch.d.xmlexpr.argvalue = NULL;
1872 0 : scratch.d.xmlexpr.argnull = NULL;
1873 : }
1874 :
1875 : /* prepare argument execution */
1876 25 : off = 0;
1877 25 : foreach(arg, xexpr->named_args)
1878 : {
1879 0 : Expr *e = (Expr *) lfirst(arg);
1880 :
1881 0 : ExecInitExprRec(e, parent, state,
1882 0 : &scratch.d.xmlexpr.named_argvalue[off],
1883 0 : &scratch.d.xmlexpr.named_argnull[off]);
1884 0 : off++;
1885 : }
1886 :
1887 25 : off = 0;
1888 73 : foreach(arg, xexpr->args)
1889 : {
1890 48 : Expr *e = (Expr *) lfirst(arg);
1891 :
1892 144 : ExecInitExprRec(e, parent, state,
1893 96 : &scratch.d.xmlexpr.argvalue[off],
1894 48 : &scratch.d.xmlexpr.argnull[off]);
1895 48 : off++;
1896 : }
1897 :
1898 : /* and evaluate the actual XML expression */
1899 25 : ExprEvalPushStep(state, &scratch);
1900 25 : break;
1901 : }
1902 :
1903 : case T_NullTest:
1904 : {
1905 1117 : NullTest *ntest = (NullTest *) node;
1906 :
1907 1117 : if (ntest->nulltesttype == IS_NULL)
1908 : {
1909 648 : if (ntest->argisrow)
1910 21 : scratch.opcode = EEOP_NULLTEST_ROWISNULL;
1911 : else
1912 627 : scratch.opcode = EEOP_NULLTEST_ISNULL;
1913 : }
1914 469 : else if (ntest->nulltesttype == IS_NOT_NULL)
1915 : {
1916 469 : if (ntest->argisrow)
1917 14 : scratch.opcode = EEOP_NULLTEST_ROWISNOTNULL;
1918 : else
1919 455 : scratch.opcode = EEOP_NULLTEST_ISNOTNULL;
1920 : }
1921 : else
1922 : {
1923 0 : elog(ERROR, "unrecognized nulltesttype: %d",
1924 : (int) ntest->nulltesttype);
1925 : }
1926 : /* initialize cache in case it's a row test */
1927 1117 : scratch.d.nulltest_row.argdesc = NULL;
1928 :
1929 : /* first evaluate argument into result variable */
1930 1117 : ExecInitExprRec(ntest->arg, parent, state,
1931 : resv, resnull);
1932 :
1933 : /* then push the test of that argument */
1934 1117 : ExprEvalPushStep(state, &scratch);
1935 1117 : break;
1936 : }
1937 :
1938 : case T_BooleanTest:
1939 : {
1940 32 : BooleanTest *btest = (BooleanTest *) node;
1941 :
1942 : /*
1943 : * Evaluate argument, directly into result datum. That's ok,
1944 : * because resv/resnull is definitely not used anywhere else,
1945 : * and will get overwritten by the below EEOP_BOOLTEST_IS_*
1946 : * step.
1947 : */
1948 32 : ExecInitExprRec(btest->arg, parent, state, resv, resnull);
1949 :
1950 32 : switch (btest->booltesttype)
1951 : {
1952 : case IS_TRUE:
1953 4 : scratch.opcode = EEOP_BOOLTEST_IS_TRUE;
1954 4 : break;
1955 : case IS_NOT_TRUE:
1956 18 : scratch.opcode = EEOP_BOOLTEST_IS_NOT_TRUE;
1957 18 : break;
1958 : case IS_FALSE:
1959 4 : scratch.opcode = EEOP_BOOLTEST_IS_FALSE;
1960 4 : break;
1961 : case IS_NOT_FALSE:
1962 4 : scratch.opcode = EEOP_BOOLTEST_IS_NOT_FALSE;
1963 4 : break;
1964 : case IS_UNKNOWN:
1965 : /* Same as scalar IS NULL test */
1966 1 : scratch.opcode = EEOP_NULLTEST_ISNULL;
1967 1 : break;
1968 : case IS_NOT_UNKNOWN:
1969 : /* Same as scalar IS NOT NULL test */
1970 1 : scratch.opcode = EEOP_NULLTEST_ISNOTNULL;
1971 1 : break;
1972 : default:
1973 0 : elog(ERROR, "unrecognized booltesttype: %d",
1974 : (int) btest->booltesttype);
1975 : }
1976 :
1977 32 : ExprEvalPushStep(state, &scratch);
1978 32 : break;
1979 : }
1980 :
1981 : case T_CoerceToDomain:
1982 : {
1983 1100 : CoerceToDomain *ctest = (CoerceToDomain *) node;
1984 :
1985 1100 : ExecInitCoerceToDomain(&scratch, ctest, parent, state,
1986 : resv, resnull);
1987 1100 : break;
1988 : }
1989 :
1990 : case T_CoerceToDomainValue:
1991 : {
1992 : /*
1993 : * Read from location identified by innermost_domainval. Note
1994 : * that innermost_domainval could be NULL, if we're compiling
1995 : * a standalone domain check rather than one embedded in a
1996 : * larger expression. In that case we must read from
1997 : * econtext->domainValue_datum. We'll take care of that
1998 : * scenario at runtime.
1999 : */
2000 717 : scratch.opcode = EEOP_DOMAIN_TESTVAL;
2001 : /* we share instruction union variant with case testval */
2002 717 : scratch.d.casetest.value = state->innermost_domainval;
2003 717 : scratch.d.casetest.isnull = state->innermost_domainnull;
2004 :
2005 717 : ExprEvalPushStep(state, &scratch);
2006 717 : break;
2007 : }
2008 :
2009 : case T_CurrentOfExpr:
2010 : {
2011 0 : scratch.opcode = EEOP_CURRENTOFEXPR;
2012 0 : ExprEvalPushStep(state, &scratch);
2013 0 : break;
2014 : }
2015 :
2016 : case T_NextValueExpr:
2017 : {
2018 30 : NextValueExpr *nve = (NextValueExpr *) node;
2019 :
2020 30 : scratch.opcode = EEOP_NEXTVALUEEXPR;
2021 30 : scratch.d.nextvalueexpr.seqid = nve->seqid;
2022 30 : scratch.d.nextvalueexpr.seqtypid = nve->typeId;
2023 :
2024 30 : ExprEvalPushStep(state, &scratch);
2025 30 : break;
2026 : }
2027 :
2028 : default:
2029 0 : elog(ERROR, "unrecognized node type: %d",
2030 : (int) nodeTag(node));
2031 : break;
2032 : }
2033 202325 : }
2034 :
2035 : /*
2036 : * Add another expression evaluation step to ExprState->steps.
2037 : *
2038 : * Note that this potentially re-allocates es->steps, therefore no pointer
2039 : * into that array may be used while the expression is still being built.
2040 : */
2041 : static void
2042 450823 : ExprEvalPushStep(ExprState *es, const ExprEvalStep *s)
2043 : {
2044 450823 : if (es->steps_alloc == 0)
2045 : {
2046 108109 : es->steps_alloc = 16;
2047 108109 : es->steps = palloc(sizeof(ExprEvalStep) * es->steps_alloc);
2048 : }
2049 342714 : else if (es->steps_alloc == es->steps_len)
2050 : {
2051 1950 : es->steps_alloc *= 2;
2052 1950 : es->steps = repalloc(es->steps,
2053 1950 : sizeof(ExprEvalStep) * es->steps_alloc);
2054 : }
2055 :
2056 450823 : memcpy(&es->steps[es->steps_len++], s, sizeof(ExprEvalStep));
2057 450823 : }
2058 :
2059 : /*
2060 : * Perform setup necessary for the evaluation of a function-like expression,
2061 : * appending argument evaluation steps to the steps list in *state, and
2062 : * setting up *scratch so it is ready to be pushed.
2063 : *
2064 : * *scratch is not pushed here, so that callers may override the opcode,
2065 : * which is useful for function-like cases like DISTINCT.
2066 : */
2067 : static void
2068 54546 : ExecInitFunc(ExprEvalStep *scratch, Expr *node, List *args, Oid funcid,
2069 : Oid inputcollid, PlanState *parent, ExprState *state)
2070 : {
2071 54546 : int nargs = list_length(args);
2072 : AclResult aclresult;
2073 : FmgrInfo *flinfo;
2074 : FunctionCallInfo fcinfo;
2075 : int argno;
2076 : ListCell *lc;
2077 :
2078 : /* Check permission to call function */
2079 54546 : aclresult = pg_proc_aclcheck(funcid, GetUserId(), ACL_EXECUTE);
2080 54546 : if (aclresult != ACLCHECK_OK)
2081 1 : aclcheck_error(aclresult, ACL_KIND_PROC, get_func_name(funcid));
2082 54545 : InvokeFunctionExecuteHook(funcid);
2083 :
2084 : /*
2085 : * Safety check on nargs. Under normal circumstances this should never
2086 : * fail, as parser should check sooner. But possibly it might fail if
2087 : * server has been compiled with FUNC_MAX_ARGS smaller than some functions
2088 : * declared in pg_proc?
2089 : */
2090 54545 : if (nargs > FUNC_MAX_ARGS)
2091 0 : ereport(ERROR,
2092 : (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
2093 : errmsg_plural("cannot pass more than %d argument to a function",
2094 : "cannot pass more than %d arguments to a function",
2095 : FUNC_MAX_ARGS,
2096 : FUNC_MAX_ARGS)));
2097 :
2098 : /* Allocate function lookup data and parameter workspace for this call */
2099 54545 : scratch->d.func.finfo = palloc0(sizeof(FmgrInfo));
2100 54545 : scratch->d.func.fcinfo_data = palloc0(sizeof(FunctionCallInfoData));
2101 54545 : flinfo = scratch->d.func.finfo;
2102 54545 : fcinfo = scratch->d.func.fcinfo_data;
2103 :
2104 : /* Set up the primary fmgr lookup information */
2105 54545 : fmgr_info(funcid, flinfo);
2106 54545 : fmgr_info_set_expr((Node *) node, flinfo);
2107 :
2108 : /* Initialize function call parameter structure too */
2109 54545 : InitFunctionCallInfoData(*fcinfo, flinfo,
2110 : nargs, inputcollid, NULL, NULL);
2111 :
2112 : /* Keep extra copies of this info to save an indirection at runtime */
2113 54545 : scratch->d.func.fn_addr = flinfo->fn_addr;
2114 54545 : scratch->d.func.nargs = nargs;
2115 :
2116 : /* We only support non-set functions here */
2117 54545 : if (flinfo->fn_retset)
2118 0 : ereport(ERROR,
2119 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2120 : errmsg("set-valued function called in context that cannot accept a set"),
2121 : parent ? executor_errposition(parent->state,
2122 : exprLocation((Node *) node)) : 0));
2123 :
2124 : /* Build code to evaluate arguments directly into the fcinfo struct */
2125 54545 : argno = 0;
2126 154307 : foreach(lc, args)
2127 : {
2128 99762 : Expr *arg = (Expr *) lfirst(lc);
2129 :
2130 99762 : if (IsA(arg, Const))
2131 : {
2132 : /*
2133 : * Don't evaluate const arguments every round; especially
2134 : * interesting for constants in comparisons.
2135 : */
2136 40560 : Const *con = (Const *) arg;
2137 :
2138 40560 : fcinfo->arg[argno] = con->constvalue;
2139 40560 : fcinfo->argnull[argno] = con->constisnull;
2140 : }
2141 : else
2142 : {
2143 59202 : ExecInitExprRec(arg, parent, state,
2144 : &fcinfo->arg[argno], &fcinfo->argnull[argno]);
2145 : }
2146 99762 : argno++;
2147 : }
2148 :
2149 : /* Insert appropriate opcode depending on strictness and stats level */
2150 54545 : if (pgstat_track_functions <= flinfo->fn_stats)
2151 : {
2152 54545 : if (flinfo->fn_strict && nargs > 0)
2153 49608 : scratch->opcode = EEOP_FUNCEXPR_STRICT;
2154 : else
2155 4937 : scratch->opcode = EEOP_FUNCEXPR;
2156 : }
2157 : else
2158 : {
2159 0 : if (flinfo->fn_strict && nargs > 0)
2160 0 : scratch->opcode = EEOP_FUNCEXPR_STRICT_FUSAGE;
2161 : else
2162 0 : scratch->opcode = EEOP_FUNCEXPR_FUSAGE;
2163 : }
2164 54545 : }
2165 :
2166 : /*
2167 : * Add expression steps deforming the ExprState's inner/outer/scan slots
2168 : * as much as required by the expression.
2169 : */
2170 : static void
2171 108110 : ExecInitExprSlots(ExprState *state, Node *node)
2172 : {
2173 108110 : LastAttnumInfo info = {0, 0, 0};
2174 : ExprEvalStep scratch;
2175 :
2176 : /*
2177 : * Figure out which attributes we're going to need.
2178 : */
2179 108110 : get_last_attnums_walker(node, &info);
2180 :
2181 : /* Emit steps as needed */
2182 108110 : if (info.last_inner > 0)
2183 : {
2184 6399 : scratch.opcode = EEOP_INNER_FETCHSOME;
2185 6399 : scratch.d.fetch.last_var = info.last_inner;
2186 6399 : ExprEvalPushStep(state, &scratch);
2187 : }
2188 108110 : if (info.last_outer > 0)
2189 : {
2190 10680 : scratch.opcode = EEOP_OUTER_FETCHSOME;
2191 10680 : scratch.d.fetch.last_var = info.last_outer;
2192 10680 : ExprEvalPushStep(state, &scratch);
2193 : }
2194 108110 : if (info.last_scan > 0)
2195 : {
2196 26454 : scratch.opcode = EEOP_SCAN_FETCHSOME;
2197 26454 : scratch.d.fetch.last_var = info.last_scan;
2198 26454 : ExprEvalPushStep(state, &scratch);
2199 : }
2200 108110 : }
2201 :
2202 : /*
2203 : * get_last_attnums_walker: expression walker for ExecInitExprSlots
2204 : */
2205 : static bool
2206 400900 : get_last_attnums_walker(Node *node, LastAttnumInfo *info)
2207 : {
2208 400900 : if (node == NULL)
2209 4808 : return false;
2210 396092 : if (IsA(node, Var))
2211 : {
2212 84858 : Var *variable = (Var *) node;
2213 84858 : AttrNumber attnum = variable->varattno;
2214 :
2215 84858 : switch (variable->varno)
2216 : {
2217 : case INNER_VAR:
2218 9794 : info->last_inner = Max(info->last_inner, attnum);
2219 9794 : break;
2220 :
2221 : case OUTER_VAR:
2222 18481 : info->last_outer = Max(info->last_outer, attnum);
2223 18481 : break;
2224 :
2225 : /* INDEX_VAR is handled by default case */
2226 :
2227 : default:
2228 56583 : info->last_scan = Max(info->last_scan, attnum);
2229 56583 : break;
2230 : }
2231 84858 : return false;
2232 : }
2233 :
2234 : /*
2235 : * Don't examine the arguments or filters of Aggrefs or WindowFuncs,
2236 : * because those do not represent expressions to be evaluated within the
2237 : * calling expression's econtext. GroupingFunc arguments are never
2238 : * evaluated at all.
2239 : */
2240 311234 : if (IsA(node, Aggref))
2241 2777 : return false;
2242 308457 : if (IsA(node, WindowFunc))
2243 166 : return false;
2244 308291 : if (IsA(node, GroupingFunc))
2245 43 : return false;
2246 308248 : return expression_tree_walker(node, get_last_attnums_walker,
2247 : (void *) info);
2248 : }
2249 :
2250 : /*
2251 : * Prepare step for the evaluation of a whole-row variable.
2252 : * The caller still has to push the step.
2253 : */
2254 : static void
2255 304 : ExecInitWholeRowVar(ExprEvalStep *scratch, Var *variable, PlanState *parent)
2256 : {
2257 : /* fill in all but the target */
2258 304 : scratch->opcode = EEOP_WHOLEROW;
2259 304 : scratch->d.wholerow.var = variable;
2260 304 : scratch->d.wholerow.first = true;
2261 304 : scratch->d.wholerow.slow = false;
2262 304 : scratch->d.wholerow.tupdesc = NULL; /* filled at runtime */
2263 304 : scratch->d.wholerow.junkFilter = NULL;
2264 :
2265 : /*
2266 : * If the input tuple came from a subquery, it might contain "resjunk"
2267 : * columns (such as GROUP BY or ORDER BY columns), which we don't want to
2268 : * keep in the whole-row result. We can get rid of such columns by
2269 : * passing the tuple through a JunkFilter --- but to make one, we have to
2270 : * lay our hands on the subquery's targetlist. Fortunately, there are not
2271 : * very many cases where this can happen, and we can identify all of them
2272 : * by examining our parent PlanState. We assume this is not an issue in
2273 : * standalone expressions that don't have parent plans. (Whole-row Vars
2274 : * can occur in such expressions, but they will always be referencing
2275 : * table rows.)
2276 : */
2277 304 : if (parent)
2278 : {
2279 299 : PlanState *subplan = NULL;
2280 :
2281 299 : switch (nodeTag(parent))
2282 : {
2283 : case T_SubqueryScanState:
2284 35 : subplan = ((SubqueryScanState *) parent)->subplan;
2285 35 : break;
2286 : case T_CteScanState:
2287 27 : subplan = ((CteScanState *) parent)->cteplanstate;
2288 27 : break;
2289 : default:
2290 237 : break;
2291 : }
2292 :
2293 299 : if (subplan)
2294 : {
2295 62 : bool junk_filter_needed = false;
2296 : ListCell *tlist;
2297 :
2298 : /* Detect whether subplan tlist actually has any junk columns */
2299 167 : foreach(tlist, subplan->plan->targetlist)
2300 : {
2301 107 : TargetEntry *tle = (TargetEntry *) lfirst(tlist);
2302 :
2303 107 : if (tle->resjunk)
2304 : {
2305 2 : junk_filter_needed = true;
2306 2 : break;
2307 : }
2308 : }
2309 :
2310 : /* If so, build the junkfilter now */
2311 62 : if (junk_filter_needed)
2312 : {
2313 2 : scratch->d.wholerow.junkFilter =
2314 4 : ExecInitJunkFilter(subplan->plan->targetlist,
2315 2 : ExecGetResultType(subplan)->tdhasoid,
2316 : ExecInitExtraTupleSlot(parent->state));
2317 : }
2318 : }
2319 : }
2320 304 : }
2321 :
2322 : /*
2323 : * Prepare evaluation of an ArrayRef expression.
2324 : */
2325 : static void
2326 728 : ExecInitArrayRef(ExprEvalStep *scratch, ArrayRef *aref, PlanState *parent,
2327 : ExprState *state, Datum *resv, bool *resnull)
2328 : {
2329 728 : bool isAssignment = (aref->refassgnexpr != NULL);
2330 728 : ArrayRefState *arefstate = palloc0(sizeof(ArrayRefState));
2331 728 : List *adjust_jumps = NIL;
2332 : ListCell *lc;
2333 : int i;
2334 :
2335 : /* Fill constant fields of ArrayRefState */
2336 728 : arefstate->isassignment = isAssignment;
2337 728 : arefstate->refelemtype = aref->refelemtype;
2338 728 : arefstate->refattrlength = get_typlen(aref->refarraytype);
2339 728 : get_typlenbyvalalign(aref->refelemtype,
2340 : &arefstate->refelemlength,
2341 : &arefstate->refelembyval,
2342 : &arefstate->refelemalign);
2343 :
2344 : /*
2345 : * Evaluate array input. It's safe to do so into resv/resnull, because we
2346 : * won't use that as target for any of the other subexpressions, and it'll
2347 : * be overwritten by the final EEOP_ARRAYREF_FETCH/ASSIGN step, which is
2348 : * pushed last.
2349 : */
2350 728 : ExecInitExprRec(aref->refexpr, parent, state, resv, resnull);
2351 :
2352 : /*
2353 : * If refexpr yields NULL, and it's a fetch, then result is NULL. We can
2354 : * implement this with just JUMP_IF_NULL, since we evaluated the array
2355 : * into the desired target location.
2356 : */
2357 728 : if (!isAssignment)
2358 : {
2359 618 : scratch->opcode = EEOP_JUMP_IF_NULL;
2360 618 : scratch->d.jump.jumpdone = -1; /* adjust later */
2361 618 : ExprEvalPushStep(state, scratch);
2362 618 : adjust_jumps = lappend_int(adjust_jumps,
2363 618 : state->steps_len - 1);
2364 : }
2365 :
2366 : /* Verify subscript list lengths are within limit */
2367 728 : if (list_length(aref->refupperindexpr) > MAXDIM)
2368 1 : ereport(ERROR,
2369 : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
2370 : errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
2371 : list_length(aref->refupperindexpr), MAXDIM)));
2372 :
2373 727 : if (list_length(aref->reflowerindexpr) > MAXDIM)
2374 0 : ereport(ERROR,
2375 : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
2376 : errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
2377 : list_length(aref->reflowerindexpr), MAXDIM)));
2378 :
2379 : /* Evaluate upper subscripts */
2380 727 : i = 0;
2381 1493 : foreach(lc, aref->refupperindexpr)
2382 : {
2383 766 : Expr *e = (Expr *) lfirst(lc);
2384 :
2385 : /* When slicing, individual subscript bounds can be omitted */
2386 766 : if (!e)
2387 : {
2388 13 : arefstate->upperprovided[i] = false;
2389 13 : i++;
2390 13 : continue;
2391 : }
2392 :
2393 753 : arefstate->upperprovided[i] = true;
2394 :
2395 : /* Each subscript is evaluated into subscriptvalue/subscriptnull */
2396 753 : ExecInitExprRec(e, parent, state,
2397 : &arefstate->subscriptvalue, &arefstate->subscriptnull);
2398 :
2399 : /* ... and then ARRAYREF_SUBSCRIPT saves it into step's workspace */
2400 753 : scratch->opcode = EEOP_ARRAYREF_SUBSCRIPT;
2401 753 : scratch->d.arrayref_subscript.state = arefstate;
2402 753 : scratch->d.arrayref_subscript.off = i;
2403 753 : scratch->d.arrayref_subscript.isupper = true;
2404 753 : scratch->d.arrayref_subscript.jumpdone = -1; /* adjust later */
2405 753 : ExprEvalPushStep(state, scratch);
2406 753 : adjust_jumps = lappend_int(adjust_jumps,
2407 753 : state->steps_len - 1);
2408 753 : i++;
2409 : }
2410 727 : arefstate->numupper = i;
2411 :
2412 : /* Evaluate lower subscripts similarly */
2413 727 : i = 0;
2414 813 : foreach(lc, aref->reflowerindexpr)
2415 : {
2416 86 : Expr *e = (Expr *) lfirst(lc);
2417 :
2418 : /* When slicing, individual subscript bounds can be omitted */
2419 86 : if (!e)
2420 : {
2421 13 : arefstate->lowerprovided[i] = false;
2422 13 : i++;
2423 13 : continue;
2424 : }
2425 :
2426 73 : arefstate->lowerprovided[i] = true;
2427 :
2428 : /* Each subscript is evaluated into subscriptvalue/subscriptnull */
2429 73 : ExecInitExprRec(e, parent, state,
2430 : &arefstate->subscriptvalue, &arefstate->subscriptnull);
2431 :
2432 : /* ... and then ARRAYREF_SUBSCRIPT saves it into step's workspace */
2433 73 : scratch->opcode = EEOP_ARRAYREF_SUBSCRIPT;
2434 73 : scratch->d.arrayref_subscript.state = arefstate;
2435 73 : scratch->d.arrayref_subscript.off = i;
2436 73 : scratch->d.arrayref_subscript.isupper = false;
2437 73 : scratch->d.arrayref_subscript.jumpdone = -1; /* adjust later */
2438 73 : ExprEvalPushStep(state, scratch);
2439 73 : adjust_jumps = lappend_int(adjust_jumps,
2440 73 : state->steps_len - 1);
2441 73 : i++;
2442 : }
2443 727 : arefstate->numlower = i;
2444 :
2445 : /* Should be impossible if parser is sane, but check anyway: */
2446 787 : if (arefstate->numlower != 0 &&
2447 60 : arefstate->numupper != arefstate->numlower)
2448 0 : elog(ERROR, "upper and lower index lists are not same length");
2449 :
2450 727 : if (isAssignment)
2451 : {
2452 : Datum *save_innermost_caseval;
2453 : bool *save_innermost_casenull;
2454 :
2455 : /*
2456 : * We might have a nested-assignment situation, in which the
2457 : * refassgnexpr is itself a FieldStore or ArrayRef that needs to
2458 : * obtain and modify the previous value of the array element or slice
2459 : * being replaced. If so, we have to extract that value from the
2460 : * array and pass it down via the CaseTestExpr mechanism. It's safe
2461 : * to reuse the CASE mechanism because there cannot be a CASE between
2462 : * here and where the value would be needed, and an array assignment
2463 : * can't be within a CASE either. (So saving and restoring
2464 : * innermost_caseval is just paranoia, but let's do it anyway.)
2465 : *
2466 : * Since fetching the old element might be a nontrivial expense, do it
2467 : * only if the argument actually needs it.
2468 : */
2469 110 : if (isAssignmentIndirectionExpr(aref->refassgnexpr))
2470 : {
2471 20 : scratch->opcode = EEOP_ARRAYREF_OLD;
2472 20 : scratch->d.arrayref.state = arefstate;
2473 20 : ExprEvalPushStep(state, scratch);
2474 : }
2475 :
2476 : /* ARRAYREF_OLD puts extracted value into prevvalue/prevnull */
2477 110 : save_innermost_caseval = state->innermost_caseval;
2478 110 : save_innermost_casenull = state->innermost_casenull;
2479 110 : state->innermost_caseval = &arefstate->prevvalue;
2480 110 : state->innermost_casenull = &arefstate->prevnull;
2481 :
2482 : /* evaluate replacement value into replacevalue/replacenull */
2483 110 : ExecInitExprRec(aref->refassgnexpr, parent, state,
2484 : &arefstate->replacevalue, &arefstate->replacenull);
2485 :
2486 110 : state->innermost_caseval = save_innermost_caseval;
2487 110 : state->innermost_casenull = save_innermost_casenull;
2488 :
2489 : /* and perform the assignment */
2490 110 : scratch->opcode = EEOP_ARRAYREF_ASSIGN;
2491 110 : scratch->d.arrayref.state = arefstate;
2492 110 : ExprEvalPushStep(state, scratch);
2493 : }
2494 : else
2495 : {
2496 : /* array fetch is much simpler */
2497 617 : scratch->opcode = EEOP_ARRAYREF_FETCH;
2498 617 : scratch->d.arrayref.state = arefstate;
2499 617 : ExprEvalPushStep(state, scratch);
2500 : }
2501 :
2502 : /* adjust jump targets */
2503 2170 : foreach(lc, adjust_jumps)
2504 : {
2505 1443 : ExprEvalStep *as = &state->steps[lfirst_int(lc)];
2506 :
2507 1443 : if (as->opcode == EEOP_ARRAYREF_SUBSCRIPT)
2508 : {
2509 826 : Assert(as->d.arrayref_subscript.jumpdone == -1);
2510 826 : as->d.arrayref_subscript.jumpdone = state->steps_len;
2511 : }
2512 : else
2513 : {
2514 617 : Assert(as->opcode == EEOP_JUMP_IF_NULL);
2515 617 : Assert(as->d.jump.jumpdone == -1);
2516 617 : as->d.jump.jumpdone = state->steps_len;
2517 : }
2518 : }
2519 727 : }
2520 :
2521 : /*
2522 : * Helper for preparing ArrayRef expressions for evaluation: is expr a nested
2523 : * FieldStore or ArrayRef that needs the old element value passed down?
2524 : *
2525 : * (We could use this in FieldStore too, but in that case passing the old
2526 : * value is so cheap there's no need.)
2527 : *
2528 : * Note: it might seem that this needs to recurse, but it does not; the
2529 : * CaseTestExpr, if any, will be directly the arg or refexpr of the top-level
2530 : * node. Nested-assignment situations give rise to expression trees in which
2531 : * each level of assignment has its own CaseTestExpr, and the recursive
2532 : * structure appears within the newvals or refassgnexpr field.
2533 : */
2534 : static bool
2535 110 : isAssignmentIndirectionExpr(Expr *expr)
2536 : {
2537 110 : if (expr == NULL)
2538 0 : return false; /* just paranoia */
2539 110 : if (IsA(expr, FieldStore))
2540 : {
2541 20 : FieldStore *fstore = (FieldStore *) expr;
2542 :
2543 20 : if (fstore->arg && IsA(fstore->arg, CaseTestExpr))
2544 20 : return true;
2545 : }
2546 90 : else if (IsA(expr, ArrayRef))
2547 : {
2548 5 : ArrayRef *arrayRef = (ArrayRef *) expr;
2549 :
2550 5 : if (arrayRef->refexpr && IsA(arrayRef->refexpr, CaseTestExpr))
2551 0 : return true;
2552 : }
2553 90 : return false;
2554 : }
2555 :
2556 : /*
2557 : * Prepare evaluation of a CoerceToDomain expression.
2558 : */
2559 : static void
2560 1100 : ExecInitCoerceToDomain(ExprEvalStep *scratch, CoerceToDomain *ctest,
2561 : PlanState *parent, ExprState *state,
2562 : Datum *resv, bool *resnull)
2563 : {
2564 : ExprEvalStep scratch2;
2565 : DomainConstraintRef *constraint_ref;
2566 1100 : Datum *domainval = NULL;
2567 1100 : bool *domainnull = NULL;
2568 : Datum *save_innermost_domainval;
2569 : bool *save_innermost_domainnull;
2570 : ListCell *l;
2571 :
2572 1100 : scratch->d.domaincheck.resulttype = ctest->resulttype;
2573 : /* we'll allocate workspace only if needed */
2574 1100 : scratch->d.domaincheck.checkvalue = NULL;
2575 1100 : scratch->d.domaincheck.checknull = NULL;
2576 :
2577 : /*
2578 : * Evaluate argument - it's fine to directly store it into resv/resnull,
2579 : * if there's constraint failures there'll be errors, otherwise it's what
2580 : * needs to be returned.
2581 : */
2582 1100 : ExecInitExprRec(ctest->arg, parent, state, resv, resnull);
2583 :
2584 : /*
2585 : * Note: if the argument is of varlena type, it could be a R/W expanded
2586 : * object. We want to return the R/W pointer as the final result, but we
2587 : * have to pass a R/O pointer as the value to be tested by any functions
2588 : * in check expressions. We don't bother to emit a MAKE_READONLY step
2589 : * unless there's actually at least one check expression, though. Until
2590 : * we've tested that, domainval/domainnull are NULL.
2591 : */
2592 :
2593 : /*
2594 : * Collect the constraints associated with the domain.
2595 : *
2596 : * Note: before PG v10 we'd recheck the set of constraints during each
2597 : * evaluation of the expression. Now we bake them into the ExprState
2598 : * during executor initialization. That means we don't need typcache.c to
2599 : * provide compiled exprs.
2600 : */
2601 1100 : constraint_ref = (DomainConstraintRef *)
2602 : palloc(sizeof(DomainConstraintRef));
2603 1100 : InitDomainConstraintRef(ctest->resulttype,
2604 : constraint_ref,
2605 : CurrentMemoryContext,
2606 : false);
2607 :
2608 : /*
2609 : * Compile code to check each domain constraint. NOTNULL constraints can
2610 : * just be applied on the resv/resnull value, but for CHECK constraints we
2611 : * need more pushups.
2612 : */
2613 1478 : foreach(l, constraint_ref->constraints)
2614 : {
2615 378 : DomainConstraintState *con = (DomainConstraintState *) lfirst(l);
2616 :
2617 378 : scratch->d.domaincheck.constraintname = con->name;
2618 :
2619 378 : switch (con->constrainttype)
2620 : {
2621 : case DOM_CONSTRAINT_NOTNULL:
2622 51 : scratch->opcode = EEOP_DOMAIN_NOTNULL;
2623 51 : ExprEvalPushStep(state, scratch);
2624 51 : break;
2625 : case DOM_CONSTRAINT_CHECK:
2626 : /* Allocate workspace for CHECK output if we didn't yet */
2627 327 : if (scratch->d.domaincheck.checkvalue == NULL)
2628 : {
2629 311 : scratch->d.domaincheck.checkvalue =
2630 311 : (Datum *) palloc(sizeof(Datum));
2631 311 : scratch->d.domaincheck.checknull =
2632 311 : (bool *) palloc(sizeof(bool));
2633 : }
2634 :
2635 : /*
2636 : * If first time through, determine where CoerceToDomainValue
2637 : * nodes should read from.
2638 : */
2639 327 : if (domainval == NULL)
2640 : {
2641 : /*
2642 : * Since value might be read multiple times, force to R/O
2643 : * - but only if it could be an expanded datum.
2644 : */
2645 311 : if (get_typlen(ctest->resulttype) == -1)
2646 : {
2647 : /* Yes, so make output workspace for MAKE_READONLY */
2648 193 : domainval = (Datum *) palloc(sizeof(Datum));
2649 193 : domainnull = (bool *) palloc(sizeof(bool));
2650 :
2651 : /* Emit MAKE_READONLY */
2652 193 : scratch2.opcode = EEOP_MAKE_READONLY;
2653 193 : scratch2.resvalue = domainval;
2654 193 : scratch2.resnull = domainnull;
2655 193 : scratch2.d.make_readonly.value = resv;
2656 193 : scratch2.d.make_readonly.isnull = resnull;
2657 193 : ExprEvalPushStep(state, &scratch2);
2658 : }
2659 : else
2660 : {
2661 : /* No, so it's fine to read from resv/resnull */
2662 118 : domainval = resv;
2663 118 : domainnull = resnull;
2664 : }
2665 : }
2666 :
2667 : /*
2668 : * Set up value to be returned by CoerceToDomainValue nodes.
2669 : * We must save and restore innermost_domainval/null fields,
2670 : * in case this node is itself within a check expression for
2671 : * another domain.
2672 : */
2673 327 : save_innermost_domainval = state->innermost_domainval;
2674 327 : save_innermost_domainnull = state->innermost_domainnull;
2675 327 : state->innermost_domainval = domainval;
2676 327 : state->innermost_domainnull = domainnull;
2677 :
2678 : /* evaluate check expression value */
2679 327 : ExecInitExprRec(con->check_expr, parent, state,
2680 : scratch->d.domaincheck.checkvalue,
2681 : scratch->d.domaincheck.checknull);
2682 :
2683 327 : state->innermost_domainval = save_innermost_domainval;
2684 327 : state->innermost_domainnull = save_innermost_domainnull;
2685 :
2686 : /* now test result */
2687 327 : scratch->opcode = EEOP_DOMAIN_CHECK;
2688 327 : ExprEvalPushStep(state, scratch);
2689 :
2690 327 : break;
2691 : default:
2692 0 : elog(ERROR, "unrecognized constraint type: %d",
2693 : (int) con->constrainttype);
2694 : break;
2695 : }
2696 : }
2697 1100 : }
|