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-2019, 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 "jit/jit.h" |
40 | #include "miscadmin.h" |
41 | #include "nodes/makefuncs.h" |
42 | #include "nodes/nodeFuncs.h" |
43 | #include "optimizer/optimizer.h" |
44 | #include "pgstat.h" |
45 | #include "utils/builtins.h" |
46 | #include "utils/datum.h" |
47 | #include "utils/lsyscache.h" |
48 | #include "utils/typcache.h" |
49 | |
50 | |
51 | typedef struct LastAttnumInfo |
52 | { |
53 | AttrNumber last_inner; |
54 | AttrNumber last_outer; |
55 | AttrNumber last_scan; |
56 | } LastAttnumInfo; |
57 | |
58 | static void ExecReadyExpr(ExprState *state); |
59 | static void ExecInitExprRec(Expr *node, ExprState *state, |
60 | Datum *resv, bool *resnull); |
61 | static void ExecInitFunc(ExprEvalStep *scratch, Expr *node, List *args, |
62 | Oid funcid, Oid inputcollid, |
63 | ExprState *state); |
64 | static void ExecInitExprSlots(ExprState *state, Node *node); |
65 | static void ExecPushExprSlots(ExprState *state, LastAttnumInfo *info); |
66 | static bool get_last_attnums_walker(Node *node, LastAttnumInfo *info); |
67 | static void ExecComputeSlotInfo(ExprState *state, ExprEvalStep *op); |
68 | static void ExecInitWholeRowVar(ExprEvalStep *scratch, Var *variable, |
69 | ExprState *state); |
70 | static void ExecInitSubscriptingRef(ExprEvalStep *scratch, |
71 | SubscriptingRef *sbsref, |
72 | ExprState *state, |
73 | Datum *resv, bool *resnull); |
74 | static bool isAssignmentIndirectionExpr(Expr *expr); |
75 | static void ExecInitCoerceToDomain(ExprEvalStep *scratch, CoerceToDomain *ctest, |
76 | ExprState *state, |
77 | Datum *resv, bool *resnull); |
78 | static void ExecBuildAggTransCall(ExprState *state, AggState *aggstate, |
79 | ExprEvalStep *scratch, |
80 | FunctionCallInfo fcinfo, AggStatePerTrans pertrans, |
81 | int transno, int setno, int setoff, bool ishash); |
82 | |
83 | |
84 | /* |
85 | * ExecInitExpr: prepare an expression tree for execution |
86 | * |
87 | * This function builds and returns an ExprState implementing the given |
88 | * Expr node tree. The return ExprState can then be handed to ExecEvalExpr |
89 | * for execution. Because the Expr tree itself is read-only as far as |
90 | * ExecInitExpr and ExecEvalExpr are concerned, several different executions |
91 | * of the same plan tree can occur concurrently. (But note that an ExprState |
92 | * does mutate at runtime, so it can't be re-used concurrently.) |
93 | * |
94 | * This must be called in a memory context that will last as long as repeated |
95 | * executions of the expression are needed. Typically the context will be |
96 | * the same as the per-query context of the associated ExprContext. |
97 | * |
98 | * Any Aggref, WindowFunc, or SubPlan nodes found in the tree are added to |
99 | * the lists of such nodes held by the parent PlanState (or more accurately, |
100 | * the AggrefExprState etc. nodes created for them are added). |
101 | * |
102 | * Note: there is no ExecEndExpr function; we assume that any resource |
103 | * cleanup needed will be handled by just releasing the memory context |
104 | * in which the state tree is built. Functions that require additional |
105 | * cleanup work can register a shutdown callback in the ExprContext. |
106 | * |
107 | * 'node' is the root of the expression tree to compile. |
108 | * 'parent' is the PlanState node that owns the expression. |
109 | * |
110 | * 'parent' may be NULL if we are preparing an expression that is not |
111 | * associated with a plan tree. (If so, it can't have aggs or subplans.) |
112 | * Such cases should usually come through ExecPrepareExpr, not directly here. |
113 | * |
114 | * Also, if 'node' is NULL, we just return NULL. This is convenient for some |
115 | * callers that may or may not have an expression that needs to be compiled. |
116 | * Note that a NULL ExprState pointer *cannot* be handed to ExecEvalExpr, |
117 | * although ExecQual and ExecCheck will accept one (and treat it as "true"). |
118 | */ |
119 | ExprState * |
120 | ExecInitExpr(Expr *node, PlanState *parent) |
121 | { |
122 | ExprState *state; |
123 | ExprEvalStep scratch = {0}; |
124 | |
125 | /* Special case: NULL expression produces a NULL ExprState pointer */ |
126 | if (node == NULL) |
127 | return NULL; |
128 | |
129 | /* Initialize ExprState with empty step list */ |
130 | state = makeNode(ExprState); |
131 | state->expr = node; |
132 | state->parent = parent; |
133 | state->ext_params = NULL; |
134 | |
135 | /* Insert EEOP_*_FETCHSOME steps as needed */ |
136 | ExecInitExprSlots(state, (Node *) node); |
137 | |
138 | /* Compile the expression proper */ |
139 | ExecInitExprRec(node, state, &state->resvalue, &state->resnull); |
140 | |
141 | /* Finally, append a DONE step */ |
142 | scratch.opcode = EEOP_DONE; |
143 | ExprEvalPushStep(state, &scratch); |
144 | |
145 | ExecReadyExpr(state); |
146 | |
147 | return state; |
148 | } |
149 | |
150 | /* |
151 | * ExecInitExprWithParams: prepare a standalone expression tree for execution |
152 | * |
153 | * This is the same as ExecInitExpr, except that there is no parent PlanState, |
154 | * and instead we may have a ParamListInfo describing PARAM_EXTERN Params. |
155 | */ |
156 | ExprState * |
157 | ExecInitExprWithParams(Expr *node, ParamListInfo ext_params) |
158 | { |
159 | ExprState *state; |
160 | ExprEvalStep scratch = {0}; |
161 | |
162 | /* Special case: NULL expression produces a NULL ExprState pointer */ |
163 | if (node == NULL) |
164 | return NULL; |
165 | |
166 | /* Initialize ExprState with empty step list */ |
167 | state = makeNode(ExprState); |
168 | state->expr = node; |
169 | state->parent = NULL; |
170 | state->ext_params = ext_params; |
171 | |
172 | /* Insert EEOP_*_FETCHSOME steps as needed */ |
173 | ExecInitExprSlots(state, (Node *) node); |
174 | |
175 | /* Compile the expression proper */ |
176 | ExecInitExprRec(node, state, &state->resvalue, &state->resnull); |
177 | |
178 | /* Finally, append a DONE step */ |
179 | scratch.opcode = EEOP_DONE; |
180 | ExprEvalPushStep(state, &scratch); |
181 | |
182 | ExecReadyExpr(state); |
183 | |
184 | return state; |
185 | } |
186 | |
187 | /* |
188 | * ExecInitQual: prepare a qual for execution by ExecQual |
189 | * |
190 | * Prepares for the evaluation of a conjunctive boolean expression (qual list |
191 | * with implicit AND semantics) that returns true if none of the |
192 | * subexpressions are false. |
193 | * |
194 | * We must return true if the list is empty. Since that's a very common case, |
195 | * we optimize it a bit further by translating to a NULL ExprState pointer |
196 | * rather than setting up an ExprState that computes constant TRUE. (Some |
197 | * especially hot-spot callers of ExecQual detect this and avoid calling |
198 | * ExecQual at all.) |
199 | * |
200 | * If any of the subexpressions yield NULL, then the result of the conjunction |
201 | * is false. This makes ExecQual primarily useful for evaluating WHERE |
202 | * clauses, since SQL specifies that tuples with null WHERE results do not |
203 | * get selected. |
204 | */ |
205 | ExprState * |
206 | ExecInitQual(List *qual, PlanState *parent) |
207 | { |
208 | ExprState *state; |
209 | ExprEvalStep scratch = {0}; |
210 | List *adjust_jumps = NIL; |
211 | ListCell *lc; |
212 | |
213 | /* short-circuit (here and in ExecQual) for empty restriction list */ |
214 | if (qual == NIL) |
215 | return NULL; |
216 | |
217 | Assert(IsA(qual, List)); |
218 | |
219 | state = makeNode(ExprState); |
220 | state->expr = (Expr *) qual; |
221 | state->parent = parent; |
222 | state->ext_params = NULL; |
223 | |
224 | /* mark expression as to be used with ExecQual() */ |
225 | state->flags = EEO_FLAG_IS_QUAL; |
226 | |
227 | /* Insert EEOP_*_FETCHSOME steps as needed */ |
228 | ExecInitExprSlots(state, (Node *) qual); |
229 | |
230 | /* |
231 | * ExecQual() needs to return false for an expression returning NULL. That |
232 | * allows us to short-circuit the evaluation the first time a NULL is |
233 | * encountered. As qual evaluation is a hot-path this warrants using a |
234 | * special opcode for qual evaluation that's simpler than BOOL_AND (which |
235 | * has more complex NULL handling). |
236 | */ |
237 | scratch.opcode = EEOP_QUAL; |
238 | |
239 | /* |
240 | * We can use ExprState's resvalue/resnull as target for each qual expr. |
241 | */ |
242 | scratch.resvalue = &state->resvalue; |
243 | scratch.resnull = &state->resnull; |
244 | |
245 | foreach(lc, qual) |
246 | { |
247 | Expr *node = (Expr *) lfirst(lc); |
248 | |
249 | /* first evaluate expression */ |
250 | ExecInitExprRec(node, state, &state->resvalue, &state->resnull); |
251 | |
252 | /* then emit EEOP_QUAL to detect if it's false (or null) */ |
253 | scratch.d.qualexpr.jumpdone = -1; |
254 | ExprEvalPushStep(state, &scratch); |
255 | adjust_jumps = lappend_int(adjust_jumps, |
256 | state->steps_len - 1); |
257 | } |
258 | |
259 | /* adjust jump targets */ |
260 | foreach(lc, adjust_jumps) |
261 | { |
262 | ExprEvalStep *as = &state->steps[lfirst_int(lc)]; |
263 | |
264 | Assert(as->opcode == EEOP_QUAL); |
265 | Assert(as->d.qualexpr.jumpdone == -1); |
266 | as->d.qualexpr.jumpdone = state->steps_len; |
267 | } |
268 | |
269 | /* |
270 | * At the end, we don't need to do anything more. The last qual expr must |
271 | * have yielded TRUE, and since its result is stored in the desired output |
272 | * location, we're done. |
273 | */ |
274 | scratch.opcode = EEOP_DONE; |
275 | ExprEvalPushStep(state, &scratch); |
276 | |
277 | ExecReadyExpr(state); |
278 | |
279 | return state; |
280 | } |
281 | |
282 | /* |
283 | * ExecInitCheck: prepare a check constraint for execution by ExecCheck |
284 | * |
285 | * This is much like ExecInitQual/ExecQual, except that a null result from |
286 | * the conjunction is treated as TRUE. This behavior is appropriate for |
287 | * evaluating CHECK constraints, since SQL specifies that NULL constraint |
288 | * conditions are not failures. |
289 | * |
290 | * Note that like ExecInitQual, this expects input in implicit-AND format. |
291 | * Users of ExecCheck that have expressions in normal explicit-AND format |
292 | * can just apply ExecInitExpr to produce suitable input for ExecCheck. |
293 | */ |
294 | ExprState * |
295 | ExecInitCheck(List *qual, PlanState *parent) |
296 | { |
297 | /* short-circuit (here and in ExecCheck) for empty restriction list */ |
298 | if (qual == NIL) |
299 | return NULL; |
300 | |
301 | Assert(IsA(qual, List)); |
302 | |
303 | /* |
304 | * Just convert the implicit-AND list to an explicit AND (if there's more |
305 | * than one entry), and compile normally. Unlike ExecQual, we can't |
306 | * short-circuit on NULL results, so the regular AND behavior is needed. |
307 | */ |
308 | return ExecInitExpr(make_ands_explicit(qual), parent); |
309 | } |
310 | |
311 | /* |
312 | * Call ExecInitExpr() on a list of expressions, return a list of ExprStates. |
313 | */ |
314 | List * |
315 | ExecInitExprList(List *nodes, PlanState *parent) |
316 | { |
317 | List *result = NIL; |
318 | ListCell *lc; |
319 | |
320 | foreach(lc, nodes) |
321 | { |
322 | Expr *e = lfirst(lc); |
323 | |
324 | result = lappend(result, ExecInitExpr(e, parent)); |
325 | } |
326 | |
327 | return result; |
328 | } |
329 | |
330 | /* |
331 | * ExecBuildProjectionInfo |
332 | * |
333 | * Build a ProjectionInfo node for evaluating the given tlist in the given |
334 | * econtext, and storing the result into the tuple slot. (Caller must have |
335 | * ensured that tuple slot has a descriptor matching the tlist!) |
336 | * |
337 | * inputDesc can be NULL, but if it is not, we check to see whether simple |
338 | * Vars in the tlist match the descriptor. It is important to provide |
339 | * inputDesc for relation-scan plan nodes, as a cross check that the relation |
340 | * hasn't been changed since the plan was made. At higher levels of a plan, |
341 | * there is no need to recheck. |
342 | * |
343 | * This is implemented by internally building an ExprState that performs the |
344 | * whole projection in one go. |
345 | * |
346 | * Caution: before PG v10, the targetList was a list of ExprStates; now it |
347 | * should be the planner-created targetlist, since we do the compilation here. |
348 | */ |
349 | ProjectionInfo * |
350 | ExecBuildProjectionInfo(List *targetList, |
351 | ExprContext *econtext, |
352 | TupleTableSlot *slot, |
353 | PlanState *parent, |
354 | TupleDesc inputDesc) |
355 | { |
356 | ProjectionInfo *projInfo = makeNode(ProjectionInfo); |
357 | ExprState *state; |
358 | ExprEvalStep scratch = {0}; |
359 | ListCell *lc; |
360 | |
361 | projInfo->pi_exprContext = econtext; |
362 | /* We embed ExprState into ProjectionInfo instead of doing extra palloc */ |
363 | projInfo->pi_state.tag.type = T_ExprState; |
364 | state = &projInfo->pi_state; |
365 | state->expr = (Expr *) targetList; |
366 | state->parent = parent; |
367 | state->ext_params = NULL; |
368 | |
369 | state->resultslot = slot; |
370 | |
371 | /* Insert EEOP_*_FETCHSOME steps as needed */ |
372 | ExecInitExprSlots(state, (Node *) targetList); |
373 | |
374 | /* Now compile each tlist column */ |
375 | foreach(lc, targetList) |
376 | { |
377 | TargetEntry *tle = lfirst_node(TargetEntry, lc); |
378 | Var *variable = NULL; |
379 | AttrNumber attnum = 0; |
380 | bool isSafeVar = false; |
381 | |
382 | /* |
383 | * If tlist expression is a safe non-system Var, use the fast-path |
384 | * ASSIGN_*_VAR opcodes. "Safe" means that we don't need to apply |
385 | * CheckVarSlotCompatibility() during plan startup. If a source slot |
386 | * was provided, we make the equivalent tests here; if a slot was not |
387 | * provided, we assume that no check is needed because we're dealing |
388 | * with a non-relation-scan-level expression. |
389 | */ |
390 | if (tle->expr != NULL && |
391 | IsA(tle->expr, Var) && |
392 | ((Var *) tle->expr)->varattno > 0) |
393 | { |
394 | /* Non-system Var, but how safe is it? */ |
395 | variable = (Var *) tle->expr; |
396 | attnum = variable->varattno; |
397 | |
398 | if (inputDesc == NULL) |
399 | isSafeVar = true; /* can't check, just assume OK */ |
400 | else if (attnum <= inputDesc->natts) |
401 | { |
402 | Form_pg_attribute attr = TupleDescAttr(inputDesc, attnum - 1); |
403 | |
404 | /* |
405 | * If user attribute is dropped or has a type mismatch, don't |
406 | * use ASSIGN_*_VAR. Instead let the normal expression |
407 | * machinery handle it (which'll possibly error out). |
408 | */ |
409 | if (!attr->attisdropped && variable->vartype == attr->atttypid) |
410 | { |
411 | isSafeVar = true; |
412 | } |
413 | } |
414 | } |
415 | |
416 | if (isSafeVar) |
417 | { |
418 | /* Fast-path: just generate an EEOP_ASSIGN_*_VAR step */ |
419 | switch (variable->varno) |
420 | { |
421 | case INNER_VAR: |
422 | /* get the tuple from the inner node */ |
423 | scratch.opcode = EEOP_ASSIGN_INNER_VAR; |
424 | break; |
425 | |
426 | case OUTER_VAR: |
427 | /* get the tuple from the outer node */ |
428 | scratch.opcode = EEOP_ASSIGN_OUTER_VAR; |
429 | break; |
430 | |
431 | /* INDEX_VAR is handled by default case */ |
432 | |
433 | default: |
434 | /* get the tuple from the relation being scanned */ |
435 | scratch.opcode = EEOP_ASSIGN_SCAN_VAR; |
436 | break; |
437 | } |
438 | |
439 | scratch.d.assign_var.attnum = attnum - 1; |
440 | scratch.d.assign_var.resultnum = tle->resno - 1; |
441 | ExprEvalPushStep(state, &scratch); |
442 | } |
443 | else |
444 | { |
445 | /* |
446 | * Otherwise, compile the column expression normally. |
447 | * |
448 | * We can't tell the expression to evaluate directly into the |
449 | * result slot, as the result slot (and the exprstate for that |
450 | * matter) can change between executions. We instead evaluate |
451 | * into the ExprState's resvalue/resnull and then move. |
452 | */ |
453 | ExecInitExprRec(tle->expr, state, |
454 | &state->resvalue, &state->resnull); |
455 | |
456 | /* |
457 | * Column might be referenced multiple times in upper nodes, so |
458 | * force value to R/O - but only if it could be an expanded datum. |
459 | */ |
460 | if (get_typlen(exprType((Node *) tle->expr)) == -1) |
461 | scratch.opcode = EEOP_ASSIGN_TMP_MAKE_RO; |
462 | else |
463 | scratch.opcode = EEOP_ASSIGN_TMP; |
464 | scratch.d.assign_tmp.resultnum = tle->resno - 1; |
465 | ExprEvalPushStep(state, &scratch); |
466 | } |
467 | } |
468 | |
469 | scratch.opcode = EEOP_DONE; |
470 | ExprEvalPushStep(state, &scratch); |
471 | |
472 | ExecReadyExpr(state); |
473 | |
474 | return projInfo; |
475 | } |
476 | |
477 | /* |
478 | * ExecPrepareExpr --- initialize for expression execution outside a normal |
479 | * Plan tree context. |
480 | * |
481 | * This differs from ExecInitExpr in that we don't assume the caller is |
482 | * already running in the EState's per-query context. Also, we run the |
483 | * passed expression tree through expression_planner() to prepare it for |
484 | * execution. (In ordinary Plan trees the regular planning process will have |
485 | * made the appropriate transformations on expressions, but for standalone |
486 | * expressions this won't have happened.) |
487 | */ |
488 | ExprState * |
489 | ExecPrepareExpr(Expr *node, EState *estate) |
490 | { |
491 | ExprState *result; |
492 | MemoryContext oldcontext; |
493 | |
494 | oldcontext = MemoryContextSwitchTo(estate->es_query_cxt); |
495 | |
496 | node = expression_planner(node); |
497 | |
498 | result = ExecInitExpr(node, NULL); |
499 | |
500 | MemoryContextSwitchTo(oldcontext); |
501 | |
502 | return result; |
503 | } |
504 | |
505 | /* |
506 | * ExecPrepareQual --- initialize for qual execution outside a normal |
507 | * Plan tree context. |
508 | * |
509 | * This differs from ExecInitQual in that we don't assume the caller is |
510 | * already running in the EState's per-query context. Also, we run the |
511 | * passed expression tree through expression_planner() to prepare it for |
512 | * execution. (In ordinary Plan trees the regular planning process will have |
513 | * made the appropriate transformations on expressions, but for standalone |
514 | * expressions this won't have happened.) |
515 | */ |
516 | ExprState * |
517 | ExecPrepareQual(List *qual, EState *estate) |
518 | { |
519 | ExprState *result; |
520 | MemoryContext oldcontext; |
521 | |
522 | oldcontext = MemoryContextSwitchTo(estate->es_query_cxt); |
523 | |
524 | qual = (List *) expression_planner((Expr *) qual); |
525 | |
526 | result = ExecInitQual(qual, NULL); |
527 | |
528 | MemoryContextSwitchTo(oldcontext); |
529 | |
530 | return result; |
531 | } |
532 | |
533 | /* |
534 | * ExecPrepareCheck -- initialize check constraint for execution outside a |
535 | * normal Plan tree context. |
536 | * |
537 | * See ExecPrepareExpr() and ExecInitCheck() for details. |
538 | */ |
539 | ExprState * |
540 | ExecPrepareCheck(List *qual, EState *estate) |
541 | { |
542 | ExprState *result; |
543 | MemoryContext oldcontext; |
544 | |
545 | oldcontext = MemoryContextSwitchTo(estate->es_query_cxt); |
546 | |
547 | qual = (List *) expression_planner((Expr *) qual); |
548 | |
549 | result = ExecInitCheck(qual, NULL); |
550 | |
551 | MemoryContextSwitchTo(oldcontext); |
552 | |
553 | return result; |
554 | } |
555 | |
556 | /* |
557 | * Call ExecPrepareExpr() on each member of a list of Exprs, and return |
558 | * a list of ExprStates. |
559 | * |
560 | * See ExecPrepareExpr() for details. |
561 | */ |
562 | List * |
563 | ExecPrepareExprList(List *nodes, EState *estate) |
564 | { |
565 | List *result = NIL; |
566 | MemoryContext oldcontext; |
567 | ListCell *lc; |
568 | |
569 | /* Ensure that the list cell nodes are in the right context too */ |
570 | oldcontext = MemoryContextSwitchTo(estate->es_query_cxt); |
571 | |
572 | foreach(lc, nodes) |
573 | { |
574 | Expr *e = (Expr *) lfirst(lc); |
575 | |
576 | result = lappend(result, ExecPrepareExpr(e, estate)); |
577 | } |
578 | |
579 | MemoryContextSwitchTo(oldcontext); |
580 | |
581 | return result; |
582 | } |
583 | |
584 | /* |
585 | * ExecCheck - evaluate a check constraint |
586 | * |
587 | * For check constraints, a null result is taken as TRUE, ie the constraint |
588 | * passes. |
589 | * |
590 | * The check constraint may have been prepared with ExecInitCheck |
591 | * (possibly via ExecPrepareCheck) if the caller had it in implicit-AND |
592 | * format, but a regular boolean expression prepared with ExecInitExpr or |
593 | * ExecPrepareExpr works too. |
594 | */ |
595 | bool |
596 | ExecCheck(ExprState *state, ExprContext *econtext) |
597 | { |
598 | Datum ret; |
599 | bool isnull; |
600 | |
601 | /* short-circuit (here and in ExecInitCheck) for empty restriction list */ |
602 | if (state == NULL) |
603 | return true; |
604 | |
605 | /* verify that expression was not compiled using ExecInitQual */ |
606 | Assert(!(state->flags & EEO_FLAG_IS_QUAL)); |
607 | |
608 | ret = ExecEvalExprSwitchContext(state, econtext, &isnull); |
609 | |
610 | if (isnull) |
611 | return true; |
612 | |
613 | return DatumGetBool(ret); |
614 | } |
615 | |
616 | /* |
617 | * Prepare a compiled expression for execution. This has to be called for |
618 | * every ExprState before it can be executed. |
619 | * |
620 | * NB: While this currently only calls ExecReadyInterpretedExpr(), |
621 | * this will likely get extended to further expression evaluation methods. |
622 | * Therefore this should be used instead of directly calling |
623 | * ExecReadyInterpretedExpr(). |
624 | */ |
625 | static void |
626 | ExecReadyExpr(ExprState *state) |
627 | { |
628 | if (jit_compile_expr(state)) |
629 | return; |
630 | |
631 | ExecReadyInterpretedExpr(state); |
632 | } |
633 | |
634 | /* |
635 | * Append the steps necessary for the evaluation of node to ExprState->steps, |
636 | * possibly recursing into sub-expressions of node. |
637 | * |
638 | * node - expression to evaluate |
639 | * state - ExprState to whose ->steps to append the necessary operations |
640 | * resv / resnull - where to store the result of the node into |
641 | */ |
642 | static void |
643 | ExecInitExprRec(Expr *node, ExprState *state, |
644 | Datum *resv, bool *resnull) |
645 | { |
646 | ExprEvalStep scratch = {0}; |
647 | |
648 | /* Guard against stack overflow due to overly complex expressions */ |
649 | check_stack_depth(); |
650 | |
651 | /* Step's output location is always what the caller gave us */ |
652 | Assert(resv != NULL && resnull != NULL); |
653 | scratch.resvalue = resv; |
654 | scratch.resnull = resnull; |
655 | |
656 | /* cases should be ordered as they are in enum NodeTag */ |
657 | switch (nodeTag(node)) |
658 | { |
659 | case T_Var: |
660 | { |
661 | Var *variable = (Var *) node; |
662 | |
663 | if (variable->varattno == InvalidAttrNumber) |
664 | { |
665 | /* whole-row Var */ |
666 | ExecInitWholeRowVar(&scratch, variable, state); |
667 | } |
668 | else if (variable->varattno <= 0) |
669 | { |
670 | /* system column */ |
671 | scratch.d.var.attnum = variable->varattno; |
672 | scratch.d.var.vartype = variable->vartype; |
673 | switch (variable->varno) |
674 | { |
675 | case INNER_VAR: |
676 | scratch.opcode = EEOP_INNER_SYSVAR; |
677 | break; |
678 | case OUTER_VAR: |
679 | scratch.opcode = EEOP_OUTER_SYSVAR; |
680 | break; |
681 | |
682 | /* INDEX_VAR is handled by default case */ |
683 | |
684 | default: |
685 | scratch.opcode = EEOP_SCAN_SYSVAR; |
686 | break; |
687 | } |
688 | } |
689 | else |
690 | { |
691 | /* regular user column */ |
692 | scratch.d.var.attnum = variable->varattno - 1; |
693 | scratch.d.var.vartype = variable->vartype; |
694 | switch (variable->varno) |
695 | { |
696 | case INNER_VAR: |
697 | scratch.opcode = EEOP_INNER_VAR; |
698 | break; |
699 | case OUTER_VAR: |
700 | scratch.opcode = EEOP_OUTER_VAR; |
701 | break; |
702 | |
703 | /* INDEX_VAR is handled by default case */ |
704 | |
705 | default: |
706 | scratch.opcode = EEOP_SCAN_VAR; |
707 | break; |
708 | } |
709 | } |
710 | |
711 | ExprEvalPushStep(state, &scratch); |
712 | break; |
713 | } |
714 | |
715 | case T_Const: |
716 | { |
717 | Const *con = (Const *) node; |
718 | |
719 | scratch.opcode = EEOP_CONST; |
720 | scratch.d.constval.value = con->constvalue; |
721 | scratch.d.constval.isnull = con->constisnull; |
722 | |
723 | ExprEvalPushStep(state, &scratch); |
724 | break; |
725 | } |
726 | |
727 | case T_Param: |
728 | { |
729 | Param *param = (Param *) node; |
730 | ParamListInfo params; |
731 | |
732 | switch (param->paramkind) |
733 | { |
734 | case PARAM_EXEC: |
735 | scratch.opcode = EEOP_PARAM_EXEC; |
736 | scratch.d.param.paramid = param->paramid; |
737 | scratch.d.param.paramtype = param->paramtype; |
738 | ExprEvalPushStep(state, &scratch); |
739 | break; |
740 | case PARAM_EXTERN: |
741 | |
742 | /* |
743 | * If we have a relevant ParamCompileHook, use it; |
744 | * otherwise compile a standard EEOP_PARAM_EXTERN |
745 | * step. ext_params, if supplied, takes precedence |
746 | * over info from the parent node's EState (if any). |
747 | */ |
748 | if (state->ext_params) |
749 | params = state->ext_params; |
750 | else if (state->parent && |
751 | state->parent->state) |
752 | params = state->parent->state->es_param_list_info; |
753 | else |
754 | params = NULL; |
755 | if (params && params->paramCompile) |
756 | { |
757 | params->paramCompile(params, param, state, |
758 | resv, resnull); |
759 | } |
760 | else |
761 | { |
762 | scratch.opcode = EEOP_PARAM_EXTERN; |
763 | scratch.d.param.paramid = param->paramid; |
764 | scratch.d.param.paramtype = param->paramtype; |
765 | ExprEvalPushStep(state, &scratch); |
766 | } |
767 | break; |
768 | default: |
769 | elog(ERROR, "unrecognized paramkind: %d" , |
770 | (int) param->paramkind); |
771 | break; |
772 | } |
773 | break; |
774 | } |
775 | |
776 | case T_Aggref: |
777 | { |
778 | Aggref *aggref = (Aggref *) node; |
779 | AggrefExprState *astate = makeNode(AggrefExprState); |
780 | |
781 | scratch.opcode = EEOP_AGGREF; |
782 | scratch.d.aggref.astate = astate; |
783 | astate->aggref = aggref; |
784 | |
785 | if (state->parent && IsA(state->parent, AggState)) |
786 | { |
787 | AggState *aggstate = (AggState *) state->parent; |
788 | |
789 | aggstate->aggs = lcons(astate, aggstate->aggs); |
790 | aggstate->numaggs++; |
791 | } |
792 | else |
793 | { |
794 | /* planner messed up */ |
795 | elog(ERROR, "Aggref found in non-Agg plan node" ); |
796 | } |
797 | |
798 | ExprEvalPushStep(state, &scratch); |
799 | break; |
800 | } |
801 | |
802 | case T_GroupingFunc: |
803 | { |
804 | GroupingFunc *grp_node = (GroupingFunc *) node; |
805 | Agg *agg; |
806 | |
807 | if (!state->parent || !IsA(state->parent, AggState) || |
808 | !IsA(state->parent->plan, Agg)) |
809 | elog(ERROR, "GroupingFunc found in non-Agg plan node" ); |
810 | |
811 | scratch.opcode = EEOP_GROUPING_FUNC; |
812 | scratch.d.grouping_func.parent = (AggState *) state->parent; |
813 | |
814 | agg = (Agg *) (state->parent->plan); |
815 | |
816 | if (agg->groupingSets) |
817 | scratch.d.grouping_func.clauses = grp_node->cols; |
818 | else |
819 | scratch.d.grouping_func.clauses = NIL; |
820 | |
821 | ExprEvalPushStep(state, &scratch); |
822 | break; |
823 | } |
824 | |
825 | case T_WindowFunc: |
826 | { |
827 | WindowFunc *wfunc = (WindowFunc *) node; |
828 | WindowFuncExprState *wfstate = makeNode(WindowFuncExprState); |
829 | |
830 | wfstate->wfunc = wfunc; |
831 | |
832 | if (state->parent && IsA(state->parent, WindowAggState)) |
833 | { |
834 | WindowAggState *winstate = (WindowAggState *) state->parent; |
835 | int nfuncs; |
836 | |
837 | winstate->funcs = lcons(wfstate, winstate->funcs); |
838 | nfuncs = ++winstate->numfuncs; |
839 | if (wfunc->winagg) |
840 | winstate->numaggs++; |
841 | |
842 | /* for now initialize agg using old style expressions */ |
843 | wfstate->args = ExecInitExprList(wfunc->args, |
844 | state->parent); |
845 | wfstate->aggfilter = ExecInitExpr(wfunc->aggfilter, |
846 | state->parent); |
847 | |
848 | /* |
849 | * Complain if the windowfunc's arguments contain any |
850 | * windowfuncs; nested window functions are semantically |
851 | * nonsensical. (This should have been caught earlier, |
852 | * but we defend against it here anyway.) |
853 | */ |
854 | if (nfuncs != winstate->numfuncs) |
855 | ereport(ERROR, |
856 | (errcode(ERRCODE_WINDOWING_ERROR), |
857 | errmsg("window function calls cannot be nested" ))); |
858 | } |
859 | else |
860 | { |
861 | /* planner messed up */ |
862 | elog(ERROR, "WindowFunc found in non-WindowAgg plan node" ); |
863 | } |
864 | |
865 | scratch.opcode = EEOP_WINDOW_FUNC; |
866 | scratch.d.window_func.wfstate = wfstate; |
867 | ExprEvalPushStep(state, &scratch); |
868 | break; |
869 | } |
870 | |
871 | case T_SubscriptingRef: |
872 | { |
873 | SubscriptingRef *sbsref = (SubscriptingRef *) node; |
874 | |
875 | ExecInitSubscriptingRef(&scratch, sbsref, state, resv, resnull); |
876 | break; |
877 | } |
878 | |
879 | case T_FuncExpr: |
880 | { |
881 | FuncExpr *func = (FuncExpr *) node; |
882 | |
883 | ExecInitFunc(&scratch, node, |
884 | func->args, func->funcid, func->inputcollid, |
885 | state); |
886 | ExprEvalPushStep(state, &scratch); |
887 | break; |
888 | } |
889 | |
890 | case T_OpExpr: |
891 | { |
892 | OpExpr *op = (OpExpr *) node; |
893 | |
894 | ExecInitFunc(&scratch, node, |
895 | op->args, op->opfuncid, op->inputcollid, |
896 | state); |
897 | ExprEvalPushStep(state, &scratch); |
898 | break; |
899 | } |
900 | |
901 | case T_DistinctExpr: |
902 | { |
903 | DistinctExpr *op = (DistinctExpr *) node; |
904 | |
905 | ExecInitFunc(&scratch, node, |
906 | op->args, op->opfuncid, op->inputcollid, |
907 | state); |
908 | |
909 | /* |
910 | * Change opcode of call instruction to EEOP_DISTINCT. |
911 | * |
912 | * XXX: historically we've not called the function usage |
913 | * pgstat infrastructure - that seems inconsistent given that |
914 | * we do so for normal function *and* operator evaluation. If |
915 | * we decided to do that here, we'd probably want separate |
916 | * opcodes for FUSAGE or not. |
917 | */ |
918 | scratch.opcode = EEOP_DISTINCT; |
919 | ExprEvalPushStep(state, &scratch); |
920 | break; |
921 | } |
922 | |
923 | case T_NullIfExpr: |
924 | { |
925 | NullIfExpr *op = (NullIfExpr *) node; |
926 | |
927 | ExecInitFunc(&scratch, node, |
928 | op->args, op->opfuncid, op->inputcollid, |
929 | state); |
930 | |
931 | /* |
932 | * Change opcode of call instruction to EEOP_NULLIF. |
933 | * |
934 | * XXX: historically we've not called the function usage |
935 | * pgstat infrastructure - that seems inconsistent given that |
936 | * we do so for normal function *and* operator evaluation. If |
937 | * we decided to do that here, we'd probably want separate |
938 | * opcodes for FUSAGE or not. |
939 | */ |
940 | scratch.opcode = EEOP_NULLIF; |
941 | ExprEvalPushStep(state, &scratch); |
942 | break; |
943 | } |
944 | |
945 | case T_ScalarArrayOpExpr: |
946 | { |
947 | ScalarArrayOpExpr *opexpr = (ScalarArrayOpExpr *) node; |
948 | Expr *scalararg; |
949 | Expr *arrayarg; |
950 | FmgrInfo *finfo; |
951 | FunctionCallInfo fcinfo; |
952 | AclResult aclresult; |
953 | |
954 | Assert(list_length(opexpr->args) == 2); |
955 | scalararg = (Expr *) linitial(opexpr->args); |
956 | arrayarg = (Expr *) lsecond(opexpr->args); |
957 | |
958 | /* Check permission to call function */ |
959 | aclresult = pg_proc_aclcheck(opexpr->opfuncid, |
960 | GetUserId(), |
961 | ACL_EXECUTE); |
962 | if (aclresult != ACLCHECK_OK) |
963 | aclcheck_error(aclresult, OBJECT_FUNCTION, |
964 | get_func_name(opexpr->opfuncid)); |
965 | InvokeFunctionExecuteHook(opexpr->opfuncid); |
966 | |
967 | /* Set up the primary fmgr lookup information */ |
968 | finfo = palloc0(sizeof(FmgrInfo)); |
969 | fcinfo = palloc0(SizeForFunctionCallInfo(2)); |
970 | fmgr_info(opexpr->opfuncid, finfo); |
971 | fmgr_info_set_expr((Node *) node, finfo); |
972 | InitFunctionCallInfoData(*fcinfo, finfo, 2, |
973 | opexpr->inputcollid, NULL, NULL); |
974 | |
975 | /* Evaluate scalar directly into left function argument */ |
976 | ExecInitExprRec(scalararg, state, |
977 | &fcinfo->args[0].value, &fcinfo->args[0].isnull); |
978 | |
979 | /* |
980 | * Evaluate array argument into our return value. There's no |
981 | * danger in that, because the return value is guaranteed to |
982 | * be overwritten by EEOP_SCALARARRAYOP, and will not be |
983 | * passed to any other expression. |
984 | */ |
985 | ExecInitExprRec(arrayarg, state, resv, resnull); |
986 | |
987 | /* And perform the operation */ |
988 | scratch.opcode = EEOP_SCALARARRAYOP; |
989 | scratch.d.scalararrayop.element_type = InvalidOid; |
990 | scratch.d.scalararrayop.useOr = opexpr->useOr; |
991 | scratch.d.scalararrayop.finfo = finfo; |
992 | scratch.d.scalararrayop.fcinfo_data = fcinfo; |
993 | scratch.d.scalararrayop.fn_addr = finfo->fn_addr; |
994 | ExprEvalPushStep(state, &scratch); |
995 | break; |
996 | } |
997 | |
998 | case T_BoolExpr: |
999 | { |
1000 | BoolExpr *boolexpr = (BoolExpr *) node; |
1001 | int nargs = list_length(boolexpr->args); |
1002 | List *adjust_jumps = NIL; |
1003 | int off; |
1004 | ListCell *lc; |
1005 | |
1006 | /* allocate scratch memory used by all steps of AND/OR */ |
1007 | if (boolexpr->boolop != NOT_EXPR) |
1008 | scratch.d.boolexpr.anynull = (bool *) palloc(sizeof(bool)); |
1009 | |
1010 | /* |
1011 | * For each argument evaluate the argument itself, then |
1012 | * perform the bool operation's appropriate handling. |
1013 | * |
1014 | * We can evaluate each argument into our result area, since |
1015 | * the short-circuiting logic means we only need to remember |
1016 | * previous NULL values. |
1017 | * |
1018 | * AND/OR is split into separate STEP_FIRST (one) / STEP (zero |
1019 | * or more) / STEP_LAST (one) steps, as each of those has to |
1020 | * perform different work. The FIRST/LAST split is valid |
1021 | * because AND/OR have at least two arguments. |
1022 | */ |
1023 | off = 0; |
1024 | foreach(lc, boolexpr->args) |
1025 | { |
1026 | Expr *arg = (Expr *) lfirst(lc); |
1027 | |
1028 | /* Evaluate argument into our output variable */ |
1029 | ExecInitExprRec(arg, state, resv, resnull); |
1030 | |
1031 | /* Perform the appropriate step type */ |
1032 | switch (boolexpr->boolop) |
1033 | { |
1034 | case AND_EXPR: |
1035 | Assert(nargs >= 2); |
1036 | |
1037 | if (off == 0) |
1038 | scratch.opcode = EEOP_BOOL_AND_STEP_FIRST; |
1039 | else if (off + 1 == nargs) |
1040 | scratch.opcode = EEOP_BOOL_AND_STEP_LAST; |
1041 | else |
1042 | scratch.opcode = EEOP_BOOL_AND_STEP; |
1043 | break; |
1044 | case OR_EXPR: |
1045 | Assert(nargs >= 2); |
1046 | |
1047 | if (off == 0) |
1048 | scratch.opcode = EEOP_BOOL_OR_STEP_FIRST; |
1049 | else if (off + 1 == nargs) |
1050 | scratch.opcode = EEOP_BOOL_OR_STEP_LAST; |
1051 | else |
1052 | scratch.opcode = EEOP_BOOL_OR_STEP; |
1053 | break; |
1054 | case NOT_EXPR: |
1055 | Assert(nargs == 1); |
1056 | |
1057 | scratch.opcode = EEOP_BOOL_NOT_STEP; |
1058 | break; |
1059 | default: |
1060 | elog(ERROR, "unrecognized boolop: %d" , |
1061 | (int) boolexpr->boolop); |
1062 | break; |
1063 | } |
1064 | |
1065 | scratch.d.boolexpr.jumpdone = -1; |
1066 | ExprEvalPushStep(state, &scratch); |
1067 | adjust_jumps = lappend_int(adjust_jumps, |
1068 | state->steps_len - 1); |
1069 | off++; |
1070 | } |
1071 | |
1072 | /* adjust jump targets */ |
1073 | foreach(lc, adjust_jumps) |
1074 | { |
1075 | ExprEvalStep *as = &state->steps[lfirst_int(lc)]; |
1076 | |
1077 | Assert(as->d.boolexpr.jumpdone == -1); |
1078 | as->d.boolexpr.jumpdone = state->steps_len; |
1079 | } |
1080 | |
1081 | break; |
1082 | } |
1083 | |
1084 | case T_SubPlan: |
1085 | { |
1086 | SubPlan *subplan = (SubPlan *) node; |
1087 | SubPlanState *sstate; |
1088 | |
1089 | if (!state->parent) |
1090 | elog(ERROR, "SubPlan found with no parent plan" ); |
1091 | |
1092 | sstate = ExecInitSubPlan(subplan, state->parent); |
1093 | |
1094 | /* add SubPlanState nodes to state->parent->subPlan */ |
1095 | state->parent->subPlan = lappend(state->parent->subPlan, |
1096 | sstate); |
1097 | |
1098 | scratch.opcode = EEOP_SUBPLAN; |
1099 | scratch.d.subplan.sstate = sstate; |
1100 | |
1101 | ExprEvalPushStep(state, &scratch); |
1102 | break; |
1103 | } |
1104 | |
1105 | case T_AlternativeSubPlan: |
1106 | { |
1107 | AlternativeSubPlan *asplan = (AlternativeSubPlan *) node; |
1108 | AlternativeSubPlanState *asstate; |
1109 | |
1110 | if (!state->parent) |
1111 | elog(ERROR, "AlternativeSubPlan found with no parent plan" ); |
1112 | |
1113 | asstate = ExecInitAlternativeSubPlan(asplan, state->parent); |
1114 | |
1115 | scratch.opcode = EEOP_ALTERNATIVE_SUBPLAN; |
1116 | scratch.d.alternative_subplan.asstate = asstate; |
1117 | |
1118 | ExprEvalPushStep(state, &scratch); |
1119 | break; |
1120 | } |
1121 | |
1122 | case T_FieldSelect: |
1123 | { |
1124 | FieldSelect *fselect = (FieldSelect *) node; |
1125 | |
1126 | /* evaluate row/record argument into result area */ |
1127 | ExecInitExprRec(fselect->arg, state, resv, resnull); |
1128 | |
1129 | /* and extract field */ |
1130 | scratch.opcode = EEOP_FIELDSELECT; |
1131 | scratch.d.fieldselect.fieldnum = fselect->fieldnum; |
1132 | scratch.d.fieldselect.resulttype = fselect->resulttype; |
1133 | scratch.d.fieldselect.argdesc = NULL; |
1134 | |
1135 | ExprEvalPushStep(state, &scratch); |
1136 | break; |
1137 | } |
1138 | |
1139 | case T_FieldStore: |
1140 | { |
1141 | FieldStore *fstore = (FieldStore *) node; |
1142 | TupleDesc tupDesc; |
1143 | TupleDesc *descp; |
1144 | Datum *values; |
1145 | bool *nulls; |
1146 | int ncolumns; |
1147 | ListCell *l1, |
1148 | *l2; |
1149 | |
1150 | /* find out the number of columns in the composite type */ |
1151 | tupDesc = lookup_rowtype_tupdesc(fstore->resulttype, -1); |
1152 | ncolumns = tupDesc->natts; |
1153 | DecrTupleDescRefCount(tupDesc); |
1154 | |
1155 | /* create workspace for column values */ |
1156 | values = (Datum *) palloc(sizeof(Datum) * ncolumns); |
1157 | nulls = (bool *) palloc(sizeof(bool) * ncolumns); |
1158 | |
1159 | /* create workspace for runtime tupdesc cache */ |
1160 | descp = (TupleDesc *) palloc(sizeof(TupleDesc)); |
1161 | *descp = NULL; |
1162 | |
1163 | /* emit code to evaluate the composite input value */ |
1164 | ExecInitExprRec(fstore->arg, state, resv, resnull); |
1165 | |
1166 | /* next, deform the input tuple into our workspace */ |
1167 | scratch.opcode = EEOP_FIELDSTORE_DEFORM; |
1168 | scratch.d.fieldstore.fstore = fstore; |
1169 | scratch.d.fieldstore.argdesc = descp; |
1170 | scratch.d.fieldstore.values = values; |
1171 | scratch.d.fieldstore.nulls = nulls; |
1172 | scratch.d.fieldstore.ncolumns = ncolumns; |
1173 | ExprEvalPushStep(state, &scratch); |
1174 | |
1175 | /* evaluate new field values, store in workspace columns */ |
1176 | forboth(l1, fstore->newvals, l2, fstore->fieldnums) |
1177 | { |
1178 | Expr *e = (Expr *) lfirst(l1); |
1179 | AttrNumber fieldnum = lfirst_int(l2); |
1180 | Datum *save_innermost_caseval; |
1181 | bool *save_innermost_casenull; |
1182 | |
1183 | if (fieldnum <= 0 || fieldnum > ncolumns) |
1184 | elog(ERROR, "field number %d is out of range in FieldStore" , |
1185 | fieldnum); |
1186 | |
1187 | /* |
1188 | * Use the CaseTestExpr mechanism to pass down the old |
1189 | * value of the field being replaced; this is needed in |
1190 | * case the newval is itself a FieldStore or |
1191 | * SubscriptingRef that has to obtain and modify the old |
1192 | * value. It's safe to reuse the CASE mechanism because |
1193 | * there cannot be a CASE between here and where the value |
1194 | * would be needed, and a field assignment can't be within |
1195 | * a CASE either. (So saving and restoring |
1196 | * innermost_caseval is just paranoia, but let's do it |
1197 | * anyway.) |
1198 | * |
1199 | * Another non-obvious point is that it's safe to use the |
1200 | * field's values[]/nulls[] entries as both the caseval |
1201 | * source and the result address for this subexpression. |
1202 | * That's okay only because (1) both FieldStore and |
1203 | * SubscriptingRef evaluate their arg or refexpr inputs |
1204 | * first, and (2) any such CaseTestExpr is directly the |
1205 | * arg or refexpr input. So any read of the caseval will |
1206 | * occur before there's a chance to overwrite it. Also, |
1207 | * if multiple entries in the newvals/fieldnums lists |
1208 | * target the same field, they'll effectively be applied |
1209 | * left-to-right which is what we want. |
1210 | */ |
1211 | save_innermost_caseval = state->innermost_caseval; |
1212 | save_innermost_casenull = state->innermost_casenull; |
1213 | state->innermost_caseval = &values[fieldnum - 1]; |
1214 | state->innermost_casenull = &nulls[fieldnum - 1]; |
1215 | |
1216 | ExecInitExprRec(e, state, |
1217 | &values[fieldnum - 1], |
1218 | &nulls[fieldnum - 1]); |
1219 | |
1220 | state->innermost_caseval = save_innermost_caseval; |
1221 | state->innermost_casenull = save_innermost_casenull; |
1222 | } |
1223 | |
1224 | /* finally, form result tuple */ |
1225 | scratch.opcode = EEOP_FIELDSTORE_FORM; |
1226 | scratch.d.fieldstore.fstore = fstore; |
1227 | scratch.d.fieldstore.argdesc = descp; |
1228 | scratch.d.fieldstore.values = values; |
1229 | scratch.d.fieldstore.nulls = nulls; |
1230 | scratch.d.fieldstore.ncolumns = ncolumns; |
1231 | ExprEvalPushStep(state, &scratch); |
1232 | break; |
1233 | } |
1234 | |
1235 | case T_RelabelType: |
1236 | { |
1237 | /* relabel doesn't need to do anything at runtime */ |
1238 | RelabelType *relabel = (RelabelType *) node; |
1239 | |
1240 | ExecInitExprRec(relabel->arg, state, resv, resnull); |
1241 | break; |
1242 | } |
1243 | |
1244 | case T_CoerceViaIO: |
1245 | { |
1246 | CoerceViaIO *iocoerce = (CoerceViaIO *) node; |
1247 | Oid iofunc; |
1248 | bool typisvarlena; |
1249 | Oid typioparam; |
1250 | FunctionCallInfo fcinfo_in; |
1251 | |
1252 | /* evaluate argument into step's result area */ |
1253 | ExecInitExprRec(iocoerce->arg, state, resv, resnull); |
1254 | |
1255 | /* |
1256 | * Prepare both output and input function calls, to be |
1257 | * evaluated inside a single evaluation step for speed - this |
1258 | * can be a very common operation. |
1259 | * |
1260 | * We don't check permissions here as a type's input/output |
1261 | * function are assumed to be executable by everyone. |
1262 | */ |
1263 | scratch.opcode = EEOP_IOCOERCE; |
1264 | |
1265 | /* lookup the source type's output function */ |
1266 | scratch.d.iocoerce.finfo_out = palloc0(sizeof(FmgrInfo)); |
1267 | scratch.d.iocoerce.fcinfo_data_out = palloc0(SizeForFunctionCallInfo(1)); |
1268 | |
1269 | getTypeOutputInfo(exprType((Node *) iocoerce->arg), |
1270 | &iofunc, &typisvarlena); |
1271 | fmgr_info(iofunc, scratch.d.iocoerce.finfo_out); |
1272 | fmgr_info_set_expr((Node *) node, scratch.d.iocoerce.finfo_out); |
1273 | InitFunctionCallInfoData(*scratch.d.iocoerce.fcinfo_data_out, |
1274 | scratch.d.iocoerce.finfo_out, |
1275 | 1, InvalidOid, NULL, NULL); |
1276 | |
1277 | /* lookup the result type's input function */ |
1278 | scratch.d.iocoerce.finfo_in = palloc0(sizeof(FmgrInfo)); |
1279 | scratch.d.iocoerce.fcinfo_data_in = palloc0(SizeForFunctionCallInfo(3)); |
1280 | |
1281 | getTypeInputInfo(iocoerce->resulttype, |
1282 | &iofunc, &typioparam); |
1283 | fmgr_info(iofunc, scratch.d.iocoerce.finfo_in); |
1284 | fmgr_info_set_expr((Node *) node, scratch.d.iocoerce.finfo_in); |
1285 | InitFunctionCallInfoData(*scratch.d.iocoerce.fcinfo_data_in, |
1286 | scratch.d.iocoerce.finfo_in, |
1287 | 3, InvalidOid, NULL, NULL); |
1288 | |
1289 | /* |
1290 | * We can preload the second and third arguments for the input |
1291 | * function, since they're constants. |
1292 | */ |
1293 | fcinfo_in = scratch.d.iocoerce.fcinfo_data_in; |
1294 | fcinfo_in->args[1].value = ObjectIdGetDatum(typioparam); |
1295 | fcinfo_in->args[1].isnull = false; |
1296 | fcinfo_in->args[2].value = Int32GetDatum(-1); |
1297 | fcinfo_in->args[2].isnull = false; |
1298 | |
1299 | ExprEvalPushStep(state, &scratch); |
1300 | break; |
1301 | } |
1302 | |
1303 | case T_ArrayCoerceExpr: |
1304 | { |
1305 | ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node; |
1306 | Oid resultelemtype; |
1307 | ExprState *elemstate; |
1308 | |
1309 | /* evaluate argument into step's result area */ |
1310 | ExecInitExprRec(acoerce->arg, state, resv, resnull); |
1311 | |
1312 | resultelemtype = get_element_type(acoerce->resulttype); |
1313 | if (!OidIsValid(resultelemtype)) |
1314 | ereport(ERROR, |
1315 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
1316 | errmsg("target type is not an array" ))); |
1317 | |
1318 | /* |
1319 | * Construct a sub-expression for the per-element expression; |
1320 | * but don't ready it until after we check it for triviality. |
1321 | * We assume it hasn't any Var references, but does have a |
1322 | * CaseTestExpr representing the source array element values. |
1323 | */ |
1324 | elemstate = makeNode(ExprState); |
1325 | elemstate->expr = acoerce->elemexpr; |
1326 | elemstate->parent = state->parent; |
1327 | elemstate->ext_params = state->ext_params; |
1328 | |
1329 | elemstate->innermost_caseval = (Datum *) palloc(sizeof(Datum)); |
1330 | elemstate->innermost_casenull = (bool *) palloc(sizeof(bool)); |
1331 | |
1332 | ExecInitExprRec(acoerce->elemexpr, elemstate, |
1333 | &elemstate->resvalue, &elemstate->resnull); |
1334 | |
1335 | if (elemstate->steps_len == 1 && |
1336 | elemstate->steps[0].opcode == EEOP_CASE_TESTVAL) |
1337 | { |
1338 | /* Trivial, so we need no per-element work at runtime */ |
1339 | elemstate = NULL; |
1340 | } |
1341 | else |
1342 | { |
1343 | /* Not trivial, so append a DONE step */ |
1344 | scratch.opcode = EEOP_DONE; |
1345 | ExprEvalPushStep(elemstate, &scratch); |
1346 | /* and ready the subexpression */ |
1347 | ExecReadyExpr(elemstate); |
1348 | } |
1349 | |
1350 | scratch.opcode = EEOP_ARRAYCOERCE; |
1351 | scratch.d.arraycoerce.elemexprstate = elemstate; |
1352 | scratch.d.arraycoerce.resultelemtype = resultelemtype; |
1353 | |
1354 | if (elemstate) |
1355 | { |
1356 | /* Set up workspace for array_map */ |
1357 | scratch.d.arraycoerce.amstate = |
1358 | (ArrayMapState *) palloc0(sizeof(ArrayMapState)); |
1359 | } |
1360 | else |
1361 | { |
1362 | /* Don't need workspace if there's no subexpression */ |
1363 | scratch.d.arraycoerce.amstate = NULL; |
1364 | } |
1365 | |
1366 | ExprEvalPushStep(state, &scratch); |
1367 | break; |
1368 | } |
1369 | |
1370 | case T_ConvertRowtypeExpr: |
1371 | { |
1372 | ConvertRowtypeExpr *convert = (ConvertRowtypeExpr *) node; |
1373 | |
1374 | /* evaluate argument into step's result area */ |
1375 | ExecInitExprRec(convert->arg, state, resv, resnull); |
1376 | |
1377 | /* and push conversion step */ |
1378 | scratch.opcode = EEOP_CONVERT_ROWTYPE; |
1379 | scratch.d.convert_rowtype.convert = convert; |
1380 | scratch.d.convert_rowtype.indesc = NULL; |
1381 | scratch.d.convert_rowtype.outdesc = NULL; |
1382 | scratch.d.convert_rowtype.map = NULL; |
1383 | scratch.d.convert_rowtype.initialized = false; |
1384 | |
1385 | ExprEvalPushStep(state, &scratch); |
1386 | break; |
1387 | } |
1388 | |
1389 | /* note that CaseWhen expressions are handled within this block */ |
1390 | case T_CaseExpr: |
1391 | { |
1392 | CaseExpr *caseExpr = (CaseExpr *) node; |
1393 | List *adjust_jumps = NIL; |
1394 | Datum *caseval = NULL; |
1395 | bool *casenull = NULL; |
1396 | ListCell *lc; |
1397 | |
1398 | /* |
1399 | * If there's a test expression, we have to evaluate it and |
1400 | * save the value where the CaseTestExpr placeholders can find |
1401 | * it. |
1402 | */ |
1403 | if (caseExpr->arg != NULL) |
1404 | { |
1405 | /* Evaluate testexpr into caseval/casenull workspace */ |
1406 | caseval = palloc(sizeof(Datum)); |
1407 | casenull = palloc(sizeof(bool)); |
1408 | |
1409 | ExecInitExprRec(caseExpr->arg, state, |
1410 | caseval, casenull); |
1411 | |
1412 | /* |
1413 | * Since value might be read multiple times, force to R/O |
1414 | * - but only if it could be an expanded datum. |
1415 | */ |
1416 | if (get_typlen(exprType((Node *) caseExpr->arg)) == -1) |
1417 | { |
1418 | /* change caseval in-place */ |
1419 | scratch.opcode = EEOP_MAKE_READONLY; |
1420 | scratch.resvalue = caseval; |
1421 | scratch.resnull = casenull; |
1422 | scratch.d.make_readonly.value = caseval; |
1423 | scratch.d.make_readonly.isnull = casenull; |
1424 | ExprEvalPushStep(state, &scratch); |
1425 | /* restore normal settings of scratch fields */ |
1426 | scratch.resvalue = resv; |
1427 | scratch.resnull = resnull; |
1428 | } |
1429 | } |
1430 | |
1431 | /* |
1432 | * Prepare to evaluate each of the WHEN clauses in turn; as |
1433 | * soon as one is true we return the value of the |
1434 | * corresponding THEN clause. If none are true then we return |
1435 | * the value of the ELSE clause, or NULL if there is none. |
1436 | */ |
1437 | foreach(lc, caseExpr->args) |
1438 | { |
1439 | CaseWhen *when = (CaseWhen *) lfirst(lc); |
1440 | Datum *save_innermost_caseval; |
1441 | bool *save_innermost_casenull; |
1442 | int whenstep; |
1443 | |
1444 | /* |
1445 | * Make testexpr result available to CaseTestExpr nodes |
1446 | * within the condition. We must save and restore prior |
1447 | * setting of innermost_caseval fields, in case this node |
1448 | * is itself within a larger CASE. |
1449 | * |
1450 | * If there's no test expression, we don't actually need |
1451 | * to save and restore these fields; but it's less code to |
1452 | * just do so unconditionally. |
1453 | */ |
1454 | save_innermost_caseval = state->innermost_caseval; |
1455 | save_innermost_casenull = state->innermost_casenull; |
1456 | state->innermost_caseval = caseval; |
1457 | state->innermost_casenull = casenull; |
1458 | |
1459 | /* evaluate condition into CASE's result variables */ |
1460 | ExecInitExprRec(when->expr, state, resv, resnull); |
1461 | |
1462 | state->innermost_caseval = save_innermost_caseval; |
1463 | state->innermost_casenull = save_innermost_casenull; |
1464 | |
1465 | /* If WHEN result isn't true, jump to next CASE arm */ |
1466 | scratch.opcode = EEOP_JUMP_IF_NOT_TRUE; |
1467 | scratch.d.jump.jumpdone = -1; /* computed later */ |
1468 | ExprEvalPushStep(state, &scratch); |
1469 | whenstep = state->steps_len - 1; |
1470 | |
1471 | /* |
1472 | * If WHEN result is true, evaluate THEN result, storing |
1473 | * it into the CASE's result variables. |
1474 | */ |
1475 | ExecInitExprRec(when->result, state, resv, resnull); |
1476 | |
1477 | /* Emit JUMP step to jump to end of CASE's code */ |
1478 | scratch.opcode = EEOP_JUMP; |
1479 | scratch.d.jump.jumpdone = -1; /* computed later */ |
1480 | ExprEvalPushStep(state, &scratch); |
1481 | |
1482 | /* |
1483 | * Don't know address for that jump yet, compute once the |
1484 | * whole CASE expression is built. |
1485 | */ |
1486 | adjust_jumps = lappend_int(adjust_jumps, |
1487 | state->steps_len - 1); |
1488 | |
1489 | /* |
1490 | * But we can set WHEN test's jump target now, to make it |
1491 | * jump to the next WHEN subexpression or the ELSE. |
1492 | */ |
1493 | state->steps[whenstep].d.jump.jumpdone = state->steps_len; |
1494 | } |
1495 | |
1496 | /* transformCaseExpr always adds a default */ |
1497 | Assert(caseExpr->defresult); |
1498 | |
1499 | /* evaluate ELSE expr into CASE's result variables */ |
1500 | ExecInitExprRec(caseExpr->defresult, state, |
1501 | resv, resnull); |
1502 | |
1503 | /* adjust jump targets */ |
1504 | foreach(lc, adjust_jumps) |
1505 | { |
1506 | ExprEvalStep *as = &state->steps[lfirst_int(lc)]; |
1507 | |
1508 | Assert(as->opcode == EEOP_JUMP); |
1509 | Assert(as->d.jump.jumpdone == -1); |
1510 | as->d.jump.jumpdone = state->steps_len; |
1511 | } |
1512 | |
1513 | break; |
1514 | } |
1515 | |
1516 | case T_CaseTestExpr: |
1517 | { |
1518 | /* |
1519 | * Read from location identified by innermost_caseval. Note |
1520 | * that innermost_caseval could be NULL, if this node isn't |
1521 | * actually within a CaseExpr, ArrayCoerceExpr, etc structure. |
1522 | * That can happen because some parts of the system abuse |
1523 | * CaseTestExpr to cause a read of a value externally supplied |
1524 | * in econtext->caseValue_datum. We'll take care of that |
1525 | * scenario at runtime. |
1526 | */ |
1527 | scratch.opcode = EEOP_CASE_TESTVAL; |
1528 | scratch.d.casetest.value = state->innermost_caseval; |
1529 | scratch.d.casetest.isnull = state->innermost_casenull; |
1530 | |
1531 | ExprEvalPushStep(state, &scratch); |
1532 | break; |
1533 | } |
1534 | |
1535 | case T_ArrayExpr: |
1536 | { |
1537 | ArrayExpr *arrayexpr = (ArrayExpr *) node; |
1538 | int nelems = list_length(arrayexpr->elements); |
1539 | ListCell *lc; |
1540 | int elemoff; |
1541 | |
1542 | /* |
1543 | * Evaluate by computing each element, and then forming the |
1544 | * array. Elements are computed into scratch arrays |
1545 | * associated with the ARRAYEXPR step. |
1546 | */ |
1547 | scratch.opcode = EEOP_ARRAYEXPR; |
1548 | scratch.d.arrayexpr.elemvalues = |
1549 | (Datum *) palloc(sizeof(Datum) * nelems); |
1550 | scratch.d.arrayexpr.elemnulls = |
1551 | (bool *) palloc(sizeof(bool) * nelems); |
1552 | scratch.d.arrayexpr.nelems = nelems; |
1553 | |
1554 | /* fill remaining fields of step */ |
1555 | scratch.d.arrayexpr.multidims = arrayexpr->multidims; |
1556 | scratch.d.arrayexpr.elemtype = arrayexpr->element_typeid; |
1557 | |
1558 | /* do one-time catalog lookup for type info */ |
1559 | get_typlenbyvalalign(arrayexpr->element_typeid, |
1560 | &scratch.d.arrayexpr.elemlength, |
1561 | &scratch.d.arrayexpr.elembyval, |
1562 | &scratch.d.arrayexpr.elemalign); |
1563 | |
1564 | /* prepare to evaluate all arguments */ |
1565 | elemoff = 0; |
1566 | foreach(lc, arrayexpr->elements) |
1567 | { |
1568 | Expr *e = (Expr *) lfirst(lc); |
1569 | |
1570 | ExecInitExprRec(e, state, |
1571 | &scratch.d.arrayexpr.elemvalues[elemoff], |
1572 | &scratch.d.arrayexpr.elemnulls[elemoff]); |
1573 | elemoff++; |
1574 | } |
1575 | |
1576 | /* and then collect all into an array */ |
1577 | ExprEvalPushStep(state, &scratch); |
1578 | break; |
1579 | } |
1580 | |
1581 | case T_RowExpr: |
1582 | { |
1583 | RowExpr *rowexpr = (RowExpr *) node; |
1584 | int nelems = list_length(rowexpr->args); |
1585 | TupleDesc tupdesc; |
1586 | int i; |
1587 | ListCell *l; |
1588 | |
1589 | /* Build tupdesc to describe result tuples */ |
1590 | if (rowexpr->row_typeid == RECORDOID) |
1591 | { |
1592 | /* generic record, use types of given expressions */ |
1593 | tupdesc = ExecTypeFromExprList(rowexpr->args); |
1594 | } |
1595 | else |
1596 | { |
1597 | /* it's been cast to a named type, use that */ |
1598 | tupdesc = lookup_rowtype_tupdesc_copy(rowexpr->row_typeid, -1); |
1599 | } |
1600 | /* In either case, adopt RowExpr's column aliases */ |
1601 | ExecTypeSetColNames(tupdesc, rowexpr->colnames); |
1602 | /* Bless the tupdesc in case it's now of type RECORD */ |
1603 | BlessTupleDesc(tupdesc); |
1604 | |
1605 | /* |
1606 | * In the named-type case, the tupdesc could have more columns |
1607 | * than are in the args list, since the type might have had |
1608 | * columns added since the ROW() was parsed. We want those |
1609 | * extra columns to go to nulls, so we make sure that the |
1610 | * workspace arrays are large enough and then initialize any |
1611 | * extra columns to read as NULLs. |
1612 | */ |
1613 | Assert(nelems <= tupdesc->natts); |
1614 | nelems = Max(nelems, tupdesc->natts); |
1615 | |
1616 | /* |
1617 | * Evaluate by first building datums for each field, and then |
1618 | * a final step forming the composite datum. |
1619 | */ |
1620 | scratch.opcode = EEOP_ROW; |
1621 | scratch.d.row.tupdesc = tupdesc; |
1622 | |
1623 | /* space for the individual field datums */ |
1624 | scratch.d.row.elemvalues = |
1625 | (Datum *) palloc(sizeof(Datum) * nelems); |
1626 | scratch.d.row.elemnulls = |
1627 | (bool *) palloc(sizeof(bool) * nelems); |
1628 | /* as explained above, make sure any extra columns are null */ |
1629 | memset(scratch.d.row.elemnulls, true, sizeof(bool) * nelems); |
1630 | |
1631 | /* Set up evaluation, skipping any deleted columns */ |
1632 | i = 0; |
1633 | foreach(l, rowexpr->args) |
1634 | { |
1635 | Form_pg_attribute att = TupleDescAttr(tupdesc, i); |
1636 | Expr *e = (Expr *) lfirst(l); |
1637 | |
1638 | if (!att->attisdropped) |
1639 | { |
1640 | /* |
1641 | * Guard against ALTER COLUMN TYPE on rowtype since |
1642 | * the RowExpr was created. XXX should we check |
1643 | * typmod too? Not sure we can be sure it'll be the |
1644 | * same. |
1645 | */ |
1646 | if (exprType((Node *) e) != att->atttypid) |
1647 | ereport(ERROR, |
1648 | (errcode(ERRCODE_DATATYPE_MISMATCH), |
1649 | errmsg("ROW() column has type %s instead of type %s" , |
1650 | format_type_be(exprType((Node *) e)), |
1651 | format_type_be(att->atttypid)))); |
1652 | } |
1653 | else |
1654 | { |
1655 | /* |
1656 | * Ignore original expression and insert a NULL. We |
1657 | * don't really care what type of NULL it is, so |
1658 | * always make an int4 NULL. |
1659 | */ |
1660 | e = (Expr *) makeNullConst(INT4OID, -1, InvalidOid); |
1661 | } |
1662 | |
1663 | /* Evaluate column expr into appropriate workspace slot */ |
1664 | ExecInitExprRec(e, state, |
1665 | &scratch.d.row.elemvalues[i], |
1666 | &scratch.d.row.elemnulls[i]); |
1667 | i++; |
1668 | } |
1669 | |
1670 | /* And finally build the row value */ |
1671 | ExprEvalPushStep(state, &scratch); |
1672 | break; |
1673 | } |
1674 | |
1675 | case T_RowCompareExpr: |
1676 | { |
1677 | RowCompareExpr *rcexpr = (RowCompareExpr *) node; |
1678 | int nopers = list_length(rcexpr->opnos); |
1679 | List *adjust_jumps = NIL; |
1680 | ListCell *l_left_expr, |
1681 | *l_right_expr, |
1682 | *l_opno, |
1683 | *l_opfamily, |
1684 | *l_inputcollid; |
1685 | ListCell *lc; |
1686 | |
1687 | /* |
1688 | * Iterate over each field, prepare comparisons. To handle |
1689 | * NULL results, prepare jumps to after the expression. If a |
1690 | * comparison yields a != 0 result, jump to the final step. |
1691 | */ |
1692 | Assert(list_length(rcexpr->largs) == nopers); |
1693 | Assert(list_length(rcexpr->rargs) == nopers); |
1694 | Assert(list_length(rcexpr->opfamilies) == nopers); |
1695 | Assert(list_length(rcexpr->inputcollids) == nopers); |
1696 | |
1697 | forfive(l_left_expr, rcexpr->largs, |
1698 | l_right_expr, rcexpr->rargs, |
1699 | l_opno, rcexpr->opnos, |
1700 | l_opfamily, rcexpr->opfamilies, |
1701 | l_inputcollid, rcexpr->inputcollids) |
1702 | { |
1703 | Expr *left_expr = (Expr *) lfirst(l_left_expr); |
1704 | Expr *right_expr = (Expr *) lfirst(l_right_expr); |
1705 | Oid opno = lfirst_oid(l_opno); |
1706 | Oid opfamily = lfirst_oid(l_opfamily); |
1707 | Oid inputcollid = lfirst_oid(l_inputcollid); |
1708 | int strategy; |
1709 | Oid lefttype; |
1710 | Oid righttype; |
1711 | Oid proc; |
1712 | FmgrInfo *finfo; |
1713 | FunctionCallInfo fcinfo; |
1714 | |
1715 | get_op_opfamily_properties(opno, opfamily, false, |
1716 | &strategy, |
1717 | &lefttype, |
1718 | &righttype); |
1719 | proc = get_opfamily_proc(opfamily, |
1720 | lefttype, |
1721 | righttype, |
1722 | BTORDER_PROC); |
1723 | if (!OidIsValid(proc)) |
1724 | elog(ERROR, "missing support function %d(%u,%u) in opfamily %u" , |
1725 | BTORDER_PROC, lefttype, righttype, opfamily); |
1726 | |
1727 | /* Set up the primary fmgr lookup information */ |
1728 | finfo = palloc0(sizeof(FmgrInfo)); |
1729 | fcinfo = palloc0(SizeForFunctionCallInfo(2)); |
1730 | fmgr_info(proc, finfo); |
1731 | fmgr_info_set_expr((Node *) node, finfo); |
1732 | InitFunctionCallInfoData(*fcinfo, finfo, 2, |
1733 | inputcollid, NULL, NULL); |
1734 | |
1735 | /* |
1736 | * If we enforced permissions checks on index support |
1737 | * functions, we'd need to make a check here. But the |
1738 | * index support machinery doesn't do that, and thus |
1739 | * neither does this code. |
1740 | */ |
1741 | |
1742 | /* evaluate left and right args directly into fcinfo */ |
1743 | ExecInitExprRec(left_expr, state, |
1744 | &fcinfo->args[0].value, &fcinfo->args[0].isnull); |
1745 | ExecInitExprRec(right_expr, state, |
1746 | &fcinfo->args[1].value, &fcinfo->args[1].isnull); |
1747 | |
1748 | scratch.opcode = EEOP_ROWCOMPARE_STEP; |
1749 | scratch.d.rowcompare_step.finfo = finfo; |
1750 | scratch.d.rowcompare_step.fcinfo_data = fcinfo; |
1751 | scratch.d.rowcompare_step.fn_addr = finfo->fn_addr; |
1752 | /* jump targets filled below */ |
1753 | scratch.d.rowcompare_step.jumpnull = -1; |
1754 | scratch.d.rowcompare_step.jumpdone = -1; |
1755 | |
1756 | ExprEvalPushStep(state, &scratch); |
1757 | adjust_jumps = lappend_int(adjust_jumps, |
1758 | state->steps_len - 1); |
1759 | } |
1760 | |
1761 | /* |
1762 | * We could have a zero-column rowtype, in which case the rows |
1763 | * necessarily compare equal. |
1764 | */ |
1765 | if (nopers == 0) |
1766 | { |
1767 | scratch.opcode = EEOP_CONST; |
1768 | scratch.d.constval.value = Int32GetDatum(0); |
1769 | scratch.d.constval.isnull = false; |
1770 | ExprEvalPushStep(state, &scratch); |
1771 | } |
1772 | |
1773 | /* Finally, examine the last comparison result */ |
1774 | scratch.opcode = EEOP_ROWCOMPARE_FINAL; |
1775 | scratch.d.rowcompare_final.rctype = rcexpr->rctype; |
1776 | ExprEvalPushStep(state, &scratch); |
1777 | |
1778 | /* adjust jump targetss */ |
1779 | foreach(lc, adjust_jumps) |
1780 | { |
1781 | ExprEvalStep *as = &state->steps[lfirst_int(lc)]; |
1782 | |
1783 | Assert(as->opcode == EEOP_ROWCOMPARE_STEP); |
1784 | Assert(as->d.rowcompare_step.jumpdone == -1); |
1785 | Assert(as->d.rowcompare_step.jumpnull == -1); |
1786 | |
1787 | /* jump to comparison evaluation */ |
1788 | as->d.rowcompare_step.jumpdone = state->steps_len - 1; |
1789 | /* jump to the following expression */ |
1790 | as->d.rowcompare_step.jumpnull = state->steps_len; |
1791 | } |
1792 | |
1793 | break; |
1794 | } |
1795 | |
1796 | case T_CoalesceExpr: |
1797 | { |
1798 | CoalesceExpr *coalesce = (CoalesceExpr *) node; |
1799 | List *adjust_jumps = NIL; |
1800 | ListCell *lc; |
1801 | |
1802 | /* We assume there's at least one arg */ |
1803 | Assert(coalesce->args != NIL); |
1804 | |
1805 | /* |
1806 | * Prepare evaluation of all coalesced arguments, after each |
1807 | * one push a step that short-circuits if not null. |
1808 | */ |
1809 | foreach(lc, coalesce->args) |
1810 | { |
1811 | Expr *e = (Expr *) lfirst(lc); |
1812 | |
1813 | /* evaluate argument, directly into result datum */ |
1814 | ExecInitExprRec(e, state, resv, resnull); |
1815 | |
1816 | /* if it's not null, skip to end of COALESCE expr */ |
1817 | scratch.opcode = EEOP_JUMP_IF_NOT_NULL; |
1818 | scratch.d.jump.jumpdone = -1; /* adjust later */ |
1819 | ExprEvalPushStep(state, &scratch); |
1820 | |
1821 | adjust_jumps = lappend_int(adjust_jumps, |
1822 | state->steps_len - 1); |
1823 | } |
1824 | |
1825 | /* |
1826 | * No need to add a constant NULL return - we only can get to |
1827 | * the end of the expression if a NULL already is being |
1828 | * returned. |
1829 | */ |
1830 | |
1831 | /* adjust jump targets */ |
1832 | foreach(lc, adjust_jumps) |
1833 | { |
1834 | ExprEvalStep *as = &state->steps[lfirst_int(lc)]; |
1835 | |
1836 | Assert(as->opcode == EEOP_JUMP_IF_NOT_NULL); |
1837 | Assert(as->d.jump.jumpdone == -1); |
1838 | as->d.jump.jumpdone = state->steps_len; |
1839 | } |
1840 | |
1841 | break; |
1842 | } |
1843 | |
1844 | case T_MinMaxExpr: |
1845 | { |
1846 | MinMaxExpr *minmaxexpr = (MinMaxExpr *) node; |
1847 | int nelems = list_length(minmaxexpr->args); |
1848 | TypeCacheEntry *typentry; |
1849 | FmgrInfo *finfo; |
1850 | FunctionCallInfo fcinfo; |
1851 | ListCell *lc; |
1852 | int off; |
1853 | |
1854 | /* Look up the btree comparison function for the datatype */ |
1855 | typentry = lookup_type_cache(minmaxexpr->minmaxtype, |
1856 | TYPECACHE_CMP_PROC); |
1857 | if (!OidIsValid(typentry->cmp_proc)) |
1858 | ereport(ERROR, |
1859 | (errcode(ERRCODE_UNDEFINED_FUNCTION), |
1860 | errmsg("could not identify a comparison function for type %s" , |
1861 | format_type_be(minmaxexpr->minmaxtype)))); |
1862 | |
1863 | /* |
1864 | * If we enforced permissions checks on index support |
1865 | * functions, we'd need to make a check here. But the index |
1866 | * support machinery doesn't do that, and thus neither does |
1867 | * this code. |
1868 | */ |
1869 | |
1870 | /* Perform function lookup */ |
1871 | finfo = palloc0(sizeof(FmgrInfo)); |
1872 | fcinfo = palloc0(SizeForFunctionCallInfo(2)); |
1873 | fmgr_info(typentry->cmp_proc, finfo); |
1874 | fmgr_info_set_expr((Node *) node, finfo); |
1875 | InitFunctionCallInfoData(*fcinfo, finfo, 2, |
1876 | minmaxexpr->inputcollid, NULL, NULL); |
1877 | |
1878 | scratch.opcode = EEOP_MINMAX; |
1879 | /* allocate space to store arguments */ |
1880 | scratch.d.minmax.values = |
1881 | (Datum *) palloc(sizeof(Datum) * nelems); |
1882 | scratch.d.minmax.nulls = |
1883 | (bool *) palloc(sizeof(bool) * nelems); |
1884 | scratch.d.minmax.nelems = nelems; |
1885 | |
1886 | scratch.d.minmax.op = minmaxexpr->op; |
1887 | scratch.d.minmax.finfo = finfo; |
1888 | scratch.d.minmax.fcinfo_data = fcinfo; |
1889 | |
1890 | /* evaluate expressions into minmax->values/nulls */ |
1891 | off = 0; |
1892 | foreach(lc, minmaxexpr->args) |
1893 | { |
1894 | Expr *e = (Expr *) lfirst(lc); |
1895 | |
1896 | ExecInitExprRec(e, state, |
1897 | &scratch.d.minmax.values[off], |
1898 | &scratch.d.minmax.nulls[off]); |
1899 | off++; |
1900 | } |
1901 | |
1902 | /* and push the final comparison */ |
1903 | ExprEvalPushStep(state, &scratch); |
1904 | break; |
1905 | } |
1906 | |
1907 | case T_SQLValueFunction: |
1908 | { |
1909 | SQLValueFunction *svf = (SQLValueFunction *) node; |
1910 | |
1911 | scratch.opcode = EEOP_SQLVALUEFUNCTION; |
1912 | scratch.d.sqlvaluefunction.svf = svf; |
1913 | |
1914 | ExprEvalPushStep(state, &scratch); |
1915 | break; |
1916 | } |
1917 | |
1918 | case T_XmlExpr: |
1919 | { |
1920 | XmlExpr *xexpr = (XmlExpr *) node; |
1921 | int nnamed = list_length(xexpr->named_args); |
1922 | int nargs = list_length(xexpr->args); |
1923 | int off; |
1924 | ListCell *arg; |
1925 | |
1926 | scratch.opcode = EEOP_XMLEXPR; |
1927 | scratch.d.xmlexpr.xexpr = xexpr; |
1928 | |
1929 | /* allocate space for storing all the arguments */ |
1930 | if (nnamed) |
1931 | { |
1932 | scratch.d.xmlexpr.named_argvalue = |
1933 | (Datum *) palloc(sizeof(Datum) * nnamed); |
1934 | scratch.d.xmlexpr.named_argnull = |
1935 | (bool *) palloc(sizeof(bool) * nnamed); |
1936 | } |
1937 | else |
1938 | { |
1939 | scratch.d.xmlexpr.named_argvalue = NULL; |
1940 | scratch.d.xmlexpr.named_argnull = NULL; |
1941 | } |
1942 | |
1943 | if (nargs) |
1944 | { |
1945 | scratch.d.xmlexpr.argvalue = |
1946 | (Datum *) palloc(sizeof(Datum) * nargs); |
1947 | scratch.d.xmlexpr.argnull = |
1948 | (bool *) palloc(sizeof(bool) * nargs); |
1949 | } |
1950 | else |
1951 | { |
1952 | scratch.d.xmlexpr.argvalue = NULL; |
1953 | scratch.d.xmlexpr.argnull = NULL; |
1954 | } |
1955 | |
1956 | /* prepare argument execution */ |
1957 | off = 0; |
1958 | foreach(arg, xexpr->named_args) |
1959 | { |
1960 | Expr *e = (Expr *) lfirst(arg); |
1961 | |
1962 | ExecInitExprRec(e, state, |
1963 | &scratch.d.xmlexpr.named_argvalue[off], |
1964 | &scratch.d.xmlexpr.named_argnull[off]); |
1965 | off++; |
1966 | } |
1967 | |
1968 | off = 0; |
1969 | foreach(arg, xexpr->args) |
1970 | { |
1971 | Expr *e = (Expr *) lfirst(arg); |
1972 | |
1973 | ExecInitExprRec(e, state, |
1974 | &scratch.d.xmlexpr.argvalue[off], |
1975 | &scratch.d.xmlexpr.argnull[off]); |
1976 | off++; |
1977 | } |
1978 | |
1979 | /* and evaluate the actual XML expression */ |
1980 | ExprEvalPushStep(state, &scratch); |
1981 | break; |
1982 | } |
1983 | |
1984 | case T_NullTest: |
1985 | { |
1986 | NullTest *ntest = (NullTest *) node; |
1987 | |
1988 | if (ntest->nulltesttype == IS_NULL) |
1989 | { |
1990 | if (ntest->argisrow) |
1991 | scratch.opcode = EEOP_NULLTEST_ROWISNULL; |
1992 | else |
1993 | scratch.opcode = EEOP_NULLTEST_ISNULL; |
1994 | } |
1995 | else if (ntest->nulltesttype == IS_NOT_NULL) |
1996 | { |
1997 | if (ntest->argisrow) |
1998 | scratch.opcode = EEOP_NULLTEST_ROWISNOTNULL; |
1999 | else |
2000 | scratch.opcode = EEOP_NULLTEST_ISNOTNULL; |
2001 | } |
2002 | else |
2003 | { |
2004 | elog(ERROR, "unrecognized nulltesttype: %d" , |
2005 | (int) ntest->nulltesttype); |
2006 | } |
2007 | /* initialize cache in case it's a row test */ |
2008 | scratch.d.nulltest_row.argdesc = NULL; |
2009 | |
2010 | /* first evaluate argument into result variable */ |
2011 | ExecInitExprRec(ntest->arg, state, |
2012 | resv, resnull); |
2013 | |
2014 | /* then push the test of that argument */ |
2015 | ExprEvalPushStep(state, &scratch); |
2016 | break; |
2017 | } |
2018 | |
2019 | case T_BooleanTest: |
2020 | { |
2021 | BooleanTest *btest = (BooleanTest *) node; |
2022 | |
2023 | /* |
2024 | * Evaluate argument, directly into result datum. That's ok, |
2025 | * because resv/resnull is definitely not used anywhere else, |
2026 | * and will get overwritten by the below EEOP_BOOLTEST_IS_* |
2027 | * step. |
2028 | */ |
2029 | ExecInitExprRec(btest->arg, state, resv, resnull); |
2030 | |
2031 | switch (btest->booltesttype) |
2032 | { |
2033 | case IS_TRUE: |
2034 | scratch.opcode = EEOP_BOOLTEST_IS_TRUE; |
2035 | break; |
2036 | case IS_NOT_TRUE: |
2037 | scratch.opcode = EEOP_BOOLTEST_IS_NOT_TRUE; |
2038 | break; |
2039 | case IS_FALSE: |
2040 | scratch.opcode = EEOP_BOOLTEST_IS_FALSE; |
2041 | break; |
2042 | case IS_NOT_FALSE: |
2043 | scratch.opcode = EEOP_BOOLTEST_IS_NOT_FALSE; |
2044 | break; |
2045 | case IS_UNKNOWN: |
2046 | /* Same as scalar IS NULL test */ |
2047 | scratch.opcode = EEOP_NULLTEST_ISNULL; |
2048 | break; |
2049 | case IS_NOT_UNKNOWN: |
2050 | /* Same as scalar IS NOT NULL test */ |
2051 | scratch.opcode = EEOP_NULLTEST_ISNOTNULL; |
2052 | break; |
2053 | default: |
2054 | elog(ERROR, "unrecognized booltesttype: %d" , |
2055 | (int) btest->booltesttype); |
2056 | } |
2057 | |
2058 | ExprEvalPushStep(state, &scratch); |
2059 | break; |
2060 | } |
2061 | |
2062 | case T_CoerceToDomain: |
2063 | { |
2064 | CoerceToDomain *ctest = (CoerceToDomain *) node; |
2065 | |
2066 | ExecInitCoerceToDomain(&scratch, ctest, state, |
2067 | resv, resnull); |
2068 | break; |
2069 | } |
2070 | |
2071 | case T_CoerceToDomainValue: |
2072 | { |
2073 | /* |
2074 | * Read from location identified by innermost_domainval. Note |
2075 | * that innermost_domainval could be NULL, if we're compiling |
2076 | * a standalone domain check rather than one embedded in a |
2077 | * larger expression. In that case we must read from |
2078 | * econtext->domainValue_datum. We'll take care of that |
2079 | * scenario at runtime. |
2080 | */ |
2081 | scratch.opcode = EEOP_DOMAIN_TESTVAL; |
2082 | /* we share instruction union variant with case testval */ |
2083 | scratch.d.casetest.value = state->innermost_domainval; |
2084 | scratch.d.casetest.isnull = state->innermost_domainnull; |
2085 | |
2086 | ExprEvalPushStep(state, &scratch); |
2087 | break; |
2088 | } |
2089 | |
2090 | case T_CurrentOfExpr: |
2091 | { |
2092 | scratch.opcode = EEOP_CURRENTOFEXPR; |
2093 | ExprEvalPushStep(state, &scratch); |
2094 | break; |
2095 | } |
2096 | |
2097 | case T_NextValueExpr: |
2098 | { |
2099 | NextValueExpr *nve = (NextValueExpr *) node; |
2100 | |
2101 | scratch.opcode = EEOP_NEXTVALUEEXPR; |
2102 | scratch.d.nextvalueexpr.seqid = nve->seqid; |
2103 | scratch.d.nextvalueexpr.seqtypid = nve->typeId; |
2104 | |
2105 | ExprEvalPushStep(state, &scratch); |
2106 | break; |
2107 | } |
2108 | |
2109 | default: |
2110 | elog(ERROR, "unrecognized node type: %d" , |
2111 | (int) nodeTag(node)); |
2112 | break; |
2113 | } |
2114 | } |
2115 | |
2116 | /* |
2117 | * Add another expression evaluation step to ExprState->steps. |
2118 | * |
2119 | * Note that this potentially re-allocates es->steps, therefore no pointer |
2120 | * into that array may be used while the expression is still being built. |
2121 | */ |
2122 | void |
2123 | ExprEvalPushStep(ExprState *es, const ExprEvalStep *s) |
2124 | { |
2125 | if (es->steps_alloc == 0) |
2126 | { |
2127 | es->steps_alloc = 16; |
2128 | es->steps = palloc(sizeof(ExprEvalStep) * es->steps_alloc); |
2129 | } |
2130 | else if (es->steps_alloc == es->steps_len) |
2131 | { |
2132 | es->steps_alloc *= 2; |
2133 | es->steps = repalloc(es->steps, |
2134 | sizeof(ExprEvalStep) * es->steps_alloc); |
2135 | } |
2136 | |
2137 | memcpy(&es->steps[es->steps_len++], s, sizeof(ExprEvalStep)); |
2138 | } |
2139 | |
2140 | /* |
2141 | * Perform setup necessary for the evaluation of a function-like expression, |
2142 | * appending argument evaluation steps to the steps list in *state, and |
2143 | * setting up *scratch so it is ready to be pushed. |
2144 | * |
2145 | * *scratch is not pushed here, so that callers may override the opcode, |
2146 | * which is useful for function-like cases like DISTINCT. |
2147 | */ |
2148 | static void |
2149 | ExecInitFunc(ExprEvalStep *scratch, Expr *node, List *args, Oid funcid, |
2150 | Oid inputcollid, ExprState *state) |
2151 | { |
2152 | int nargs = list_length(args); |
2153 | AclResult aclresult; |
2154 | FmgrInfo *flinfo; |
2155 | FunctionCallInfo fcinfo; |
2156 | int argno; |
2157 | ListCell *lc; |
2158 | |
2159 | /* Check permission to call function */ |
2160 | aclresult = pg_proc_aclcheck(funcid, GetUserId(), ACL_EXECUTE); |
2161 | if (aclresult != ACLCHECK_OK) |
2162 | aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(funcid)); |
2163 | InvokeFunctionExecuteHook(funcid); |
2164 | |
2165 | /* |
2166 | * Safety check on nargs. Under normal circumstances this should never |
2167 | * fail, as parser should check sooner. But possibly it might fail if |
2168 | * server has been compiled with FUNC_MAX_ARGS smaller than some functions |
2169 | * declared in pg_proc? |
2170 | */ |
2171 | if (nargs > FUNC_MAX_ARGS) |
2172 | ereport(ERROR, |
2173 | (errcode(ERRCODE_TOO_MANY_ARGUMENTS), |
2174 | errmsg_plural("cannot pass more than %d argument to a function" , |
2175 | "cannot pass more than %d arguments to a function" , |
2176 | FUNC_MAX_ARGS, |
2177 | FUNC_MAX_ARGS))); |
2178 | |
2179 | /* Allocate function lookup data and parameter workspace for this call */ |
2180 | scratch->d.func.finfo = palloc0(sizeof(FmgrInfo)); |
2181 | scratch->d.func.fcinfo_data = palloc0(SizeForFunctionCallInfo(nargs)); |
2182 | flinfo = scratch->d.func.finfo; |
2183 | fcinfo = scratch->d.func.fcinfo_data; |
2184 | |
2185 | /* Set up the primary fmgr lookup information */ |
2186 | fmgr_info(funcid, flinfo); |
2187 | fmgr_info_set_expr((Node *) node, flinfo); |
2188 | |
2189 | /* Initialize function call parameter structure too */ |
2190 | InitFunctionCallInfoData(*fcinfo, flinfo, |
2191 | nargs, inputcollid, NULL, NULL); |
2192 | |
2193 | /* Keep extra copies of this info to save an indirection at runtime */ |
2194 | scratch->d.func.fn_addr = flinfo->fn_addr; |
2195 | scratch->d.func.nargs = nargs; |
2196 | |
2197 | /* We only support non-set functions here */ |
2198 | if (flinfo->fn_retset) |
2199 | ereport(ERROR, |
2200 | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
2201 | errmsg("set-valued function called in context that cannot accept a set" ), |
2202 | state->parent ? |
2203 | executor_errposition(state->parent->state, |
2204 | exprLocation((Node *) node)) : 0)); |
2205 | |
2206 | /* Build code to evaluate arguments directly into the fcinfo struct */ |
2207 | argno = 0; |
2208 | foreach(lc, args) |
2209 | { |
2210 | Expr *arg = (Expr *) lfirst(lc); |
2211 | |
2212 | if (IsA(arg, Const)) |
2213 | { |
2214 | /* |
2215 | * Don't evaluate const arguments every round; especially |
2216 | * interesting for constants in comparisons. |
2217 | */ |
2218 | Const *con = (Const *) arg; |
2219 | |
2220 | fcinfo->args[argno].value = con->constvalue; |
2221 | fcinfo->args[argno].isnull = con->constisnull; |
2222 | } |
2223 | else |
2224 | { |
2225 | ExecInitExprRec(arg, state, |
2226 | &fcinfo->args[argno].value, |
2227 | &fcinfo->args[argno].isnull); |
2228 | } |
2229 | argno++; |
2230 | } |
2231 | |
2232 | /* Insert appropriate opcode depending on strictness and stats level */ |
2233 | if (pgstat_track_functions <= flinfo->fn_stats) |
2234 | { |
2235 | if (flinfo->fn_strict && nargs > 0) |
2236 | scratch->opcode = EEOP_FUNCEXPR_STRICT; |
2237 | else |
2238 | scratch->opcode = EEOP_FUNCEXPR; |
2239 | } |
2240 | else |
2241 | { |
2242 | if (flinfo->fn_strict && nargs > 0) |
2243 | scratch->opcode = EEOP_FUNCEXPR_STRICT_FUSAGE; |
2244 | else |
2245 | scratch->opcode = EEOP_FUNCEXPR_FUSAGE; |
2246 | } |
2247 | } |
2248 | |
2249 | /* |
2250 | * Add expression steps deforming the ExprState's inner/outer/scan slots |
2251 | * as much as required by the expression. |
2252 | */ |
2253 | static void |
2254 | ExecInitExprSlots(ExprState *state, Node *node) |
2255 | { |
2256 | LastAttnumInfo info = {0, 0, 0}; |
2257 | |
2258 | /* |
2259 | * Figure out which attributes we're going to need. |
2260 | */ |
2261 | get_last_attnums_walker(node, &info); |
2262 | |
2263 | ExecPushExprSlots(state, &info); |
2264 | } |
2265 | |
2266 | /* |
2267 | * Add steps deforming the ExprState's inner/out/scan slots as much as |
2268 | * indicated by info. This is useful when building an ExprState covering more |
2269 | * than one expression. |
2270 | */ |
2271 | static void |
2272 | ExecPushExprSlots(ExprState *state, LastAttnumInfo *info) |
2273 | { |
2274 | ExprEvalStep scratch = {0}; |
2275 | |
2276 | scratch.resvalue = NULL; |
2277 | scratch.resnull = NULL; |
2278 | |
2279 | /* Emit steps as needed */ |
2280 | if (info->last_inner > 0) |
2281 | { |
2282 | scratch.opcode = EEOP_INNER_FETCHSOME; |
2283 | scratch.d.fetch.last_var = info->last_inner; |
2284 | scratch.d.fetch.fixed = false; |
2285 | scratch.d.fetch.kind = NULL; |
2286 | scratch.d.fetch.known_desc = NULL; |
2287 | ExecComputeSlotInfo(state, &scratch); |
2288 | ExprEvalPushStep(state, &scratch); |
2289 | } |
2290 | if (info->last_outer > 0) |
2291 | { |
2292 | scratch.opcode = EEOP_OUTER_FETCHSOME; |
2293 | scratch.d.fetch.last_var = info->last_outer; |
2294 | scratch.d.fetch.fixed = false; |
2295 | scratch.d.fetch.kind = NULL; |
2296 | scratch.d.fetch.known_desc = NULL; |
2297 | ExecComputeSlotInfo(state, &scratch); |
2298 | ExprEvalPushStep(state, &scratch); |
2299 | } |
2300 | if (info->last_scan > 0) |
2301 | { |
2302 | scratch.opcode = EEOP_SCAN_FETCHSOME; |
2303 | scratch.d.fetch.last_var = info->last_scan; |
2304 | scratch.d.fetch.fixed = false; |
2305 | scratch.d.fetch.kind = NULL; |
2306 | scratch.d.fetch.known_desc = NULL; |
2307 | ExecComputeSlotInfo(state, &scratch); |
2308 | ExprEvalPushStep(state, &scratch); |
2309 | } |
2310 | } |
2311 | |
2312 | /* |
2313 | * get_last_attnums_walker: expression walker for ExecInitExprSlots |
2314 | */ |
2315 | static bool |
2316 | get_last_attnums_walker(Node *node, LastAttnumInfo *info) |
2317 | { |
2318 | if (node == NULL) |
2319 | return false; |
2320 | if (IsA(node, Var)) |
2321 | { |
2322 | Var *variable = (Var *) node; |
2323 | AttrNumber attnum = variable->varattno; |
2324 | |
2325 | switch (variable->varno) |
2326 | { |
2327 | case INNER_VAR: |
2328 | info->last_inner = Max(info->last_inner, attnum); |
2329 | break; |
2330 | |
2331 | case OUTER_VAR: |
2332 | info->last_outer = Max(info->last_outer, attnum); |
2333 | break; |
2334 | |
2335 | /* INDEX_VAR is handled by default case */ |
2336 | |
2337 | default: |
2338 | info->last_scan = Max(info->last_scan, attnum); |
2339 | break; |
2340 | } |
2341 | return false; |
2342 | } |
2343 | |
2344 | /* |
2345 | * Don't examine the arguments or filters of Aggrefs or WindowFuncs, |
2346 | * because those do not represent expressions to be evaluated within the |
2347 | * calling expression's econtext. GroupingFunc arguments are never |
2348 | * evaluated at all. |
2349 | */ |
2350 | if (IsA(node, Aggref)) |
2351 | return false; |
2352 | if (IsA(node, WindowFunc)) |
2353 | return false; |
2354 | if (IsA(node, GroupingFunc)) |
2355 | return false; |
2356 | return expression_tree_walker(node, get_last_attnums_walker, |
2357 | (void *) info); |
2358 | } |
2359 | |
2360 | /* |
2361 | * Compute additional information for EEOP_*_FETCHSOME ops. |
2362 | * |
2363 | * The goal is to determine whether a slot is 'fixed', that is, every |
2364 | * evaluation of the expression will have the same type of slot, with an |
2365 | * equivalent descriptor. |
2366 | */ |
2367 | static void |
2368 | ExecComputeSlotInfo(ExprState *state, ExprEvalStep *op) |
2369 | { |
2370 | PlanState *parent = state->parent; |
2371 | TupleDesc desc = NULL; |
2372 | const TupleTableSlotOps *tts_ops = NULL; |
2373 | bool isfixed = false; |
2374 | |
2375 | if (op->d.fetch.known_desc != NULL) |
2376 | { |
2377 | desc = op->d.fetch.known_desc; |
2378 | tts_ops = op->d.fetch.kind; |
2379 | isfixed = op->d.fetch.kind != NULL; |
2380 | } |
2381 | else if (!parent) |
2382 | { |
2383 | isfixed = false; |
2384 | } |
2385 | else if (op->opcode == EEOP_INNER_FETCHSOME) |
2386 | { |
2387 | PlanState *is = innerPlanState(parent); |
2388 | |
2389 | if (parent->inneropsset && !parent->inneropsfixed) |
2390 | { |
2391 | isfixed = false; |
2392 | } |
2393 | else if (parent->inneropsset && parent->innerops) |
2394 | { |
2395 | isfixed = true; |
2396 | tts_ops = parent->innerops; |
2397 | desc = ExecGetResultType(is); |
2398 | } |
2399 | else if (is) |
2400 | { |
2401 | tts_ops = ExecGetResultSlotOps(is, &isfixed); |
2402 | desc = ExecGetResultType(is); |
2403 | } |
2404 | } |
2405 | else if (op->opcode == EEOP_OUTER_FETCHSOME) |
2406 | { |
2407 | PlanState *os = outerPlanState(parent); |
2408 | |
2409 | if (parent->outeropsset && !parent->outeropsfixed) |
2410 | { |
2411 | isfixed = false; |
2412 | } |
2413 | else if (parent->outeropsset && parent->outerops) |
2414 | { |
2415 | isfixed = true; |
2416 | tts_ops = parent->outerops; |
2417 | desc = ExecGetResultType(os); |
2418 | } |
2419 | else if (os) |
2420 | { |
2421 | tts_ops = ExecGetResultSlotOps(os, &isfixed); |
2422 | desc = ExecGetResultType(os); |
2423 | } |
2424 | } |
2425 | else if (op->opcode == EEOP_SCAN_FETCHSOME) |
2426 | { |
2427 | desc = parent->scandesc; |
2428 | |
2429 | if (parent && parent->scanops) |
2430 | tts_ops = parent->scanops; |
2431 | |
2432 | if (parent->scanopsset) |
2433 | isfixed = parent->scanopsfixed; |
2434 | } |
2435 | |
2436 | if (isfixed && desc != NULL && tts_ops != NULL) |
2437 | { |
2438 | op->d.fetch.fixed = true; |
2439 | op->d.fetch.kind = tts_ops; |
2440 | op->d.fetch.known_desc = desc; |
2441 | } |
2442 | else |
2443 | { |
2444 | op->d.fetch.fixed = false; |
2445 | op->d.fetch.kind = NULL; |
2446 | op->d.fetch.known_desc = NULL; |
2447 | } |
2448 | } |
2449 | |
2450 | /* |
2451 | * Prepare step for the evaluation of a whole-row variable. |
2452 | * The caller still has to push the step. |
2453 | */ |
2454 | static void |
2455 | ExecInitWholeRowVar(ExprEvalStep *scratch, Var *variable, ExprState *state) |
2456 | { |
2457 | PlanState *parent = state->parent; |
2458 | |
2459 | /* fill in all but the target */ |
2460 | scratch->opcode = EEOP_WHOLEROW; |
2461 | scratch->d.wholerow.var = variable; |
2462 | scratch->d.wholerow.first = true; |
2463 | scratch->d.wholerow.slow = false; |
2464 | scratch->d.wholerow.tupdesc = NULL; /* filled at runtime */ |
2465 | scratch->d.wholerow.junkFilter = NULL; |
2466 | |
2467 | /* |
2468 | * If the input tuple came from a subquery, it might contain "resjunk" |
2469 | * columns (such as GROUP BY or ORDER BY columns), which we don't want to |
2470 | * keep in the whole-row result. We can get rid of such columns by |
2471 | * passing the tuple through a JunkFilter --- but to make one, we have to |
2472 | * lay our hands on the subquery's targetlist. Fortunately, there are not |
2473 | * very many cases where this can happen, and we can identify all of them |
2474 | * by examining our parent PlanState. We assume this is not an issue in |
2475 | * standalone expressions that don't have parent plans. (Whole-row Vars |
2476 | * can occur in such expressions, but they will always be referencing |
2477 | * table rows.) |
2478 | */ |
2479 | if (parent) |
2480 | { |
2481 | PlanState *subplan = NULL; |
2482 | |
2483 | switch (nodeTag(parent)) |
2484 | { |
2485 | case T_SubqueryScanState: |
2486 | subplan = ((SubqueryScanState *) parent)->subplan; |
2487 | break; |
2488 | case T_CteScanState: |
2489 | subplan = ((CteScanState *) parent)->cteplanstate; |
2490 | break; |
2491 | default: |
2492 | break; |
2493 | } |
2494 | |
2495 | if (subplan) |
2496 | { |
2497 | bool junk_filter_needed = false; |
2498 | ListCell *tlist; |
2499 | |
2500 | /* Detect whether subplan tlist actually has any junk columns */ |
2501 | foreach(tlist, subplan->plan->targetlist) |
2502 | { |
2503 | TargetEntry *tle = (TargetEntry *) lfirst(tlist); |
2504 | |
2505 | if (tle->resjunk) |
2506 | { |
2507 | junk_filter_needed = true; |
2508 | break; |
2509 | } |
2510 | } |
2511 | |
2512 | /* If so, build the junkfilter now */ |
2513 | if (junk_filter_needed) |
2514 | { |
2515 | scratch->d.wholerow.junkFilter = |
2516 | ExecInitJunkFilter(subplan->plan->targetlist, |
2517 | ExecInitExtraTupleSlot(parent->state, NULL, |
2518 | &TTSOpsVirtual)); |
2519 | } |
2520 | } |
2521 | } |
2522 | } |
2523 | |
2524 | /* |
2525 | * Prepare evaluation of a SubscriptingRef expression. |
2526 | */ |
2527 | static void |
2528 | ExecInitSubscriptingRef(ExprEvalStep *scratch, SubscriptingRef *sbsref, |
2529 | ExprState *state, Datum *resv, bool *resnull) |
2530 | { |
2531 | bool isAssignment = (sbsref->refassgnexpr != NULL); |
2532 | SubscriptingRefState *sbsrefstate = palloc0(sizeof(SubscriptingRefState)); |
2533 | List *adjust_jumps = NIL; |
2534 | ListCell *lc; |
2535 | int i; |
2536 | |
2537 | /* Fill constant fields of SubscriptingRefState */ |
2538 | sbsrefstate->isassignment = isAssignment; |
2539 | sbsrefstate->refelemtype = sbsref->refelemtype; |
2540 | sbsrefstate->refattrlength = get_typlen(sbsref->refcontainertype); |
2541 | get_typlenbyvalalign(sbsref->refelemtype, |
2542 | &sbsrefstate->refelemlength, |
2543 | &sbsrefstate->refelembyval, |
2544 | &sbsrefstate->refelemalign); |
2545 | |
2546 | /* |
2547 | * Evaluate array input. It's safe to do so into resv/resnull, because we |
2548 | * won't use that as target for any of the other subexpressions, and it'll |
2549 | * be overwritten by the final EEOP_SBSREF_FETCH/ASSIGN step, which is |
2550 | * pushed last. |
2551 | */ |
2552 | ExecInitExprRec(sbsref->refexpr, state, resv, resnull); |
2553 | |
2554 | /* |
2555 | * If refexpr yields NULL, and it's a fetch, then result is NULL. We can |
2556 | * implement this with just JUMP_IF_NULL, since we evaluated the array |
2557 | * into the desired target location. |
2558 | */ |
2559 | if (!isAssignment) |
2560 | { |
2561 | scratch->opcode = EEOP_JUMP_IF_NULL; |
2562 | scratch->d.jump.jumpdone = -1; /* adjust later */ |
2563 | ExprEvalPushStep(state, scratch); |
2564 | adjust_jumps = lappend_int(adjust_jumps, |
2565 | state->steps_len - 1); |
2566 | } |
2567 | |
2568 | /* Verify subscript list lengths are within limit */ |
2569 | if (list_length(sbsref->refupperindexpr) > MAXDIM) |
2570 | ereport(ERROR, |
2571 | (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), |
2572 | errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)" , |
2573 | list_length(sbsref->refupperindexpr), MAXDIM))); |
2574 | |
2575 | if (list_length(sbsref->reflowerindexpr) > MAXDIM) |
2576 | ereport(ERROR, |
2577 | (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), |
2578 | errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)" , |
2579 | list_length(sbsref->reflowerindexpr), MAXDIM))); |
2580 | |
2581 | /* Evaluate upper subscripts */ |
2582 | i = 0; |
2583 | foreach(lc, sbsref->refupperindexpr) |
2584 | { |
2585 | Expr *e = (Expr *) lfirst(lc); |
2586 | |
2587 | /* When slicing, individual subscript bounds can be omitted */ |
2588 | if (!e) |
2589 | { |
2590 | sbsrefstate->upperprovided[i] = false; |
2591 | i++; |
2592 | continue; |
2593 | } |
2594 | |
2595 | sbsrefstate->upperprovided[i] = true; |
2596 | |
2597 | /* Each subscript is evaluated into subscriptvalue/subscriptnull */ |
2598 | ExecInitExprRec(e, state, |
2599 | &sbsrefstate->subscriptvalue, &sbsrefstate->subscriptnull); |
2600 | |
2601 | /* ... and then SBSREF_SUBSCRIPT saves it into step's workspace */ |
2602 | scratch->opcode = EEOP_SBSREF_SUBSCRIPT; |
2603 | scratch->d.sbsref_subscript.state = sbsrefstate; |
2604 | scratch->d.sbsref_subscript.off = i; |
2605 | scratch->d.sbsref_subscript.isupper = true; |
2606 | scratch->d.sbsref_subscript.jumpdone = -1; /* adjust later */ |
2607 | ExprEvalPushStep(state, scratch); |
2608 | adjust_jumps = lappend_int(adjust_jumps, |
2609 | state->steps_len - 1); |
2610 | i++; |
2611 | } |
2612 | sbsrefstate->numupper = i; |
2613 | |
2614 | /* Evaluate lower subscripts similarly */ |
2615 | i = 0; |
2616 | foreach(lc, sbsref->reflowerindexpr) |
2617 | { |
2618 | Expr *e = (Expr *) lfirst(lc); |
2619 | |
2620 | /* When slicing, individual subscript bounds can be omitted */ |
2621 | if (!e) |
2622 | { |
2623 | sbsrefstate->lowerprovided[i] = false; |
2624 | i++; |
2625 | continue; |
2626 | } |
2627 | |
2628 | sbsrefstate->lowerprovided[i] = true; |
2629 | |
2630 | /* Each subscript is evaluated into subscriptvalue/subscriptnull */ |
2631 | ExecInitExprRec(e, state, |
2632 | &sbsrefstate->subscriptvalue, &sbsrefstate->subscriptnull); |
2633 | |
2634 | /* ... and then SBSREF_SUBSCRIPT saves it into step's workspace */ |
2635 | scratch->opcode = EEOP_SBSREF_SUBSCRIPT; |
2636 | scratch->d.sbsref_subscript.state = sbsrefstate; |
2637 | scratch->d.sbsref_subscript.off = i; |
2638 | scratch->d.sbsref_subscript.isupper = false; |
2639 | scratch->d.sbsref_subscript.jumpdone = -1; /* adjust later */ |
2640 | ExprEvalPushStep(state, scratch); |
2641 | adjust_jumps = lappend_int(adjust_jumps, |
2642 | state->steps_len - 1); |
2643 | i++; |
2644 | } |
2645 | sbsrefstate->numlower = i; |
2646 | |
2647 | /* Should be impossible if parser is sane, but check anyway: */ |
2648 | if (sbsrefstate->numlower != 0 && |
2649 | sbsrefstate->numupper != sbsrefstate->numlower) |
2650 | elog(ERROR, "upper and lower index lists are not same length" ); |
2651 | |
2652 | if (isAssignment) |
2653 | { |
2654 | Datum *save_innermost_caseval; |
2655 | bool *save_innermost_casenull; |
2656 | |
2657 | /* |
2658 | * We might have a nested-assignment situation, in which the |
2659 | * refassgnexpr is itself a FieldStore or SubscriptingRef that needs |
2660 | * to obtain and modify the previous value of the array element or |
2661 | * slice being replaced. If so, we have to extract that value from |
2662 | * the array and pass it down via the CaseTestExpr mechanism. It's |
2663 | * safe to reuse the CASE mechanism because there cannot be a CASE |
2664 | * between here and where the value would be needed, and an array |
2665 | * assignment can't be within a CASE either. (So saving and restoring |
2666 | * innermost_caseval is just paranoia, but let's do it anyway.) |
2667 | * |
2668 | * Since fetching the old element might be a nontrivial expense, do it |
2669 | * only if the argument actually needs it. |
2670 | */ |
2671 | if (isAssignmentIndirectionExpr(sbsref->refassgnexpr)) |
2672 | { |
2673 | scratch->opcode = EEOP_SBSREF_OLD; |
2674 | scratch->d.sbsref.state = sbsrefstate; |
2675 | ExprEvalPushStep(state, scratch); |
2676 | } |
2677 | |
2678 | /* SBSREF_OLD puts extracted value into prevvalue/prevnull */ |
2679 | save_innermost_caseval = state->innermost_caseval; |
2680 | save_innermost_casenull = state->innermost_casenull; |
2681 | state->innermost_caseval = &sbsrefstate->prevvalue; |
2682 | state->innermost_casenull = &sbsrefstate->prevnull; |
2683 | |
2684 | /* evaluate replacement value into replacevalue/replacenull */ |
2685 | ExecInitExprRec(sbsref->refassgnexpr, state, |
2686 | &sbsrefstate->replacevalue, &sbsrefstate->replacenull); |
2687 | |
2688 | state->innermost_caseval = save_innermost_caseval; |
2689 | state->innermost_casenull = save_innermost_casenull; |
2690 | |
2691 | /* and perform the assignment */ |
2692 | scratch->opcode = EEOP_SBSREF_ASSIGN; |
2693 | scratch->d.sbsref.state = sbsrefstate; |
2694 | ExprEvalPushStep(state, scratch); |
2695 | |
2696 | } |
2697 | else |
2698 | { |
2699 | /* array fetch is much simpler */ |
2700 | scratch->opcode = EEOP_SBSREF_FETCH; |
2701 | scratch->d.sbsref.state = sbsrefstate; |
2702 | ExprEvalPushStep(state, scratch); |
2703 | |
2704 | } |
2705 | |
2706 | /* adjust jump targets */ |
2707 | foreach(lc, adjust_jumps) |
2708 | { |
2709 | ExprEvalStep *as = &state->steps[lfirst_int(lc)]; |
2710 | |
2711 | if (as->opcode == EEOP_SBSREF_SUBSCRIPT) |
2712 | { |
2713 | Assert(as->d.sbsref_subscript.jumpdone == -1); |
2714 | as->d.sbsref_subscript.jumpdone = state->steps_len; |
2715 | } |
2716 | else |
2717 | { |
2718 | Assert(as->opcode == EEOP_JUMP_IF_NULL); |
2719 | Assert(as->d.jump.jumpdone == -1); |
2720 | as->d.jump.jumpdone = state->steps_len; |
2721 | } |
2722 | } |
2723 | } |
2724 | |
2725 | /* |
2726 | * Helper for preparing SubscriptingRef expressions for evaluation: is expr |
2727 | * a nested FieldStore or SubscriptingRef that needs the old element value |
2728 | * passed down? |
2729 | * |
2730 | * (We could use this in FieldStore too, but in that case passing the old |
2731 | * value is so cheap there's no need.) |
2732 | * |
2733 | * Note: it might seem that this needs to recurse, but it does not; the |
2734 | * CaseTestExpr, if any, will be directly the arg or refexpr of the top-level |
2735 | * node. Nested-assignment situations give rise to expression trees in which |
2736 | * each level of assignment has its own CaseTestExpr, and the recursive |
2737 | * structure appears within the newvals or refassgnexpr field. |
2738 | */ |
2739 | static bool |
2740 | isAssignmentIndirectionExpr(Expr *expr) |
2741 | { |
2742 | if (expr == NULL) |
2743 | return false; /* just paranoia */ |
2744 | if (IsA(expr, FieldStore)) |
2745 | { |
2746 | FieldStore *fstore = (FieldStore *) expr; |
2747 | |
2748 | if (fstore->arg && IsA(fstore->arg, CaseTestExpr)) |
2749 | return true; |
2750 | } |
2751 | else if (IsA(expr, SubscriptingRef)) |
2752 | { |
2753 | SubscriptingRef *sbsRef = (SubscriptingRef *) expr; |
2754 | |
2755 | if (sbsRef->refexpr && IsA(sbsRef->refexpr, CaseTestExpr)) |
2756 | return true; |
2757 | } |
2758 | return false; |
2759 | } |
2760 | |
2761 | /* |
2762 | * Prepare evaluation of a CoerceToDomain expression. |
2763 | */ |
2764 | static void |
2765 | ExecInitCoerceToDomain(ExprEvalStep *scratch, CoerceToDomain *ctest, |
2766 | ExprState *state, Datum *resv, bool *resnull) |
2767 | { |
2768 | ExprEvalStep scratch2 = {0}; |
2769 | DomainConstraintRef *constraint_ref; |
2770 | Datum *domainval = NULL; |
2771 | bool *domainnull = NULL; |
2772 | Datum *save_innermost_domainval; |
2773 | bool *save_innermost_domainnull; |
2774 | ListCell *l; |
2775 | |
2776 | scratch->d.domaincheck.resulttype = ctest->resulttype; |
2777 | /* we'll allocate workspace only if needed */ |
2778 | scratch->d.domaincheck.checkvalue = NULL; |
2779 | scratch->d.domaincheck.checknull = NULL; |
2780 | |
2781 | /* |
2782 | * Evaluate argument - it's fine to directly store it into resv/resnull, |
2783 | * if there's constraint failures there'll be errors, otherwise it's what |
2784 | * needs to be returned. |
2785 | */ |
2786 | ExecInitExprRec(ctest->arg, state, resv, resnull); |
2787 | |
2788 | /* |
2789 | * Note: if the argument is of varlena type, it could be a R/W expanded |
2790 | * object. We want to return the R/W pointer as the final result, but we |
2791 | * have to pass a R/O pointer as the value to be tested by any functions |
2792 | * in check expressions. We don't bother to emit a MAKE_READONLY step |
2793 | * unless there's actually at least one check expression, though. Until |
2794 | * we've tested that, domainval/domainnull are NULL. |
2795 | */ |
2796 | |
2797 | /* |
2798 | * Collect the constraints associated with the domain. |
2799 | * |
2800 | * Note: before PG v10 we'd recheck the set of constraints during each |
2801 | * evaluation of the expression. Now we bake them into the ExprState |
2802 | * during executor initialization. That means we don't need typcache.c to |
2803 | * provide compiled exprs. |
2804 | */ |
2805 | constraint_ref = (DomainConstraintRef *) |
2806 | palloc(sizeof(DomainConstraintRef)); |
2807 | InitDomainConstraintRef(ctest->resulttype, |
2808 | constraint_ref, |
2809 | CurrentMemoryContext, |
2810 | false); |
2811 | |
2812 | /* |
2813 | * Compile code to check each domain constraint. NOTNULL constraints can |
2814 | * just be applied on the resv/resnull value, but for CHECK constraints we |
2815 | * need more pushups. |
2816 | */ |
2817 | foreach(l, constraint_ref->constraints) |
2818 | { |
2819 | DomainConstraintState *con = (DomainConstraintState *) lfirst(l); |
2820 | |
2821 | scratch->d.domaincheck.constraintname = con->name; |
2822 | |
2823 | switch (con->constrainttype) |
2824 | { |
2825 | case DOM_CONSTRAINT_NOTNULL: |
2826 | scratch->opcode = EEOP_DOMAIN_NOTNULL; |
2827 | ExprEvalPushStep(state, scratch); |
2828 | break; |
2829 | case DOM_CONSTRAINT_CHECK: |
2830 | /* Allocate workspace for CHECK output if we didn't yet */ |
2831 | if (scratch->d.domaincheck.checkvalue == NULL) |
2832 | { |
2833 | scratch->d.domaincheck.checkvalue = |
2834 | (Datum *) palloc(sizeof(Datum)); |
2835 | scratch->d.domaincheck.checknull = |
2836 | (bool *) palloc(sizeof(bool)); |
2837 | } |
2838 | |
2839 | /* |
2840 | * If first time through, determine where CoerceToDomainValue |
2841 | * nodes should read from. |
2842 | */ |
2843 | if (domainval == NULL) |
2844 | { |
2845 | /* |
2846 | * Since value might be read multiple times, force to R/O |
2847 | * - but only if it could be an expanded datum. |
2848 | */ |
2849 | if (get_typlen(ctest->resulttype) == -1) |
2850 | { |
2851 | /* Yes, so make output workspace for MAKE_READONLY */ |
2852 | domainval = (Datum *) palloc(sizeof(Datum)); |
2853 | domainnull = (bool *) palloc(sizeof(bool)); |
2854 | |
2855 | /* Emit MAKE_READONLY */ |
2856 | scratch2.opcode = EEOP_MAKE_READONLY; |
2857 | scratch2.resvalue = domainval; |
2858 | scratch2.resnull = domainnull; |
2859 | scratch2.d.make_readonly.value = resv; |
2860 | scratch2.d.make_readonly.isnull = resnull; |
2861 | ExprEvalPushStep(state, &scratch2); |
2862 | } |
2863 | else |
2864 | { |
2865 | /* No, so it's fine to read from resv/resnull */ |
2866 | domainval = resv; |
2867 | domainnull = resnull; |
2868 | } |
2869 | } |
2870 | |
2871 | /* |
2872 | * Set up value to be returned by CoerceToDomainValue nodes. |
2873 | * We must save and restore innermost_domainval/null fields, |
2874 | * in case this node is itself within a check expression for |
2875 | * another domain. |
2876 | */ |
2877 | save_innermost_domainval = state->innermost_domainval; |
2878 | save_innermost_domainnull = state->innermost_domainnull; |
2879 | state->innermost_domainval = domainval; |
2880 | state->innermost_domainnull = domainnull; |
2881 | |
2882 | /* evaluate check expression value */ |
2883 | ExecInitExprRec(con->check_expr, state, |
2884 | scratch->d.domaincheck.checkvalue, |
2885 | scratch->d.domaincheck.checknull); |
2886 | |
2887 | state->innermost_domainval = save_innermost_domainval; |
2888 | state->innermost_domainnull = save_innermost_domainnull; |
2889 | |
2890 | /* now test result */ |
2891 | scratch->opcode = EEOP_DOMAIN_CHECK; |
2892 | ExprEvalPushStep(state, scratch); |
2893 | |
2894 | break; |
2895 | default: |
2896 | elog(ERROR, "unrecognized constraint type: %d" , |
2897 | (int) con->constrainttype); |
2898 | break; |
2899 | } |
2900 | } |
2901 | } |
2902 | |
2903 | /* |
2904 | * Build transition/combine function invocations for all aggregate transition |
2905 | * / combination function invocations in a grouping sets phase. This has to |
2906 | * invoke all sort based transitions in a phase (if doSort is true), all hash |
2907 | * based transitions (if doHash is true), or both (both true). |
2908 | * |
2909 | * The resulting expression will, for each set of transition values, first |
2910 | * check for filters, evaluate aggregate input, check that that input is not |
2911 | * NULL for a strict transition function, and then finally invoke the |
2912 | * transition for each of the concurrently computed grouping sets. |
2913 | */ |
2914 | ExprState * |
2915 | ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase, |
2916 | bool doSort, bool doHash) |
2917 | { |
2918 | ExprState *state = makeNode(ExprState); |
2919 | PlanState *parent = &aggstate->ss.ps; |
2920 | ExprEvalStep scratch = {0}; |
2921 | int transno = 0; |
2922 | int setoff = 0; |
2923 | bool isCombine = DO_AGGSPLIT_COMBINE(aggstate->aggsplit); |
2924 | LastAttnumInfo deform = {0, 0, 0}; |
2925 | |
2926 | state->expr = (Expr *) aggstate; |
2927 | state->parent = parent; |
2928 | |
2929 | scratch.resvalue = &state->resvalue; |
2930 | scratch.resnull = &state->resnull; |
2931 | |
2932 | /* |
2933 | * First figure out which slots, and how many columns from each, we're |
2934 | * going to need. |
2935 | */ |
2936 | for (transno = 0; transno < aggstate->numtrans; transno++) |
2937 | { |
2938 | AggStatePerTrans pertrans = &aggstate->pertrans[transno]; |
2939 | |
2940 | get_last_attnums_walker((Node *) pertrans->aggref->aggdirectargs, |
2941 | &deform); |
2942 | get_last_attnums_walker((Node *) pertrans->aggref->args, |
2943 | &deform); |
2944 | get_last_attnums_walker((Node *) pertrans->aggref->aggorder, |
2945 | &deform); |
2946 | get_last_attnums_walker((Node *) pertrans->aggref->aggdistinct, |
2947 | &deform); |
2948 | get_last_attnums_walker((Node *) pertrans->aggref->aggfilter, |
2949 | &deform); |
2950 | } |
2951 | ExecPushExprSlots(state, &deform); |
2952 | |
2953 | /* |
2954 | * Emit instructions for each transition value / grouping set combination. |
2955 | */ |
2956 | for (transno = 0; transno < aggstate->numtrans; transno++) |
2957 | { |
2958 | AggStatePerTrans pertrans = &aggstate->pertrans[transno]; |
2959 | int argno; |
2960 | int setno; |
2961 | FunctionCallInfo trans_fcinfo = pertrans->transfn_fcinfo; |
2962 | ListCell *arg; |
2963 | ListCell *bail; |
2964 | List *adjust_bailout = NIL; |
2965 | NullableDatum *strictargs = NULL; |
2966 | bool *strictnulls = NULL; |
2967 | |
2968 | /* |
2969 | * If filter present, emit. Do so before evaluating the input, to |
2970 | * avoid potentially unneeded computations, or even worse, unintended |
2971 | * side-effects. When combining, all the necessary filtering has |
2972 | * already been done. |
2973 | */ |
2974 | if (pertrans->aggref->aggfilter && !isCombine) |
2975 | { |
2976 | /* evaluate filter expression */ |
2977 | ExecInitExprRec(pertrans->aggref->aggfilter, state, |
2978 | &state->resvalue, &state->resnull); |
2979 | /* and jump out if false */ |
2980 | scratch.opcode = EEOP_JUMP_IF_NOT_TRUE; |
2981 | scratch.d.jump.jumpdone = -1; /* adjust later */ |
2982 | ExprEvalPushStep(state, &scratch); |
2983 | adjust_bailout = lappend_int(adjust_bailout, |
2984 | state->steps_len - 1); |
2985 | } |
2986 | |
2987 | /* |
2988 | * Evaluate arguments to aggregate/combine function. |
2989 | */ |
2990 | argno = 0; |
2991 | if (isCombine) |
2992 | { |
2993 | /* |
2994 | * Combining two aggregate transition values. Instead of directly |
2995 | * coming from a tuple the input is a, potentially deserialized, |
2996 | * transition value. |
2997 | */ |
2998 | TargetEntry *source_tle; |
2999 | |
3000 | Assert(pertrans->numSortCols == 0); |
3001 | Assert(list_length(pertrans->aggref->args) == 1); |
3002 | |
3003 | strictargs = trans_fcinfo->args + 1; |
3004 | source_tle = (TargetEntry *) linitial(pertrans->aggref->args); |
3005 | |
3006 | /* |
3007 | * deserialfn_oid will be set if we must deserialize the input |
3008 | * state before calling the combine function. |
3009 | */ |
3010 | if (!OidIsValid(pertrans->deserialfn_oid)) |
3011 | { |
3012 | /* |
3013 | * Start from 1, since the 0th arg will be the transition |
3014 | * value |
3015 | */ |
3016 | ExecInitExprRec(source_tle->expr, state, |
3017 | &trans_fcinfo->args[argno + 1].value, |
3018 | &trans_fcinfo->args[argno + 1].isnull); |
3019 | } |
3020 | else |
3021 | { |
3022 | FunctionCallInfo ds_fcinfo = pertrans->deserialfn_fcinfo; |
3023 | |
3024 | /* evaluate argument */ |
3025 | ExecInitExprRec(source_tle->expr, state, |
3026 | &ds_fcinfo->args[0].value, |
3027 | &ds_fcinfo->args[0].isnull); |
3028 | |
3029 | /* Dummy second argument for type-safety reasons */ |
3030 | ds_fcinfo->args[1].value = PointerGetDatum(NULL); |
3031 | ds_fcinfo->args[1].isnull = false; |
3032 | |
3033 | /* |
3034 | * Don't call a strict deserialization function with NULL |
3035 | * input |
3036 | */ |
3037 | if (pertrans->deserialfn.fn_strict) |
3038 | scratch.opcode = EEOP_AGG_STRICT_DESERIALIZE; |
3039 | else |
3040 | scratch.opcode = EEOP_AGG_DESERIALIZE; |
3041 | |
3042 | scratch.d.agg_deserialize.aggstate = aggstate; |
3043 | scratch.d.agg_deserialize.fcinfo_data = ds_fcinfo; |
3044 | scratch.d.agg_deserialize.jumpnull = -1; /* adjust later */ |
3045 | scratch.resvalue = &trans_fcinfo->args[argno + 1].value; |
3046 | scratch.resnull = &trans_fcinfo->args[argno + 1].isnull; |
3047 | |
3048 | ExprEvalPushStep(state, &scratch); |
3049 | adjust_bailout = lappend_int(adjust_bailout, |
3050 | state->steps_len - 1); |
3051 | |
3052 | /* restore normal settings of scratch fields */ |
3053 | scratch.resvalue = &state->resvalue; |
3054 | scratch.resnull = &state->resnull; |
3055 | } |
3056 | argno++; |
3057 | } |
3058 | else if (pertrans->numSortCols == 0) |
3059 | { |
3060 | /* |
3061 | * Normal transition function without ORDER BY / DISTINCT. |
3062 | */ |
3063 | strictargs = trans_fcinfo->args + 1; |
3064 | |
3065 | foreach(arg, pertrans->aggref->args) |
3066 | { |
3067 | TargetEntry *source_tle = (TargetEntry *) lfirst(arg); |
3068 | |
3069 | /* |
3070 | * Start from 1, since the 0th arg will be the transition |
3071 | * value |
3072 | */ |
3073 | ExecInitExprRec(source_tle->expr, state, |
3074 | &trans_fcinfo->args[argno + 1].value, |
3075 | &trans_fcinfo->args[argno + 1].isnull); |
3076 | argno++; |
3077 | } |
3078 | } |
3079 | else if (pertrans->numInputs == 1) |
3080 | { |
3081 | /* |
3082 | * DISTINCT and/or ORDER BY case, with a single column sorted on. |
3083 | */ |
3084 | TargetEntry *source_tle = |
3085 | (TargetEntry *) linitial(pertrans->aggref->args); |
3086 | |
3087 | Assert(list_length(pertrans->aggref->args) == 1); |
3088 | |
3089 | ExecInitExprRec(source_tle->expr, state, |
3090 | &state->resvalue, |
3091 | &state->resnull); |
3092 | strictnulls = &state->resnull; |
3093 | argno++; |
3094 | } |
3095 | else |
3096 | { |
3097 | /* |
3098 | * DISTINCT and/or ORDER BY case, with multiple columns sorted on. |
3099 | */ |
3100 | Datum *values = pertrans->sortslot->tts_values; |
3101 | bool *nulls = pertrans->sortslot->tts_isnull; |
3102 | |
3103 | strictnulls = nulls; |
3104 | |
3105 | foreach(arg, pertrans->aggref->args) |
3106 | { |
3107 | TargetEntry *source_tle = (TargetEntry *) lfirst(arg); |
3108 | |
3109 | ExecInitExprRec(source_tle->expr, state, |
3110 | &values[argno], &nulls[argno]); |
3111 | argno++; |
3112 | } |
3113 | } |
3114 | Assert(pertrans->numInputs == argno); |
3115 | |
3116 | /* |
3117 | * For a strict transfn, nothing happens when there's a NULL input; we |
3118 | * just keep the prior transValue. This is true for both plain and |
3119 | * sorted/distinct aggregates. |
3120 | */ |
3121 | if (trans_fcinfo->flinfo->fn_strict && pertrans->numTransInputs > 0) |
3122 | { |
3123 | if (strictnulls) |
3124 | scratch.opcode = EEOP_AGG_STRICT_INPUT_CHECK_NULLS; |
3125 | else |
3126 | scratch.opcode = EEOP_AGG_STRICT_INPUT_CHECK_ARGS; |
3127 | scratch.d.agg_strict_input_check.nulls = strictnulls; |
3128 | scratch.d.agg_strict_input_check.args = strictargs; |
3129 | scratch.d.agg_strict_input_check.jumpnull = -1; /* adjust later */ |
3130 | scratch.d.agg_strict_input_check.nargs = pertrans->numTransInputs; |
3131 | ExprEvalPushStep(state, &scratch); |
3132 | adjust_bailout = lappend_int(adjust_bailout, |
3133 | state->steps_len - 1); |
3134 | } |
3135 | |
3136 | /* |
3137 | * Call transition function (once for each concurrently evaluated |
3138 | * grouping set). Do so for both sort and hash based computations, as |
3139 | * applicable. |
3140 | */ |
3141 | setoff = 0; |
3142 | if (doSort) |
3143 | { |
3144 | int processGroupingSets = Max(phase->numsets, 1); |
3145 | |
3146 | for (setno = 0; setno < processGroupingSets; setno++) |
3147 | { |
3148 | ExecBuildAggTransCall(state, aggstate, &scratch, trans_fcinfo, |
3149 | pertrans, transno, setno, setoff, false); |
3150 | setoff++; |
3151 | } |
3152 | } |
3153 | |
3154 | if (doHash) |
3155 | { |
3156 | int numHashes = aggstate->num_hashes; |
3157 | |
3158 | /* in MIXED mode, there'll be preceding transition values */ |
3159 | if (aggstate->aggstrategy != AGG_HASHED) |
3160 | setoff = aggstate->maxsets; |
3161 | else |
3162 | setoff = 0; |
3163 | |
3164 | for (setno = 0; setno < numHashes; setno++) |
3165 | { |
3166 | ExecBuildAggTransCall(state, aggstate, &scratch, trans_fcinfo, |
3167 | pertrans, transno, setno, setoff, true); |
3168 | setoff++; |
3169 | } |
3170 | } |
3171 | |
3172 | /* adjust early bail out jump target(s) */ |
3173 | foreach(bail, adjust_bailout) |
3174 | { |
3175 | ExprEvalStep *as = &state->steps[lfirst_int(bail)]; |
3176 | |
3177 | if (as->opcode == EEOP_JUMP_IF_NOT_TRUE) |
3178 | { |
3179 | Assert(as->d.jump.jumpdone == -1); |
3180 | as->d.jump.jumpdone = state->steps_len; |
3181 | } |
3182 | else if (as->opcode == EEOP_AGG_STRICT_INPUT_CHECK_ARGS || |
3183 | as->opcode == EEOP_AGG_STRICT_INPUT_CHECK_NULLS) |
3184 | { |
3185 | Assert(as->d.agg_strict_input_check.jumpnull == -1); |
3186 | as->d.agg_strict_input_check.jumpnull = state->steps_len; |
3187 | } |
3188 | else if (as->opcode == EEOP_AGG_STRICT_DESERIALIZE) |
3189 | { |
3190 | Assert(as->d.agg_deserialize.jumpnull == -1); |
3191 | as->d.agg_deserialize.jumpnull = state->steps_len; |
3192 | } |
3193 | } |
3194 | } |
3195 | |
3196 | scratch.resvalue = NULL; |
3197 | scratch.resnull = NULL; |
3198 | scratch.opcode = EEOP_DONE; |
3199 | ExprEvalPushStep(state, &scratch); |
3200 | |
3201 | ExecReadyExpr(state); |
3202 | |
3203 | return state; |
3204 | } |
3205 | |
3206 | /* |
3207 | * Build transition/combine function invocation for a single transition |
3208 | * value. This is separated from ExecBuildAggTrans() because there are |
3209 | * multiple callsites (hash and sort in some grouping set cases). |
3210 | */ |
3211 | static void |
3212 | ExecBuildAggTransCall(ExprState *state, AggState *aggstate, |
3213 | ExprEvalStep *scratch, |
3214 | FunctionCallInfo fcinfo, AggStatePerTrans pertrans, |
3215 | int transno, int setno, int setoff, bool ishash) |
3216 | { |
3217 | int adjust_init_jumpnull = -1; |
3218 | int adjust_strict_jumpnull = -1; |
3219 | ExprContext *aggcontext; |
3220 | |
3221 | if (ishash) |
3222 | aggcontext = aggstate->hashcontext; |
3223 | else |
3224 | aggcontext = aggstate->aggcontexts[setno]; |
3225 | |
3226 | /* |
3227 | * If the initial value for the transition state doesn't exist in the |
3228 | * pg_aggregate table then we will let the first non-NULL value returned |
3229 | * from the outer procNode become the initial value. (This is useful for |
3230 | * aggregates like max() and min().) The noTransValue flag signals that we |
3231 | * still need to do this. |
3232 | */ |
3233 | if (pertrans->numSortCols == 0 && |
3234 | fcinfo->flinfo->fn_strict && |
3235 | pertrans->initValueIsNull) |
3236 | { |
3237 | scratch->opcode = EEOP_AGG_INIT_TRANS; |
3238 | scratch->d.agg_init_trans.aggstate = aggstate; |
3239 | scratch->d.agg_init_trans.pertrans = pertrans; |
3240 | scratch->d.agg_init_trans.setno = setno; |
3241 | scratch->d.agg_init_trans.setoff = setoff; |
3242 | scratch->d.agg_init_trans.transno = transno; |
3243 | scratch->d.agg_init_trans.aggcontext = aggcontext; |
3244 | scratch->d.agg_init_trans.jumpnull = -1; /* adjust later */ |
3245 | ExprEvalPushStep(state, scratch); |
3246 | |
3247 | /* see comment about jumping out below */ |
3248 | adjust_init_jumpnull = state->steps_len - 1; |
3249 | } |
3250 | |
3251 | if (pertrans->numSortCols == 0 && |
3252 | fcinfo->flinfo->fn_strict) |
3253 | { |
3254 | scratch->opcode = EEOP_AGG_STRICT_TRANS_CHECK; |
3255 | scratch->d.agg_strict_trans_check.aggstate = aggstate; |
3256 | scratch->d.agg_strict_trans_check.setno = setno; |
3257 | scratch->d.agg_strict_trans_check.setoff = setoff; |
3258 | scratch->d.agg_strict_trans_check.transno = transno; |
3259 | scratch->d.agg_strict_trans_check.jumpnull = -1; /* adjust later */ |
3260 | ExprEvalPushStep(state, scratch); |
3261 | |
3262 | /* |
3263 | * Note, we don't push into adjust_bailout here - those jump to the |
3264 | * end of all transition value computations. Here a single transition |
3265 | * value is NULL, so just skip processing the individual value. |
3266 | */ |
3267 | adjust_strict_jumpnull = state->steps_len - 1; |
3268 | } |
3269 | |
3270 | /* invoke appropriate transition implementation */ |
3271 | if (pertrans->numSortCols == 0 && pertrans->transtypeByVal) |
3272 | scratch->opcode = EEOP_AGG_PLAIN_TRANS_BYVAL; |
3273 | else if (pertrans->numSortCols == 0) |
3274 | scratch->opcode = EEOP_AGG_PLAIN_TRANS; |
3275 | else if (pertrans->numInputs == 1) |
3276 | scratch->opcode = EEOP_AGG_ORDERED_TRANS_DATUM; |
3277 | else |
3278 | scratch->opcode = EEOP_AGG_ORDERED_TRANS_TUPLE; |
3279 | |
3280 | scratch->d.agg_trans.aggstate = aggstate; |
3281 | scratch->d.agg_trans.pertrans = pertrans; |
3282 | scratch->d.agg_trans.setno = setno; |
3283 | scratch->d.agg_trans.setoff = setoff; |
3284 | scratch->d.agg_trans.transno = transno; |
3285 | scratch->d.agg_trans.aggcontext = aggcontext; |
3286 | ExprEvalPushStep(state, scratch); |
3287 | |
3288 | /* adjust jumps so they jump till after transition invocation */ |
3289 | if (adjust_init_jumpnull != -1) |
3290 | { |
3291 | ExprEvalStep *as = &state->steps[adjust_init_jumpnull]; |
3292 | |
3293 | Assert(as->d.agg_init_trans.jumpnull == -1); |
3294 | as->d.agg_init_trans.jumpnull = state->steps_len; |
3295 | } |
3296 | if (adjust_strict_jumpnull != -1) |
3297 | { |
3298 | ExprEvalStep *as = &state->steps[adjust_strict_jumpnull]; |
3299 | |
3300 | Assert(as->d.agg_strict_trans_check.jumpnull == -1); |
3301 | as->d.agg_strict_trans_check.jumpnull = state->steps_len; |
3302 | } |
3303 | } |
3304 | |
3305 | /* |
3306 | * Build equality expression that can be evaluated using ExecQual(), returning |
3307 | * true if the expression context's inner/outer tuple are NOT DISTINCT. I.e |
3308 | * two nulls match, a null and a not-null don't match. |
3309 | * |
3310 | * desc: tuple descriptor of the to-be-compared tuples |
3311 | * numCols: the number of attributes to be examined |
3312 | * keyColIdx: array of attribute column numbers |
3313 | * eqFunctions: array of function oids of the equality functions to use |
3314 | * parent: parent executor node |
3315 | */ |
3316 | ExprState * |
3317 | ExecBuildGroupingEqual(TupleDesc ldesc, TupleDesc rdesc, |
3318 | const TupleTableSlotOps *lops, const TupleTableSlotOps *rops, |
3319 | int numCols, |
3320 | const AttrNumber *keyColIdx, |
3321 | const Oid *eqfunctions, |
3322 | const Oid *collations, |
3323 | PlanState *parent) |
3324 | { |
3325 | ExprState *state = makeNode(ExprState); |
3326 | ExprEvalStep scratch = {0}; |
3327 | int natt; |
3328 | int maxatt = -1; |
3329 | List *adjust_jumps = NIL; |
3330 | ListCell *lc; |
3331 | |
3332 | /* |
3333 | * When no columns are actually compared, the result's always true. See |
3334 | * special case in ExecQual(). |
3335 | */ |
3336 | if (numCols == 0) |
3337 | return NULL; |
3338 | |
3339 | state->expr = NULL; |
3340 | state->flags = EEO_FLAG_IS_QUAL; |
3341 | state->parent = parent; |
3342 | |
3343 | scratch.resvalue = &state->resvalue; |
3344 | scratch.resnull = &state->resnull; |
3345 | |
3346 | /* compute max needed attribute */ |
3347 | for (natt = 0; natt < numCols; natt++) |
3348 | { |
3349 | int attno = keyColIdx[natt]; |
3350 | |
3351 | if (attno > maxatt) |
3352 | maxatt = attno; |
3353 | } |
3354 | Assert(maxatt >= 0); |
3355 | |
3356 | /* push deform steps */ |
3357 | scratch.opcode = EEOP_INNER_FETCHSOME; |
3358 | scratch.d.fetch.last_var = maxatt; |
3359 | scratch.d.fetch.fixed = false; |
3360 | scratch.d.fetch.known_desc = ldesc; |
3361 | scratch.d.fetch.kind = lops; |
3362 | ExecComputeSlotInfo(state, &scratch); |
3363 | ExprEvalPushStep(state, &scratch); |
3364 | |
3365 | scratch.opcode = EEOP_OUTER_FETCHSOME; |
3366 | scratch.d.fetch.last_var = maxatt; |
3367 | scratch.d.fetch.fixed = false; |
3368 | scratch.d.fetch.known_desc = rdesc; |
3369 | scratch.d.fetch.kind = rops; |
3370 | ExecComputeSlotInfo(state, &scratch); |
3371 | ExprEvalPushStep(state, &scratch); |
3372 | |
3373 | /* |
3374 | * Start comparing at the last field (least significant sort key). That's |
3375 | * the most likely to be different if we are dealing with sorted input. |
3376 | */ |
3377 | for (natt = numCols; --natt >= 0;) |
3378 | { |
3379 | int attno = keyColIdx[natt]; |
3380 | Form_pg_attribute latt = TupleDescAttr(ldesc, attno - 1); |
3381 | Form_pg_attribute ratt = TupleDescAttr(rdesc, attno - 1); |
3382 | Oid foid = eqfunctions[natt]; |
3383 | Oid collid = collations[natt]; |
3384 | FmgrInfo *finfo; |
3385 | FunctionCallInfo fcinfo; |
3386 | AclResult aclresult; |
3387 | |
3388 | /* Check permission to call function */ |
3389 | aclresult = pg_proc_aclcheck(foid, GetUserId(), ACL_EXECUTE); |
3390 | if (aclresult != ACLCHECK_OK) |
3391 | aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(foid)); |
3392 | |
3393 | InvokeFunctionExecuteHook(foid); |
3394 | |
3395 | /* Set up the primary fmgr lookup information */ |
3396 | finfo = palloc0(sizeof(FmgrInfo)); |
3397 | fcinfo = palloc0(SizeForFunctionCallInfo(2)); |
3398 | fmgr_info(foid, finfo); |
3399 | fmgr_info_set_expr(NULL, finfo); |
3400 | InitFunctionCallInfoData(*fcinfo, finfo, 2, |
3401 | collid, NULL, NULL); |
3402 | |
3403 | /* left arg */ |
3404 | scratch.opcode = EEOP_INNER_VAR; |
3405 | scratch.d.var.attnum = attno - 1; |
3406 | scratch.d.var.vartype = latt->atttypid; |
3407 | scratch.resvalue = &fcinfo->args[0].value; |
3408 | scratch.resnull = &fcinfo->args[0].isnull; |
3409 | ExprEvalPushStep(state, &scratch); |
3410 | |
3411 | /* right arg */ |
3412 | scratch.opcode = EEOP_OUTER_VAR; |
3413 | scratch.d.var.attnum = attno - 1; |
3414 | scratch.d.var.vartype = ratt->atttypid; |
3415 | scratch.resvalue = &fcinfo->args[1].value; |
3416 | scratch.resnull = &fcinfo->args[1].isnull; |
3417 | ExprEvalPushStep(state, &scratch); |
3418 | |
3419 | /* evaluate distinctness */ |
3420 | scratch.opcode = EEOP_NOT_DISTINCT; |
3421 | scratch.d.func.finfo = finfo; |
3422 | scratch.d.func.fcinfo_data = fcinfo; |
3423 | scratch.d.func.fn_addr = finfo->fn_addr; |
3424 | scratch.d.func.nargs = 2; |
3425 | scratch.resvalue = &state->resvalue; |
3426 | scratch.resnull = &state->resnull; |
3427 | ExprEvalPushStep(state, &scratch); |
3428 | |
3429 | /* then emit EEOP_QUAL to detect if result is false (or null) */ |
3430 | scratch.opcode = EEOP_QUAL; |
3431 | scratch.d.qualexpr.jumpdone = -1; |
3432 | scratch.resvalue = &state->resvalue; |
3433 | scratch.resnull = &state->resnull; |
3434 | ExprEvalPushStep(state, &scratch); |
3435 | adjust_jumps = lappend_int(adjust_jumps, |
3436 | state->steps_len - 1); |
3437 | } |
3438 | |
3439 | /* adjust jump targets */ |
3440 | foreach(lc, adjust_jumps) |
3441 | { |
3442 | ExprEvalStep *as = &state->steps[lfirst_int(lc)]; |
3443 | |
3444 | Assert(as->opcode == EEOP_QUAL); |
3445 | Assert(as->d.qualexpr.jumpdone == -1); |
3446 | as->d.qualexpr.jumpdone = state->steps_len; |
3447 | } |
3448 | |
3449 | scratch.resvalue = NULL; |
3450 | scratch.resnull = NULL; |
3451 | scratch.opcode = EEOP_DONE; |
3452 | ExprEvalPushStep(state, &scratch); |
3453 | |
3454 | ExecReadyExpr(state); |
3455 | |
3456 | return state; |
3457 | } |
3458 | |