/src/postgres/src/backend/executor/execExpr.c
Line | Count | Source |
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_{RETURN|NO_RETURN} 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-2025, 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_proc.h" |
36 | | #include "catalog/pg_type.h" |
37 | | #include "executor/execExpr.h" |
38 | | #include "executor/nodeSubplan.h" |
39 | | #include "funcapi.h" |
40 | | #include "jit/jit.h" |
41 | | #include "miscadmin.h" |
42 | | #include "nodes/makefuncs.h" |
43 | | #include "nodes/nodeFuncs.h" |
44 | | #include "nodes/subscripting.h" |
45 | | #include "optimizer/optimizer.h" |
46 | | #include "pgstat.h" |
47 | | #include "utils/acl.h" |
48 | | #include "utils/array.h" |
49 | | #include "utils/builtins.h" |
50 | | #include "utils/jsonfuncs.h" |
51 | | #include "utils/jsonpath.h" |
52 | | #include "utils/lsyscache.h" |
53 | | #include "utils/typcache.h" |
54 | | |
55 | | |
56 | | typedef struct ExprSetupInfo |
57 | | { |
58 | | /* |
59 | | * Highest attribute numbers fetched from inner/outer/scan/old/new tuple |
60 | | * slots: |
61 | | */ |
62 | | AttrNumber last_inner; |
63 | | AttrNumber last_outer; |
64 | | AttrNumber last_scan; |
65 | | AttrNumber last_old; |
66 | | AttrNumber last_new; |
67 | | /* MULTIEXPR SubPlan nodes appearing in the expression: */ |
68 | | List *multiexpr_subplans; |
69 | | } ExprSetupInfo; |
70 | | |
71 | | static void ExecReadyExpr(ExprState *state); |
72 | | static void ExecInitExprRec(Expr *node, ExprState *state, |
73 | | Datum *resv, bool *resnull); |
74 | | static void ExecInitFunc(ExprEvalStep *scratch, Expr *node, List *args, |
75 | | Oid funcid, Oid inputcollid, |
76 | | ExprState *state); |
77 | | static void ExecInitSubPlanExpr(SubPlan *subplan, |
78 | | ExprState *state, |
79 | | Datum *resv, bool *resnull); |
80 | | static void ExecCreateExprSetupSteps(ExprState *state, Node *node); |
81 | | static void ExecPushExprSetupSteps(ExprState *state, ExprSetupInfo *info); |
82 | | static bool expr_setup_walker(Node *node, ExprSetupInfo *info); |
83 | | static bool ExecComputeSlotInfo(ExprState *state, ExprEvalStep *op); |
84 | | static void ExecInitWholeRowVar(ExprEvalStep *scratch, Var *variable, |
85 | | ExprState *state); |
86 | | static void ExecInitSubscriptingRef(ExprEvalStep *scratch, |
87 | | SubscriptingRef *sbsref, |
88 | | ExprState *state, |
89 | | Datum *resv, bool *resnull); |
90 | | static bool isAssignmentIndirectionExpr(Expr *expr); |
91 | | static void ExecInitCoerceToDomain(ExprEvalStep *scratch, CoerceToDomain *ctest, |
92 | | ExprState *state, |
93 | | Datum *resv, bool *resnull); |
94 | | static void ExecBuildAggTransCall(ExprState *state, AggState *aggstate, |
95 | | ExprEvalStep *scratch, |
96 | | FunctionCallInfo fcinfo, AggStatePerTrans pertrans, |
97 | | int transno, int setno, int setoff, bool ishash, |
98 | | bool nullcheck); |
99 | | static void ExecInitJsonExpr(JsonExpr *jsexpr, ExprState *state, |
100 | | Datum *resv, bool *resnull, |
101 | | ExprEvalStep *scratch); |
102 | | static void ExecInitJsonCoercion(ExprState *state, JsonReturning *returning, |
103 | | ErrorSaveContext *escontext, bool omit_quotes, |
104 | | bool exists_coerce, |
105 | | Datum *resv, bool *resnull); |
106 | | |
107 | | |
108 | | /* |
109 | | * ExecInitExpr: prepare an expression tree for execution |
110 | | * |
111 | | * This function builds and returns an ExprState implementing the given |
112 | | * Expr node tree. The return ExprState can then be handed to ExecEvalExpr |
113 | | * for execution. Because the Expr tree itself is read-only as far as |
114 | | * ExecInitExpr and ExecEvalExpr are concerned, several different executions |
115 | | * of the same plan tree can occur concurrently. (But note that an ExprState |
116 | | * does mutate at runtime, so it can't be re-used concurrently.) |
117 | | * |
118 | | * This must be called in a memory context that will last as long as repeated |
119 | | * executions of the expression are needed. Typically the context will be |
120 | | * the same as the per-query context of the associated ExprContext. |
121 | | * |
122 | | * Any Aggref, WindowFunc, or SubPlan nodes found in the tree are added to |
123 | | * the lists of such nodes held by the parent PlanState. |
124 | | * |
125 | | * Note: there is no ExecEndExpr function; we assume that any resource |
126 | | * cleanup needed will be handled by just releasing the memory context |
127 | | * in which the state tree is built. Functions that require additional |
128 | | * cleanup work can register a shutdown callback in the ExprContext. |
129 | | * |
130 | | * 'node' is the root of the expression tree to compile. |
131 | | * 'parent' is the PlanState node that owns the expression. |
132 | | * |
133 | | * 'parent' may be NULL if we are preparing an expression that is not |
134 | | * associated with a plan tree. (If so, it can't have aggs or subplans.) |
135 | | * Such cases should usually come through ExecPrepareExpr, not directly here. |
136 | | * |
137 | | * Also, if 'node' is NULL, we just return NULL. This is convenient for some |
138 | | * callers that may or may not have an expression that needs to be compiled. |
139 | | * Note that a NULL ExprState pointer *cannot* be handed to ExecEvalExpr, |
140 | | * although ExecQual and ExecCheck will accept one (and treat it as "true"). |
141 | | */ |
142 | | ExprState * |
143 | | ExecInitExpr(Expr *node, PlanState *parent) |
144 | 0 | { |
145 | 0 | ExprState *state; |
146 | 0 | ExprEvalStep scratch = {0}; |
147 | | |
148 | | /* Special case: NULL expression produces a NULL ExprState pointer */ |
149 | 0 | if (node == NULL) |
150 | 0 | return NULL; |
151 | | |
152 | | /* Initialize ExprState with empty step list */ |
153 | 0 | state = makeNode(ExprState); |
154 | 0 | state->expr = node; |
155 | 0 | state->parent = parent; |
156 | 0 | state->ext_params = NULL; |
157 | | |
158 | | /* Insert setup steps as needed */ |
159 | 0 | ExecCreateExprSetupSteps(state, (Node *) node); |
160 | | |
161 | | /* Compile the expression proper */ |
162 | 0 | ExecInitExprRec(node, state, &state->resvalue, &state->resnull); |
163 | | |
164 | | /* Finally, append a DONE step */ |
165 | 0 | scratch.opcode = EEOP_DONE_RETURN; |
166 | 0 | ExprEvalPushStep(state, &scratch); |
167 | |
|
168 | 0 | ExecReadyExpr(state); |
169 | |
|
170 | 0 | return state; |
171 | 0 | } |
172 | | |
173 | | /* |
174 | | * ExecInitExprWithParams: prepare a standalone expression tree for execution |
175 | | * |
176 | | * This is the same as ExecInitExpr, except that there is no parent PlanState, |
177 | | * and instead we may have a ParamListInfo describing PARAM_EXTERN Params. |
178 | | */ |
179 | | ExprState * |
180 | | ExecInitExprWithParams(Expr *node, ParamListInfo ext_params) |
181 | 0 | { |
182 | 0 | ExprState *state; |
183 | 0 | ExprEvalStep scratch = {0}; |
184 | | |
185 | | /* Special case: NULL expression produces a NULL ExprState pointer */ |
186 | 0 | if (node == NULL) |
187 | 0 | return NULL; |
188 | | |
189 | | /* Initialize ExprState with empty step list */ |
190 | 0 | state = makeNode(ExprState); |
191 | 0 | state->expr = node; |
192 | 0 | state->parent = NULL; |
193 | 0 | state->ext_params = ext_params; |
194 | | |
195 | | /* Insert setup steps as needed */ |
196 | 0 | ExecCreateExprSetupSteps(state, (Node *) node); |
197 | | |
198 | | /* Compile the expression proper */ |
199 | 0 | ExecInitExprRec(node, state, &state->resvalue, &state->resnull); |
200 | | |
201 | | /* Finally, append a DONE step */ |
202 | 0 | scratch.opcode = EEOP_DONE_RETURN; |
203 | 0 | ExprEvalPushStep(state, &scratch); |
204 | |
|
205 | 0 | ExecReadyExpr(state); |
206 | |
|
207 | 0 | return state; |
208 | 0 | } |
209 | | |
210 | | /* |
211 | | * ExecInitQual: prepare a qual for execution by ExecQual |
212 | | * |
213 | | * Prepares for the evaluation of a conjunctive boolean expression (qual list |
214 | | * with implicit AND semantics) that returns true if none of the |
215 | | * subexpressions are false. |
216 | | * |
217 | | * We must return true if the list is empty. Since that's a very common case, |
218 | | * we optimize it a bit further by translating to a NULL ExprState pointer |
219 | | * rather than setting up an ExprState that computes constant TRUE. (Some |
220 | | * especially hot-spot callers of ExecQual detect this and avoid calling |
221 | | * ExecQual at all.) |
222 | | * |
223 | | * If any of the subexpressions yield NULL, then the result of the conjunction |
224 | | * is false. This makes ExecQual primarily useful for evaluating WHERE |
225 | | * clauses, since SQL specifies that tuples with null WHERE results do not |
226 | | * get selected. |
227 | | */ |
228 | | ExprState * |
229 | | ExecInitQual(List *qual, PlanState *parent) |
230 | 0 | { |
231 | 0 | ExprState *state; |
232 | 0 | ExprEvalStep scratch = {0}; |
233 | 0 | List *adjust_jumps = NIL; |
234 | | |
235 | | /* short-circuit (here and in ExecQual) for empty restriction list */ |
236 | 0 | if (qual == NIL) |
237 | 0 | return NULL; |
238 | | |
239 | 0 | Assert(IsA(qual, List)); |
240 | |
|
241 | 0 | state = makeNode(ExprState); |
242 | 0 | state->expr = (Expr *) qual; |
243 | 0 | state->parent = parent; |
244 | 0 | state->ext_params = NULL; |
245 | | |
246 | | /* mark expression as to be used with ExecQual() */ |
247 | 0 | state->flags = EEO_FLAG_IS_QUAL; |
248 | | |
249 | | /* Insert setup steps as needed */ |
250 | 0 | ExecCreateExprSetupSteps(state, (Node *) qual); |
251 | | |
252 | | /* |
253 | | * ExecQual() needs to return false for an expression returning NULL. That |
254 | | * allows us to short-circuit the evaluation the first time a NULL is |
255 | | * encountered. As qual evaluation is a hot-path this warrants using a |
256 | | * special opcode for qual evaluation that's simpler than BOOL_AND (which |
257 | | * has more complex NULL handling). |
258 | | */ |
259 | 0 | scratch.opcode = EEOP_QUAL; |
260 | | |
261 | | /* |
262 | | * We can use ExprState's resvalue/resnull as target for each qual expr. |
263 | | */ |
264 | 0 | scratch.resvalue = &state->resvalue; |
265 | 0 | scratch.resnull = &state->resnull; |
266 | |
|
267 | 0 | foreach_ptr(Expr, node, qual) |
268 | 0 | { |
269 | | /* first evaluate expression */ |
270 | 0 | ExecInitExprRec(node, state, &state->resvalue, &state->resnull); |
271 | | |
272 | | /* then emit EEOP_QUAL to detect if it's false (or null) */ |
273 | 0 | scratch.d.qualexpr.jumpdone = -1; |
274 | 0 | ExprEvalPushStep(state, &scratch); |
275 | 0 | adjust_jumps = lappend_int(adjust_jumps, |
276 | 0 | state->steps_len - 1); |
277 | 0 | } |
278 | | |
279 | | /* adjust jump targets */ |
280 | 0 | foreach_int(jump, adjust_jumps) |
281 | 0 | { |
282 | 0 | ExprEvalStep *as = &state->steps[jump]; |
283 | |
|
284 | 0 | Assert(as->opcode == EEOP_QUAL); |
285 | 0 | Assert(as->d.qualexpr.jumpdone == -1); |
286 | 0 | as->d.qualexpr.jumpdone = state->steps_len; |
287 | 0 | } |
288 | | |
289 | | /* |
290 | | * At the end, we don't need to do anything more. The last qual expr must |
291 | | * have yielded TRUE, and since its result is stored in the desired output |
292 | | * location, we're done. |
293 | | */ |
294 | 0 | scratch.opcode = EEOP_DONE_RETURN; |
295 | 0 | ExprEvalPushStep(state, &scratch); |
296 | |
|
297 | 0 | ExecReadyExpr(state); |
298 | |
|
299 | 0 | return state; |
300 | 0 | } |
301 | | |
302 | | /* |
303 | | * ExecInitCheck: prepare a check constraint for execution by ExecCheck |
304 | | * |
305 | | * This is much like ExecInitQual/ExecQual, except that a null result from |
306 | | * the conjunction is treated as TRUE. This behavior is appropriate for |
307 | | * evaluating CHECK constraints, since SQL specifies that NULL constraint |
308 | | * conditions are not failures. |
309 | | * |
310 | | * Note that like ExecInitQual, this expects input in implicit-AND format. |
311 | | * Users of ExecCheck that have expressions in normal explicit-AND format |
312 | | * can just apply ExecInitExpr to produce suitable input for ExecCheck. |
313 | | */ |
314 | | ExprState * |
315 | | ExecInitCheck(List *qual, PlanState *parent) |
316 | 0 | { |
317 | | /* short-circuit (here and in ExecCheck) for empty restriction list */ |
318 | 0 | if (qual == NIL) |
319 | 0 | return NULL; |
320 | | |
321 | 0 | Assert(IsA(qual, List)); |
322 | | |
323 | | /* |
324 | | * Just convert the implicit-AND list to an explicit AND (if there's more |
325 | | * than one entry), and compile normally. Unlike ExecQual, we can't |
326 | | * short-circuit on NULL results, so the regular AND behavior is needed. |
327 | | */ |
328 | 0 | return ExecInitExpr(make_ands_explicit(qual), parent); |
329 | 0 | } |
330 | | |
331 | | /* |
332 | | * Call ExecInitExpr() on a list of expressions, return a list of ExprStates. |
333 | | */ |
334 | | List * |
335 | | ExecInitExprList(List *nodes, PlanState *parent) |
336 | 0 | { |
337 | 0 | List *result = NIL; |
338 | 0 | ListCell *lc; |
339 | |
|
340 | 0 | foreach(lc, nodes) |
341 | 0 | { |
342 | 0 | Expr *e = lfirst(lc); |
343 | |
|
344 | 0 | result = lappend(result, ExecInitExpr(e, parent)); |
345 | 0 | } |
346 | |
|
347 | 0 | return result; |
348 | 0 | } |
349 | | |
350 | | /* |
351 | | * ExecBuildProjectionInfo |
352 | | * |
353 | | * Build a ProjectionInfo node for evaluating the given tlist in the given |
354 | | * econtext, and storing the result into the tuple slot. (Caller must have |
355 | | * ensured that tuple slot has a descriptor matching the tlist!) |
356 | | * |
357 | | * inputDesc can be NULL, but if it is not, we check to see whether simple |
358 | | * Vars in the tlist match the descriptor. It is important to provide |
359 | | * inputDesc for relation-scan plan nodes, as a cross check that the relation |
360 | | * hasn't been changed since the plan was made. At higher levels of a plan, |
361 | | * there is no need to recheck. |
362 | | * |
363 | | * This is implemented by internally building an ExprState that performs the |
364 | | * whole projection in one go. |
365 | | * |
366 | | * Caution: before PG v10, the targetList was a list of ExprStates; now it |
367 | | * should be the planner-created targetlist, since we do the compilation here. |
368 | | */ |
369 | | ProjectionInfo * |
370 | | ExecBuildProjectionInfo(List *targetList, |
371 | | ExprContext *econtext, |
372 | | TupleTableSlot *slot, |
373 | | PlanState *parent, |
374 | | TupleDesc inputDesc) |
375 | 0 | { |
376 | 0 | ProjectionInfo *projInfo = makeNode(ProjectionInfo); |
377 | 0 | ExprState *state; |
378 | 0 | ExprEvalStep scratch = {0}; |
379 | 0 | ListCell *lc; |
380 | |
|
381 | 0 | projInfo->pi_exprContext = econtext; |
382 | | /* We embed ExprState into ProjectionInfo instead of doing extra palloc */ |
383 | 0 | projInfo->pi_state.type = T_ExprState; |
384 | 0 | state = &projInfo->pi_state; |
385 | 0 | state->expr = (Expr *) targetList; |
386 | 0 | state->parent = parent; |
387 | 0 | state->ext_params = NULL; |
388 | |
|
389 | 0 | state->resultslot = slot; |
390 | | |
391 | | /* Insert setup steps as needed */ |
392 | 0 | ExecCreateExprSetupSteps(state, (Node *) targetList); |
393 | | |
394 | | /* Now compile each tlist column */ |
395 | 0 | foreach(lc, targetList) |
396 | 0 | { |
397 | 0 | TargetEntry *tle = lfirst_node(TargetEntry, lc); |
398 | 0 | Var *variable = NULL; |
399 | 0 | AttrNumber attnum = 0; |
400 | 0 | bool isSafeVar = false; |
401 | | |
402 | | /* |
403 | | * If tlist expression is a safe non-system Var, use the fast-path |
404 | | * ASSIGN_*_VAR opcodes. "Safe" means that we don't need to apply |
405 | | * CheckVarSlotCompatibility() during plan startup. If a source slot |
406 | | * was provided, we make the equivalent tests here; if a slot was not |
407 | | * provided, we assume that no check is needed because we're dealing |
408 | | * with a non-relation-scan-level expression. |
409 | | */ |
410 | 0 | if (tle->expr != NULL && |
411 | 0 | IsA(tle->expr, Var) && |
412 | 0 | ((Var *) tle->expr)->varattno > 0) |
413 | 0 | { |
414 | | /* Non-system Var, but how safe is it? */ |
415 | 0 | variable = (Var *) tle->expr; |
416 | 0 | attnum = variable->varattno; |
417 | |
|
418 | 0 | if (inputDesc == NULL) |
419 | 0 | isSafeVar = true; /* can't check, just assume OK */ |
420 | 0 | else if (attnum <= inputDesc->natts) |
421 | 0 | { |
422 | 0 | Form_pg_attribute attr = TupleDescAttr(inputDesc, attnum - 1); |
423 | | |
424 | | /* |
425 | | * If user attribute is dropped or has a type mismatch, don't |
426 | | * use ASSIGN_*_VAR. Instead let the normal expression |
427 | | * machinery handle it (which'll possibly error out). |
428 | | */ |
429 | 0 | if (!attr->attisdropped && variable->vartype == attr->atttypid) |
430 | 0 | { |
431 | 0 | isSafeVar = true; |
432 | 0 | } |
433 | 0 | } |
434 | 0 | } |
435 | |
|
436 | 0 | if (isSafeVar) |
437 | 0 | { |
438 | | /* Fast-path: just generate an EEOP_ASSIGN_*_VAR step */ |
439 | 0 | switch (variable->varno) |
440 | 0 | { |
441 | 0 | case INNER_VAR: |
442 | | /* get the tuple from the inner node */ |
443 | 0 | scratch.opcode = EEOP_ASSIGN_INNER_VAR; |
444 | 0 | break; |
445 | | |
446 | 0 | case OUTER_VAR: |
447 | | /* get the tuple from the outer node */ |
448 | 0 | scratch.opcode = EEOP_ASSIGN_OUTER_VAR; |
449 | 0 | break; |
450 | | |
451 | | /* INDEX_VAR is handled by default case */ |
452 | | |
453 | 0 | default: |
454 | | |
455 | | /* |
456 | | * Get the tuple from the relation being scanned, or the |
457 | | * old/new tuple slot, if old/new values were requested. |
458 | | */ |
459 | 0 | switch (variable->varreturningtype) |
460 | 0 | { |
461 | 0 | case VAR_RETURNING_DEFAULT: |
462 | 0 | scratch.opcode = EEOP_ASSIGN_SCAN_VAR; |
463 | 0 | break; |
464 | 0 | case VAR_RETURNING_OLD: |
465 | 0 | scratch.opcode = EEOP_ASSIGN_OLD_VAR; |
466 | 0 | state->flags |= EEO_FLAG_HAS_OLD; |
467 | 0 | break; |
468 | 0 | case VAR_RETURNING_NEW: |
469 | 0 | scratch.opcode = EEOP_ASSIGN_NEW_VAR; |
470 | 0 | state->flags |= EEO_FLAG_HAS_NEW; |
471 | 0 | break; |
472 | 0 | } |
473 | 0 | break; |
474 | 0 | } |
475 | | |
476 | 0 | scratch.d.assign_var.attnum = attnum - 1; |
477 | 0 | scratch.d.assign_var.resultnum = tle->resno - 1; |
478 | 0 | ExprEvalPushStep(state, &scratch); |
479 | 0 | } |
480 | 0 | else |
481 | 0 | { |
482 | | /* |
483 | | * Otherwise, compile the column expression normally. |
484 | | * |
485 | | * We can't tell the expression to evaluate directly into the |
486 | | * result slot, as the result slot (and the exprstate for that |
487 | | * matter) can change between executions. We instead evaluate |
488 | | * into the ExprState's resvalue/resnull and then move. |
489 | | */ |
490 | 0 | ExecInitExprRec(tle->expr, state, |
491 | 0 | &state->resvalue, &state->resnull); |
492 | | |
493 | | /* |
494 | | * Column might be referenced multiple times in upper nodes, so |
495 | | * force value to R/O - but only if it could be an expanded datum. |
496 | | */ |
497 | 0 | if (get_typlen(exprType((Node *) tle->expr)) == -1) |
498 | 0 | scratch.opcode = EEOP_ASSIGN_TMP_MAKE_RO; |
499 | 0 | else |
500 | 0 | scratch.opcode = EEOP_ASSIGN_TMP; |
501 | 0 | scratch.d.assign_tmp.resultnum = tle->resno - 1; |
502 | 0 | ExprEvalPushStep(state, &scratch); |
503 | 0 | } |
504 | 0 | } |
505 | | |
506 | 0 | scratch.opcode = EEOP_DONE_NO_RETURN; |
507 | 0 | ExprEvalPushStep(state, &scratch); |
508 | |
|
509 | 0 | ExecReadyExpr(state); |
510 | |
|
511 | 0 | return projInfo; |
512 | 0 | } |
513 | | |
514 | | /* |
515 | | * ExecBuildUpdateProjection |
516 | | * |
517 | | * Build a ProjectionInfo node for constructing a new tuple during UPDATE. |
518 | | * The projection will be executed in the given econtext and the result will |
519 | | * be stored into the given tuple slot. (Caller must have ensured that tuple |
520 | | * slot has a descriptor matching the target rel!) |
521 | | * |
522 | | * When evalTargetList is false, targetList contains the UPDATE ... SET |
523 | | * expressions that have already been computed by a subplan node; the values |
524 | | * from this tlist are assumed to be available in the "outer" tuple slot. |
525 | | * When evalTargetList is true, targetList contains the UPDATE ... SET |
526 | | * expressions that must be computed (which could contain references to |
527 | | * the outer, inner, or scan tuple slots). |
528 | | * |
529 | | * In either case, targetColnos contains a list of the target column numbers |
530 | | * corresponding to the non-resjunk entries of targetList. The tlist values |
531 | | * are assigned into these columns of the result tuple slot. Target columns |
532 | | * not listed in targetColnos are filled from the UPDATE's old tuple, which |
533 | | * is assumed to be available in the "scan" tuple slot. |
534 | | * |
535 | | * targetList can also contain resjunk columns. These must be evaluated |
536 | | * if evalTargetList is true, but their values are discarded. |
537 | | * |
538 | | * relDesc must describe the relation we intend to update. |
539 | | * |
540 | | * This is basically a specialized variant of ExecBuildProjectionInfo. |
541 | | * However, it also performs sanity checks equivalent to ExecCheckPlanOutput. |
542 | | * Since we never make a normal tlist equivalent to the whole |
543 | | * tuple-to-be-assigned, there is no convenient way to apply |
544 | | * ExecCheckPlanOutput, so we must do our safety checks here. |
545 | | */ |
546 | | ProjectionInfo * |
547 | | ExecBuildUpdateProjection(List *targetList, |
548 | | bool evalTargetList, |
549 | | List *targetColnos, |
550 | | TupleDesc relDesc, |
551 | | ExprContext *econtext, |
552 | | TupleTableSlot *slot, |
553 | | PlanState *parent) |
554 | 0 | { |
555 | 0 | ProjectionInfo *projInfo = makeNode(ProjectionInfo); |
556 | 0 | ExprState *state; |
557 | 0 | int nAssignableCols; |
558 | 0 | bool sawJunk; |
559 | 0 | Bitmapset *assignedCols; |
560 | 0 | ExprSetupInfo deform = {0, 0, 0, 0, 0, NIL}; |
561 | 0 | ExprEvalStep scratch = {0}; |
562 | 0 | int outerattnum; |
563 | 0 | ListCell *lc, |
564 | 0 | *lc2; |
565 | |
|
566 | 0 | projInfo->pi_exprContext = econtext; |
567 | | /* We embed ExprState into ProjectionInfo instead of doing extra palloc */ |
568 | 0 | projInfo->pi_state.type = T_ExprState; |
569 | 0 | state = &projInfo->pi_state; |
570 | 0 | if (evalTargetList) |
571 | 0 | state->expr = (Expr *) targetList; |
572 | 0 | else |
573 | 0 | state->expr = NULL; /* not used */ |
574 | 0 | state->parent = parent; |
575 | 0 | state->ext_params = NULL; |
576 | |
|
577 | 0 | state->resultslot = slot; |
578 | | |
579 | | /* |
580 | | * Examine the targetList to see how many non-junk columns there are, and |
581 | | * to verify that the non-junk columns come before the junk ones. |
582 | | */ |
583 | 0 | nAssignableCols = 0; |
584 | 0 | sawJunk = false; |
585 | 0 | foreach(lc, targetList) |
586 | 0 | { |
587 | 0 | TargetEntry *tle = lfirst_node(TargetEntry, lc); |
588 | |
|
589 | 0 | if (tle->resjunk) |
590 | 0 | sawJunk = true; |
591 | 0 | else |
592 | 0 | { |
593 | 0 | if (sawJunk) |
594 | 0 | elog(ERROR, "subplan target list is out of order"); |
595 | 0 | nAssignableCols++; |
596 | 0 | } |
597 | 0 | } |
598 | | |
599 | | /* We should have one targetColnos entry per non-junk column */ |
600 | 0 | if (nAssignableCols != list_length(targetColnos)) |
601 | 0 | elog(ERROR, "targetColnos does not match subplan target list"); |
602 | | |
603 | | /* |
604 | | * Build a bitmapset of the columns in targetColnos. (We could just use |
605 | | * list_member_int() tests, but that risks O(N^2) behavior with many |
606 | | * columns.) |
607 | | */ |
608 | 0 | assignedCols = NULL; |
609 | 0 | foreach(lc, targetColnos) |
610 | 0 | { |
611 | 0 | AttrNumber targetattnum = lfirst_int(lc); |
612 | |
|
613 | 0 | assignedCols = bms_add_member(assignedCols, targetattnum); |
614 | 0 | } |
615 | | |
616 | | /* |
617 | | * We need to insert EEOP_*_FETCHSOME steps to ensure the input tuples are |
618 | | * sufficiently deconstructed. The scan tuple must be deconstructed at |
619 | | * least as far as the last old column we need. |
620 | | */ |
621 | 0 | for (int attnum = relDesc->natts; attnum > 0; attnum--) |
622 | 0 | { |
623 | 0 | CompactAttribute *attr = TupleDescCompactAttr(relDesc, attnum - 1); |
624 | |
|
625 | 0 | if (attr->attisdropped) |
626 | 0 | continue; |
627 | 0 | if (bms_is_member(attnum, assignedCols)) |
628 | 0 | continue; |
629 | 0 | deform.last_scan = attnum; |
630 | 0 | break; |
631 | 0 | } |
632 | | |
633 | | /* |
634 | | * If we're actually evaluating the tlist, incorporate its input |
635 | | * requirements too; otherwise, we'll just need to fetch the appropriate |
636 | | * number of columns of the "outer" tuple. |
637 | | */ |
638 | 0 | if (evalTargetList) |
639 | 0 | expr_setup_walker((Node *) targetList, &deform); |
640 | 0 | else |
641 | 0 | deform.last_outer = nAssignableCols; |
642 | |
|
643 | 0 | ExecPushExprSetupSteps(state, &deform); |
644 | | |
645 | | /* |
646 | | * Now generate code to evaluate the tlist's assignable expressions or |
647 | | * fetch them from the outer tuple, incidentally validating that they'll |
648 | | * be of the right data type. The checks above ensure that the forboth() |
649 | | * will iterate over exactly the non-junk columns. Note that we don't |
650 | | * bother evaluating any remaining resjunk columns. |
651 | | */ |
652 | 0 | outerattnum = 0; |
653 | 0 | forboth(lc, targetList, lc2, targetColnos) |
654 | 0 | { |
655 | 0 | TargetEntry *tle = lfirst_node(TargetEntry, lc); |
656 | 0 | AttrNumber targetattnum = lfirst_int(lc2); |
657 | 0 | Form_pg_attribute attr; |
658 | |
|
659 | 0 | Assert(!tle->resjunk); |
660 | | |
661 | | /* |
662 | | * Apply sanity checks comparable to ExecCheckPlanOutput(). |
663 | | */ |
664 | 0 | if (targetattnum <= 0 || targetattnum > relDesc->natts) |
665 | 0 | ereport(ERROR, |
666 | 0 | (errcode(ERRCODE_DATATYPE_MISMATCH), |
667 | 0 | errmsg("table row type and query-specified row type do not match"), |
668 | 0 | errdetail("Query has too many columns."))); |
669 | 0 | attr = TupleDescAttr(relDesc, targetattnum - 1); |
670 | |
|
671 | 0 | if (attr->attisdropped) |
672 | 0 | ereport(ERROR, |
673 | 0 | (errcode(ERRCODE_DATATYPE_MISMATCH), |
674 | 0 | errmsg("table row type and query-specified row type do not match"), |
675 | 0 | errdetail("Query provides a value for a dropped column at ordinal position %d.", |
676 | 0 | targetattnum))); |
677 | 0 | if (exprType((Node *) tle->expr) != attr->atttypid) |
678 | 0 | ereport(ERROR, |
679 | 0 | (errcode(ERRCODE_DATATYPE_MISMATCH), |
680 | 0 | errmsg("table row type and query-specified row type do not match"), |
681 | 0 | errdetail("Table has type %s at ordinal position %d, but query expects %s.", |
682 | 0 | format_type_be(attr->atttypid), |
683 | 0 | targetattnum, |
684 | 0 | format_type_be(exprType((Node *) tle->expr))))); |
685 | | |
686 | | /* OK, generate code to perform the assignment. */ |
687 | 0 | if (evalTargetList) |
688 | 0 | { |
689 | | /* |
690 | | * We must evaluate the TLE's expression and assign it. We do not |
691 | | * bother jumping through hoops for "safe" Vars like |
692 | | * ExecBuildProjectionInfo does; this is a relatively less-used |
693 | | * path and it doesn't seem worth expending code for that. |
694 | | */ |
695 | 0 | ExecInitExprRec(tle->expr, state, |
696 | 0 | &state->resvalue, &state->resnull); |
697 | | /* Needn't worry about read-only-ness here, either. */ |
698 | 0 | scratch.opcode = EEOP_ASSIGN_TMP; |
699 | 0 | scratch.d.assign_tmp.resultnum = targetattnum - 1; |
700 | 0 | ExprEvalPushStep(state, &scratch); |
701 | 0 | } |
702 | 0 | else |
703 | 0 | { |
704 | | /* Just assign from the outer tuple. */ |
705 | 0 | scratch.opcode = EEOP_ASSIGN_OUTER_VAR; |
706 | 0 | scratch.d.assign_var.attnum = outerattnum; |
707 | 0 | scratch.d.assign_var.resultnum = targetattnum - 1; |
708 | 0 | ExprEvalPushStep(state, &scratch); |
709 | 0 | } |
710 | 0 | outerattnum++; |
711 | 0 | } |
712 | | |
713 | | /* |
714 | | * Now generate code to copy over any old columns that were not assigned |
715 | | * to, and to ensure that dropped columns are set to NULL. |
716 | | */ |
717 | 0 | for (int attnum = 1; attnum <= relDesc->natts; attnum++) |
718 | 0 | { |
719 | 0 | CompactAttribute *attr = TupleDescCompactAttr(relDesc, attnum - 1); |
720 | |
|
721 | 0 | if (attr->attisdropped) |
722 | 0 | { |
723 | | /* Put a null into the ExprState's resvalue/resnull ... */ |
724 | 0 | scratch.opcode = EEOP_CONST; |
725 | 0 | scratch.resvalue = &state->resvalue; |
726 | 0 | scratch.resnull = &state->resnull; |
727 | 0 | scratch.d.constval.value = (Datum) 0; |
728 | 0 | scratch.d.constval.isnull = true; |
729 | 0 | ExprEvalPushStep(state, &scratch); |
730 | | /* ... then assign it to the result slot */ |
731 | 0 | scratch.opcode = EEOP_ASSIGN_TMP; |
732 | 0 | scratch.d.assign_tmp.resultnum = attnum - 1; |
733 | 0 | ExprEvalPushStep(state, &scratch); |
734 | 0 | } |
735 | 0 | else if (!bms_is_member(attnum, assignedCols)) |
736 | 0 | { |
737 | | /* Certainly the right type, so needn't check */ |
738 | 0 | scratch.opcode = EEOP_ASSIGN_SCAN_VAR; |
739 | 0 | scratch.d.assign_var.attnum = attnum - 1; |
740 | 0 | scratch.d.assign_var.resultnum = attnum - 1; |
741 | 0 | ExprEvalPushStep(state, &scratch); |
742 | 0 | } |
743 | 0 | } |
744 | |
|
745 | 0 | scratch.opcode = EEOP_DONE_NO_RETURN; |
746 | 0 | ExprEvalPushStep(state, &scratch); |
747 | |
|
748 | 0 | ExecReadyExpr(state); |
749 | |
|
750 | 0 | return projInfo; |
751 | 0 | } |
752 | | |
753 | | /* |
754 | | * ExecPrepareExpr --- initialize for expression execution outside a normal |
755 | | * Plan tree context. |
756 | | * |
757 | | * This differs from ExecInitExpr in that we don't assume the caller is |
758 | | * already running in the EState's per-query context. Also, we run the |
759 | | * passed expression tree through expression_planner() to prepare it for |
760 | | * execution. (In ordinary Plan trees the regular planning process will have |
761 | | * made the appropriate transformations on expressions, but for standalone |
762 | | * expressions this won't have happened.) |
763 | | */ |
764 | | ExprState * |
765 | | ExecPrepareExpr(Expr *node, EState *estate) |
766 | 0 | { |
767 | 0 | ExprState *result; |
768 | 0 | MemoryContext oldcontext; |
769 | |
|
770 | 0 | oldcontext = MemoryContextSwitchTo(estate->es_query_cxt); |
771 | |
|
772 | 0 | node = expression_planner(node); |
773 | |
|
774 | 0 | result = ExecInitExpr(node, NULL); |
775 | |
|
776 | 0 | MemoryContextSwitchTo(oldcontext); |
777 | |
|
778 | 0 | return result; |
779 | 0 | } |
780 | | |
781 | | /* |
782 | | * ExecPrepareQual --- initialize for qual execution outside a normal |
783 | | * Plan tree context. |
784 | | * |
785 | | * This differs from ExecInitQual in that we don't assume the caller is |
786 | | * already running in the EState's per-query context. Also, we run the |
787 | | * passed expression tree through expression_planner() to prepare it for |
788 | | * execution. (In ordinary Plan trees the regular planning process will have |
789 | | * made the appropriate transformations on expressions, but for standalone |
790 | | * expressions this won't have happened.) |
791 | | */ |
792 | | ExprState * |
793 | | ExecPrepareQual(List *qual, EState *estate) |
794 | 0 | { |
795 | 0 | ExprState *result; |
796 | 0 | MemoryContext oldcontext; |
797 | |
|
798 | 0 | oldcontext = MemoryContextSwitchTo(estate->es_query_cxt); |
799 | |
|
800 | 0 | qual = (List *) expression_planner((Expr *) qual); |
801 | |
|
802 | 0 | result = ExecInitQual(qual, NULL); |
803 | |
|
804 | 0 | MemoryContextSwitchTo(oldcontext); |
805 | |
|
806 | 0 | return result; |
807 | 0 | } |
808 | | |
809 | | /* |
810 | | * ExecPrepareCheck -- initialize check constraint for execution outside a |
811 | | * normal Plan tree context. |
812 | | * |
813 | | * See ExecPrepareExpr() and ExecInitCheck() for details. |
814 | | */ |
815 | | ExprState * |
816 | | ExecPrepareCheck(List *qual, EState *estate) |
817 | 0 | { |
818 | 0 | ExprState *result; |
819 | 0 | MemoryContext oldcontext; |
820 | |
|
821 | 0 | oldcontext = MemoryContextSwitchTo(estate->es_query_cxt); |
822 | |
|
823 | 0 | qual = (List *) expression_planner((Expr *) qual); |
824 | |
|
825 | 0 | result = ExecInitCheck(qual, NULL); |
826 | |
|
827 | 0 | MemoryContextSwitchTo(oldcontext); |
828 | |
|
829 | 0 | return result; |
830 | 0 | } |
831 | | |
832 | | /* |
833 | | * Call ExecPrepareExpr() on each member of a list of Exprs, and return |
834 | | * a list of ExprStates. |
835 | | * |
836 | | * See ExecPrepareExpr() for details. |
837 | | */ |
838 | | List * |
839 | | ExecPrepareExprList(List *nodes, EState *estate) |
840 | 0 | { |
841 | 0 | List *result = NIL; |
842 | 0 | MemoryContext oldcontext; |
843 | 0 | ListCell *lc; |
844 | | |
845 | | /* Ensure that the list cell nodes are in the right context too */ |
846 | 0 | oldcontext = MemoryContextSwitchTo(estate->es_query_cxt); |
847 | |
|
848 | 0 | foreach(lc, nodes) |
849 | 0 | { |
850 | 0 | Expr *e = (Expr *) lfirst(lc); |
851 | |
|
852 | 0 | result = lappend(result, ExecPrepareExpr(e, estate)); |
853 | 0 | } |
854 | |
|
855 | 0 | MemoryContextSwitchTo(oldcontext); |
856 | |
|
857 | 0 | return result; |
858 | 0 | } |
859 | | |
860 | | /* |
861 | | * ExecCheck - evaluate a check constraint |
862 | | * |
863 | | * For check constraints, a null result is taken as TRUE, ie the constraint |
864 | | * passes. |
865 | | * |
866 | | * The check constraint may have been prepared with ExecInitCheck |
867 | | * (possibly via ExecPrepareCheck) if the caller had it in implicit-AND |
868 | | * format, but a regular boolean expression prepared with ExecInitExpr or |
869 | | * ExecPrepareExpr works too. |
870 | | */ |
871 | | bool |
872 | | ExecCheck(ExprState *state, ExprContext *econtext) |
873 | 0 | { |
874 | 0 | Datum ret; |
875 | 0 | bool isnull; |
876 | | |
877 | | /* short-circuit (here and in ExecInitCheck) for empty restriction list */ |
878 | 0 | if (state == NULL) |
879 | 0 | return true; |
880 | | |
881 | | /* verify that expression was not compiled using ExecInitQual */ |
882 | 0 | Assert(!(state->flags & EEO_FLAG_IS_QUAL)); |
883 | |
|
884 | 0 | ret = ExecEvalExprSwitchContext(state, econtext, &isnull); |
885 | |
|
886 | 0 | if (isnull) |
887 | 0 | return true; |
888 | | |
889 | 0 | return DatumGetBool(ret); |
890 | 0 | } |
891 | | |
892 | | /* |
893 | | * Prepare a compiled expression for execution. This has to be called for |
894 | | * every ExprState before it can be executed. |
895 | | * |
896 | | * NB: While this currently only calls ExecReadyInterpretedExpr(), |
897 | | * this will likely get extended to further expression evaluation methods. |
898 | | * Therefore this should be used instead of directly calling |
899 | | * ExecReadyInterpretedExpr(). |
900 | | */ |
901 | | static void |
902 | | ExecReadyExpr(ExprState *state) |
903 | 0 | { |
904 | 0 | if (jit_compile_expr(state)) |
905 | 0 | return; |
906 | | |
907 | 0 | ExecReadyInterpretedExpr(state); |
908 | 0 | } |
909 | | |
910 | | /* |
911 | | * Append the steps necessary for the evaluation of node to ExprState->steps, |
912 | | * possibly recursing into sub-expressions of node. |
913 | | * |
914 | | * node - expression to evaluate |
915 | | * state - ExprState to whose ->steps to append the necessary operations |
916 | | * resv / resnull - where to store the result of the node into |
917 | | */ |
918 | | static void |
919 | | ExecInitExprRec(Expr *node, ExprState *state, |
920 | | Datum *resv, bool *resnull) |
921 | 0 | { |
922 | 0 | ExprEvalStep scratch = {0}; |
923 | | |
924 | | /* Guard against stack overflow due to overly complex expressions */ |
925 | 0 | check_stack_depth(); |
926 | | |
927 | | /* Step's output location is always what the caller gave us */ |
928 | 0 | Assert(resv != NULL && resnull != NULL); |
929 | 0 | scratch.resvalue = resv; |
930 | 0 | scratch.resnull = resnull; |
931 | | |
932 | | /* cases should be ordered as they are in enum NodeTag */ |
933 | 0 | switch (nodeTag(node)) |
934 | 0 | { |
935 | 0 | case T_Var: |
936 | 0 | { |
937 | 0 | Var *variable = (Var *) node; |
938 | |
|
939 | 0 | if (variable->varattno == InvalidAttrNumber) |
940 | 0 | { |
941 | | /* whole-row Var */ |
942 | 0 | ExecInitWholeRowVar(&scratch, variable, state); |
943 | 0 | } |
944 | 0 | else if (variable->varattno <= 0) |
945 | 0 | { |
946 | | /* system column */ |
947 | 0 | scratch.d.var.attnum = variable->varattno; |
948 | 0 | scratch.d.var.vartype = variable->vartype; |
949 | 0 | scratch.d.var.varreturningtype = variable->varreturningtype; |
950 | 0 | switch (variable->varno) |
951 | 0 | { |
952 | 0 | case INNER_VAR: |
953 | 0 | scratch.opcode = EEOP_INNER_SYSVAR; |
954 | 0 | break; |
955 | 0 | case OUTER_VAR: |
956 | 0 | scratch.opcode = EEOP_OUTER_SYSVAR; |
957 | 0 | break; |
958 | | |
959 | | /* INDEX_VAR is handled by default case */ |
960 | | |
961 | 0 | default: |
962 | 0 | switch (variable->varreturningtype) |
963 | 0 | { |
964 | 0 | case VAR_RETURNING_DEFAULT: |
965 | 0 | scratch.opcode = EEOP_SCAN_SYSVAR; |
966 | 0 | break; |
967 | 0 | case VAR_RETURNING_OLD: |
968 | 0 | scratch.opcode = EEOP_OLD_SYSVAR; |
969 | 0 | state->flags |= EEO_FLAG_HAS_OLD; |
970 | 0 | break; |
971 | 0 | case VAR_RETURNING_NEW: |
972 | 0 | scratch.opcode = EEOP_NEW_SYSVAR; |
973 | 0 | state->flags |= EEO_FLAG_HAS_NEW; |
974 | 0 | break; |
975 | 0 | } |
976 | 0 | break; |
977 | 0 | } |
978 | 0 | } |
979 | 0 | else |
980 | 0 | { |
981 | | /* regular user column */ |
982 | 0 | scratch.d.var.attnum = variable->varattno - 1; |
983 | 0 | scratch.d.var.vartype = variable->vartype; |
984 | 0 | scratch.d.var.varreturningtype = variable->varreturningtype; |
985 | 0 | switch (variable->varno) |
986 | 0 | { |
987 | 0 | case INNER_VAR: |
988 | 0 | scratch.opcode = EEOP_INNER_VAR; |
989 | 0 | break; |
990 | 0 | case OUTER_VAR: |
991 | 0 | scratch.opcode = EEOP_OUTER_VAR; |
992 | 0 | break; |
993 | | |
994 | | /* INDEX_VAR is handled by default case */ |
995 | | |
996 | 0 | default: |
997 | 0 | switch (variable->varreturningtype) |
998 | 0 | { |
999 | 0 | case VAR_RETURNING_DEFAULT: |
1000 | 0 | scratch.opcode = EEOP_SCAN_VAR; |
1001 | 0 | break; |
1002 | 0 | case VAR_RETURNING_OLD: |
1003 | 0 | scratch.opcode = EEOP_OLD_VAR; |
1004 | 0 | state->flags |= EEO_FLAG_HAS_OLD; |
1005 | 0 | break; |
1006 | 0 | case VAR_RETURNING_NEW: |
1007 | 0 | scratch.opcode = EEOP_NEW_VAR; |
1008 | 0 | state->flags |= EEO_FLAG_HAS_NEW; |
1009 | 0 | break; |
1010 | 0 | } |
1011 | 0 | break; |
1012 | 0 | } |
1013 | 0 | } |
1014 | | |
1015 | 0 | ExprEvalPushStep(state, &scratch); |
1016 | 0 | break; |
1017 | 0 | } |
1018 | | |
1019 | 0 | case T_Const: |
1020 | 0 | { |
1021 | 0 | Const *con = (Const *) node; |
1022 | |
|
1023 | 0 | scratch.opcode = EEOP_CONST; |
1024 | 0 | scratch.d.constval.value = con->constvalue; |
1025 | 0 | scratch.d.constval.isnull = con->constisnull; |
1026 | |
|
1027 | 0 | ExprEvalPushStep(state, &scratch); |
1028 | 0 | break; |
1029 | 0 | } |
1030 | | |
1031 | 0 | case T_Param: |
1032 | 0 | { |
1033 | 0 | Param *param = (Param *) node; |
1034 | 0 | ParamListInfo params; |
1035 | |
|
1036 | 0 | switch (param->paramkind) |
1037 | 0 | { |
1038 | 0 | case PARAM_EXEC: |
1039 | 0 | scratch.opcode = EEOP_PARAM_EXEC; |
1040 | 0 | scratch.d.param.paramid = param->paramid; |
1041 | 0 | scratch.d.param.paramtype = param->paramtype; |
1042 | 0 | ExprEvalPushStep(state, &scratch); |
1043 | 0 | break; |
1044 | 0 | case PARAM_EXTERN: |
1045 | | |
1046 | | /* |
1047 | | * If we have a relevant ParamCompileHook, use it; |
1048 | | * otherwise compile a standard EEOP_PARAM_EXTERN |
1049 | | * step. ext_params, if supplied, takes precedence |
1050 | | * over info from the parent node's EState (if any). |
1051 | | */ |
1052 | 0 | if (state->ext_params) |
1053 | 0 | params = state->ext_params; |
1054 | 0 | else if (state->parent && |
1055 | 0 | state->parent->state) |
1056 | 0 | params = state->parent->state->es_param_list_info; |
1057 | 0 | else |
1058 | 0 | params = NULL; |
1059 | 0 | if (params && params->paramCompile) |
1060 | 0 | { |
1061 | 0 | params->paramCompile(params, param, state, |
1062 | 0 | resv, resnull); |
1063 | 0 | } |
1064 | 0 | else |
1065 | 0 | { |
1066 | 0 | scratch.opcode = EEOP_PARAM_EXTERN; |
1067 | 0 | scratch.d.param.paramid = param->paramid; |
1068 | 0 | scratch.d.param.paramtype = param->paramtype; |
1069 | 0 | ExprEvalPushStep(state, &scratch); |
1070 | 0 | } |
1071 | 0 | break; |
1072 | 0 | default: |
1073 | 0 | elog(ERROR, "unrecognized paramkind: %d", |
1074 | 0 | (int) param->paramkind); |
1075 | 0 | break; |
1076 | 0 | } |
1077 | 0 | break; |
1078 | 0 | } |
1079 | | |
1080 | 0 | case T_Aggref: |
1081 | 0 | { |
1082 | 0 | Aggref *aggref = (Aggref *) node; |
1083 | |
|
1084 | 0 | scratch.opcode = EEOP_AGGREF; |
1085 | 0 | scratch.d.aggref.aggno = aggref->aggno; |
1086 | |
|
1087 | 0 | if (state->parent && IsA(state->parent, AggState)) |
1088 | 0 | { |
1089 | 0 | AggState *aggstate = (AggState *) state->parent; |
1090 | |
|
1091 | 0 | aggstate->aggs = lappend(aggstate->aggs, aggref); |
1092 | 0 | } |
1093 | 0 | else |
1094 | 0 | { |
1095 | | /* planner messed up */ |
1096 | 0 | elog(ERROR, "Aggref found in non-Agg plan node"); |
1097 | 0 | } |
1098 | | |
1099 | 0 | ExprEvalPushStep(state, &scratch); |
1100 | 0 | break; |
1101 | 0 | } |
1102 | | |
1103 | 0 | case T_GroupingFunc: |
1104 | 0 | { |
1105 | 0 | GroupingFunc *grp_node = (GroupingFunc *) node; |
1106 | 0 | Agg *agg; |
1107 | |
|
1108 | 0 | if (!state->parent || !IsA(state->parent, AggState) || |
1109 | 0 | !IsA(state->parent->plan, Agg)) |
1110 | 0 | elog(ERROR, "GroupingFunc found in non-Agg plan node"); |
1111 | | |
1112 | 0 | scratch.opcode = EEOP_GROUPING_FUNC; |
1113 | |
|
1114 | 0 | agg = (Agg *) (state->parent->plan); |
1115 | |
|
1116 | 0 | if (agg->groupingSets) |
1117 | 0 | scratch.d.grouping_func.clauses = grp_node->cols; |
1118 | 0 | else |
1119 | 0 | scratch.d.grouping_func.clauses = NIL; |
1120 | |
|
1121 | 0 | ExprEvalPushStep(state, &scratch); |
1122 | 0 | break; |
1123 | 0 | } |
1124 | | |
1125 | 0 | case T_WindowFunc: |
1126 | 0 | { |
1127 | 0 | WindowFunc *wfunc = (WindowFunc *) node; |
1128 | 0 | WindowFuncExprState *wfstate = makeNode(WindowFuncExprState); |
1129 | |
|
1130 | 0 | wfstate->wfunc = wfunc; |
1131 | |
|
1132 | 0 | if (state->parent && IsA(state->parent, WindowAggState)) |
1133 | 0 | { |
1134 | 0 | WindowAggState *winstate = (WindowAggState *) state->parent; |
1135 | 0 | int nfuncs; |
1136 | |
|
1137 | 0 | winstate->funcs = lappend(winstate->funcs, wfstate); |
1138 | 0 | nfuncs = ++winstate->numfuncs; |
1139 | 0 | if (wfunc->winagg) |
1140 | 0 | winstate->numaggs++; |
1141 | | |
1142 | | /* for now initialize agg using old style expressions */ |
1143 | 0 | wfstate->args = ExecInitExprList(wfunc->args, |
1144 | 0 | state->parent); |
1145 | 0 | wfstate->aggfilter = ExecInitExpr(wfunc->aggfilter, |
1146 | 0 | state->parent); |
1147 | | |
1148 | | /* |
1149 | | * Complain if the windowfunc's arguments contain any |
1150 | | * windowfuncs; nested window functions are semantically |
1151 | | * nonsensical. (This should have been caught earlier, |
1152 | | * but we defend against it here anyway.) |
1153 | | */ |
1154 | 0 | if (nfuncs != winstate->numfuncs) |
1155 | 0 | ereport(ERROR, |
1156 | 0 | (errcode(ERRCODE_WINDOWING_ERROR), |
1157 | 0 | errmsg("window function calls cannot be nested"))); |
1158 | 0 | } |
1159 | 0 | else |
1160 | 0 | { |
1161 | | /* planner messed up */ |
1162 | 0 | elog(ERROR, "WindowFunc found in non-WindowAgg plan node"); |
1163 | 0 | } |
1164 | | |
1165 | 0 | scratch.opcode = EEOP_WINDOW_FUNC; |
1166 | 0 | scratch.d.window_func.wfstate = wfstate; |
1167 | 0 | ExprEvalPushStep(state, &scratch); |
1168 | 0 | break; |
1169 | 0 | } |
1170 | | |
1171 | 0 | case T_MergeSupportFunc: |
1172 | 0 | { |
1173 | | /* must be in a MERGE, else something messed up */ |
1174 | 0 | if (!state->parent || |
1175 | 0 | !IsA(state->parent, ModifyTableState) || |
1176 | 0 | ((ModifyTableState *) state->parent)->operation != CMD_MERGE) |
1177 | 0 | elog(ERROR, "MergeSupportFunc found in non-merge plan node"); |
1178 | | |
1179 | 0 | scratch.opcode = EEOP_MERGE_SUPPORT_FUNC; |
1180 | 0 | ExprEvalPushStep(state, &scratch); |
1181 | 0 | break; |
1182 | 0 | } |
1183 | | |
1184 | 0 | case T_SubscriptingRef: |
1185 | 0 | { |
1186 | 0 | SubscriptingRef *sbsref = (SubscriptingRef *) node; |
1187 | |
|
1188 | 0 | ExecInitSubscriptingRef(&scratch, sbsref, state, resv, resnull); |
1189 | 0 | break; |
1190 | 0 | } |
1191 | | |
1192 | 0 | case T_FuncExpr: |
1193 | 0 | { |
1194 | 0 | FuncExpr *func = (FuncExpr *) node; |
1195 | |
|
1196 | 0 | ExecInitFunc(&scratch, node, |
1197 | 0 | func->args, func->funcid, func->inputcollid, |
1198 | 0 | state); |
1199 | 0 | ExprEvalPushStep(state, &scratch); |
1200 | 0 | break; |
1201 | 0 | } |
1202 | | |
1203 | 0 | case T_OpExpr: |
1204 | 0 | { |
1205 | 0 | OpExpr *op = (OpExpr *) node; |
1206 | |
|
1207 | 0 | ExecInitFunc(&scratch, node, |
1208 | 0 | op->args, op->opfuncid, op->inputcollid, |
1209 | 0 | state); |
1210 | 0 | ExprEvalPushStep(state, &scratch); |
1211 | 0 | break; |
1212 | 0 | } |
1213 | | |
1214 | 0 | case T_DistinctExpr: |
1215 | 0 | { |
1216 | 0 | DistinctExpr *op = (DistinctExpr *) node; |
1217 | |
|
1218 | 0 | ExecInitFunc(&scratch, node, |
1219 | 0 | op->args, op->opfuncid, op->inputcollid, |
1220 | 0 | state); |
1221 | | |
1222 | | /* |
1223 | | * Change opcode of call instruction to EEOP_DISTINCT. |
1224 | | * |
1225 | | * XXX: historically we've not called the function usage |
1226 | | * pgstat infrastructure - that seems inconsistent given that |
1227 | | * we do so for normal function *and* operator evaluation. If |
1228 | | * we decided to do that here, we'd probably want separate |
1229 | | * opcodes for FUSAGE or not. |
1230 | | */ |
1231 | 0 | scratch.opcode = EEOP_DISTINCT; |
1232 | 0 | ExprEvalPushStep(state, &scratch); |
1233 | 0 | break; |
1234 | 0 | } |
1235 | | |
1236 | 0 | case T_NullIfExpr: |
1237 | 0 | { |
1238 | 0 | NullIfExpr *op = (NullIfExpr *) node; |
1239 | |
|
1240 | 0 | ExecInitFunc(&scratch, node, |
1241 | 0 | op->args, op->opfuncid, op->inputcollid, |
1242 | 0 | state); |
1243 | | |
1244 | | /* |
1245 | | * If first argument is of varlena type, we'll need to ensure |
1246 | | * that the value passed to the comparison function is a |
1247 | | * read-only pointer. |
1248 | | */ |
1249 | 0 | scratch.d.func.make_ro = |
1250 | 0 | (get_typlen(exprType((Node *) linitial(op->args))) == -1); |
1251 | | |
1252 | | /* |
1253 | | * Change opcode of call instruction to EEOP_NULLIF. |
1254 | | * |
1255 | | * XXX: historically we've not called the function usage |
1256 | | * pgstat infrastructure - that seems inconsistent given that |
1257 | | * we do so for normal function *and* operator evaluation. If |
1258 | | * we decided to do that here, we'd probably want separate |
1259 | | * opcodes for FUSAGE or not. |
1260 | | */ |
1261 | 0 | scratch.opcode = EEOP_NULLIF; |
1262 | 0 | ExprEvalPushStep(state, &scratch); |
1263 | 0 | break; |
1264 | 0 | } |
1265 | | |
1266 | 0 | case T_ScalarArrayOpExpr: |
1267 | 0 | { |
1268 | 0 | ScalarArrayOpExpr *opexpr = (ScalarArrayOpExpr *) node; |
1269 | 0 | Expr *scalararg; |
1270 | 0 | Expr *arrayarg; |
1271 | 0 | FmgrInfo *finfo; |
1272 | 0 | FunctionCallInfo fcinfo; |
1273 | 0 | AclResult aclresult; |
1274 | 0 | Oid cmpfuncid; |
1275 | | |
1276 | | /* |
1277 | | * Select the correct comparison function. When we do hashed |
1278 | | * NOT IN clauses, the opfuncid will be the inequality |
1279 | | * comparison function and negfuncid will be set to equality. |
1280 | | * We need to use the equality function for hash probes. |
1281 | | */ |
1282 | 0 | if (OidIsValid(opexpr->negfuncid)) |
1283 | 0 | { |
1284 | 0 | Assert(OidIsValid(opexpr->hashfuncid)); |
1285 | 0 | cmpfuncid = opexpr->negfuncid; |
1286 | 0 | } |
1287 | 0 | else |
1288 | 0 | cmpfuncid = opexpr->opfuncid; |
1289 | |
|
1290 | 0 | Assert(list_length(opexpr->args) == 2); |
1291 | 0 | scalararg = (Expr *) linitial(opexpr->args); |
1292 | 0 | arrayarg = (Expr *) lsecond(opexpr->args); |
1293 | | |
1294 | | /* Check permission to call function */ |
1295 | 0 | aclresult = object_aclcheck(ProcedureRelationId, cmpfuncid, |
1296 | 0 | GetUserId(), |
1297 | 0 | ACL_EXECUTE); |
1298 | 0 | if (aclresult != ACLCHECK_OK) |
1299 | 0 | aclcheck_error(aclresult, OBJECT_FUNCTION, |
1300 | 0 | get_func_name(cmpfuncid)); |
1301 | 0 | InvokeFunctionExecuteHook(cmpfuncid); |
1302 | |
|
1303 | 0 | if (OidIsValid(opexpr->hashfuncid)) |
1304 | 0 | { |
1305 | 0 | aclresult = object_aclcheck(ProcedureRelationId, opexpr->hashfuncid, |
1306 | 0 | GetUserId(), |
1307 | 0 | ACL_EXECUTE); |
1308 | 0 | if (aclresult != ACLCHECK_OK) |
1309 | 0 | aclcheck_error(aclresult, OBJECT_FUNCTION, |
1310 | 0 | get_func_name(opexpr->hashfuncid)); |
1311 | 0 | InvokeFunctionExecuteHook(opexpr->hashfuncid); |
1312 | 0 | } |
1313 | | |
1314 | | /* Set up the primary fmgr lookup information */ |
1315 | 0 | finfo = palloc0(sizeof(FmgrInfo)); |
1316 | 0 | fcinfo = palloc0(SizeForFunctionCallInfo(2)); |
1317 | 0 | fmgr_info(cmpfuncid, finfo); |
1318 | 0 | fmgr_info_set_expr((Node *) node, finfo); |
1319 | 0 | InitFunctionCallInfoData(*fcinfo, finfo, 2, |
1320 | 0 | opexpr->inputcollid, NULL, NULL); |
1321 | | |
1322 | | /* |
1323 | | * If hashfuncid is set, we create a EEOP_HASHED_SCALARARRAYOP |
1324 | | * step instead of a EEOP_SCALARARRAYOP. This provides much |
1325 | | * faster lookup performance than the normal linear search |
1326 | | * when the number of items in the array is anything but very |
1327 | | * small. |
1328 | | */ |
1329 | 0 | if (OidIsValid(opexpr->hashfuncid)) |
1330 | 0 | { |
1331 | | /* Evaluate scalar directly into left function argument */ |
1332 | 0 | ExecInitExprRec(scalararg, state, |
1333 | 0 | &fcinfo->args[0].value, &fcinfo->args[0].isnull); |
1334 | | |
1335 | | /* |
1336 | | * Evaluate array argument into our return value. There's |
1337 | | * no danger in that, because the return value is |
1338 | | * guaranteed to be overwritten by |
1339 | | * EEOP_HASHED_SCALARARRAYOP, and will not be passed to |
1340 | | * any other expression. |
1341 | | */ |
1342 | 0 | ExecInitExprRec(arrayarg, state, resv, resnull); |
1343 | | |
1344 | | /* And perform the operation */ |
1345 | 0 | scratch.opcode = EEOP_HASHED_SCALARARRAYOP; |
1346 | 0 | scratch.d.hashedscalararrayop.inclause = opexpr->useOr; |
1347 | 0 | scratch.d.hashedscalararrayop.finfo = finfo; |
1348 | 0 | scratch.d.hashedscalararrayop.fcinfo_data = fcinfo; |
1349 | 0 | scratch.d.hashedscalararrayop.saop = opexpr; |
1350 | | |
1351 | |
|
1352 | 0 | ExprEvalPushStep(state, &scratch); |
1353 | 0 | } |
1354 | 0 | else |
1355 | 0 | { |
1356 | | /* Evaluate scalar directly into left function argument */ |
1357 | 0 | ExecInitExprRec(scalararg, state, |
1358 | 0 | &fcinfo->args[0].value, |
1359 | 0 | &fcinfo->args[0].isnull); |
1360 | | |
1361 | | /* |
1362 | | * Evaluate array argument into our return value. There's |
1363 | | * no danger in that, because the return value is |
1364 | | * guaranteed to be overwritten by EEOP_SCALARARRAYOP, and |
1365 | | * will not be passed to any other expression. |
1366 | | */ |
1367 | 0 | ExecInitExprRec(arrayarg, state, resv, resnull); |
1368 | | |
1369 | | /* And perform the operation */ |
1370 | 0 | scratch.opcode = EEOP_SCALARARRAYOP; |
1371 | 0 | scratch.d.scalararrayop.element_type = InvalidOid; |
1372 | 0 | scratch.d.scalararrayop.useOr = opexpr->useOr; |
1373 | 0 | scratch.d.scalararrayop.finfo = finfo; |
1374 | 0 | scratch.d.scalararrayop.fcinfo_data = fcinfo; |
1375 | 0 | scratch.d.scalararrayop.fn_addr = finfo->fn_addr; |
1376 | 0 | ExprEvalPushStep(state, &scratch); |
1377 | 0 | } |
1378 | 0 | break; |
1379 | 0 | } |
1380 | | |
1381 | 0 | case T_BoolExpr: |
1382 | 0 | { |
1383 | 0 | BoolExpr *boolexpr = (BoolExpr *) node; |
1384 | 0 | int nargs = list_length(boolexpr->args); |
1385 | 0 | List *adjust_jumps = NIL; |
1386 | 0 | int off; |
1387 | 0 | ListCell *lc; |
1388 | | |
1389 | | /* allocate scratch memory used by all steps of AND/OR */ |
1390 | 0 | if (boolexpr->boolop != NOT_EXPR) |
1391 | 0 | scratch.d.boolexpr.anynull = (bool *) palloc(sizeof(bool)); |
1392 | | |
1393 | | /* |
1394 | | * For each argument evaluate the argument itself, then |
1395 | | * perform the bool operation's appropriate handling. |
1396 | | * |
1397 | | * We can evaluate each argument into our result area, since |
1398 | | * the short-circuiting logic means we only need to remember |
1399 | | * previous NULL values. |
1400 | | * |
1401 | | * AND/OR is split into separate STEP_FIRST (one) / STEP (zero |
1402 | | * or more) / STEP_LAST (one) steps, as each of those has to |
1403 | | * perform different work. The FIRST/LAST split is valid |
1404 | | * because AND/OR have at least two arguments. |
1405 | | */ |
1406 | 0 | off = 0; |
1407 | 0 | foreach(lc, boolexpr->args) |
1408 | 0 | { |
1409 | 0 | Expr *arg = (Expr *) lfirst(lc); |
1410 | | |
1411 | | /* Evaluate argument into our output variable */ |
1412 | 0 | ExecInitExprRec(arg, state, resv, resnull); |
1413 | | |
1414 | | /* Perform the appropriate step type */ |
1415 | 0 | switch (boolexpr->boolop) |
1416 | 0 | { |
1417 | 0 | case AND_EXPR: |
1418 | 0 | Assert(nargs >= 2); |
1419 | |
|
1420 | 0 | if (off == 0) |
1421 | 0 | scratch.opcode = EEOP_BOOL_AND_STEP_FIRST; |
1422 | 0 | else if (off + 1 == nargs) |
1423 | 0 | scratch.opcode = EEOP_BOOL_AND_STEP_LAST; |
1424 | 0 | else |
1425 | 0 | scratch.opcode = EEOP_BOOL_AND_STEP; |
1426 | 0 | break; |
1427 | 0 | case OR_EXPR: |
1428 | 0 | Assert(nargs >= 2); |
1429 | |
|
1430 | 0 | if (off == 0) |
1431 | 0 | scratch.opcode = EEOP_BOOL_OR_STEP_FIRST; |
1432 | 0 | else if (off + 1 == nargs) |
1433 | 0 | scratch.opcode = EEOP_BOOL_OR_STEP_LAST; |
1434 | 0 | else |
1435 | 0 | scratch.opcode = EEOP_BOOL_OR_STEP; |
1436 | 0 | break; |
1437 | 0 | case NOT_EXPR: |
1438 | 0 | Assert(nargs == 1); |
1439 | |
|
1440 | 0 | scratch.opcode = EEOP_BOOL_NOT_STEP; |
1441 | 0 | break; |
1442 | 0 | default: |
1443 | 0 | elog(ERROR, "unrecognized boolop: %d", |
1444 | 0 | (int) boolexpr->boolop); |
1445 | 0 | break; |
1446 | 0 | } |
1447 | | |
1448 | 0 | scratch.d.boolexpr.jumpdone = -1; |
1449 | 0 | ExprEvalPushStep(state, &scratch); |
1450 | 0 | adjust_jumps = lappend_int(adjust_jumps, |
1451 | 0 | state->steps_len - 1); |
1452 | 0 | off++; |
1453 | 0 | } |
1454 | | |
1455 | | /* adjust jump targets */ |
1456 | 0 | foreach(lc, adjust_jumps) |
1457 | 0 | { |
1458 | 0 | ExprEvalStep *as = &state->steps[lfirst_int(lc)]; |
1459 | |
|
1460 | 0 | Assert(as->d.boolexpr.jumpdone == -1); |
1461 | 0 | as->d.boolexpr.jumpdone = state->steps_len; |
1462 | 0 | } |
1463 | |
|
1464 | 0 | break; |
1465 | 0 | } |
1466 | | |
1467 | 0 | case T_SubPlan: |
1468 | 0 | { |
1469 | 0 | SubPlan *subplan = (SubPlan *) node; |
1470 | | |
1471 | | /* |
1472 | | * Real execution of a MULTIEXPR SubPlan has already been |
1473 | | * done. What we have to do here is return a dummy NULL record |
1474 | | * value in case this targetlist element is assigned |
1475 | | * someplace. |
1476 | | */ |
1477 | 0 | if (subplan->subLinkType == MULTIEXPR_SUBLINK) |
1478 | 0 | { |
1479 | 0 | scratch.opcode = EEOP_CONST; |
1480 | 0 | scratch.d.constval.value = (Datum) 0; |
1481 | 0 | scratch.d.constval.isnull = true; |
1482 | 0 | ExprEvalPushStep(state, &scratch); |
1483 | 0 | break; |
1484 | 0 | } |
1485 | | |
1486 | 0 | ExecInitSubPlanExpr(subplan, state, resv, resnull); |
1487 | 0 | break; |
1488 | 0 | } |
1489 | | |
1490 | 0 | case T_FieldSelect: |
1491 | 0 | { |
1492 | 0 | FieldSelect *fselect = (FieldSelect *) node; |
1493 | | |
1494 | | /* evaluate row/record argument into result area */ |
1495 | 0 | ExecInitExprRec(fselect->arg, state, resv, resnull); |
1496 | | |
1497 | | /* and extract field */ |
1498 | 0 | scratch.opcode = EEOP_FIELDSELECT; |
1499 | 0 | scratch.d.fieldselect.fieldnum = fselect->fieldnum; |
1500 | 0 | scratch.d.fieldselect.resulttype = fselect->resulttype; |
1501 | 0 | scratch.d.fieldselect.rowcache.cacheptr = NULL; |
1502 | |
|
1503 | 0 | ExprEvalPushStep(state, &scratch); |
1504 | 0 | break; |
1505 | 0 | } |
1506 | | |
1507 | 0 | case T_FieldStore: |
1508 | 0 | { |
1509 | 0 | FieldStore *fstore = (FieldStore *) node; |
1510 | 0 | TupleDesc tupDesc; |
1511 | 0 | ExprEvalRowtypeCache *rowcachep; |
1512 | 0 | Datum *values; |
1513 | 0 | bool *nulls; |
1514 | 0 | int ncolumns; |
1515 | 0 | ListCell *l1, |
1516 | 0 | *l2; |
1517 | | |
1518 | | /* find out the number of columns in the composite type */ |
1519 | 0 | tupDesc = lookup_rowtype_tupdesc(fstore->resulttype, -1); |
1520 | 0 | ncolumns = tupDesc->natts; |
1521 | 0 | ReleaseTupleDesc(tupDesc); |
1522 | | |
1523 | | /* create workspace for column values */ |
1524 | 0 | values = (Datum *) palloc(sizeof(Datum) * ncolumns); |
1525 | 0 | nulls = (bool *) palloc(sizeof(bool) * ncolumns); |
1526 | | |
1527 | | /* create shared composite-type-lookup cache struct */ |
1528 | 0 | rowcachep = palloc(sizeof(ExprEvalRowtypeCache)); |
1529 | 0 | rowcachep->cacheptr = NULL; |
1530 | | |
1531 | | /* emit code to evaluate the composite input value */ |
1532 | 0 | ExecInitExprRec(fstore->arg, state, resv, resnull); |
1533 | | |
1534 | | /* next, deform the input tuple into our workspace */ |
1535 | 0 | scratch.opcode = EEOP_FIELDSTORE_DEFORM; |
1536 | 0 | scratch.d.fieldstore.fstore = fstore; |
1537 | 0 | scratch.d.fieldstore.rowcache = rowcachep; |
1538 | 0 | scratch.d.fieldstore.values = values; |
1539 | 0 | scratch.d.fieldstore.nulls = nulls; |
1540 | 0 | scratch.d.fieldstore.ncolumns = ncolumns; |
1541 | 0 | ExprEvalPushStep(state, &scratch); |
1542 | | |
1543 | | /* evaluate new field values, store in workspace columns */ |
1544 | 0 | forboth(l1, fstore->newvals, l2, fstore->fieldnums) |
1545 | 0 | { |
1546 | 0 | Expr *e = (Expr *) lfirst(l1); |
1547 | 0 | AttrNumber fieldnum = lfirst_int(l2); |
1548 | 0 | Datum *save_innermost_caseval; |
1549 | 0 | bool *save_innermost_casenull; |
1550 | |
|
1551 | 0 | if (fieldnum <= 0 || fieldnum > ncolumns) |
1552 | 0 | elog(ERROR, "field number %d is out of range in FieldStore", |
1553 | 0 | fieldnum); |
1554 | | |
1555 | | /* |
1556 | | * Use the CaseTestExpr mechanism to pass down the old |
1557 | | * value of the field being replaced; this is needed in |
1558 | | * case the newval is itself a FieldStore or |
1559 | | * SubscriptingRef that has to obtain and modify the old |
1560 | | * value. It's safe to reuse the CASE mechanism because |
1561 | | * there cannot be a CASE between here and where the value |
1562 | | * would be needed, and a field assignment can't be within |
1563 | | * a CASE either. (So saving and restoring |
1564 | | * innermost_caseval is just paranoia, but let's do it |
1565 | | * anyway.) |
1566 | | * |
1567 | | * Another non-obvious point is that it's safe to use the |
1568 | | * field's values[]/nulls[] entries as both the caseval |
1569 | | * source and the result address for this subexpression. |
1570 | | * That's okay only because (1) both FieldStore and |
1571 | | * SubscriptingRef evaluate their arg or refexpr inputs |
1572 | | * first, and (2) any such CaseTestExpr is directly the |
1573 | | * arg or refexpr input. So any read of the caseval will |
1574 | | * occur before there's a chance to overwrite it. Also, |
1575 | | * if multiple entries in the newvals/fieldnums lists |
1576 | | * target the same field, they'll effectively be applied |
1577 | | * left-to-right which is what we want. |
1578 | | */ |
1579 | 0 | save_innermost_caseval = state->innermost_caseval; |
1580 | 0 | save_innermost_casenull = state->innermost_casenull; |
1581 | 0 | state->innermost_caseval = &values[fieldnum - 1]; |
1582 | 0 | state->innermost_casenull = &nulls[fieldnum - 1]; |
1583 | |
|
1584 | 0 | ExecInitExprRec(e, state, |
1585 | 0 | &values[fieldnum - 1], |
1586 | 0 | &nulls[fieldnum - 1]); |
1587 | |
|
1588 | 0 | state->innermost_caseval = save_innermost_caseval; |
1589 | 0 | state->innermost_casenull = save_innermost_casenull; |
1590 | 0 | } |
1591 | | |
1592 | | /* finally, form result tuple */ |
1593 | 0 | scratch.opcode = EEOP_FIELDSTORE_FORM; |
1594 | 0 | scratch.d.fieldstore.fstore = fstore; |
1595 | 0 | scratch.d.fieldstore.rowcache = rowcachep; |
1596 | 0 | scratch.d.fieldstore.values = values; |
1597 | 0 | scratch.d.fieldstore.nulls = nulls; |
1598 | 0 | scratch.d.fieldstore.ncolumns = ncolumns; |
1599 | 0 | ExprEvalPushStep(state, &scratch); |
1600 | 0 | break; |
1601 | 0 | } |
1602 | | |
1603 | 0 | case T_RelabelType: |
1604 | 0 | { |
1605 | | /* relabel doesn't need to do anything at runtime */ |
1606 | 0 | RelabelType *relabel = (RelabelType *) node; |
1607 | |
|
1608 | 0 | ExecInitExprRec(relabel->arg, state, resv, resnull); |
1609 | 0 | break; |
1610 | 0 | } |
1611 | | |
1612 | 0 | case T_CoerceViaIO: |
1613 | 0 | { |
1614 | 0 | CoerceViaIO *iocoerce = (CoerceViaIO *) node; |
1615 | 0 | Oid iofunc; |
1616 | 0 | bool typisvarlena; |
1617 | 0 | Oid typioparam; |
1618 | 0 | FunctionCallInfo fcinfo_in; |
1619 | | |
1620 | | /* evaluate argument into step's result area */ |
1621 | 0 | ExecInitExprRec(iocoerce->arg, state, resv, resnull); |
1622 | | |
1623 | | /* |
1624 | | * Prepare both output and input function calls, to be |
1625 | | * evaluated inside a single evaluation step for speed - this |
1626 | | * can be a very common operation. |
1627 | | * |
1628 | | * We don't check permissions here as a type's input/output |
1629 | | * function are assumed to be executable by everyone. |
1630 | | */ |
1631 | 0 | if (state->escontext == NULL) |
1632 | 0 | scratch.opcode = EEOP_IOCOERCE; |
1633 | 0 | else |
1634 | 0 | scratch.opcode = EEOP_IOCOERCE_SAFE; |
1635 | | |
1636 | | /* lookup the source type's output function */ |
1637 | 0 | scratch.d.iocoerce.finfo_out = palloc0(sizeof(FmgrInfo)); |
1638 | 0 | scratch.d.iocoerce.fcinfo_data_out = palloc0(SizeForFunctionCallInfo(1)); |
1639 | |
|
1640 | 0 | getTypeOutputInfo(exprType((Node *) iocoerce->arg), |
1641 | 0 | &iofunc, &typisvarlena); |
1642 | 0 | fmgr_info(iofunc, scratch.d.iocoerce.finfo_out); |
1643 | 0 | fmgr_info_set_expr((Node *) node, scratch.d.iocoerce.finfo_out); |
1644 | 0 | InitFunctionCallInfoData(*scratch.d.iocoerce.fcinfo_data_out, |
1645 | 0 | scratch.d.iocoerce.finfo_out, |
1646 | 0 | 1, InvalidOid, NULL, NULL); |
1647 | | |
1648 | | /* lookup the result type's input function */ |
1649 | 0 | scratch.d.iocoerce.finfo_in = palloc0(sizeof(FmgrInfo)); |
1650 | 0 | scratch.d.iocoerce.fcinfo_data_in = palloc0(SizeForFunctionCallInfo(3)); |
1651 | |
|
1652 | 0 | getTypeInputInfo(iocoerce->resulttype, |
1653 | 0 | &iofunc, &typioparam); |
1654 | 0 | fmgr_info(iofunc, scratch.d.iocoerce.finfo_in); |
1655 | 0 | fmgr_info_set_expr((Node *) node, scratch.d.iocoerce.finfo_in); |
1656 | 0 | InitFunctionCallInfoData(*scratch.d.iocoerce.fcinfo_data_in, |
1657 | 0 | scratch.d.iocoerce.finfo_in, |
1658 | 0 | 3, InvalidOid, NULL, NULL); |
1659 | | |
1660 | | /* |
1661 | | * We can preload the second and third arguments for the input |
1662 | | * function, since they're constants. |
1663 | | */ |
1664 | 0 | fcinfo_in = scratch.d.iocoerce.fcinfo_data_in; |
1665 | 0 | fcinfo_in->args[1].value = ObjectIdGetDatum(typioparam); |
1666 | 0 | fcinfo_in->args[1].isnull = false; |
1667 | 0 | fcinfo_in->args[2].value = Int32GetDatum(-1); |
1668 | 0 | fcinfo_in->args[2].isnull = false; |
1669 | |
|
1670 | 0 | fcinfo_in->context = (Node *) state->escontext; |
1671 | |
|
1672 | 0 | ExprEvalPushStep(state, &scratch); |
1673 | 0 | break; |
1674 | 0 | } |
1675 | | |
1676 | 0 | case T_ArrayCoerceExpr: |
1677 | 0 | { |
1678 | 0 | ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node; |
1679 | 0 | Oid resultelemtype; |
1680 | 0 | ExprState *elemstate; |
1681 | | |
1682 | | /* evaluate argument into step's result area */ |
1683 | 0 | ExecInitExprRec(acoerce->arg, state, resv, resnull); |
1684 | |
|
1685 | 0 | resultelemtype = get_element_type(acoerce->resulttype); |
1686 | 0 | if (!OidIsValid(resultelemtype)) |
1687 | 0 | ereport(ERROR, |
1688 | 0 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
1689 | 0 | errmsg("target type is not an array"))); |
1690 | | |
1691 | | /* |
1692 | | * Construct a sub-expression for the per-element expression; |
1693 | | * but don't ready it until after we check it for triviality. |
1694 | | * We assume it hasn't any Var references, but does have a |
1695 | | * CaseTestExpr representing the source array element values. |
1696 | | */ |
1697 | 0 | elemstate = makeNode(ExprState); |
1698 | 0 | elemstate->expr = acoerce->elemexpr; |
1699 | 0 | elemstate->parent = state->parent; |
1700 | 0 | elemstate->ext_params = state->ext_params; |
1701 | |
|
1702 | 0 | elemstate->innermost_caseval = (Datum *) palloc(sizeof(Datum)); |
1703 | 0 | elemstate->innermost_casenull = (bool *) palloc(sizeof(bool)); |
1704 | |
|
1705 | 0 | ExecInitExprRec(acoerce->elemexpr, elemstate, |
1706 | 0 | &elemstate->resvalue, &elemstate->resnull); |
1707 | |
|
1708 | 0 | if (elemstate->steps_len == 1 && |
1709 | 0 | elemstate->steps[0].opcode == EEOP_CASE_TESTVAL) |
1710 | 0 | { |
1711 | | /* Trivial, so we need no per-element work at runtime */ |
1712 | 0 | elemstate = NULL; |
1713 | 0 | } |
1714 | 0 | else |
1715 | 0 | { |
1716 | | /* Not trivial, so append a DONE step */ |
1717 | 0 | scratch.opcode = EEOP_DONE_RETURN; |
1718 | 0 | ExprEvalPushStep(elemstate, &scratch); |
1719 | | /* and ready the subexpression */ |
1720 | 0 | ExecReadyExpr(elemstate); |
1721 | 0 | } |
1722 | |
|
1723 | 0 | scratch.opcode = EEOP_ARRAYCOERCE; |
1724 | 0 | scratch.d.arraycoerce.elemexprstate = elemstate; |
1725 | 0 | scratch.d.arraycoerce.resultelemtype = resultelemtype; |
1726 | |
|
1727 | 0 | if (elemstate) |
1728 | 0 | { |
1729 | | /* Set up workspace for array_map */ |
1730 | 0 | scratch.d.arraycoerce.amstate = |
1731 | 0 | (ArrayMapState *) palloc0(sizeof(ArrayMapState)); |
1732 | 0 | } |
1733 | 0 | else |
1734 | 0 | { |
1735 | | /* Don't need workspace if there's no subexpression */ |
1736 | 0 | scratch.d.arraycoerce.amstate = NULL; |
1737 | 0 | } |
1738 | |
|
1739 | 0 | ExprEvalPushStep(state, &scratch); |
1740 | 0 | break; |
1741 | 0 | } |
1742 | | |
1743 | 0 | case T_ConvertRowtypeExpr: |
1744 | 0 | { |
1745 | 0 | ConvertRowtypeExpr *convert = (ConvertRowtypeExpr *) node; |
1746 | 0 | ExprEvalRowtypeCache *rowcachep; |
1747 | | |
1748 | | /* cache structs must be out-of-line for space reasons */ |
1749 | 0 | rowcachep = palloc(2 * sizeof(ExprEvalRowtypeCache)); |
1750 | 0 | rowcachep[0].cacheptr = NULL; |
1751 | 0 | rowcachep[1].cacheptr = NULL; |
1752 | | |
1753 | | /* evaluate argument into step's result area */ |
1754 | 0 | ExecInitExprRec(convert->arg, state, resv, resnull); |
1755 | | |
1756 | | /* and push conversion step */ |
1757 | 0 | scratch.opcode = EEOP_CONVERT_ROWTYPE; |
1758 | 0 | scratch.d.convert_rowtype.inputtype = |
1759 | 0 | exprType((Node *) convert->arg); |
1760 | 0 | scratch.d.convert_rowtype.outputtype = convert->resulttype; |
1761 | 0 | scratch.d.convert_rowtype.incache = &rowcachep[0]; |
1762 | 0 | scratch.d.convert_rowtype.outcache = &rowcachep[1]; |
1763 | 0 | scratch.d.convert_rowtype.map = NULL; |
1764 | |
|
1765 | 0 | ExprEvalPushStep(state, &scratch); |
1766 | 0 | break; |
1767 | 0 | } |
1768 | | |
1769 | | /* note that CaseWhen expressions are handled within this block */ |
1770 | 0 | case T_CaseExpr: |
1771 | 0 | { |
1772 | 0 | CaseExpr *caseExpr = (CaseExpr *) node; |
1773 | 0 | List *adjust_jumps = NIL; |
1774 | 0 | Datum *caseval = NULL; |
1775 | 0 | bool *casenull = NULL; |
1776 | 0 | ListCell *lc; |
1777 | | |
1778 | | /* |
1779 | | * If there's a test expression, we have to evaluate it and |
1780 | | * save the value where the CaseTestExpr placeholders can find |
1781 | | * it. |
1782 | | */ |
1783 | 0 | if (caseExpr->arg != NULL) |
1784 | 0 | { |
1785 | | /* Evaluate testexpr into caseval/casenull workspace */ |
1786 | 0 | caseval = palloc(sizeof(Datum)); |
1787 | 0 | casenull = palloc(sizeof(bool)); |
1788 | |
|
1789 | 0 | ExecInitExprRec(caseExpr->arg, state, |
1790 | 0 | caseval, casenull); |
1791 | | |
1792 | | /* |
1793 | | * Since value might be read multiple times, force to R/O |
1794 | | * - but only if it could be an expanded datum. |
1795 | | */ |
1796 | 0 | if (get_typlen(exprType((Node *) caseExpr->arg)) == -1) |
1797 | 0 | { |
1798 | | /* change caseval in-place */ |
1799 | 0 | scratch.opcode = EEOP_MAKE_READONLY; |
1800 | 0 | scratch.resvalue = caseval; |
1801 | 0 | scratch.resnull = casenull; |
1802 | 0 | scratch.d.make_readonly.value = caseval; |
1803 | 0 | scratch.d.make_readonly.isnull = casenull; |
1804 | 0 | ExprEvalPushStep(state, &scratch); |
1805 | | /* restore normal settings of scratch fields */ |
1806 | 0 | scratch.resvalue = resv; |
1807 | 0 | scratch.resnull = resnull; |
1808 | 0 | } |
1809 | 0 | } |
1810 | | |
1811 | | /* |
1812 | | * Prepare to evaluate each of the WHEN clauses in turn; as |
1813 | | * soon as one is true we return the value of the |
1814 | | * corresponding THEN clause. If none are true then we return |
1815 | | * the value of the ELSE clause, or NULL if there is none. |
1816 | | */ |
1817 | 0 | foreach(lc, caseExpr->args) |
1818 | 0 | { |
1819 | 0 | CaseWhen *when = (CaseWhen *) lfirst(lc); |
1820 | 0 | Datum *save_innermost_caseval; |
1821 | 0 | bool *save_innermost_casenull; |
1822 | 0 | int whenstep; |
1823 | | |
1824 | | /* |
1825 | | * Make testexpr result available to CaseTestExpr nodes |
1826 | | * within the condition. We must save and restore prior |
1827 | | * setting of innermost_caseval fields, in case this node |
1828 | | * is itself within a larger CASE. |
1829 | | * |
1830 | | * If there's no test expression, we don't actually need |
1831 | | * to save and restore these fields; but it's less code to |
1832 | | * just do so unconditionally. |
1833 | | */ |
1834 | 0 | save_innermost_caseval = state->innermost_caseval; |
1835 | 0 | save_innermost_casenull = state->innermost_casenull; |
1836 | 0 | state->innermost_caseval = caseval; |
1837 | 0 | state->innermost_casenull = casenull; |
1838 | | |
1839 | | /* evaluate condition into CASE's result variables */ |
1840 | 0 | ExecInitExprRec(when->expr, state, resv, resnull); |
1841 | |
|
1842 | 0 | state->innermost_caseval = save_innermost_caseval; |
1843 | 0 | state->innermost_casenull = save_innermost_casenull; |
1844 | | |
1845 | | /* If WHEN result isn't true, jump to next CASE arm */ |
1846 | 0 | scratch.opcode = EEOP_JUMP_IF_NOT_TRUE; |
1847 | 0 | scratch.d.jump.jumpdone = -1; /* computed later */ |
1848 | 0 | ExprEvalPushStep(state, &scratch); |
1849 | 0 | whenstep = state->steps_len - 1; |
1850 | | |
1851 | | /* |
1852 | | * If WHEN result is true, evaluate THEN result, storing |
1853 | | * it into the CASE's result variables. |
1854 | | */ |
1855 | 0 | ExecInitExprRec(when->result, state, resv, resnull); |
1856 | | |
1857 | | /* Emit JUMP step to jump to end of CASE's code */ |
1858 | 0 | scratch.opcode = EEOP_JUMP; |
1859 | 0 | scratch.d.jump.jumpdone = -1; /* computed later */ |
1860 | 0 | ExprEvalPushStep(state, &scratch); |
1861 | | |
1862 | | /* |
1863 | | * Don't know address for that jump yet, compute once the |
1864 | | * whole CASE expression is built. |
1865 | | */ |
1866 | 0 | adjust_jumps = lappend_int(adjust_jumps, |
1867 | 0 | state->steps_len - 1); |
1868 | | |
1869 | | /* |
1870 | | * But we can set WHEN test's jump target now, to make it |
1871 | | * jump to the next WHEN subexpression or the ELSE. |
1872 | | */ |
1873 | 0 | state->steps[whenstep].d.jump.jumpdone = state->steps_len; |
1874 | 0 | } |
1875 | | |
1876 | | /* transformCaseExpr always adds a default */ |
1877 | 0 | Assert(caseExpr->defresult); |
1878 | | |
1879 | | /* evaluate ELSE expr into CASE's result variables */ |
1880 | 0 | ExecInitExprRec(caseExpr->defresult, state, |
1881 | 0 | resv, resnull); |
1882 | | |
1883 | | /* adjust jump targets */ |
1884 | 0 | foreach(lc, adjust_jumps) |
1885 | 0 | { |
1886 | 0 | ExprEvalStep *as = &state->steps[lfirst_int(lc)]; |
1887 | |
|
1888 | 0 | Assert(as->opcode == EEOP_JUMP); |
1889 | 0 | Assert(as->d.jump.jumpdone == -1); |
1890 | 0 | as->d.jump.jumpdone = state->steps_len; |
1891 | 0 | } |
1892 | |
|
1893 | 0 | break; |
1894 | 0 | } |
1895 | | |
1896 | 0 | case T_CaseTestExpr: |
1897 | 0 | { |
1898 | | /* |
1899 | | * Read from location identified by innermost_caseval. Note |
1900 | | * that innermost_caseval could be NULL, if this node isn't |
1901 | | * actually within a CaseExpr, ArrayCoerceExpr, etc structure. |
1902 | | * That can happen because some parts of the system abuse |
1903 | | * CaseTestExpr to cause a read of a value externally supplied |
1904 | | * in econtext->caseValue_datum. We'll take care of that by |
1905 | | * generating a specialized operation. |
1906 | | */ |
1907 | 0 | if (state->innermost_caseval == NULL) |
1908 | 0 | scratch.opcode = EEOP_CASE_TESTVAL_EXT; |
1909 | 0 | else |
1910 | 0 | { |
1911 | 0 | scratch.opcode = EEOP_CASE_TESTVAL; |
1912 | 0 | scratch.d.casetest.value = state->innermost_caseval; |
1913 | 0 | scratch.d.casetest.isnull = state->innermost_casenull; |
1914 | 0 | } |
1915 | 0 | ExprEvalPushStep(state, &scratch); |
1916 | 0 | break; |
1917 | 0 | } |
1918 | | |
1919 | 0 | case T_ArrayExpr: |
1920 | 0 | { |
1921 | 0 | ArrayExpr *arrayexpr = (ArrayExpr *) node; |
1922 | 0 | int nelems = list_length(arrayexpr->elements); |
1923 | 0 | ListCell *lc; |
1924 | 0 | int elemoff; |
1925 | | |
1926 | | /* |
1927 | | * Evaluate by computing each element, and then forming the |
1928 | | * array. Elements are computed into scratch arrays |
1929 | | * associated with the ARRAYEXPR step. |
1930 | | */ |
1931 | 0 | scratch.opcode = EEOP_ARRAYEXPR; |
1932 | 0 | scratch.d.arrayexpr.elemvalues = |
1933 | 0 | (Datum *) palloc(sizeof(Datum) * nelems); |
1934 | 0 | scratch.d.arrayexpr.elemnulls = |
1935 | 0 | (bool *) palloc(sizeof(bool) * nelems); |
1936 | 0 | scratch.d.arrayexpr.nelems = nelems; |
1937 | | |
1938 | | /* fill remaining fields of step */ |
1939 | 0 | scratch.d.arrayexpr.multidims = arrayexpr->multidims; |
1940 | 0 | scratch.d.arrayexpr.elemtype = arrayexpr->element_typeid; |
1941 | | |
1942 | | /* do one-time catalog lookup for type info */ |
1943 | 0 | get_typlenbyvalalign(arrayexpr->element_typeid, |
1944 | 0 | &scratch.d.arrayexpr.elemlength, |
1945 | 0 | &scratch.d.arrayexpr.elembyval, |
1946 | 0 | &scratch.d.arrayexpr.elemalign); |
1947 | | |
1948 | | /* prepare to evaluate all arguments */ |
1949 | 0 | elemoff = 0; |
1950 | 0 | foreach(lc, arrayexpr->elements) |
1951 | 0 | { |
1952 | 0 | Expr *e = (Expr *) lfirst(lc); |
1953 | |
|
1954 | 0 | ExecInitExprRec(e, state, |
1955 | 0 | &scratch.d.arrayexpr.elemvalues[elemoff], |
1956 | 0 | &scratch.d.arrayexpr.elemnulls[elemoff]); |
1957 | 0 | elemoff++; |
1958 | 0 | } |
1959 | | |
1960 | | /* and then collect all into an array */ |
1961 | 0 | ExprEvalPushStep(state, &scratch); |
1962 | 0 | break; |
1963 | 0 | } |
1964 | | |
1965 | 0 | case T_RowExpr: |
1966 | 0 | { |
1967 | 0 | RowExpr *rowexpr = (RowExpr *) node; |
1968 | 0 | int nelems = list_length(rowexpr->args); |
1969 | 0 | TupleDesc tupdesc; |
1970 | 0 | int i; |
1971 | 0 | ListCell *l; |
1972 | | |
1973 | | /* Build tupdesc to describe result tuples */ |
1974 | 0 | if (rowexpr->row_typeid == RECORDOID) |
1975 | 0 | { |
1976 | | /* generic record, use types of given expressions */ |
1977 | 0 | tupdesc = ExecTypeFromExprList(rowexpr->args); |
1978 | | /* ... but adopt RowExpr's column aliases */ |
1979 | 0 | ExecTypeSetColNames(tupdesc, rowexpr->colnames); |
1980 | | /* Bless the tupdesc so it can be looked up later */ |
1981 | 0 | BlessTupleDesc(tupdesc); |
1982 | 0 | } |
1983 | 0 | else |
1984 | 0 | { |
1985 | | /* it's been cast to a named type, use that */ |
1986 | 0 | tupdesc = lookup_rowtype_tupdesc_copy(rowexpr->row_typeid, -1); |
1987 | 0 | } |
1988 | | |
1989 | | /* |
1990 | | * In the named-type case, the tupdesc could have more columns |
1991 | | * than are in the args list, since the type might have had |
1992 | | * columns added since the ROW() was parsed. We want those |
1993 | | * extra columns to go to nulls, so we make sure that the |
1994 | | * workspace arrays are large enough and then initialize any |
1995 | | * extra columns to read as NULLs. |
1996 | | */ |
1997 | 0 | Assert(nelems <= tupdesc->natts); |
1998 | 0 | nelems = Max(nelems, tupdesc->natts); |
1999 | | |
2000 | | /* |
2001 | | * Evaluate by first building datums for each field, and then |
2002 | | * a final step forming the composite datum. |
2003 | | */ |
2004 | 0 | scratch.opcode = EEOP_ROW; |
2005 | 0 | scratch.d.row.tupdesc = tupdesc; |
2006 | | |
2007 | | /* space for the individual field datums */ |
2008 | 0 | scratch.d.row.elemvalues = |
2009 | 0 | (Datum *) palloc(sizeof(Datum) * nelems); |
2010 | 0 | scratch.d.row.elemnulls = |
2011 | 0 | (bool *) palloc(sizeof(bool) * nelems); |
2012 | | /* as explained above, make sure any extra columns are null */ |
2013 | 0 | memset(scratch.d.row.elemnulls, true, sizeof(bool) * nelems); |
2014 | | |
2015 | | /* Set up evaluation, skipping any deleted columns */ |
2016 | 0 | i = 0; |
2017 | 0 | foreach(l, rowexpr->args) |
2018 | 0 | { |
2019 | 0 | Form_pg_attribute att = TupleDescAttr(tupdesc, i); |
2020 | 0 | Expr *e = (Expr *) lfirst(l); |
2021 | |
|
2022 | 0 | if (!att->attisdropped) |
2023 | 0 | { |
2024 | | /* |
2025 | | * Guard against ALTER COLUMN TYPE on rowtype since |
2026 | | * the RowExpr was created. XXX should we check |
2027 | | * typmod too? Not sure we can be sure it'll be the |
2028 | | * same. |
2029 | | */ |
2030 | 0 | if (exprType((Node *) e) != att->atttypid) |
2031 | 0 | ereport(ERROR, |
2032 | 0 | (errcode(ERRCODE_DATATYPE_MISMATCH), |
2033 | 0 | errmsg("ROW() column has type %s instead of type %s", |
2034 | 0 | format_type_be(exprType((Node *) e)), |
2035 | 0 | format_type_be(att->atttypid)))); |
2036 | 0 | } |
2037 | 0 | else |
2038 | 0 | { |
2039 | | /* |
2040 | | * Ignore original expression and insert a NULL. We |
2041 | | * don't really care what type of NULL it is, so |
2042 | | * always make an int4 NULL. |
2043 | | */ |
2044 | 0 | e = (Expr *) makeNullConst(INT4OID, -1, InvalidOid); |
2045 | 0 | } |
2046 | | |
2047 | | /* Evaluate column expr into appropriate workspace slot */ |
2048 | 0 | ExecInitExprRec(e, state, |
2049 | 0 | &scratch.d.row.elemvalues[i], |
2050 | 0 | &scratch.d.row.elemnulls[i]); |
2051 | 0 | i++; |
2052 | 0 | } |
2053 | | |
2054 | | /* And finally build the row value */ |
2055 | 0 | ExprEvalPushStep(state, &scratch); |
2056 | 0 | break; |
2057 | 0 | } |
2058 | | |
2059 | 0 | case T_RowCompareExpr: |
2060 | 0 | { |
2061 | 0 | RowCompareExpr *rcexpr = (RowCompareExpr *) node; |
2062 | 0 | int nopers = list_length(rcexpr->opnos); |
2063 | 0 | List *adjust_jumps = NIL; |
2064 | 0 | ListCell *l_left_expr, |
2065 | 0 | *l_right_expr, |
2066 | 0 | *l_opno, |
2067 | 0 | *l_opfamily, |
2068 | 0 | *l_inputcollid; |
2069 | 0 | ListCell *lc; |
2070 | | |
2071 | | /* |
2072 | | * Iterate over each field, prepare comparisons. To handle |
2073 | | * NULL results, prepare jumps to after the expression. If a |
2074 | | * comparison yields a != 0 result, jump to the final step. |
2075 | | */ |
2076 | 0 | Assert(list_length(rcexpr->largs) == nopers); |
2077 | 0 | Assert(list_length(rcexpr->rargs) == nopers); |
2078 | 0 | Assert(list_length(rcexpr->opfamilies) == nopers); |
2079 | 0 | Assert(list_length(rcexpr->inputcollids) == nopers); |
2080 | |
|
2081 | 0 | forfive(l_left_expr, rcexpr->largs, |
2082 | 0 | l_right_expr, rcexpr->rargs, |
2083 | 0 | l_opno, rcexpr->opnos, |
2084 | 0 | l_opfamily, rcexpr->opfamilies, |
2085 | 0 | l_inputcollid, rcexpr->inputcollids) |
2086 | 0 | { |
2087 | 0 | Expr *left_expr = (Expr *) lfirst(l_left_expr); |
2088 | 0 | Expr *right_expr = (Expr *) lfirst(l_right_expr); |
2089 | 0 | Oid opno = lfirst_oid(l_opno); |
2090 | 0 | Oid opfamily = lfirst_oid(l_opfamily); |
2091 | 0 | Oid inputcollid = lfirst_oid(l_inputcollid); |
2092 | 0 | int strategy; |
2093 | 0 | Oid lefttype; |
2094 | 0 | Oid righttype; |
2095 | 0 | Oid proc; |
2096 | 0 | FmgrInfo *finfo; |
2097 | 0 | FunctionCallInfo fcinfo; |
2098 | |
|
2099 | 0 | get_op_opfamily_properties(opno, opfamily, false, |
2100 | 0 | &strategy, |
2101 | 0 | &lefttype, |
2102 | 0 | &righttype); |
2103 | 0 | proc = get_opfamily_proc(opfamily, |
2104 | 0 | lefttype, |
2105 | 0 | righttype, |
2106 | 0 | BTORDER_PROC); |
2107 | 0 | if (!OidIsValid(proc)) |
2108 | 0 | elog(ERROR, "missing support function %d(%u,%u) in opfamily %u", |
2109 | 0 | BTORDER_PROC, lefttype, righttype, opfamily); |
2110 | | |
2111 | | /* Set up the primary fmgr lookup information */ |
2112 | 0 | finfo = palloc0(sizeof(FmgrInfo)); |
2113 | 0 | fcinfo = palloc0(SizeForFunctionCallInfo(2)); |
2114 | 0 | fmgr_info(proc, finfo); |
2115 | 0 | fmgr_info_set_expr((Node *) node, finfo); |
2116 | 0 | InitFunctionCallInfoData(*fcinfo, finfo, 2, |
2117 | 0 | inputcollid, NULL, NULL); |
2118 | | |
2119 | | /* |
2120 | | * If we enforced permissions checks on index support |
2121 | | * functions, we'd need to make a check here. But the |
2122 | | * index support machinery doesn't do that, and thus |
2123 | | * neither does this code. |
2124 | | */ |
2125 | | |
2126 | | /* evaluate left and right args directly into fcinfo */ |
2127 | 0 | ExecInitExprRec(left_expr, state, |
2128 | 0 | &fcinfo->args[0].value, &fcinfo->args[0].isnull); |
2129 | 0 | ExecInitExprRec(right_expr, state, |
2130 | 0 | &fcinfo->args[1].value, &fcinfo->args[1].isnull); |
2131 | |
|
2132 | 0 | scratch.opcode = EEOP_ROWCOMPARE_STEP; |
2133 | 0 | scratch.d.rowcompare_step.finfo = finfo; |
2134 | 0 | scratch.d.rowcompare_step.fcinfo_data = fcinfo; |
2135 | 0 | scratch.d.rowcompare_step.fn_addr = finfo->fn_addr; |
2136 | | /* jump targets filled below */ |
2137 | 0 | scratch.d.rowcompare_step.jumpnull = -1; |
2138 | 0 | scratch.d.rowcompare_step.jumpdone = -1; |
2139 | |
|
2140 | 0 | ExprEvalPushStep(state, &scratch); |
2141 | 0 | adjust_jumps = lappend_int(adjust_jumps, |
2142 | 0 | state->steps_len - 1); |
2143 | 0 | } |
2144 | | |
2145 | | /* |
2146 | | * We could have a zero-column rowtype, in which case the rows |
2147 | | * necessarily compare equal. |
2148 | | */ |
2149 | 0 | if (nopers == 0) |
2150 | 0 | { |
2151 | 0 | scratch.opcode = EEOP_CONST; |
2152 | 0 | scratch.d.constval.value = Int32GetDatum(0); |
2153 | 0 | scratch.d.constval.isnull = false; |
2154 | 0 | ExprEvalPushStep(state, &scratch); |
2155 | 0 | } |
2156 | | |
2157 | | /* Finally, examine the last comparison result */ |
2158 | 0 | scratch.opcode = EEOP_ROWCOMPARE_FINAL; |
2159 | 0 | scratch.d.rowcompare_final.cmptype = rcexpr->cmptype; |
2160 | 0 | ExprEvalPushStep(state, &scratch); |
2161 | | |
2162 | | /* adjust jump targets */ |
2163 | 0 | foreach(lc, adjust_jumps) |
2164 | 0 | { |
2165 | 0 | ExprEvalStep *as = &state->steps[lfirst_int(lc)]; |
2166 | |
|
2167 | 0 | Assert(as->opcode == EEOP_ROWCOMPARE_STEP); |
2168 | 0 | Assert(as->d.rowcompare_step.jumpdone == -1); |
2169 | 0 | Assert(as->d.rowcompare_step.jumpnull == -1); |
2170 | | |
2171 | | /* jump to comparison evaluation */ |
2172 | 0 | as->d.rowcompare_step.jumpdone = state->steps_len - 1; |
2173 | | /* jump to the following expression */ |
2174 | 0 | as->d.rowcompare_step.jumpnull = state->steps_len; |
2175 | 0 | } |
2176 | |
|
2177 | 0 | break; |
2178 | 0 | } |
2179 | | |
2180 | 0 | case T_CoalesceExpr: |
2181 | 0 | { |
2182 | 0 | CoalesceExpr *coalesce = (CoalesceExpr *) node; |
2183 | 0 | List *adjust_jumps = NIL; |
2184 | 0 | ListCell *lc; |
2185 | | |
2186 | | /* We assume there's at least one arg */ |
2187 | 0 | Assert(coalesce->args != NIL); |
2188 | | |
2189 | | /* |
2190 | | * Prepare evaluation of all coalesced arguments, after each |
2191 | | * one push a step that short-circuits if not null. |
2192 | | */ |
2193 | 0 | foreach(lc, coalesce->args) |
2194 | 0 | { |
2195 | 0 | Expr *e = (Expr *) lfirst(lc); |
2196 | | |
2197 | | /* evaluate argument, directly into result datum */ |
2198 | 0 | ExecInitExprRec(e, state, resv, resnull); |
2199 | | |
2200 | | /* if it's not null, skip to end of COALESCE expr */ |
2201 | 0 | scratch.opcode = EEOP_JUMP_IF_NOT_NULL; |
2202 | 0 | scratch.d.jump.jumpdone = -1; /* adjust later */ |
2203 | 0 | ExprEvalPushStep(state, &scratch); |
2204 | |
|
2205 | 0 | adjust_jumps = lappend_int(adjust_jumps, |
2206 | 0 | state->steps_len - 1); |
2207 | 0 | } |
2208 | | |
2209 | | /* |
2210 | | * No need to add a constant NULL return - we only can get to |
2211 | | * the end of the expression if a NULL already is being |
2212 | | * returned. |
2213 | | */ |
2214 | | |
2215 | | /* adjust jump targets */ |
2216 | 0 | foreach(lc, adjust_jumps) |
2217 | 0 | { |
2218 | 0 | ExprEvalStep *as = &state->steps[lfirst_int(lc)]; |
2219 | |
|
2220 | 0 | Assert(as->opcode == EEOP_JUMP_IF_NOT_NULL); |
2221 | 0 | Assert(as->d.jump.jumpdone == -1); |
2222 | 0 | as->d.jump.jumpdone = state->steps_len; |
2223 | 0 | } |
2224 | |
|
2225 | 0 | break; |
2226 | 0 | } |
2227 | | |
2228 | 0 | case T_MinMaxExpr: |
2229 | 0 | { |
2230 | 0 | MinMaxExpr *minmaxexpr = (MinMaxExpr *) node; |
2231 | 0 | int nelems = list_length(minmaxexpr->args); |
2232 | 0 | TypeCacheEntry *typentry; |
2233 | 0 | FmgrInfo *finfo; |
2234 | 0 | FunctionCallInfo fcinfo; |
2235 | 0 | ListCell *lc; |
2236 | 0 | int off; |
2237 | | |
2238 | | /* Look up the btree comparison function for the datatype */ |
2239 | 0 | typentry = lookup_type_cache(minmaxexpr->minmaxtype, |
2240 | 0 | TYPECACHE_CMP_PROC); |
2241 | 0 | if (!OidIsValid(typentry->cmp_proc)) |
2242 | 0 | ereport(ERROR, |
2243 | 0 | (errcode(ERRCODE_UNDEFINED_FUNCTION), |
2244 | 0 | errmsg("could not identify a comparison function for type %s", |
2245 | 0 | format_type_be(minmaxexpr->minmaxtype)))); |
2246 | | |
2247 | | /* |
2248 | | * If we enforced permissions checks on index support |
2249 | | * functions, we'd need to make a check here. But the index |
2250 | | * support machinery doesn't do that, and thus neither does |
2251 | | * this code. |
2252 | | */ |
2253 | | |
2254 | | /* Perform function lookup */ |
2255 | 0 | finfo = palloc0(sizeof(FmgrInfo)); |
2256 | 0 | fcinfo = palloc0(SizeForFunctionCallInfo(2)); |
2257 | 0 | fmgr_info(typentry->cmp_proc, finfo); |
2258 | 0 | fmgr_info_set_expr((Node *) node, finfo); |
2259 | 0 | InitFunctionCallInfoData(*fcinfo, finfo, 2, |
2260 | 0 | minmaxexpr->inputcollid, NULL, NULL); |
2261 | |
|
2262 | 0 | scratch.opcode = EEOP_MINMAX; |
2263 | | /* allocate space to store arguments */ |
2264 | 0 | scratch.d.minmax.values = |
2265 | 0 | (Datum *) palloc(sizeof(Datum) * nelems); |
2266 | 0 | scratch.d.minmax.nulls = |
2267 | 0 | (bool *) palloc(sizeof(bool) * nelems); |
2268 | 0 | scratch.d.minmax.nelems = nelems; |
2269 | |
|
2270 | 0 | scratch.d.minmax.op = minmaxexpr->op; |
2271 | 0 | scratch.d.minmax.finfo = finfo; |
2272 | 0 | scratch.d.minmax.fcinfo_data = fcinfo; |
2273 | | |
2274 | | /* evaluate expressions into minmax->values/nulls */ |
2275 | 0 | off = 0; |
2276 | 0 | foreach(lc, minmaxexpr->args) |
2277 | 0 | { |
2278 | 0 | Expr *e = (Expr *) lfirst(lc); |
2279 | |
|
2280 | 0 | ExecInitExprRec(e, state, |
2281 | 0 | &scratch.d.minmax.values[off], |
2282 | 0 | &scratch.d.minmax.nulls[off]); |
2283 | 0 | off++; |
2284 | 0 | } |
2285 | | |
2286 | | /* and push the final comparison */ |
2287 | 0 | ExprEvalPushStep(state, &scratch); |
2288 | 0 | break; |
2289 | 0 | } |
2290 | | |
2291 | 0 | case T_SQLValueFunction: |
2292 | 0 | { |
2293 | 0 | SQLValueFunction *svf = (SQLValueFunction *) node; |
2294 | |
|
2295 | 0 | scratch.opcode = EEOP_SQLVALUEFUNCTION; |
2296 | 0 | scratch.d.sqlvaluefunction.svf = svf; |
2297 | |
|
2298 | 0 | ExprEvalPushStep(state, &scratch); |
2299 | 0 | break; |
2300 | 0 | } |
2301 | | |
2302 | 0 | case T_XmlExpr: |
2303 | 0 | { |
2304 | 0 | XmlExpr *xexpr = (XmlExpr *) node; |
2305 | 0 | int nnamed = list_length(xexpr->named_args); |
2306 | 0 | int nargs = list_length(xexpr->args); |
2307 | 0 | int off; |
2308 | 0 | ListCell *arg; |
2309 | |
|
2310 | 0 | scratch.opcode = EEOP_XMLEXPR; |
2311 | 0 | scratch.d.xmlexpr.xexpr = xexpr; |
2312 | | |
2313 | | /* allocate space for storing all the arguments */ |
2314 | 0 | if (nnamed) |
2315 | 0 | { |
2316 | 0 | scratch.d.xmlexpr.named_argvalue = |
2317 | 0 | (Datum *) palloc(sizeof(Datum) * nnamed); |
2318 | 0 | scratch.d.xmlexpr.named_argnull = |
2319 | 0 | (bool *) palloc(sizeof(bool) * nnamed); |
2320 | 0 | } |
2321 | 0 | else |
2322 | 0 | { |
2323 | 0 | scratch.d.xmlexpr.named_argvalue = NULL; |
2324 | 0 | scratch.d.xmlexpr.named_argnull = NULL; |
2325 | 0 | } |
2326 | |
|
2327 | 0 | if (nargs) |
2328 | 0 | { |
2329 | 0 | scratch.d.xmlexpr.argvalue = |
2330 | 0 | (Datum *) palloc(sizeof(Datum) * nargs); |
2331 | 0 | scratch.d.xmlexpr.argnull = |
2332 | 0 | (bool *) palloc(sizeof(bool) * nargs); |
2333 | 0 | } |
2334 | 0 | else |
2335 | 0 | { |
2336 | 0 | scratch.d.xmlexpr.argvalue = NULL; |
2337 | 0 | scratch.d.xmlexpr.argnull = NULL; |
2338 | 0 | } |
2339 | | |
2340 | | /* prepare argument execution */ |
2341 | 0 | off = 0; |
2342 | 0 | foreach(arg, xexpr->named_args) |
2343 | 0 | { |
2344 | 0 | Expr *e = (Expr *) lfirst(arg); |
2345 | |
|
2346 | 0 | ExecInitExprRec(e, state, |
2347 | 0 | &scratch.d.xmlexpr.named_argvalue[off], |
2348 | 0 | &scratch.d.xmlexpr.named_argnull[off]); |
2349 | 0 | off++; |
2350 | 0 | } |
2351 | |
|
2352 | 0 | off = 0; |
2353 | 0 | foreach(arg, xexpr->args) |
2354 | 0 | { |
2355 | 0 | Expr *e = (Expr *) lfirst(arg); |
2356 | |
|
2357 | 0 | ExecInitExprRec(e, state, |
2358 | 0 | &scratch.d.xmlexpr.argvalue[off], |
2359 | 0 | &scratch.d.xmlexpr.argnull[off]); |
2360 | 0 | off++; |
2361 | 0 | } |
2362 | | |
2363 | | /* and evaluate the actual XML expression */ |
2364 | 0 | ExprEvalPushStep(state, &scratch); |
2365 | 0 | break; |
2366 | 0 | } |
2367 | | |
2368 | 0 | case T_JsonValueExpr: |
2369 | 0 | { |
2370 | 0 | JsonValueExpr *jve = (JsonValueExpr *) node; |
2371 | |
|
2372 | 0 | Assert(jve->raw_expr != NULL); |
2373 | 0 | ExecInitExprRec(jve->raw_expr, state, resv, resnull); |
2374 | 0 | Assert(jve->formatted_expr != NULL); |
2375 | 0 | ExecInitExprRec(jve->formatted_expr, state, resv, resnull); |
2376 | 0 | break; |
2377 | 0 | } |
2378 | | |
2379 | 0 | case T_JsonConstructorExpr: |
2380 | 0 | { |
2381 | 0 | JsonConstructorExpr *ctor = (JsonConstructorExpr *) node; |
2382 | 0 | List *args = ctor->args; |
2383 | 0 | ListCell *lc; |
2384 | 0 | int nargs = list_length(args); |
2385 | 0 | int argno = 0; |
2386 | |
|
2387 | 0 | if (ctor->func) |
2388 | 0 | { |
2389 | 0 | ExecInitExprRec(ctor->func, state, resv, resnull); |
2390 | 0 | } |
2391 | 0 | else if ((ctor->type == JSCTOR_JSON_PARSE && !ctor->unique) || |
2392 | 0 | ctor->type == JSCTOR_JSON_SERIALIZE) |
2393 | 0 | { |
2394 | | /* Use the value of the first argument as result */ |
2395 | 0 | ExecInitExprRec(linitial(args), state, resv, resnull); |
2396 | 0 | } |
2397 | 0 | else |
2398 | 0 | { |
2399 | 0 | JsonConstructorExprState *jcstate; |
2400 | |
|
2401 | 0 | jcstate = palloc0(sizeof(JsonConstructorExprState)); |
2402 | |
|
2403 | 0 | scratch.opcode = EEOP_JSON_CONSTRUCTOR; |
2404 | 0 | scratch.d.json_constructor.jcstate = jcstate; |
2405 | |
|
2406 | 0 | jcstate->constructor = ctor; |
2407 | 0 | jcstate->arg_values = (Datum *) palloc(sizeof(Datum) * nargs); |
2408 | 0 | jcstate->arg_nulls = (bool *) palloc(sizeof(bool) * nargs); |
2409 | 0 | jcstate->arg_types = (Oid *) palloc(sizeof(Oid) * nargs); |
2410 | 0 | jcstate->nargs = nargs; |
2411 | |
|
2412 | 0 | foreach(lc, args) |
2413 | 0 | { |
2414 | 0 | Expr *arg = (Expr *) lfirst(lc); |
2415 | |
|
2416 | 0 | jcstate->arg_types[argno] = exprType((Node *) arg); |
2417 | |
|
2418 | 0 | if (IsA(arg, Const)) |
2419 | 0 | { |
2420 | | /* Don't evaluate const arguments every round */ |
2421 | 0 | Const *con = (Const *) arg; |
2422 | |
|
2423 | 0 | jcstate->arg_values[argno] = con->constvalue; |
2424 | 0 | jcstate->arg_nulls[argno] = con->constisnull; |
2425 | 0 | } |
2426 | 0 | else |
2427 | 0 | { |
2428 | 0 | ExecInitExprRec(arg, state, |
2429 | 0 | &jcstate->arg_values[argno], |
2430 | 0 | &jcstate->arg_nulls[argno]); |
2431 | 0 | } |
2432 | 0 | argno++; |
2433 | 0 | } |
2434 | | |
2435 | | /* prepare type cache for datum_to_json[b]() */ |
2436 | 0 | if (ctor->type == JSCTOR_JSON_SCALAR) |
2437 | 0 | { |
2438 | 0 | bool is_jsonb = |
2439 | 0 | ctor->returning->format->format_type == JS_FORMAT_JSONB; |
2440 | |
|
2441 | 0 | jcstate->arg_type_cache = |
2442 | 0 | palloc(sizeof(*jcstate->arg_type_cache) * nargs); |
2443 | |
|
2444 | 0 | for (int i = 0; i < nargs; i++) |
2445 | 0 | { |
2446 | 0 | JsonTypeCategory category; |
2447 | 0 | Oid outfuncid; |
2448 | 0 | Oid typid = jcstate->arg_types[i]; |
2449 | |
|
2450 | 0 | json_categorize_type(typid, is_jsonb, |
2451 | 0 | &category, &outfuncid); |
2452 | |
|
2453 | 0 | jcstate->arg_type_cache[i].outfuncid = outfuncid; |
2454 | 0 | jcstate->arg_type_cache[i].category = (int) category; |
2455 | 0 | } |
2456 | 0 | } |
2457 | |
|
2458 | 0 | ExprEvalPushStep(state, &scratch); |
2459 | 0 | } |
2460 | |
|
2461 | 0 | if (ctor->coercion) |
2462 | 0 | { |
2463 | 0 | Datum *innermost_caseval = state->innermost_caseval; |
2464 | 0 | bool *innermost_isnull = state->innermost_casenull; |
2465 | |
|
2466 | 0 | state->innermost_caseval = resv; |
2467 | 0 | state->innermost_casenull = resnull; |
2468 | |
|
2469 | 0 | ExecInitExprRec(ctor->coercion, state, resv, resnull); |
2470 | |
|
2471 | 0 | state->innermost_caseval = innermost_caseval; |
2472 | 0 | state->innermost_casenull = innermost_isnull; |
2473 | 0 | } |
2474 | 0 | } |
2475 | 0 | break; |
2476 | | |
2477 | 0 | case T_JsonIsPredicate: |
2478 | 0 | { |
2479 | 0 | JsonIsPredicate *pred = (JsonIsPredicate *) node; |
2480 | |
|
2481 | 0 | ExecInitExprRec((Expr *) pred->expr, state, resv, resnull); |
2482 | |
|
2483 | 0 | scratch.opcode = EEOP_IS_JSON; |
2484 | 0 | scratch.d.is_json.pred = pred; |
2485 | |
|
2486 | 0 | ExprEvalPushStep(state, &scratch); |
2487 | 0 | break; |
2488 | 0 | } |
2489 | | |
2490 | 0 | case T_JsonExpr: |
2491 | 0 | { |
2492 | 0 | JsonExpr *jsexpr = castNode(JsonExpr, node); |
2493 | | |
2494 | | /* |
2495 | | * No need to initialize a full JsonExprState For |
2496 | | * JSON_TABLE(), because the upstream caller tfuncFetchRows() |
2497 | | * is only interested in the value of formatted_expr. |
2498 | | */ |
2499 | 0 | if (jsexpr->op == JSON_TABLE_OP) |
2500 | 0 | ExecInitExprRec((Expr *) jsexpr->formatted_expr, state, |
2501 | 0 | resv, resnull); |
2502 | 0 | else |
2503 | 0 | ExecInitJsonExpr(jsexpr, state, resv, resnull, &scratch); |
2504 | 0 | break; |
2505 | 0 | } |
2506 | | |
2507 | 0 | case T_NullTest: |
2508 | 0 | { |
2509 | 0 | NullTest *ntest = (NullTest *) node; |
2510 | |
|
2511 | 0 | if (ntest->nulltesttype == IS_NULL) |
2512 | 0 | { |
2513 | 0 | if (ntest->argisrow) |
2514 | 0 | scratch.opcode = EEOP_NULLTEST_ROWISNULL; |
2515 | 0 | else |
2516 | 0 | scratch.opcode = EEOP_NULLTEST_ISNULL; |
2517 | 0 | } |
2518 | 0 | else if (ntest->nulltesttype == IS_NOT_NULL) |
2519 | 0 | { |
2520 | 0 | if (ntest->argisrow) |
2521 | 0 | scratch.opcode = EEOP_NULLTEST_ROWISNOTNULL; |
2522 | 0 | else |
2523 | 0 | scratch.opcode = EEOP_NULLTEST_ISNOTNULL; |
2524 | 0 | } |
2525 | 0 | else |
2526 | 0 | { |
2527 | 0 | elog(ERROR, "unrecognized nulltesttype: %d", |
2528 | 0 | (int) ntest->nulltesttype); |
2529 | 0 | } |
2530 | | /* initialize cache in case it's a row test */ |
2531 | 0 | scratch.d.nulltest_row.rowcache.cacheptr = NULL; |
2532 | | |
2533 | | /* first evaluate argument into result variable */ |
2534 | 0 | ExecInitExprRec(ntest->arg, state, |
2535 | 0 | resv, resnull); |
2536 | | |
2537 | | /* then push the test of that argument */ |
2538 | 0 | ExprEvalPushStep(state, &scratch); |
2539 | 0 | break; |
2540 | 0 | } |
2541 | | |
2542 | 0 | case T_BooleanTest: |
2543 | 0 | { |
2544 | 0 | BooleanTest *btest = (BooleanTest *) node; |
2545 | | |
2546 | | /* |
2547 | | * Evaluate argument, directly into result datum. That's ok, |
2548 | | * because resv/resnull is definitely not used anywhere else, |
2549 | | * and will get overwritten by the below EEOP_BOOLTEST_IS_* |
2550 | | * step. |
2551 | | */ |
2552 | 0 | ExecInitExprRec(btest->arg, state, resv, resnull); |
2553 | |
|
2554 | 0 | switch (btest->booltesttype) |
2555 | 0 | { |
2556 | 0 | case IS_TRUE: |
2557 | 0 | scratch.opcode = EEOP_BOOLTEST_IS_TRUE; |
2558 | 0 | break; |
2559 | 0 | case IS_NOT_TRUE: |
2560 | 0 | scratch.opcode = EEOP_BOOLTEST_IS_NOT_TRUE; |
2561 | 0 | break; |
2562 | 0 | case IS_FALSE: |
2563 | 0 | scratch.opcode = EEOP_BOOLTEST_IS_FALSE; |
2564 | 0 | break; |
2565 | 0 | case IS_NOT_FALSE: |
2566 | 0 | scratch.opcode = EEOP_BOOLTEST_IS_NOT_FALSE; |
2567 | 0 | break; |
2568 | 0 | case IS_UNKNOWN: |
2569 | | /* Same as scalar IS NULL test */ |
2570 | 0 | scratch.opcode = EEOP_NULLTEST_ISNULL; |
2571 | 0 | break; |
2572 | 0 | case IS_NOT_UNKNOWN: |
2573 | | /* Same as scalar IS NOT NULL test */ |
2574 | 0 | scratch.opcode = EEOP_NULLTEST_ISNOTNULL; |
2575 | 0 | break; |
2576 | 0 | default: |
2577 | 0 | elog(ERROR, "unrecognized booltesttype: %d", |
2578 | 0 | (int) btest->booltesttype); |
2579 | 0 | } |
2580 | | |
2581 | 0 | ExprEvalPushStep(state, &scratch); |
2582 | 0 | break; |
2583 | 0 | } |
2584 | | |
2585 | 0 | case T_CoerceToDomain: |
2586 | 0 | { |
2587 | 0 | CoerceToDomain *ctest = (CoerceToDomain *) node; |
2588 | |
|
2589 | 0 | ExecInitCoerceToDomain(&scratch, ctest, state, |
2590 | 0 | resv, resnull); |
2591 | 0 | break; |
2592 | 0 | } |
2593 | | |
2594 | 0 | case T_CoerceToDomainValue: |
2595 | 0 | { |
2596 | | /* |
2597 | | * Read from location identified by innermost_domainval. Note |
2598 | | * that innermost_domainval could be NULL, if we're compiling |
2599 | | * a standalone domain check rather than one embedded in a |
2600 | | * larger expression. In that case we must read from |
2601 | | * econtext->domainValue_datum. We'll take care of that by |
2602 | | * generating a specialized operation. |
2603 | | */ |
2604 | 0 | if (state->innermost_domainval == NULL) |
2605 | 0 | scratch.opcode = EEOP_DOMAIN_TESTVAL_EXT; |
2606 | 0 | else |
2607 | 0 | { |
2608 | 0 | scratch.opcode = EEOP_DOMAIN_TESTVAL; |
2609 | | /* we share instruction union variant with case testval */ |
2610 | 0 | scratch.d.casetest.value = state->innermost_domainval; |
2611 | 0 | scratch.d.casetest.isnull = state->innermost_domainnull; |
2612 | 0 | } |
2613 | 0 | ExprEvalPushStep(state, &scratch); |
2614 | 0 | break; |
2615 | 0 | } |
2616 | | |
2617 | 0 | case T_CurrentOfExpr: |
2618 | 0 | { |
2619 | 0 | scratch.opcode = EEOP_CURRENTOFEXPR; |
2620 | 0 | ExprEvalPushStep(state, &scratch); |
2621 | 0 | break; |
2622 | 0 | } |
2623 | | |
2624 | 0 | case T_NextValueExpr: |
2625 | 0 | { |
2626 | 0 | NextValueExpr *nve = (NextValueExpr *) node; |
2627 | |
|
2628 | 0 | scratch.opcode = EEOP_NEXTVALUEEXPR; |
2629 | 0 | scratch.d.nextvalueexpr.seqid = nve->seqid; |
2630 | 0 | scratch.d.nextvalueexpr.seqtypid = nve->typeId; |
2631 | |
|
2632 | 0 | ExprEvalPushStep(state, &scratch); |
2633 | 0 | break; |
2634 | 0 | } |
2635 | | |
2636 | 0 | case T_ReturningExpr: |
2637 | 0 | { |
2638 | 0 | ReturningExpr *rexpr = (ReturningExpr *) node; |
2639 | 0 | int retstep; |
2640 | | |
2641 | | /* Skip expression evaluation if OLD/NEW row doesn't exist */ |
2642 | 0 | scratch.opcode = EEOP_RETURNINGEXPR; |
2643 | 0 | scratch.d.returningexpr.nullflag = rexpr->retold ? |
2644 | 0 | EEO_FLAG_OLD_IS_NULL : EEO_FLAG_NEW_IS_NULL; |
2645 | 0 | scratch.d.returningexpr.jumpdone = -1; /* set below */ |
2646 | 0 | ExprEvalPushStep(state, &scratch); |
2647 | 0 | retstep = state->steps_len - 1; |
2648 | | |
2649 | | /* Steps to evaluate expression to return */ |
2650 | 0 | ExecInitExprRec(rexpr->retexpr, state, resv, resnull); |
2651 | | |
2652 | | /* Jump target used if OLD/NEW row doesn't exist */ |
2653 | 0 | state->steps[retstep].d.returningexpr.jumpdone = state->steps_len; |
2654 | | |
2655 | | /* Update ExprState flags */ |
2656 | 0 | if (rexpr->retold) |
2657 | 0 | state->flags |= EEO_FLAG_HAS_OLD; |
2658 | 0 | else |
2659 | 0 | state->flags |= EEO_FLAG_HAS_NEW; |
2660 | |
|
2661 | 0 | break; |
2662 | 0 | } |
2663 | | |
2664 | 0 | default: |
2665 | 0 | elog(ERROR, "unrecognized node type: %d", |
2666 | 0 | (int) nodeTag(node)); |
2667 | 0 | break; |
2668 | 0 | } |
2669 | 0 | } |
2670 | | |
2671 | | /* |
2672 | | * Add another expression evaluation step to ExprState->steps. |
2673 | | * |
2674 | | * Note that this potentially re-allocates es->steps, therefore no pointer |
2675 | | * into that array may be used while the expression is still being built. |
2676 | | */ |
2677 | | void |
2678 | | ExprEvalPushStep(ExprState *es, const ExprEvalStep *s) |
2679 | 0 | { |
2680 | 0 | if (es->steps_alloc == 0) |
2681 | 0 | { |
2682 | 0 | es->steps_alloc = 16; |
2683 | 0 | es->steps = palloc(sizeof(ExprEvalStep) * es->steps_alloc); |
2684 | 0 | } |
2685 | 0 | else if (es->steps_alloc == es->steps_len) |
2686 | 0 | { |
2687 | 0 | es->steps_alloc *= 2; |
2688 | 0 | es->steps = repalloc(es->steps, |
2689 | 0 | sizeof(ExprEvalStep) * es->steps_alloc); |
2690 | 0 | } |
2691 | |
|
2692 | 0 | memcpy(&es->steps[es->steps_len++], s, sizeof(ExprEvalStep)); |
2693 | 0 | } |
2694 | | |
2695 | | /* |
2696 | | * Perform setup necessary for the evaluation of a function-like expression, |
2697 | | * appending argument evaluation steps to the steps list in *state, and |
2698 | | * setting up *scratch so it is ready to be pushed. |
2699 | | * |
2700 | | * *scratch is not pushed here, so that callers may override the opcode, |
2701 | | * which is useful for function-like cases like DISTINCT. |
2702 | | */ |
2703 | | static void |
2704 | | ExecInitFunc(ExprEvalStep *scratch, Expr *node, List *args, Oid funcid, |
2705 | | Oid inputcollid, ExprState *state) |
2706 | 0 | { |
2707 | 0 | int nargs = list_length(args); |
2708 | 0 | AclResult aclresult; |
2709 | 0 | FmgrInfo *flinfo; |
2710 | 0 | FunctionCallInfo fcinfo; |
2711 | 0 | int argno; |
2712 | 0 | ListCell *lc; |
2713 | | |
2714 | | /* Check permission to call function */ |
2715 | 0 | aclresult = object_aclcheck(ProcedureRelationId, funcid, GetUserId(), ACL_EXECUTE); |
2716 | 0 | if (aclresult != ACLCHECK_OK) |
2717 | 0 | aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(funcid)); |
2718 | 0 | InvokeFunctionExecuteHook(funcid); |
2719 | | |
2720 | | /* |
2721 | | * Safety check on nargs. Under normal circumstances this should never |
2722 | | * fail, as parser should check sooner. But possibly it might fail if |
2723 | | * server has been compiled with FUNC_MAX_ARGS smaller than some functions |
2724 | | * declared in pg_proc? |
2725 | | */ |
2726 | 0 | if (nargs > FUNC_MAX_ARGS) |
2727 | 0 | ereport(ERROR, |
2728 | 0 | (errcode(ERRCODE_TOO_MANY_ARGUMENTS), |
2729 | 0 | errmsg_plural("cannot pass more than %d argument to a function", |
2730 | 0 | "cannot pass more than %d arguments to a function", |
2731 | 0 | FUNC_MAX_ARGS, |
2732 | 0 | FUNC_MAX_ARGS))); |
2733 | | |
2734 | | /* Allocate function lookup data and parameter workspace for this call */ |
2735 | 0 | scratch->d.func.finfo = palloc0(sizeof(FmgrInfo)); |
2736 | 0 | scratch->d.func.fcinfo_data = palloc0(SizeForFunctionCallInfo(nargs)); |
2737 | 0 | flinfo = scratch->d.func.finfo; |
2738 | 0 | fcinfo = scratch->d.func.fcinfo_data; |
2739 | | |
2740 | | /* Set up the primary fmgr lookup information */ |
2741 | 0 | fmgr_info(funcid, flinfo); |
2742 | 0 | fmgr_info_set_expr((Node *) node, flinfo); |
2743 | | |
2744 | | /* Initialize function call parameter structure too */ |
2745 | 0 | InitFunctionCallInfoData(*fcinfo, flinfo, |
2746 | 0 | nargs, inputcollid, NULL, NULL); |
2747 | | |
2748 | | /* Keep extra copies of this info to save an indirection at runtime */ |
2749 | 0 | scratch->d.func.fn_addr = flinfo->fn_addr; |
2750 | 0 | scratch->d.func.nargs = nargs; |
2751 | | |
2752 | | /* We only support non-set functions here */ |
2753 | 0 | if (flinfo->fn_retset) |
2754 | 0 | ereport(ERROR, |
2755 | 0 | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
2756 | 0 | errmsg("set-valued function called in context that cannot accept a set"), |
2757 | 0 | state->parent ? |
2758 | 0 | executor_errposition(state->parent->state, |
2759 | 0 | exprLocation((Node *) node)) : 0)); |
2760 | | |
2761 | | /* Build code to evaluate arguments directly into the fcinfo struct */ |
2762 | 0 | argno = 0; |
2763 | 0 | foreach(lc, args) |
2764 | 0 | { |
2765 | 0 | Expr *arg = (Expr *) lfirst(lc); |
2766 | |
|
2767 | 0 | if (IsA(arg, Const)) |
2768 | 0 | { |
2769 | | /* |
2770 | | * Don't evaluate const arguments every round; especially |
2771 | | * interesting for constants in comparisons. |
2772 | | */ |
2773 | 0 | Const *con = (Const *) arg; |
2774 | |
|
2775 | 0 | fcinfo->args[argno].value = con->constvalue; |
2776 | 0 | fcinfo->args[argno].isnull = con->constisnull; |
2777 | 0 | } |
2778 | 0 | else |
2779 | 0 | { |
2780 | 0 | ExecInitExprRec(arg, state, |
2781 | 0 | &fcinfo->args[argno].value, |
2782 | 0 | &fcinfo->args[argno].isnull); |
2783 | 0 | } |
2784 | 0 | argno++; |
2785 | 0 | } |
2786 | | |
2787 | | /* Insert appropriate opcode depending on strictness and stats level */ |
2788 | 0 | if (pgstat_track_functions <= flinfo->fn_stats) |
2789 | 0 | { |
2790 | 0 | if (flinfo->fn_strict && nargs > 0) |
2791 | 0 | { |
2792 | | /* Choose nargs optimized implementation if available. */ |
2793 | 0 | if (nargs == 1) |
2794 | 0 | scratch->opcode = EEOP_FUNCEXPR_STRICT_1; |
2795 | 0 | else if (nargs == 2) |
2796 | 0 | scratch->opcode = EEOP_FUNCEXPR_STRICT_2; |
2797 | 0 | else |
2798 | 0 | scratch->opcode = EEOP_FUNCEXPR_STRICT; |
2799 | 0 | } |
2800 | 0 | else |
2801 | 0 | scratch->opcode = EEOP_FUNCEXPR; |
2802 | 0 | } |
2803 | 0 | else |
2804 | 0 | { |
2805 | 0 | if (flinfo->fn_strict && nargs > 0) |
2806 | 0 | scratch->opcode = EEOP_FUNCEXPR_STRICT_FUSAGE; |
2807 | 0 | else |
2808 | 0 | scratch->opcode = EEOP_FUNCEXPR_FUSAGE; |
2809 | 0 | } |
2810 | 0 | } |
2811 | | |
2812 | | /* |
2813 | | * Append the steps necessary for the evaluation of a SubPlan node to |
2814 | | * ExprState->steps. |
2815 | | * |
2816 | | * subplan - SubPlan expression to evaluate |
2817 | | * state - ExprState to whose ->steps to append the necessary operations |
2818 | | * resv / resnull - where to store the result of the node into |
2819 | | */ |
2820 | | static void |
2821 | | ExecInitSubPlanExpr(SubPlan *subplan, |
2822 | | ExprState *state, |
2823 | | Datum *resv, bool *resnull) |
2824 | 0 | { |
2825 | 0 | ExprEvalStep scratch = {0}; |
2826 | 0 | SubPlanState *sstate; |
2827 | 0 | ListCell *pvar; |
2828 | 0 | ListCell *l; |
2829 | |
|
2830 | 0 | if (!state->parent) |
2831 | 0 | elog(ERROR, "SubPlan found with no parent plan"); |
2832 | | |
2833 | | /* |
2834 | | * Generate steps to evaluate input arguments for the subplan. |
2835 | | * |
2836 | | * We evaluate the argument expressions into ExprState's resvalue/resnull, |
2837 | | * and then use PARAM_SET to update the parameter. We do that, instead of |
2838 | | * evaluating directly into the param, to avoid depending on the pointer |
2839 | | * value remaining stable / being included in the generated expression. No |
2840 | | * danger of conflicts with other uses of resvalue/resnull as storing and |
2841 | | * using the value always is in subsequent steps. |
2842 | | * |
2843 | | * Any calculation we have to do can be done in the parent econtext, since |
2844 | | * the Param values don't need to have per-query lifetime. |
2845 | | */ |
2846 | 0 | Assert(list_length(subplan->parParam) == list_length(subplan->args)); |
2847 | 0 | forboth(l, subplan->parParam, pvar, subplan->args) |
2848 | 0 | { |
2849 | 0 | int paramid = lfirst_int(l); |
2850 | 0 | Expr *arg = (Expr *) lfirst(pvar); |
2851 | |
|
2852 | 0 | ExecInitExprRec(arg, state, |
2853 | 0 | &state->resvalue, &state->resnull); |
2854 | |
|
2855 | 0 | scratch.opcode = EEOP_PARAM_SET; |
2856 | 0 | scratch.d.param.paramid = paramid; |
2857 | | /* paramtype's not actually used, but we might as well fill it */ |
2858 | 0 | scratch.d.param.paramtype = exprType((Node *) arg); |
2859 | 0 | ExprEvalPushStep(state, &scratch); |
2860 | 0 | } |
2861 | |
|
2862 | 0 | sstate = ExecInitSubPlan(subplan, state->parent); |
2863 | | |
2864 | | /* add SubPlanState nodes to state->parent->subPlan */ |
2865 | 0 | state->parent->subPlan = lappend(state->parent->subPlan, |
2866 | 0 | sstate); |
2867 | |
|
2868 | 0 | scratch.opcode = EEOP_SUBPLAN; |
2869 | 0 | scratch.resvalue = resv; |
2870 | 0 | scratch.resnull = resnull; |
2871 | 0 | scratch.d.subplan.sstate = sstate; |
2872 | |
|
2873 | 0 | ExprEvalPushStep(state, &scratch); |
2874 | 0 | } |
2875 | | |
2876 | | /* |
2877 | | * Add expression steps performing setup that's needed before any of the |
2878 | | * main execution of the expression. |
2879 | | */ |
2880 | | static void |
2881 | | ExecCreateExprSetupSteps(ExprState *state, Node *node) |
2882 | 0 | { |
2883 | 0 | ExprSetupInfo info = {0, 0, 0, 0, 0, NIL}; |
2884 | | |
2885 | | /* Prescan to find out what we need. */ |
2886 | 0 | expr_setup_walker(node, &info); |
2887 | | |
2888 | | /* And generate those steps. */ |
2889 | 0 | ExecPushExprSetupSteps(state, &info); |
2890 | 0 | } |
2891 | | |
2892 | | /* |
2893 | | * Add steps performing expression setup as indicated by "info". |
2894 | | * This is useful when building an ExprState covering more than one expression. |
2895 | | */ |
2896 | | static void |
2897 | | ExecPushExprSetupSteps(ExprState *state, ExprSetupInfo *info) |
2898 | 0 | { |
2899 | 0 | ExprEvalStep scratch = {0}; |
2900 | 0 | ListCell *lc; |
2901 | |
|
2902 | 0 | scratch.resvalue = NULL; |
2903 | 0 | scratch.resnull = NULL; |
2904 | | |
2905 | | /* |
2906 | | * Add steps deforming the ExprState's inner/outer/scan/old/new slots as |
2907 | | * much as required by any Vars appearing in the expression. |
2908 | | */ |
2909 | 0 | if (info->last_inner > 0) |
2910 | 0 | { |
2911 | 0 | scratch.opcode = EEOP_INNER_FETCHSOME; |
2912 | 0 | scratch.d.fetch.last_var = info->last_inner; |
2913 | 0 | scratch.d.fetch.fixed = false; |
2914 | 0 | scratch.d.fetch.kind = NULL; |
2915 | 0 | scratch.d.fetch.known_desc = NULL; |
2916 | 0 | if (ExecComputeSlotInfo(state, &scratch)) |
2917 | 0 | ExprEvalPushStep(state, &scratch); |
2918 | 0 | } |
2919 | 0 | if (info->last_outer > 0) |
2920 | 0 | { |
2921 | 0 | scratch.opcode = EEOP_OUTER_FETCHSOME; |
2922 | 0 | scratch.d.fetch.last_var = info->last_outer; |
2923 | 0 | scratch.d.fetch.fixed = false; |
2924 | 0 | scratch.d.fetch.kind = NULL; |
2925 | 0 | scratch.d.fetch.known_desc = NULL; |
2926 | 0 | if (ExecComputeSlotInfo(state, &scratch)) |
2927 | 0 | ExprEvalPushStep(state, &scratch); |
2928 | 0 | } |
2929 | 0 | if (info->last_scan > 0) |
2930 | 0 | { |
2931 | 0 | scratch.opcode = EEOP_SCAN_FETCHSOME; |
2932 | 0 | scratch.d.fetch.last_var = info->last_scan; |
2933 | 0 | scratch.d.fetch.fixed = false; |
2934 | 0 | scratch.d.fetch.kind = NULL; |
2935 | 0 | scratch.d.fetch.known_desc = NULL; |
2936 | 0 | if (ExecComputeSlotInfo(state, &scratch)) |
2937 | 0 | ExprEvalPushStep(state, &scratch); |
2938 | 0 | } |
2939 | 0 | if (info->last_old > 0) |
2940 | 0 | { |
2941 | 0 | scratch.opcode = EEOP_OLD_FETCHSOME; |
2942 | 0 | scratch.d.fetch.last_var = info->last_old; |
2943 | 0 | scratch.d.fetch.fixed = false; |
2944 | 0 | scratch.d.fetch.kind = NULL; |
2945 | 0 | scratch.d.fetch.known_desc = NULL; |
2946 | 0 | if (ExecComputeSlotInfo(state, &scratch)) |
2947 | 0 | ExprEvalPushStep(state, &scratch); |
2948 | 0 | } |
2949 | 0 | if (info->last_new > 0) |
2950 | 0 | { |
2951 | 0 | scratch.opcode = EEOP_NEW_FETCHSOME; |
2952 | 0 | scratch.d.fetch.last_var = info->last_new; |
2953 | 0 | scratch.d.fetch.fixed = false; |
2954 | 0 | scratch.d.fetch.kind = NULL; |
2955 | 0 | scratch.d.fetch.known_desc = NULL; |
2956 | 0 | if (ExecComputeSlotInfo(state, &scratch)) |
2957 | 0 | ExprEvalPushStep(state, &scratch); |
2958 | 0 | } |
2959 | | |
2960 | | /* |
2961 | | * Add steps to execute any MULTIEXPR SubPlans appearing in the |
2962 | | * expression. We need to evaluate these before any of the Params |
2963 | | * referencing their outputs are used, but after we've prepared for any |
2964 | | * Var references they may contain. (There cannot be cross-references |
2965 | | * between MULTIEXPR SubPlans, so we needn't worry about their order.) |
2966 | | */ |
2967 | 0 | foreach(lc, info->multiexpr_subplans) |
2968 | 0 | { |
2969 | 0 | SubPlan *subplan = (SubPlan *) lfirst(lc); |
2970 | |
|
2971 | 0 | Assert(subplan->subLinkType == MULTIEXPR_SUBLINK); |
2972 | | |
2973 | | /* The result can be ignored, but we better put it somewhere */ |
2974 | 0 | ExecInitSubPlanExpr(subplan, state, |
2975 | 0 | &state->resvalue, &state->resnull); |
2976 | 0 | } |
2977 | 0 | } |
2978 | | |
2979 | | /* |
2980 | | * expr_setup_walker: expression walker for ExecCreateExprSetupSteps |
2981 | | */ |
2982 | | static bool |
2983 | | expr_setup_walker(Node *node, ExprSetupInfo *info) |
2984 | 0 | { |
2985 | 0 | if (node == NULL) |
2986 | 0 | return false; |
2987 | 0 | if (IsA(node, Var)) |
2988 | 0 | { |
2989 | 0 | Var *variable = (Var *) node; |
2990 | 0 | AttrNumber attnum = variable->varattno; |
2991 | |
|
2992 | 0 | switch (variable->varno) |
2993 | 0 | { |
2994 | 0 | case INNER_VAR: |
2995 | 0 | info->last_inner = Max(info->last_inner, attnum); |
2996 | 0 | break; |
2997 | | |
2998 | 0 | case OUTER_VAR: |
2999 | 0 | info->last_outer = Max(info->last_outer, attnum); |
3000 | 0 | break; |
3001 | | |
3002 | | /* INDEX_VAR is handled by default case */ |
3003 | | |
3004 | 0 | default: |
3005 | 0 | switch (variable->varreturningtype) |
3006 | 0 | { |
3007 | 0 | case VAR_RETURNING_DEFAULT: |
3008 | 0 | info->last_scan = Max(info->last_scan, attnum); |
3009 | 0 | break; |
3010 | 0 | case VAR_RETURNING_OLD: |
3011 | 0 | info->last_old = Max(info->last_old, attnum); |
3012 | 0 | break; |
3013 | 0 | case VAR_RETURNING_NEW: |
3014 | 0 | info->last_new = Max(info->last_new, attnum); |
3015 | 0 | break; |
3016 | 0 | } |
3017 | 0 | break; |
3018 | 0 | } |
3019 | 0 | return false; |
3020 | 0 | } |
3021 | | |
3022 | | /* Collect all MULTIEXPR SubPlans, too */ |
3023 | 0 | if (IsA(node, SubPlan)) |
3024 | 0 | { |
3025 | 0 | SubPlan *subplan = (SubPlan *) node; |
3026 | |
|
3027 | 0 | if (subplan->subLinkType == MULTIEXPR_SUBLINK) |
3028 | 0 | info->multiexpr_subplans = lappend(info->multiexpr_subplans, |
3029 | 0 | subplan); |
3030 | 0 | } |
3031 | | |
3032 | | /* |
3033 | | * Don't examine the arguments or filters of Aggrefs or WindowFuncs, |
3034 | | * because those do not represent expressions to be evaluated within the |
3035 | | * calling expression's econtext. GroupingFunc arguments are never |
3036 | | * evaluated at all. |
3037 | | */ |
3038 | 0 | if (IsA(node, Aggref)) |
3039 | 0 | return false; |
3040 | 0 | if (IsA(node, WindowFunc)) |
3041 | 0 | return false; |
3042 | 0 | if (IsA(node, GroupingFunc)) |
3043 | 0 | return false; |
3044 | 0 | return expression_tree_walker(node, expr_setup_walker, info); |
3045 | 0 | } |
3046 | | |
3047 | | /* |
3048 | | * Compute additional information for EEOP_*_FETCHSOME ops. |
3049 | | * |
3050 | | * The goal is to determine whether a slot is 'fixed', that is, every |
3051 | | * evaluation of the expression will have the same type of slot, with an |
3052 | | * equivalent descriptor. |
3053 | | * |
3054 | | * EEOP_OLD_FETCHSOME and EEOP_NEW_FETCHSOME are used to process RETURNING, if |
3055 | | * OLD/NEW columns are referred to explicitly. In both cases, the tuple |
3056 | | * descriptor comes from the parent scan node, so we treat them the same as |
3057 | | * EEOP_SCAN_FETCHSOME. |
3058 | | * |
3059 | | * Returns true if the deforming step is required, false otherwise. |
3060 | | */ |
3061 | | static bool |
3062 | | ExecComputeSlotInfo(ExprState *state, ExprEvalStep *op) |
3063 | 0 | { |
3064 | 0 | PlanState *parent = state->parent; |
3065 | 0 | TupleDesc desc = NULL; |
3066 | 0 | const TupleTableSlotOps *tts_ops = NULL; |
3067 | 0 | bool isfixed = false; |
3068 | 0 | ExprEvalOp opcode = op->opcode; |
3069 | |
|
3070 | 0 | Assert(opcode == EEOP_INNER_FETCHSOME || |
3071 | 0 | opcode == EEOP_OUTER_FETCHSOME || |
3072 | 0 | opcode == EEOP_SCAN_FETCHSOME || |
3073 | 0 | opcode == EEOP_OLD_FETCHSOME || |
3074 | 0 | opcode == EEOP_NEW_FETCHSOME); |
3075 | |
|
3076 | 0 | if (op->d.fetch.known_desc != NULL) |
3077 | 0 | { |
3078 | 0 | desc = op->d.fetch.known_desc; |
3079 | 0 | tts_ops = op->d.fetch.kind; |
3080 | 0 | isfixed = op->d.fetch.kind != NULL; |
3081 | 0 | } |
3082 | 0 | else if (!parent) |
3083 | 0 | { |
3084 | 0 | isfixed = false; |
3085 | 0 | } |
3086 | 0 | else if (opcode == EEOP_INNER_FETCHSOME) |
3087 | 0 | { |
3088 | 0 | PlanState *is = innerPlanState(parent); |
3089 | |
|
3090 | 0 | if (parent->inneropsset && !parent->inneropsfixed) |
3091 | 0 | { |
3092 | 0 | isfixed = false; |
3093 | 0 | } |
3094 | 0 | else if (parent->inneropsset && parent->innerops) |
3095 | 0 | { |
3096 | 0 | isfixed = true; |
3097 | 0 | tts_ops = parent->innerops; |
3098 | 0 | desc = ExecGetResultType(is); |
3099 | 0 | } |
3100 | 0 | else if (is) |
3101 | 0 | { |
3102 | 0 | tts_ops = ExecGetResultSlotOps(is, &isfixed); |
3103 | 0 | desc = ExecGetResultType(is); |
3104 | 0 | } |
3105 | 0 | } |
3106 | 0 | else if (opcode == EEOP_OUTER_FETCHSOME) |
3107 | 0 | { |
3108 | 0 | PlanState *os = outerPlanState(parent); |
3109 | |
|
3110 | 0 | if (parent->outeropsset && !parent->outeropsfixed) |
3111 | 0 | { |
3112 | 0 | isfixed = false; |
3113 | 0 | } |
3114 | 0 | else if (parent->outeropsset && parent->outerops) |
3115 | 0 | { |
3116 | 0 | isfixed = true; |
3117 | 0 | tts_ops = parent->outerops; |
3118 | 0 | desc = ExecGetResultType(os); |
3119 | 0 | } |
3120 | 0 | else if (os) |
3121 | 0 | { |
3122 | 0 | tts_ops = ExecGetResultSlotOps(os, &isfixed); |
3123 | 0 | desc = ExecGetResultType(os); |
3124 | 0 | } |
3125 | 0 | } |
3126 | 0 | else if (opcode == EEOP_SCAN_FETCHSOME || |
3127 | 0 | opcode == EEOP_OLD_FETCHSOME || |
3128 | 0 | opcode == EEOP_NEW_FETCHSOME) |
3129 | 0 | { |
3130 | 0 | desc = parent->scandesc; |
3131 | |
|
3132 | 0 | if (parent->scanops) |
3133 | 0 | tts_ops = parent->scanops; |
3134 | |
|
3135 | 0 | if (parent->scanopsset) |
3136 | 0 | isfixed = parent->scanopsfixed; |
3137 | 0 | } |
3138 | |
|
3139 | 0 | if (isfixed && desc != NULL && tts_ops != NULL) |
3140 | 0 | { |
3141 | 0 | op->d.fetch.fixed = true; |
3142 | 0 | op->d.fetch.kind = tts_ops; |
3143 | 0 | op->d.fetch.known_desc = desc; |
3144 | 0 | } |
3145 | 0 | else |
3146 | 0 | { |
3147 | 0 | op->d.fetch.fixed = false; |
3148 | 0 | op->d.fetch.kind = NULL; |
3149 | 0 | op->d.fetch.known_desc = NULL; |
3150 | 0 | } |
3151 | | |
3152 | | /* if the slot is known to always virtual we never need to deform */ |
3153 | 0 | if (op->d.fetch.fixed && op->d.fetch.kind == &TTSOpsVirtual) |
3154 | 0 | return false; |
3155 | | |
3156 | 0 | return true; |
3157 | 0 | } |
3158 | | |
3159 | | /* |
3160 | | * Prepare step for the evaluation of a whole-row variable. |
3161 | | * The caller still has to push the step. |
3162 | | */ |
3163 | | static void |
3164 | | ExecInitWholeRowVar(ExprEvalStep *scratch, Var *variable, ExprState *state) |
3165 | 0 | { |
3166 | 0 | PlanState *parent = state->parent; |
3167 | | |
3168 | | /* fill in all but the target */ |
3169 | 0 | scratch->opcode = EEOP_WHOLEROW; |
3170 | 0 | scratch->d.wholerow.var = variable; |
3171 | 0 | scratch->d.wholerow.first = true; |
3172 | 0 | scratch->d.wholerow.slow = false; |
3173 | 0 | scratch->d.wholerow.tupdesc = NULL; /* filled at runtime */ |
3174 | 0 | scratch->d.wholerow.junkFilter = NULL; |
3175 | | |
3176 | | /* update ExprState flags if Var refers to OLD/NEW */ |
3177 | 0 | if (variable->varreturningtype == VAR_RETURNING_OLD) |
3178 | 0 | state->flags |= EEO_FLAG_HAS_OLD; |
3179 | 0 | else if (variable->varreturningtype == VAR_RETURNING_NEW) |
3180 | 0 | state->flags |= EEO_FLAG_HAS_NEW; |
3181 | | |
3182 | | /* |
3183 | | * If the input tuple came from a subquery, it might contain "resjunk" |
3184 | | * columns (such as GROUP BY or ORDER BY columns), which we don't want to |
3185 | | * keep in the whole-row result. We can get rid of such columns by |
3186 | | * passing the tuple through a JunkFilter --- but to make one, we have to |
3187 | | * lay our hands on the subquery's targetlist. Fortunately, there are not |
3188 | | * very many cases where this can happen, and we can identify all of them |
3189 | | * by examining our parent PlanState. We assume this is not an issue in |
3190 | | * standalone expressions that don't have parent plans. (Whole-row Vars |
3191 | | * can occur in such expressions, but they will always be referencing |
3192 | | * table rows.) |
3193 | | */ |
3194 | 0 | if (parent) |
3195 | 0 | { |
3196 | 0 | PlanState *subplan = NULL; |
3197 | |
|
3198 | 0 | switch (nodeTag(parent)) |
3199 | 0 | { |
3200 | 0 | case T_SubqueryScanState: |
3201 | 0 | subplan = ((SubqueryScanState *) parent)->subplan; |
3202 | 0 | break; |
3203 | 0 | case T_CteScanState: |
3204 | 0 | subplan = ((CteScanState *) parent)->cteplanstate; |
3205 | 0 | break; |
3206 | 0 | default: |
3207 | 0 | break; |
3208 | 0 | } |
3209 | | |
3210 | 0 | if (subplan) |
3211 | 0 | { |
3212 | 0 | bool junk_filter_needed = false; |
3213 | 0 | ListCell *tlist; |
3214 | | |
3215 | | /* Detect whether subplan tlist actually has any junk columns */ |
3216 | 0 | foreach(tlist, subplan->plan->targetlist) |
3217 | 0 | { |
3218 | 0 | TargetEntry *tle = (TargetEntry *) lfirst(tlist); |
3219 | |
|
3220 | 0 | if (tle->resjunk) |
3221 | 0 | { |
3222 | 0 | junk_filter_needed = true; |
3223 | 0 | break; |
3224 | 0 | } |
3225 | 0 | } |
3226 | | |
3227 | | /* If so, build the junkfilter now */ |
3228 | 0 | if (junk_filter_needed) |
3229 | 0 | { |
3230 | 0 | scratch->d.wholerow.junkFilter = |
3231 | 0 | ExecInitJunkFilter(subplan->plan->targetlist, |
3232 | 0 | ExecInitExtraTupleSlot(parent->state, NULL, |
3233 | 0 | &TTSOpsVirtual)); |
3234 | 0 | } |
3235 | 0 | } |
3236 | 0 | } |
3237 | 0 | } |
3238 | | |
3239 | | /* |
3240 | | * Prepare evaluation of a SubscriptingRef expression. |
3241 | | */ |
3242 | | static void |
3243 | | ExecInitSubscriptingRef(ExprEvalStep *scratch, SubscriptingRef *sbsref, |
3244 | | ExprState *state, Datum *resv, bool *resnull) |
3245 | 0 | { |
3246 | 0 | bool isAssignment = (sbsref->refassgnexpr != NULL); |
3247 | 0 | int nupper = list_length(sbsref->refupperindexpr); |
3248 | 0 | int nlower = list_length(sbsref->reflowerindexpr); |
3249 | 0 | const SubscriptRoutines *sbsroutines; |
3250 | 0 | SubscriptingRefState *sbsrefstate; |
3251 | 0 | SubscriptExecSteps methods; |
3252 | 0 | char *ptr; |
3253 | 0 | List *adjust_jumps = NIL; |
3254 | 0 | ListCell *lc; |
3255 | 0 | int i; |
3256 | | |
3257 | | /* Look up the subscripting support methods */ |
3258 | 0 | sbsroutines = getSubscriptingRoutines(sbsref->refcontainertype, NULL); |
3259 | 0 | if (!sbsroutines) |
3260 | 0 | ereport(ERROR, |
3261 | 0 | (errcode(ERRCODE_DATATYPE_MISMATCH), |
3262 | 0 | errmsg("cannot subscript type %s because it does not support subscripting", |
3263 | 0 | format_type_be(sbsref->refcontainertype)), |
3264 | 0 | state->parent ? |
3265 | 0 | executor_errposition(state->parent->state, |
3266 | 0 | exprLocation((Node *) sbsref)) : 0)); |
3267 | | |
3268 | | /* Allocate sbsrefstate, with enough space for per-subscript arrays too */ |
3269 | 0 | sbsrefstate = palloc0(MAXALIGN(sizeof(SubscriptingRefState)) + |
3270 | 0 | (nupper + nlower) * (sizeof(Datum) + |
3271 | 0 | 2 * sizeof(bool))); |
3272 | | |
3273 | | /* Fill constant fields of SubscriptingRefState */ |
3274 | 0 | sbsrefstate->isassignment = isAssignment; |
3275 | 0 | sbsrefstate->numupper = nupper; |
3276 | 0 | sbsrefstate->numlower = nlower; |
3277 | | /* Set up per-subscript arrays */ |
3278 | 0 | ptr = ((char *) sbsrefstate) + MAXALIGN(sizeof(SubscriptingRefState)); |
3279 | 0 | sbsrefstate->upperindex = (Datum *) ptr; |
3280 | 0 | ptr += nupper * sizeof(Datum); |
3281 | 0 | sbsrefstate->lowerindex = (Datum *) ptr; |
3282 | 0 | ptr += nlower * sizeof(Datum); |
3283 | 0 | sbsrefstate->upperprovided = (bool *) ptr; |
3284 | 0 | ptr += nupper * sizeof(bool); |
3285 | 0 | sbsrefstate->lowerprovided = (bool *) ptr; |
3286 | 0 | ptr += nlower * sizeof(bool); |
3287 | 0 | sbsrefstate->upperindexnull = (bool *) ptr; |
3288 | 0 | ptr += nupper * sizeof(bool); |
3289 | 0 | sbsrefstate->lowerindexnull = (bool *) ptr; |
3290 | | /* ptr += nlower * sizeof(bool); */ |
3291 | | |
3292 | | /* |
3293 | | * Let the container-type-specific code have a chance. It must fill the |
3294 | | * "methods" struct with function pointers for us to possibly use in |
3295 | | * execution steps below; and it can optionally set up some data pointed |
3296 | | * to by the workspace field. |
3297 | | */ |
3298 | 0 | memset(&methods, 0, sizeof(methods)); |
3299 | 0 | sbsroutines->exec_setup(sbsref, sbsrefstate, &methods); |
3300 | | |
3301 | | /* |
3302 | | * Evaluate array input. It's safe to do so into resv/resnull, because we |
3303 | | * won't use that as target for any of the other subexpressions, and it'll |
3304 | | * be overwritten by the final EEOP_SBSREF_FETCH/ASSIGN step, which is |
3305 | | * pushed last. |
3306 | | */ |
3307 | 0 | ExecInitExprRec(sbsref->refexpr, state, resv, resnull); |
3308 | | |
3309 | | /* |
3310 | | * If refexpr yields NULL, and the operation should be strict, then result |
3311 | | * is NULL. We can implement this with just JUMP_IF_NULL, since we |
3312 | | * evaluated the array into the desired target location. |
3313 | | */ |
3314 | 0 | if (!isAssignment && sbsroutines->fetch_strict) |
3315 | 0 | { |
3316 | 0 | scratch->opcode = EEOP_JUMP_IF_NULL; |
3317 | 0 | scratch->d.jump.jumpdone = -1; /* adjust later */ |
3318 | 0 | ExprEvalPushStep(state, scratch); |
3319 | 0 | adjust_jumps = lappend_int(adjust_jumps, |
3320 | 0 | state->steps_len - 1); |
3321 | 0 | } |
3322 | | |
3323 | | /* Evaluate upper subscripts */ |
3324 | 0 | i = 0; |
3325 | 0 | foreach(lc, sbsref->refupperindexpr) |
3326 | 0 | { |
3327 | 0 | Expr *e = (Expr *) lfirst(lc); |
3328 | | |
3329 | | /* When slicing, individual subscript bounds can be omitted */ |
3330 | 0 | if (!e) |
3331 | 0 | { |
3332 | 0 | sbsrefstate->upperprovided[i] = false; |
3333 | 0 | sbsrefstate->upperindexnull[i] = true; |
3334 | 0 | } |
3335 | 0 | else |
3336 | 0 | { |
3337 | 0 | sbsrefstate->upperprovided[i] = true; |
3338 | | /* Each subscript is evaluated into appropriate array entry */ |
3339 | 0 | ExecInitExprRec(e, state, |
3340 | 0 | &sbsrefstate->upperindex[i], |
3341 | 0 | &sbsrefstate->upperindexnull[i]); |
3342 | 0 | } |
3343 | 0 | i++; |
3344 | 0 | } |
3345 | | |
3346 | | /* Evaluate lower subscripts similarly */ |
3347 | 0 | i = 0; |
3348 | 0 | foreach(lc, sbsref->reflowerindexpr) |
3349 | 0 | { |
3350 | 0 | Expr *e = (Expr *) lfirst(lc); |
3351 | | |
3352 | | /* When slicing, individual subscript bounds can be omitted */ |
3353 | 0 | if (!e) |
3354 | 0 | { |
3355 | 0 | sbsrefstate->lowerprovided[i] = false; |
3356 | 0 | sbsrefstate->lowerindexnull[i] = true; |
3357 | 0 | } |
3358 | 0 | else |
3359 | 0 | { |
3360 | 0 | sbsrefstate->lowerprovided[i] = true; |
3361 | | /* Each subscript is evaluated into appropriate array entry */ |
3362 | 0 | ExecInitExprRec(e, state, |
3363 | 0 | &sbsrefstate->lowerindex[i], |
3364 | 0 | &sbsrefstate->lowerindexnull[i]); |
3365 | 0 | } |
3366 | 0 | i++; |
3367 | 0 | } |
3368 | | |
3369 | | /* SBSREF_SUBSCRIPTS checks and converts all the subscripts at once */ |
3370 | 0 | if (methods.sbs_check_subscripts) |
3371 | 0 | { |
3372 | 0 | scratch->opcode = EEOP_SBSREF_SUBSCRIPTS; |
3373 | 0 | scratch->d.sbsref_subscript.subscriptfunc = methods.sbs_check_subscripts; |
3374 | 0 | scratch->d.sbsref_subscript.state = sbsrefstate; |
3375 | 0 | scratch->d.sbsref_subscript.jumpdone = -1; /* adjust later */ |
3376 | 0 | ExprEvalPushStep(state, scratch); |
3377 | 0 | adjust_jumps = lappend_int(adjust_jumps, |
3378 | 0 | state->steps_len - 1); |
3379 | 0 | } |
3380 | |
|
3381 | 0 | if (isAssignment) |
3382 | 0 | { |
3383 | 0 | Datum *save_innermost_caseval; |
3384 | 0 | bool *save_innermost_casenull; |
3385 | | |
3386 | | /* Check for unimplemented methods */ |
3387 | 0 | if (!methods.sbs_assign) |
3388 | 0 | ereport(ERROR, |
3389 | 0 | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
3390 | 0 | errmsg("type %s does not support subscripted assignment", |
3391 | 0 | format_type_be(sbsref->refcontainertype)))); |
3392 | | |
3393 | | /* |
3394 | | * We might have a nested-assignment situation, in which the |
3395 | | * refassgnexpr is itself a FieldStore or SubscriptingRef that needs |
3396 | | * to obtain and modify the previous value of the array element or |
3397 | | * slice being replaced. If so, we have to extract that value from |
3398 | | * the array and pass it down via the CaseTestExpr mechanism. It's |
3399 | | * safe to reuse the CASE mechanism because there cannot be a CASE |
3400 | | * between here and where the value would be needed, and an array |
3401 | | * assignment can't be within a CASE either. (So saving and restoring |
3402 | | * innermost_caseval is just paranoia, but let's do it anyway.) |
3403 | | * |
3404 | | * Since fetching the old element might be a nontrivial expense, do it |
3405 | | * only if the argument actually needs it. |
3406 | | */ |
3407 | 0 | if (isAssignmentIndirectionExpr(sbsref->refassgnexpr)) |
3408 | 0 | { |
3409 | 0 | if (!methods.sbs_fetch_old) |
3410 | 0 | ereport(ERROR, |
3411 | 0 | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
3412 | 0 | errmsg("type %s does not support subscripted assignment", |
3413 | 0 | format_type_be(sbsref->refcontainertype)))); |
3414 | 0 | scratch->opcode = EEOP_SBSREF_OLD; |
3415 | 0 | scratch->d.sbsref.subscriptfunc = methods.sbs_fetch_old; |
3416 | 0 | scratch->d.sbsref.state = sbsrefstate; |
3417 | 0 | ExprEvalPushStep(state, scratch); |
3418 | 0 | } |
3419 | | |
3420 | | /* SBSREF_OLD puts extracted value into prevvalue/prevnull */ |
3421 | 0 | save_innermost_caseval = state->innermost_caseval; |
3422 | 0 | save_innermost_casenull = state->innermost_casenull; |
3423 | 0 | state->innermost_caseval = &sbsrefstate->prevvalue; |
3424 | 0 | state->innermost_casenull = &sbsrefstate->prevnull; |
3425 | | |
3426 | | /* evaluate replacement value into replacevalue/replacenull */ |
3427 | 0 | ExecInitExprRec(sbsref->refassgnexpr, state, |
3428 | 0 | &sbsrefstate->replacevalue, &sbsrefstate->replacenull); |
3429 | |
|
3430 | 0 | state->innermost_caseval = save_innermost_caseval; |
3431 | 0 | state->innermost_casenull = save_innermost_casenull; |
3432 | | |
3433 | | /* and perform the assignment */ |
3434 | 0 | scratch->opcode = EEOP_SBSREF_ASSIGN; |
3435 | 0 | scratch->d.sbsref.subscriptfunc = methods.sbs_assign; |
3436 | 0 | scratch->d.sbsref.state = sbsrefstate; |
3437 | 0 | ExprEvalPushStep(state, scratch); |
3438 | 0 | } |
3439 | 0 | else |
3440 | 0 | { |
3441 | | /* array fetch is much simpler */ |
3442 | 0 | scratch->opcode = EEOP_SBSREF_FETCH; |
3443 | 0 | scratch->d.sbsref.subscriptfunc = methods.sbs_fetch; |
3444 | 0 | scratch->d.sbsref.state = sbsrefstate; |
3445 | 0 | ExprEvalPushStep(state, scratch); |
3446 | 0 | } |
3447 | | |
3448 | | /* adjust jump targets */ |
3449 | 0 | foreach(lc, adjust_jumps) |
3450 | 0 | { |
3451 | 0 | ExprEvalStep *as = &state->steps[lfirst_int(lc)]; |
3452 | |
|
3453 | 0 | if (as->opcode == EEOP_SBSREF_SUBSCRIPTS) |
3454 | 0 | { |
3455 | 0 | Assert(as->d.sbsref_subscript.jumpdone == -1); |
3456 | 0 | as->d.sbsref_subscript.jumpdone = state->steps_len; |
3457 | 0 | } |
3458 | 0 | else |
3459 | 0 | { |
3460 | 0 | Assert(as->opcode == EEOP_JUMP_IF_NULL); |
3461 | 0 | Assert(as->d.jump.jumpdone == -1); |
3462 | 0 | as->d.jump.jumpdone = state->steps_len; |
3463 | 0 | } |
3464 | 0 | } |
3465 | 0 | } |
3466 | | |
3467 | | /* |
3468 | | * Helper for preparing SubscriptingRef expressions for evaluation: is expr |
3469 | | * a nested FieldStore or SubscriptingRef that needs the old element value |
3470 | | * passed down? |
3471 | | * |
3472 | | * (We could use this in FieldStore too, but in that case passing the old |
3473 | | * value is so cheap there's no need.) |
3474 | | * |
3475 | | * Note: it might seem that this needs to recurse, but in most cases it does |
3476 | | * not; the CaseTestExpr, if any, will be directly the arg or refexpr of the |
3477 | | * top-level node. Nested-assignment situations give rise to expression |
3478 | | * trees in which each level of assignment has its own CaseTestExpr, and the |
3479 | | * recursive structure appears within the newvals or refassgnexpr field. |
3480 | | * There is an exception, though: if the array is an array-of-domain, we will |
3481 | | * have a CoerceToDomain or RelabelType as the refassgnexpr, and we need to |
3482 | | * be able to look through that. |
3483 | | */ |
3484 | | static bool |
3485 | | isAssignmentIndirectionExpr(Expr *expr) |
3486 | 0 | { |
3487 | 0 | if (expr == NULL) |
3488 | 0 | return false; /* just paranoia */ |
3489 | 0 | if (IsA(expr, FieldStore)) |
3490 | 0 | { |
3491 | 0 | FieldStore *fstore = (FieldStore *) expr; |
3492 | |
|
3493 | 0 | if (fstore->arg && IsA(fstore->arg, CaseTestExpr)) |
3494 | 0 | return true; |
3495 | 0 | } |
3496 | 0 | else if (IsA(expr, SubscriptingRef)) |
3497 | 0 | { |
3498 | 0 | SubscriptingRef *sbsRef = (SubscriptingRef *) expr; |
3499 | |
|
3500 | 0 | if (sbsRef->refexpr && IsA(sbsRef->refexpr, CaseTestExpr)) |
3501 | 0 | return true; |
3502 | 0 | } |
3503 | 0 | else if (IsA(expr, CoerceToDomain)) |
3504 | 0 | { |
3505 | 0 | CoerceToDomain *cd = (CoerceToDomain *) expr; |
3506 | |
|
3507 | 0 | return isAssignmentIndirectionExpr(cd->arg); |
3508 | 0 | } |
3509 | 0 | else if (IsA(expr, RelabelType)) |
3510 | 0 | { |
3511 | 0 | RelabelType *r = (RelabelType *) expr; |
3512 | |
|
3513 | 0 | return isAssignmentIndirectionExpr(r->arg); |
3514 | 0 | } |
3515 | 0 | return false; |
3516 | 0 | } |
3517 | | |
3518 | | /* |
3519 | | * Prepare evaluation of a CoerceToDomain expression. |
3520 | | */ |
3521 | | static void |
3522 | | ExecInitCoerceToDomain(ExprEvalStep *scratch, CoerceToDomain *ctest, |
3523 | | ExprState *state, Datum *resv, bool *resnull) |
3524 | 0 | { |
3525 | 0 | DomainConstraintRef *constraint_ref; |
3526 | 0 | Datum *domainval = NULL; |
3527 | 0 | bool *domainnull = NULL; |
3528 | 0 | ListCell *l; |
3529 | |
|
3530 | 0 | scratch->d.domaincheck.resulttype = ctest->resulttype; |
3531 | | /* we'll allocate workspace only if needed */ |
3532 | 0 | scratch->d.domaincheck.checkvalue = NULL; |
3533 | 0 | scratch->d.domaincheck.checknull = NULL; |
3534 | 0 | scratch->d.domaincheck.escontext = state->escontext; |
3535 | | |
3536 | | /* |
3537 | | * Evaluate argument - it's fine to directly store it into resv/resnull, |
3538 | | * if there's constraint failures there'll be errors, otherwise it's what |
3539 | | * needs to be returned. |
3540 | | */ |
3541 | 0 | ExecInitExprRec(ctest->arg, state, resv, resnull); |
3542 | | |
3543 | | /* |
3544 | | * Note: if the argument is of varlena type, it could be a R/W expanded |
3545 | | * object. We want to return the R/W pointer as the final result, but we |
3546 | | * have to pass a R/O pointer as the value to be tested by any functions |
3547 | | * in check expressions. We don't bother to emit a MAKE_READONLY step |
3548 | | * unless there's actually at least one check expression, though. Until |
3549 | | * we've tested that, domainval/domainnull are NULL. |
3550 | | */ |
3551 | | |
3552 | | /* |
3553 | | * Collect the constraints associated with the domain. |
3554 | | * |
3555 | | * Note: before PG v10 we'd recheck the set of constraints during each |
3556 | | * evaluation of the expression. Now we bake them into the ExprState |
3557 | | * during executor initialization. That means we don't need typcache.c to |
3558 | | * provide compiled exprs. |
3559 | | */ |
3560 | 0 | constraint_ref = (DomainConstraintRef *) |
3561 | 0 | palloc(sizeof(DomainConstraintRef)); |
3562 | 0 | InitDomainConstraintRef(ctest->resulttype, |
3563 | 0 | constraint_ref, |
3564 | 0 | CurrentMemoryContext, |
3565 | 0 | false); |
3566 | | |
3567 | | /* |
3568 | | * Compile code to check each domain constraint. NOTNULL constraints can |
3569 | | * just be applied on the resv/resnull value, but for CHECK constraints we |
3570 | | * need more pushups. |
3571 | | */ |
3572 | 0 | foreach(l, constraint_ref->constraints) |
3573 | 0 | { |
3574 | 0 | DomainConstraintState *con = (DomainConstraintState *) lfirst(l); |
3575 | 0 | Datum *save_innermost_domainval; |
3576 | 0 | bool *save_innermost_domainnull; |
3577 | |
|
3578 | 0 | scratch->d.domaincheck.constraintname = con->name; |
3579 | |
|
3580 | 0 | switch (con->constrainttype) |
3581 | 0 | { |
3582 | 0 | case DOM_CONSTRAINT_NOTNULL: |
3583 | 0 | scratch->opcode = EEOP_DOMAIN_NOTNULL; |
3584 | 0 | ExprEvalPushStep(state, scratch); |
3585 | 0 | break; |
3586 | 0 | case DOM_CONSTRAINT_CHECK: |
3587 | | /* Allocate workspace for CHECK output if we didn't yet */ |
3588 | 0 | if (scratch->d.domaincheck.checkvalue == NULL) |
3589 | 0 | { |
3590 | 0 | scratch->d.domaincheck.checkvalue = |
3591 | 0 | (Datum *) palloc(sizeof(Datum)); |
3592 | 0 | scratch->d.domaincheck.checknull = |
3593 | 0 | (bool *) palloc(sizeof(bool)); |
3594 | 0 | } |
3595 | | |
3596 | | /* |
3597 | | * If first time through, determine where CoerceToDomainValue |
3598 | | * nodes should read from. |
3599 | | */ |
3600 | 0 | if (domainval == NULL) |
3601 | 0 | { |
3602 | | /* |
3603 | | * Since value might be read multiple times, force to R/O |
3604 | | * - but only if it could be an expanded datum. |
3605 | | */ |
3606 | 0 | if (get_typlen(ctest->resulttype) == -1) |
3607 | 0 | { |
3608 | 0 | ExprEvalStep scratch2 = {0}; |
3609 | | |
3610 | | /* Yes, so make output workspace for MAKE_READONLY */ |
3611 | 0 | domainval = (Datum *) palloc(sizeof(Datum)); |
3612 | 0 | domainnull = (bool *) palloc(sizeof(bool)); |
3613 | | |
3614 | | /* Emit MAKE_READONLY */ |
3615 | 0 | scratch2.opcode = EEOP_MAKE_READONLY; |
3616 | 0 | scratch2.resvalue = domainval; |
3617 | 0 | scratch2.resnull = domainnull; |
3618 | 0 | scratch2.d.make_readonly.value = resv; |
3619 | 0 | scratch2.d.make_readonly.isnull = resnull; |
3620 | 0 | ExprEvalPushStep(state, &scratch2); |
3621 | 0 | } |
3622 | 0 | else |
3623 | 0 | { |
3624 | | /* No, so it's fine to read from resv/resnull */ |
3625 | 0 | domainval = resv; |
3626 | 0 | domainnull = resnull; |
3627 | 0 | } |
3628 | 0 | } |
3629 | | |
3630 | | /* |
3631 | | * Set up value to be returned by CoerceToDomainValue nodes. |
3632 | | * We must save and restore innermost_domainval/null fields, |
3633 | | * in case this node is itself within a check expression for |
3634 | | * another domain. |
3635 | | */ |
3636 | 0 | save_innermost_domainval = state->innermost_domainval; |
3637 | 0 | save_innermost_domainnull = state->innermost_domainnull; |
3638 | 0 | state->innermost_domainval = domainval; |
3639 | 0 | state->innermost_domainnull = domainnull; |
3640 | | |
3641 | | /* evaluate check expression value */ |
3642 | 0 | ExecInitExprRec(con->check_expr, state, |
3643 | 0 | scratch->d.domaincheck.checkvalue, |
3644 | 0 | scratch->d.domaincheck.checknull); |
3645 | |
|
3646 | 0 | state->innermost_domainval = save_innermost_domainval; |
3647 | 0 | state->innermost_domainnull = save_innermost_domainnull; |
3648 | | |
3649 | | /* now test result */ |
3650 | 0 | scratch->opcode = EEOP_DOMAIN_CHECK; |
3651 | 0 | ExprEvalPushStep(state, scratch); |
3652 | |
|
3653 | 0 | break; |
3654 | 0 | default: |
3655 | 0 | elog(ERROR, "unrecognized constraint type: %d", |
3656 | 0 | (int) con->constrainttype); |
3657 | 0 | break; |
3658 | 0 | } |
3659 | 0 | } |
3660 | 0 | } |
3661 | | |
3662 | | /* |
3663 | | * Build transition/combine function invocations for all aggregate transition |
3664 | | * / combination function invocations in a grouping sets phase. This has to |
3665 | | * invoke all sort based transitions in a phase (if doSort is true), all hash |
3666 | | * based transitions (if doHash is true), or both (both true). |
3667 | | * |
3668 | | * The resulting expression will, for each set of transition values, first |
3669 | | * check for filters, evaluate aggregate input, check that that input is not |
3670 | | * NULL for a strict transition function, and then finally invoke the |
3671 | | * transition for each of the concurrently computed grouping sets. |
3672 | | * |
3673 | | * If nullcheck is true, the generated code will check for a NULL pointer to |
3674 | | * the array of AggStatePerGroup, and skip evaluation if so. |
3675 | | */ |
3676 | | ExprState * |
3677 | | ExecBuildAggTrans(AggState *aggstate, AggStatePerPhase phase, |
3678 | | bool doSort, bool doHash, bool nullcheck) |
3679 | 0 | { |
3680 | 0 | ExprState *state = makeNode(ExprState); |
3681 | 0 | PlanState *parent = &aggstate->ss.ps; |
3682 | 0 | ExprEvalStep scratch = {0}; |
3683 | 0 | bool isCombine = DO_AGGSPLIT_COMBINE(aggstate->aggsplit); |
3684 | 0 | ExprSetupInfo deform = {0, 0, 0, 0, 0, NIL}; |
3685 | |
|
3686 | 0 | state->expr = (Expr *) aggstate; |
3687 | 0 | state->parent = parent; |
3688 | |
|
3689 | 0 | scratch.resvalue = &state->resvalue; |
3690 | 0 | scratch.resnull = &state->resnull; |
3691 | | |
3692 | | /* |
3693 | | * First figure out which slots, and how many columns from each, we're |
3694 | | * going to need. |
3695 | | */ |
3696 | 0 | for (int transno = 0; transno < aggstate->numtrans; transno++) |
3697 | 0 | { |
3698 | 0 | AggStatePerTrans pertrans = &aggstate->pertrans[transno]; |
3699 | |
|
3700 | 0 | expr_setup_walker((Node *) pertrans->aggref->aggdirectargs, |
3701 | 0 | &deform); |
3702 | 0 | expr_setup_walker((Node *) pertrans->aggref->args, |
3703 | 0 | &deform); |
3704 | 0 | expr_setup_walker((Node *) pertrans->aggref->aggorder, |
3705 | 0 | &deform); |
3706 | 0 | expr_setup_walker((Node *) pertrans->aggref->aggdistinct, |
3707 | 0 | &deform); |
3708 | 0 | expr_setup_walker((Node *) pertrans->aggref->aggfilter, |
3709 | 0 | &deform); |
3710 | 0 | } |
3711 | 0 | ExecPushExprSetupSteps(state, &deform); |
3712 | | |
3713 | | /* |
3714 | | * Emit instructions for each transition value / grouping set combination. |
3715 | | */ |
3716 | 0 | for (int transno = 0; transno < aggstate->numtrans; transno++) |
3717 | 0 | { |
3718 | 0 | AggStatePerTrans pertrans = &aggstate->pertrans[transno]; |
3719 | 0 | FunctionCallInfo trans_fcinfo = pertrans->transfn_fcinfo; |
3720 | 0 | List *adjust_bailout = NIL; |
3721 | 0 | NullableDatum *strictargs = NULL; |
3722 | 0 | bool *strictnulls = NULL; |
3723 | 0 | int argno; |
3724 | 0 | ListCell *bail; |
3725 | | |
3726 | | /* |
3727 | | * If filter present, emit. Do so before evaluating the input, to |
3728 | | * avoid potentially unneeded computations, or even worse, unintended |
3729 | | * side-effects. When combining, all the necessary filtering has |
3730 | | * already been done. |
3731 | | */ |
3732 | 0 | if (pertrans->aggref->aggfilter && !isCombine) |
3733 | 0 | { |
3734 | | /* evaluate filter expression */ |
3735 | 0 | ExecInitExprRec(pertrans->aggref->aggfilter, state, |
3736 | 0 | &state->resvalue, &state->resnull); |
3737 | | /* and jump out if false */ |
3738 | 0 | scratch.opcode = EEOP_JUMP_IF_NOT_TRUE; |
3739 | 0 | scratch.d.jump.jumpdone = -1; /* adjust later */ |
3740 | 0 | ExprEvalPushStep(state, &scratch); |
3741 | 0 | adjust_bailout = lappend_int(adjust_bailout, |
3742 | 0 | state->steps_len - 1); |
3743 | 0 | } |
3744 | | |
3745 | | /* |
3746 | | * Evaluate arguments to aggregate/combine function. |
3747 | | */ |
3748 | 0 | argno = 0; |
3749 | 0 | if (isCombine) |
3750 | 0 | { |
3751 | | /* |
3752 | | * Combining two aggregate transition values. Instead of directly |
3753 | | * coming from a tuple the input is a, potentially deserialized, |
3754 | | * transition value. |
3755 | | */ |
3756 | 0 | TargetEntry *source_tle; |
3757 | |
|
3758 | 0 | Assert(pertrans->numSortCols == 0); |
3759 | 0 | Assert(list_length(pertrans->aggref->args) == 1); |
3760 | |
|
3761 | 0 | strictargs = trans_fcinfo->args + 1; |
3762 | 0 | source_tle = (TargetEntry *) linitial(pertrans->aggref->args); |
3763 | | |
3764 | | /* |
3765 | | * deserialfn_oid will be set if we must deserialize the input |
3766 | | * state before calling the combine function. |
3767 | | */ |
3768 | 0 | if (!OidIsValid(pertrans->deserialfn_oid)) |
3769 | 0 | { |
3770 | | /* |
3771 | | * Start from 1, since the 0th arg will be the transition |
3772 | | * value |
3773 | | */ |
3774 | 0 | ExecInitExprRec(source_tle->expr, state, |
3775 | 0 | &trans_fcinfo->args[argno + 1].value, |
3776 | 0 | &trans_fcinfo->args[argno + 1].isnull); |
3777 | 0 | } |
3778 | 0 | else |
3779 | 0 | { |
3780 | 0 | FunctionCallInfo ds_fcinfo = pertrans->deserialfn_fcinfo; |
3781 | | |
3782 | | /* evaluate argument */ |
3783 | 0 | ExecInitExprRec(source_tle->expr, state, |
3784 | 0 | &ds_fcinfo->args[0].value, |
3785 | 0 | &ds_fcinfo->args[0].isnull); |
3786 | | |
3787 | | /* Dummy second argument for type-safety reasons */ |
3788 | 0 | ds_fcinfo->args[1].value = PointerGetDatum(NULL); |
3789 | 0 | ds_fcinfo->args[1].isnull = false; |
3790 | | |
3791 | | /* |
3792 | | * Don't call a strict deserialization function with NULL |
3793 | | * input |
3794 | | */ |
3795 | 0 | if (pertrans->deserialfn.fn_strict) |
3796 | 0 | scratch.opcode = EEOP_AGG_STRICT_DESERIALIZE; |
3797 | 0 | else |
3798 | 0 | scratch.opcode = EEOP_AGG_DESERIALIZE; |
3799 | |
|
3800 | 0 | scratch.d.agg_deserialize.fcinfo_data = ds_fcinfo; |
3801 | 0 | scratch.d.agg_deserialize.jumpnull = -1; /* adjust later */ |
3802 | 0 | scratch.resvalue = &trans_fcinfo->args[argno + 1].value; |
3803 | 0 | scratch.resnull = &trans_fcinfo->args[argno + 1].isnull; |
3804 | |
|
3805 | 0 | ExprEvalPushStep(state, &scratch); |
3806 | | /* don't add an adjustment unless the function is strict */ |
3807 | 0 | if (pertrans->deserialfn.fn_strict) |
3808 | 0 | adjust_bailout = lappend_int(adjust_bailout, |
3809 | 0 | state->steps_len - 1); |
3810 | | |
3811 | | /* restore normal settings of scratch fields */ |
3812 | 0 | scratch.resvalue = &state->resvalue; |
3813 | 0 | scratch.resnull = &state->resnull; |
3814 | 0 | } |
3815 | 0 | argno++; |
3816 | |
|
3817 | 0 | Assert(pertrans->numInputs == argno); |
3818 | 0 | } |
3819 | 0 | else if (!pertrans->aggsortrequired) |
3820 | 0 | { |
3821 | 0 | ListCell *arg; |
3822 | | |
3823 | | /* |
3824 | | * Normal transition function without ORDER BY / DISTINCT or with |
3825 | | * ORDER BY / DISTINCT but the planner has given us pre-sorted |
3826 | | * input. |
3827 | | */ |
3828 | 0 | strictargs = trans_fcinfo->args + 1; |
3829 | |
|
3830 | 0 | foreach(arg, pertrans->aggref->args) |
3831 | 0 | { |
3832 | 0 | TargetEntry *source_tle = (TargetEntry *) lfirst(arg); |
3833 | | |
3834 | | /* |
3835 | | * Don't initialize args for any ORDER BY clause that might |
3836 | | * exist in a presorted aggregate. |
3837 | | */ |
3838 | 0 | if (argno == pertrans->numTransInputs) |
3839 | 0 | break; |
3840 | | |
3841 | | /* |
3842 | | * Start from 1, since the 0th arg will be the transition |
3843 | | * value |
3844 | | */ |
3845 | 0 | ExecInitExprRec(source_tle->expr, state, |
3846 | 0 | &trans_fcinfo->args[argno + 1].value, |
3847 | 0 | &trans_fcinfo->args[argno + 1].isnull); |
3848 | 0 | argno++; |
3849 | 0 | } |
3850 | 0 | Assert(pertrans->numTransInputs == argno); |
3851 | 0 | } |
3852 | 0 | else if (pertrans->numInputs == 1) |
3853 | 0 | { |
3854 | | /* |
3855 | | * Non-presorted DISTINCT and/or ORDER BY case, with a single |
3856 | | * column sorted on. |
3857 | | */ |
3858 | 0 | TargetEntry *source_tle = |
3859 | 0 | (TargetEntry *) linitial(pertrans->aggref->args); |
3860 | |
|
3861 | 0 | Assert(list_length(pertrans->aggref->args) == 1); |
3862 | |
|
3863 | 0 | ExecInitExprRec(source_tle->expr, state, |
3864 | 0 | &state->resvalue, |
3865 | 0 | &state->resnull); |
3866 | 0 | strictnulls = &state->resnull; |
3867 | 0 | argno++; |
3868 | |
|
3869 | 0 | Assert(pertrans->numInputs == argno); |
3870 | 0 | } |
3871 | 0 | else |
3872 | 0 | { |
3873 | | /* |
3874 | | * Non-presorted DISTINCT and/or ORDER BY case, with multiple |
3875 | | * columns sorted on. |
3876 | | */ |
3877 | 0 | Datum *values = pertrans->sortslot->tts_values; |
3878 | 0 | bool *nulls = pertrans->sortslot->tts_isnull; |
3879 | 0 | ListCell *arg; |
3880 | |
|
3881 | 0 | strictnulls = nulls; |
3882 | |
|
3883 | 0 | foreach(arg, pertrans->aggref->args) |
3884 | 0 | { |
3885 | 0 | TargetEntry *source_tle = (TargetEntry *) lfirst(arg); |
3886 | |
|
3887 | 0 | ExecInitExprRec(source_tle->expr, state, |
3888 | 0 | &values[argno], &nulls[argno]); |
3889 | 0 | argno++; |
3890 | 0 | } |
3891 | 0 | Assert(pertrans->numInputs == argno); |
3892 | 0 | } |
3893 | | |
3894 | | /* |
3895 | | * For a strict transfn, nothing happens when there's a NULL input; we |
3896 | | * just keep the prior transValue. This is true for both plain and |
3897 | | * sorted/distinct aggregates. |
3898 | | */ |
3899 | 0 | if (trans_fcinfo->flinfo->fn_strict && pertrans->numTransInputs > 0) |
3900 | 0 | { |
3901 | 0 | if (strictnulls) |
3902 | 0 | scratch.opcode = EEOP_AGG_STRICT_INPUT_CHECK_NULLS; |
3903 | 0 | else if (strictargs && pertrans->numTransInputs == 1) |
3904 | 0 | scratch.opcode = EEOP_AGG_STRICT_INPUT_CHECK_ARGS_1; |
3905 | 0 | else |
3906 | 0 | scratch.opcode = EEOP_AGG_STRICT_INPUT_CHECK_ARGS; |
3907 | 0 | scratch.d.agg_strict_input_check.nulls = strictnulls; |
3908 | 0 | scratch.d.agg_strict_input_check.args = strictargs; |
3909 | 0 | scratch.d.agg_strict_input_check.jumpnull = -1; /* adjust later */ |
3910 | 0 | scratch.d.agg_strict_input_check.nargs = pertrans->numTransInputs; |
3911 | 0 | ExprEvalPushStep(state, &scratch); |
3912 | 0 | adjust_bailout = lappend_int(adjust_bailout, |
3913 | 0 | state->steps_len - 1); |
3914 | 0 | } |
3915 | | |
3916 | | /* Handle DISTINCT aggregates which have pre-sorted input */ |
3917 | 0 | if (pertrans->numDistinctCols > 0 && !pertrans->aggsortrequired) |
3918 | 0 | { |
3919 | 0 | if (pertrans->numDistinctCols > 1) |
3920 | 0 | scratch.opcode = EEOP_AGG_PRESORTED_DISTINCT_MULTI; |
3921 | 0 | else |
3922 | 0 | scratch.opcode = EEOP_AGG_PRESORTED_DISTINCT_SINGLE; |
3923 | |
|
3924 | 0 | scratch.d.agg_presorted_distinctcheck.pertrans = pertrans; |
3925 | 0 | scratch.d.agg_presorted_distinctcheck.jumpdistinct = -1; /* adjust later */ |
3926 | 0 | ExprEvalPushStep(state, &scratch); |
3927 | 0 | adjust_bailout = lappend_int(adjust_bailout, |
3928 | 0 | state->steps_len - 1); |
3929 | 0 | } |
3930 | | |
3931 | | /* |
3932 | | * Call transition function (once for each concurrently evaluated |
3933 | | * grouping set). Do so for both sort and hash based computations, as |
3934 | | * applicable. |
3935 | | */ |
3936 | 0 | if (doSort) |
3937 | 0 | { |
3938 | 0 | int processGroupingSets = Max(phase->numsets, 1); |
3939 | 0 | int setoff = 0; |
3940 | |
|
3941 | 0 | for (int setno = 0; setno < processGroupingSets; setno++) |
3942 | 0 | { |
3943 | 0 | ExecBuildAggTransCall(state, aggstate, &scratch, trans_fcinfo, |
3944 | 0 | pertrans, transno, setno, setoff, false, |
3945 | 0 | nullcheck); |
3946 | 0 | setoff++; |
3947 | 0 | } |
3948 | 0 | } |
3949 | |
|
3950 | 0 | if (doHash) |
3951 | 0 | { |
3952 | 0 | int numHashes = aggstate->num_hashes; |
3953 | 0 | int setoff; |
3954 | | |
3955 | | /* in MIXED mode, there'll be preceding transition values */ |
3956 | 0 | if (aggstate->aggstrategy != AGG_HASHED) |
3957 | 0 | setoff = aggstate->maxsets; |
3958 | 0 | else |
3959 | 0 | setoff = 0; |
3960 | |
|
3961 | 0 | for (int setno = 0; setno < numHashes; setno++) |
3962 | 0 | { |
3963 | 0 | ExecBuildAggTransCall(state, aggstate, &scratch, trans_fcinfo, |
3964 | 0 | pertrans, transno, setno, setoff, true, |
3965 | 0 | nullcheck); |
3966 | 0 | setoff++; |
3967 | 0 | } |
3968 | 0 | } |
3969 | | |
3970 | | /* adjust early bail out jump target(s) */ |
3971 | 0 | foreach(bail, adjust_bailout) |
3972 | 0 | { |
3973 | 0 | ExprEvalStep *as = &state->steps[lfirst_int(bail)]; |
3974 | |
|
3975 | 0 | if (as->opcode == EEOP_JUMP_IF_NOT_TRUE) |
3976 | 0 | { |
3977 | 0 | Assert(as->d.jump.jumpdone == -1); |
3978 | 0 | as->d.jump.jumpdone = state->steps_len; |
3979 | 0 | } |
3980 | 0 | else if (as->opcode == EEOP_AGG_STRICT_INPUT_CHECK_ARGS || |
3981 | 0 | as->opcode == EEOP_AGG_STRICT_INPUT_CHECK_ARGS_1 || |
3982 | 0 | as->opcode == EEOP_AGG_STRICT_INPUT_CHECK_NULLS) |
3983 | 0 | { |
3984 | 0 | Assert(as->d.agg_strict_input_check.jumpnull == -1); |
3985 | 0 | as->d.agg_strict_input_check.jumpnull = state->steps_len; |
3986 | 0 | } |
3987 | 0 | else if (as->opcode == EEOP_AGG_STRICT_DESERIALIZE) |
3988 | 0 | { |
3989 | 0 | Assert(as->d.agg_deserialize.jumpnull == -1); |
3990 | 0 | as->d.agg_deserialize.jumpnull = state->steps_len; |
3991 | 0 | } |
3992 | 0 | else if (as->opcode == EEOP_AGG_PRESORTED_DISTINCT_SINGLE || |
3993 | 0 | as->opcode == EEOP_AGG_PRESORTED_DISTINCT_MULTI) |
3994 | 0 | { |
3995 | 0 | Assert(as->d.agg_presorted_distinctcheck.jumpdistinct == -1); |
3996 | 0 | as->d.agg_presorted_distinctcheck.jumpdistinct = state->steps_len; |
3997 | 0 | } |
3998 | 0 | else |
3999 | 0 | Assert(false); |
4000 | 0 | } |
4001 | 0 | } |
4002 | |
|
4003 | 0 | scratch.resvalue = NULL; |
4004 | 0 | scratch.resnull = NULL; |
4005 | 0 | scratch.opcode = EEOP_DONE_NO_RETURN; |
4006 | 0 | ExprEvalPushStep(state, &scratch); |
4007 | |
|
4008 | 0 | ExecReadyExpr(state); |
4009 | |
|
4010 | 0 | return state; |
4011 | 0 | } |
4012 | | |
4013 | | /* |
4014 | | * Build transition/combine function invocation for a single transition |
4015 | | * value. This is separated from ExecBuildAggTrans() because there are |
4016 | | * multiple callsites (hash and sort in some grouping set cases). |
4017 | | */ |
4018 | | static void |
4019 | | ExecBuildAggTransCall(ExprState *state, AggState *aggstate, |
4020 | | ExprEvalStep *scratch, |
4021 | | FunctionCallInfo fcinfo, AggStatePerTrans pertrans, |
4022 | | int transno, int setno, int setoff, bool ishash, |
4023 | | bool nullcheck) |
4024 | 0 | { |
4025 | 0 | ExprContext *aggcontext; |
4026 | 0 | int adjust_jumpnull = -1; |
4027 | |
|
4028 | 0 | if (ishash) |
4029 | 0 | aggcontext = aggstate->hashcontext; |
4030 | 0 | else |
4031 | 0 | aggcontext = aggstate->aggcontexts[setno]; |
4032 | | |
4033 | | /* add check for NULL pointer? */ |
4034 | 0 | if (nullcheck) |
4035 | 0 | { |
4036 | 0 | scratch->opcode = EEOP_AGG_PLAIN_PERGROUP_NULLCHECK; |
4037 | 0 | scratch->d.agg_plain_pergroup_nullcheck.setoff = setoff; |
4038 | | /* adjust later */ |
4039 | 0 | scratch->d.agg_plain_pergroup_nullcheck.jumpnull = -1; |
4040 | 0 | ExprEvalPushStep(state, scratch); |
4041 | 0 | adjust_jumpnull = state->steps_len - 1; |
4042 | 0 | } |
4043 | | |
4044 | | /* |
4045 | | * Determine appropriate transition implementation. |
4046 | | * |
4047 | | * For non-ordered aggregates and ORDER BY / DISTINCT aggregates with |
4048 | | * presorted input: |
4049 | | * |
4050 | | * If the initial value for the transition state doesn't exist in the |
4051 | | * pg_aggregate table then we will let the first non-NULL value returned |
4052 | | * from the outer procNode become the initial value. (This is useful for |
4053 | | * aggregates like max() and min().) The noTransValue flag signals that we |
4054 | | * need to do so. If true, generate a |
4055 | | * EEOP_AGG_INIT_STRICT_PLAIN_TRANS{,_BYVAL} step. This step also needs to |
4056 | | * do the work described next: |
4057 | | * |
4058 | | * If the function is strict, but does have an initial value, choose |
4059 | | * EEOP_AGG_STRICT_PLAIN_TRANS{,_BYVAL}, which skips the transition |
4060 | | * function if the transition value has become NULL (because a previous |
4061 | | * transition function returned NULL). This step also needs to do the work |
4062 | | * described next: |
4063 | | * |
4064 | | * Otherwise we call EEOP_AGG_PLAIN_TRANS{,_BYVAL}, which does not have to |
4065 | | * perform either of the above checks. |
4066 | | * |
4067 | | * Having steps with overlapping responsibilities is not nice, but |
4068 | | * aggregations are very performance sensitive, making this worthwhile. |
4069 | | * |
4070 | | * For ordered aggregates: |
4071 | | * |
4072 | | * Only need to choose between the faster path for a single ordered |
4073 | | * column, and the one between multiple columns. Checking strictness etc |
4074 | | * is done when finalizing the aggregate. See |
4075 | | * process_ordered_aggregate_{single, multi} and |
4076 | | * advance_transition_function. |
4077 | | */ |
4078 | 0 | if (!pertrans->aggsortrequired) |
4079 | 0 | { |
4080 | 0 | if (pertrans->transtypeByVal) |
4081 | 0 | { |
4082 | 0 | if (fcinfo->flinfo->fn_strict && |
4083 | 0 | pertrans->initValueIsNull) |
4084 | 0 | scratch->opcode = EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL; |
4085 | 0 | else if (fcinfo->flinfo->fn_strict) |
4086 | 0 | scratch->opcode = EEOP_AGG_PLAIN_TRANS_STRICT_BYVAL; |
4087 | 0 | else |
4088 | 0 | scratch->opcode = EEOP_AGG_PLAIN_TRANS_BYVAL; |
4089 | 0 | } |
4090 | 0 | else |
4091 | 0 | { |
4092 | 0 | if (fcinfo->flinfo->fn_strict && |
4093 | 0 | pertrans->initValueIsNull) |
4094 | 0 | scratch->opcode = EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYREF; |
4095 | 0 | else if (fcinfo->flinfo->fn_strict) |
4096 | 0 | scratch->opcode = EEOP_AGG_PLAIN_TRANS_STRICT_BYREF; |
4097 | 0 | else |
4098 | 0 | scratch->opcode = EEOP_AGG_PLAIN_TRANS_BYREF; |
4099 | 0 | } |
4100 | 0 | } |
4101 | 0 | else if (pertrans->numInputs == 1) |
4102 | 0 | scratch->opcode = EEOP_AGG_ORDERED_TRANS_DATUM; |
4103 | 0 | else |
4104 | 0 | scratch->opcode = EEOP_AGG_ORDERED_TRANS_TUPLE; |
4105 | |
|
4106 | 0 | scratch->d.agg_trans.pertrans = pertrans; |
4107 | 0 | scratch->d.agg_trans.setno = setno; |
4108 | 0 | scratch->d.agg_trans.setoff = setoff; |
4109 | 0 | scratch->d.agg_trans.transno = transno; |
4110 | 0 | scratch->d.agg_trans.aggcontext = aggcontext; |
4111 | 0 | ExprEvalPushStep(state, scratch); |
4112 | | |
4113 | | /* fix up jumpnull */ |
4114 | 0 | if (adjust_jumpnull != -1) |
4115 | 0 | { |
4116 | 0 | ExprEvalStep *as = &state->steps[adjust_jumpnull]; |
4117 | |
|
4118 | 0 | Assert(as->opcode == EEOP_AGG_PLAIN_PERGROUP_NULLCHECK); |
4119 | 0 | Assert(as->d.agg_plain_pergroup_nullcheck.jumpnull == -1); |
4120 | 0 | as->d.agg_plain_pergroup_nullcheck.jumpnull = state->steps_len; |
4121 | 0 | } |
4122 | 0 | } |
4123 | | |
4124 | | /* |
4125 | | * Build an ExprState that calls the given hash function(s) on the attnums |
4126 | | * given by 'keyColIdx' . When numCols > 1, the hash values returned by each |
4127 | | * hash function are combined to produce a single hash value. |
4128 | | * |
4129 | | * desc: tuple descriptor for the to-be-hashed columns |
4130 | | * ops: TupleTableSlotOps to use for the give TupleDesc |
4131 | | * hashfunctions: FmgrInfos for each hash function to call, one per numCols. |
4132 | | * These are used directly in the returned ExprState so must remain allocated. |
4133 | | * collations: collation to use when calling the hash function. |
4134 | | * numCols: array length of hashfunctions, collations and keyColIdx. |
4135 | | * parent: PlanState node that the resulting ExprState will be evaluated at |
4136 | | * init_value: Normally 0, but can be set to other values to seed the hash |
4137 | | * with. Non-zero is marginally slower, so best to only use if it's provably |
4138 | | * worthwhile. |
4139 | | */ |
4140 | | ExprState * |
4141 | | ExecBuildHash32FromAttrs(TupleDesc desc, const TupleTableSlotOps *ops, |
4142 | | FmgrInfo *hashfunctions, Oid *collations, |
4143 | | int numCols, AttrNumber *keyColIdx, |
4144 | | PlanState *parent, uint32 init_value) |
4145 | 0 | { |
4146 | 0 | ExprState *state = makeNode(ExprState); |
4147 | 0 | ExprEvalStep scratch = {0}; |
4148 | 0 | NullableDatum *iresult = NULL; |
4149 | 0 | intptr_t opcode; |
4150 | 0 | AttrNumber last_attnum = 0; |
4151 | |
|
4152 | 0 | Assert(numCols >= 0); |
4153 | |
|
4154 | 0 | state->parent = parent; |
4155 | | |
4156 | | /* |
4157 | | * Make a place to store intermediate hash values between subsequent |
4158 | | * hashing of individual columns. We only need this if there is more than |
4159 | | * one column to hash or an initial value plus one column. |
4160 | | */ |
4161 | 0 | if ((int64) numCols + (init_value != 0) > 1) |
4162 | 0 | iresult = palloc(sizeof(NullableDatum)); |
4163 | | |
4164 | | /* find the highest attnum so we deform the tuple to that point */ |
4165 | 0 | for (int i = 0; i < numCols; i++) |
4166 | 0 | last_attnum = Max(last_attnum, keyColIdx[i]); |
4167 | |
|
4168 | 0 | scratch.opcode = EEOP_INNER_FETCHSOME; |
4169 | 0 | scratch.d.fetch.last_var = last_attnum; |
4170 | 0 | scratch.d.fetch.fixed = false; |
4171 | 0 | scratch.d.fetch.kind = ops; |
4172 | 0 | scratch.d.fetch.known_desc = desc; |
4173 | 0 | if (ExecComputeSlotInfo(state, &scratch)) |
4174 | 0 | ExprEvalPushStep(state, &scratch); |
4175 | |
|
4176 | 0 | if (init_value == 0) |
4177 | 0 | { |
4178 | | /* |
4179 | | * No initial value, so we can assign the result of the hash function |
4180 | | * for the first attribute without having to concern ourselves with |
4181 | | * combining the result with any initial value. |
4182 | | */ |
4183 | 0 | opcode = EEOP_HASHDATUM_FIRST; |
4184 | 0 | } |
4185 | 0 | else |
4186 | 0 | { |
4187 | | /* |
4188 | | * Set up operation to set the initial value. Normally we store this |
4189 | | * in the intermediate hash value location, but if there are no |
4190 | | * columns to hash, store it in the ExprState's result field. |
4191 | | */ |
4192 | 0 | scratch.opcode = EEOP_HASHDATUM_SET_INITVAL; |
4193 | 0 | scratch.d.hashdatum_initvalue.init_value = UInt32GetDatum(init_value); |
4194 | 0 | scratch.resvalue = numCols > 0 ? &iresult->value : &state->resvalue; |
4195 | 0 | scratch.resnull = numCols > 0 ? &iresult->isnull : &state->resnull; |
4196 | |
|
4197 | 0 | ExprEvalPushStep(state, &scratch); |
4198 | | |
4199 | | /* |
4200 | | * When using an initial value use the NEXT32 ops as the FIRST ops |
4201 | | * would overwrite the stored initial value. |
4202 | | */ |
4203 | 0 | opcode = EEOP_HASHDATUM_NEXT32; |
4204 | 0 | } |
4205 | |
|
4206 | 0 | for (int i = 0; i < numCols; i++) |
4207 | 0 | { |
4208 | 0 | FmgrInfo *finfo; |
4209 | 0 | FunctionCallInfo fcinfo; |
4210 | 0 | Oid inputcollid = collations[i]; |
4211 | 0 | AttrNumber attnum = keyColIdx[i] - 1; |
4212 | |
|
4213 | 0 | finfo = &hashfunctions[i]; |
4214 | 0 | fcinfo = palloc0(SizeForFunctionCallInfo(1)); |
4215 | | |
4216 | | /* Initialize function call parameter structure too */ |
4217 | 0 | InitFunctionCallInfoData(*fcinfo, finfo, 1, inputcollid, NULL, NULL); |
4218 | | |
4219 | | /* |
4220 | | * Fetch inner Var for this attnum and store it in the 1st arg of the |
4221 | | * hash func. |
4222 | | */ |
4223 | 0 | scratch.opcode = EEOP_INNER_VAR; |
4224 | 0 | scratch.resvalue = &fcinfo->args[0].value; |
4225 | 0 | scratch.resnull = &fcinfo->args[0].isnull; |
4226 | 0 | scratch.d.var.attnum = attnum; |
4227 | 0 | scratch.d.var.vartype = TupleDescAttr(desc, attnum)->atttypid; |
4228 | 0 | scratch.d.var.varreturningtype = VAR_RETURNING_DEFAULT; |
4229 | |
|
4230 | 0 | ExprEvalPushStep(state, &scratch); |
4231 | | |
4232 | | /* Call the hash function */ |
4233 | 0 | scratch.opcode = opcode; |
4234 | |
|
4235 | 0 | if (i == numCols - 1) |
4236 | 0 | { |
4237 | | /* |
4238 | | * The result for hashing the final column is stored in the |
4239 | | * ExprState. |
4240 | | */ |
4241 | 0 | scratch.resvalue = &state->resvalue; |
4242 | 0 | scratch.resnull = &state->resnull; |
4243 | 0 | } |
4244 | 0 | else |
4245 | 0 | { |
4246 | 0 | Assert(iresult != NULL); |
4247 | | |
4248 | | /* intermediate values are stored in an intermediate result */ |
4249 | 0 | scratch.resvalue = &iresult->value; |
4250 | 0 | scratch.resnull = &iresult->isnull; |
4251 | 0 | } |
4252 | | |
4253 | | /* |
4254 | | * NEXT32 opcodes need to look at the intermediate result. We might |
4255 | | * as well just set this for all ops. FIRSTs won't look at it. |
4256 | | */ |
4257 | 0 | scratch.d.hashdatum.iresult = iresult; |
4258 | |
|
4259 | 0 | scratch.d.hashdatum.finfo = finfo; |
4260 | 0 | scratch.d.hashdatum.fcinfo_data = fcinfo; |
4261 | 0 | scratch.d.hashdatum.fn_addr = finfo->fn_addr; |
4262 | 0 | scratch.d.hashdatum.jumpdone = -1; |
4263 | |
|
4264 | 0 | ExprEvalPushStep(state, &scratch); |
4265 | | |
4266 | | /* subsequent attnums must be combined with the previous */ |
4267 | 0 | opcode = EEOP_HASHDATUM_NEXT32; |
4268 | 0 | } |
4269 | |
|
4270 | 0 | scratch.resvalue = NULL; |
4271 | 0 | scratch.resnull = NULL; |
4272 | 0 | scratch.opcode = EEOP_DONE_RETURN; |
4273 | 0 | ExprEvalPushStep(state, &scratch); |
4274 | |
|
4275 | 0 | ExecReadyExpr(state); |
4276 | |
|
4277 | 0 | return state; |
4278 | 0 | } |
4279 | | |
4280 | | /* |
4281 | | * Build an ExprState that calls the given hash function(s) on the given |
4282 | | * 'hash_exprs'. When multiple expressions are present, the hash values |
4283 | | * returned by each hash function are combined to produce a single hash value. |
4284 | | * |
4285 | | * desc: tuple descriptor for the to-be-hashed expressions |
4286 | | * ops: TupleTableSlotOps for the TupleDesc |
4287 | | * hashfunc_oids: Oid for each hash function to call, one for each 'hash_expr' |
4288 | | * collations: collation to use when calling the hash function. |
4289 | | * hash_expr: list of expressions to hash the value of |
4290 | | * opstrict: array corresponding to the 'hashfunc_oids' to store op_strict() |
4291 | | * parent: PlanState node that the 'hash_exprs' will be evaluated at |
4292 | | * init_value: Normally 0, but can be set to other values to seed the hash |
4293 | | * with some other value. Using non-zero is slightly less efficient but can |
4294 | | * be useful. |
4295 | | * keep_nulls: if true, evaluation of the returned ExprState will abort early |
4296 | | * returning NULL if the given hash function is strict and the Datum to hash |
4297 | | * is null. When set to false, any NULL input Datums are skipped. |
4298 | | */ |
4299 | | ExprState * |
4300 | | ExecBuildHash32Expr(TupleDesc desc, const TupleTableSlotOps *ops, |
4301 | | const Oid *hashfunc_oids, const List *collations, |
4302 | | const List *hash_exprs, const bool *opstrict, |
4303 | | PlanState *parent, uint32 init_value, bool keep_nulls) |
4304 | 0 | { |
4305 | 0 | ExprState *state = makeNode(ExprState); |
4306 | 0 | ExprEvalStep scratch = {0}; |
4307 | 0 | NullableDatum *iresult = NULL; |
4308 | 0 | List *adjust_jumps = NIL; |
4309 | 0 | ListCell *lc; |
4310 | 0 | ListCell *lc2; |
4311 | 0 | intptr_t strict_opcode; |
4312 | 0 | intptr_t opcode; |
4313 | 0 | int num_exprs = list_length(hash_exprs); |
4314 | |
|
4315 | 0 | Assert(num_exprs == list_length(collations)); |
4316 | |
|
4317 | 0 | state->parent = parent; |
4318 | | |
4319 | | /* Insert setup steps as needed. */ |
4320 | 0 | ExecCreateExprSetupSteps(state, (Node *) hash_exprs); |
4321 | | |
4322 | | /* |
4323 | | * Make a place to store intermediate hash values between subsequent |
4324 | | * hashing of individual expressions. We only need this if there is more |
4325 | | * than one expression to hash or an initial value plus one expression. |
4326 | | */ |
4327 | 0 | if ((int64) num_exprs + (init_value != 0) > 1) |
4328 | 0 | iresult = palloc(sizeof(NullableDatum)); |
4329 | |
|
4330 | 0 | if (init_value == 0) |
4331 | 0 | { |
4332 | | /* |
4333 | | * No initial value, so we can assign the result of the hash function |
4334 | | * for the first hash_expr without having to concern ourselves with |
4335 | | * combining the result with any initial value. |
4336 | | */ |
4337 | 0 | strict_opcode = EEOP_HASHDATUM_FIRST_STRICT; |
4338 | 0 | opcode = EEOP_HASHDATUM_FIRST; |
4339 | 0 | } |
4340 | 0 | else |
4341 | 0 | { |
4342 | | /* |
4343 | | * Set up operation to set the initial value. Normally we store this |
4344 | | * in the intermediate hash value location, but if there are no exprs |
4345 | | * to hash, store it in the ExprState's result field. |
4346 | | */ |
4347 | 0 | scratch.opcode = EEOP_HASHDATUM_SET_INITVAL; |
4348 | 0 | scratch.d.hashdatum_initvalue.init_value = UInt32GetDatum(init_value); |
4349 | 0 | scratch.resvalue = num_exprs > 0 ? &iresult->value : &state->resvalue; |
4350 | 0 | scratch.resnull = num_exprs > 0 ? &iresult->isnull : &state->resnull; |
4351 | |
|
4352 | 0 | ExprEvalPushStep(state, &scratch); |
4353 | | |
4354 | | /* |
4355 | | * When using an initial value use the NEXT32/NEXT32_STRICT ops as the |
4356 | | * FIRST/FIRST_STRICT ops would overwrite the stored initial value. |
4357 | | */ |
4358 | 0 | strict_opcode = EEOP_HASHDATUM_NEXT32_STRICT; |
4359 | 0 | opcode = EEOP_HASHDATUM_NEXT32; |
4360 | 0 | } |
4361 | |
|
4362 | 0 | forboth(lc, hash_exprs, lc2, collations) |
4363 | 0 | { |
4364 | 0 | Expr *expr = (Expr *) lfirst(lc); |
4365 | 0 | FmgrInfo *finfo; |
4366 | 0 | FunctionCallInfo fcinfo; |
4367 | 0 | int i = foreach_current_index(lc); |
4368 | 0 | Oid funcid; |
4369 | 0 | Oid inputcollid = lfirst_oid(lc2); |
4370 | |
|
4371 | 0 | funcid = hashfunc_oids[i]; |
4372 | | |
4373 | | /* Allocate hash function lookup data. */ |
4374 | 0 | finfo = palloc0(sizeof(FmgrInfo)); |
4375 | 0 | fcinfo = palloc0(SizeForFunctionCallInfo(1)); |
4376 | |
|
4377 | 0 | fmgr_info(funcid, finfo); |
4378 | | |
4379 | | /* |
4380 | | * Build the steps to evaluate the hash function's argument have it so |
4381 | | * the value of that is stored in the 0th argument of the hash func. |
4382 | | */ |
4383 | 0 | ExecInitExprRec(expr, |
4384 | 0 | state, |
4385 | 0 | &fcinfo->args[0].value, |
4386 | 0 | &fcinfo->args[0].isnull); |
4387 | |
|
4388 | 0 | if (i == num_exprs - 1) |
4389 | 0 | { |
4390 | | /* the result for hashing the final expr is stored in the state */ |
4391 | 0 | scratch.resvalue = &state->resvalue; |
4392 | 0 | scratch.resnull = &state->resnull; |
4393 | 0 | } |
4394 | 0 | else |
4395 | 0 | { |
4396 | 0 | Assert(iresult != NULL); |
4397 | | |
4398 | | /* intermediate values are stored in an intermediate result */ |
4399 | 0 | scratch.resvalue = &iresult->value; |
4400 | 0 | scratch.resnull = &iresult->isnull; |
4401 | 0 | } |
4402 | | |
4403 | | /* |
4404 | | * NEXT32 opcodes need to look at the intermediate result. We might |
4405 | | * as well just set this for all ops. FIRSTs won't look at it. |
4406 | | */ |
4407 | 0 | scratch.d.hashdatum.iresult = iresult; |
4408 | | |
4409 | | /* Initialize function call parameter structure too */ |
4410 | 0 | InitFunctionCallInfoData(*fcinfo, finfo, 1, inputcollid, NULL, NULL); |
4411 | |
|
4412 | 0 | scratch.d.hashdatum.finfo = finfo; |
4413 | 0 | scratch.d.hashdatum.fcinfo_data = fcinfo; |
4414 | 0 | scratch.d.hashdatum.fn_addr = finfo->fn_addr; |
4415 | |
|
4416 | 0 | scratch.opcode = opstrict[i] && !keep_nulls ? strict_opcode : opcode; |
4417 | 0 | scratch.d.hashdatum.jumpdone = -1; |
4418 | |
|
4419 | 0 | ExprEvalPushStep(state, &scratch); |
4420 | 0 | adjust_jumps = lappend_int(adjust_jumps, state->steps_len - 1); |
4421 | | |
4422 | | /* |
4423 | | * For subsequent keys we must combine the hash value with the |
4424 | | * previous hashes. |
4425 | | */ |
4426 | 0 | strict_opcode = EEOP_HASHDATUM_NEXT32_STRICT; |
4427 | 0 | opcode = EEOP_HASHDATUM_NEXT32; |
4428 | 0 | } |
4429 | | |
4430 | | /* adjust jump targets */ |
4431 | 0 | foreach(lc, adjust_jumps) |
4432 | 0 | { |
4433 | 0 | ExprEvalStep *as = &state->steps[lfirst_int(lc)]; |
4434 | |
|
4435 | 0 | Assert(as->opcode == EEOP_HASHDATUM_FIRST || |
4436 | 0 | as->opcode == EEOP_HASHDATUM_FIRST_STRICT || |
4437 | 0 | as->opcode == EEOP_HASHDATUM_NEXT32 || |
4438 | 0 | as->opcode == EEOP_HASHDATUM_NEXT32_STRICT); |
4439 | 0 | Assert(as->d.hashdatum.jumpdone == -1); |
4440 | 0 | as->d.hashdatum.jumpdone = state->steps_len; |
4441 | 0 | } |
4442 | |
|
4443 | 0 | scratch.resvalue = NULL; |
4444 | 0 | scratch.resnull = NULL; |
4445 | 0 | scratch.opcode = EEOP_DONE_RETURN; |
4446 | 0 | ExprEvalPushStep(state, &scratch); |
4447 | |
|
4448 | 0 | ExecReadyExpr(state); |
4449 | |
|
4450 | 0 | return state; |
4451 | 0 | } |
4452 | | |
4453 | | /* |
4454 | | * Build equality expression that can be evaluated using ExecQual(), returning |
4455 | | * true if the expression context's inner/outer tuple are NOT DISTINCT. I.e |
4456 | | * two nulls match, a null and a not-null don't match. |
4457 | | * |
4458 | | * desc: tuple descriptor of the to-be-compared tuples |
4459 | | * numCols: the number of attributes to be examined |
4460 | | * keyColIdx: array of attribute column numbers |
4461 | | * eqFunctions: array of function oids of the equality functions to use |
4462 | | * parent: parent executor node |
4463 | | */ |
4464 | | ExprState * |
4465 | | ExecBuildGroupingEqual(TupleDesc ldesc, TupleDesc rdesc, |
4466 | | const TupleTableSlotOps *lops, const TupleTableSlotOps *rops, |
4467 | | int numCols, |
4468 | | const AttrNumber *keyColIdx, |
4469 | | const Oid *eqfunctions, |
4470 | | const Oid *collations, |
4471 | | PlanState *parent) |
4472 | 0 | { |
4473 | 0 | ExprState *state = makeNode(ExprState); |
4474 | 0 | ExprEvalStep scratch = {0}; |
4475 | 0 | int maxatt = -1; |
4476 | 0 | List *adjust_jumps = NIL; |
4477 | 0 | ListCell *lc; |
4478 | | |
4479 | | /* |
4480 | | * When no columns are actually compared, the result's always true. See |
4481 | | * special case in ExecQual(). |
4482 | | */ |
4483 | 0 | if (numCols == 0) |
4484 | 0 | return NULL; |
4485 | | |
4486 | 0 | state->expr = NULL; |
4487 | 0 | state->flags = EEO_FLAG_IS_QUAL; |
4488 | 0 | state->parent = parent; |
4489 | |
|
4490 | 0 | scratch.resvalue = &state->resvalue; |
4491 | 0 | scratch.resnull = &state->resnull; |
4492 | | |
4493 | | /* compute max needed attribute */ |
4494 | 0 | for (int natt = 0; natt < numCols; natt++) |
4495 | 0 | { |
4496 | 0 | int attno = keyColIdx[natt]; |
4497 | |
|
4498 | 0 | if (attno > maxatt) |
4499 | 0 | maxatt = attno; |
4500 | 0 | } |
4501 | 0 | Assert(maxatt >= 0); |
4502 | | |
4503 | | /* push deform steps */ |
4504 | 0 | scratch.opcode = EEOP_INNER_FETCHSOME; |
4505 | 0 | scratch.d.fetch.last_var = maxatt; |
4506 | 0 | scratch.d.fetch.fixed = false; |
4507 | 0 | scratch.d.fetch.known_desc = ldesc; |
4508 | 0 | scratch.d.fetch.kind = lops; |
4509 | 0 | if (ExecComputeSlotInfo(state, &scratch)) |
4510 | 0 | ExprEvalPushStep(state, &scratch); |
4511 | |
|
4512 | 0 | scratch.opcode = EEOP_OUTER_FETCHSOME; |
4513 | 0 | scratch.d.fetch.last_var = maxatt; |
4514 | 0 | scratch.d.fetch.fixed = false; |
4515 | 0 | scratch.d.fetch.known_desc = rdesc; |
4516 | 0 | scratch.d.fetch.kind = rops; |
4517 | 0 | if (ExecComputeSlotInfo(state, &scratch)) |
4518 | 0 | ExprEvalPushStep(state, &scratch); |
4519 | | |
4520 | | /* |
4521 | | * Start comparing at the last field (least significant sort key). That's |
4522 | | * the most likely to be different if we are dealing with sorted input. |
4523 | | */ |
4524 | 0 | for (int natt = numCols; --natt >= 0;) |
4525 | 0 | { |
4526 | 0 | int attno = keyColIdx[natt]; |
4527 | 0 | Form_pg_attribute latt = TupleDescAttr(ldesc, attno - 1); |
4528 | 0 | Form_pg_attribute ratt = TupleDescAttr(rdesc, attno - 1); |
4529 | 0 | Oid foid = eqfunctions[natt]; |
4530 | 0 | Oid collid = collations[natt]; |
4531 | 0 | FmgrInfo *finfo; |
4532 | 0 | FunctionCallInfo fcinfo; |
4533 | 0 | AclResult aclresult; |
4534 | | |
4535 | | /* Check permission to call function */ |
4536 | 0 | aclresult = object_aclcheck(ProcedureRelationId, foid, GetUserId(), ACL_EXECUTE); |
4537 | 0 | if (aclresult != ACLCHECK_OK) |
4538 | 0 | aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(foid)); |
4539 | |
|
4540 | 0 | InvokeFunctionExecuteHook(foid); |
4541 | | |
4542 | | /* Set up the primary fmgr lookup information */ |
4543 | 0 | finfo = palloc0(sizeof(FmgrInfo)); |
4544 | 0 | fcinfo = palloc0(SizeForFunctionCallInfo(2)); |
4545 | 0 | fmgr_info(foid, finfo); |
4546 | 0 | fmgr_info_set_expr(NULL, finfo); |
4547 | 0 | InitFunctionCallInfoData(*fcinfo, finfo, 2, |
4548 | 0 | collid, NULL, NULL); |
4549 | | |
4550 | | /* left arg */ |
4551 | 0 | scratch.opcode = EEOP_INNER_VAR; |
4552 | 0 | scratch.d.var.attnum = attno - 1; |
4553 | 0 | scratch.d.var.vartype = latt->atttypid; |
4554 | 0 | scratch.d.var.varreturningtype = VAR_RETURNING_DEFAULT; |
4555 | 0 | scratch.resvalue = &fcinfo->args[0].value; |
4556 | 0 | scratch.resnull = &fcinfo->args[0].isnull; |
4557 | 0 | ExprEvalPushStep(state, &scratch); |
4558 | | |
4559 | | /* right arg */ |
4560 | 0 | scratch.opcode = EEOP_OUTER_VAR; |
4561 | 0 | scratch.d.var.attnum = attno - 1; |
4562 | 0 | scratch.d.var.vartype = ratt->atttypid; |
4563 | 0 | scratch.d.var.varreturningtype = VAR_RETURNING_DEFAULT; |
4564 | 0 | scratch.resvalue = &fcinfo->args[1].value; |
4565 | 0 | scratch.resnull = &fcinfo->args[1].isnull; |
4566 | 0 | ExprEvalPushStep(state, &scratch); |
4567 | | |
4568 | | /* evaluate distinctness */ |
4569 | 0 | scratch.opcode = EEOP_NOT_DISTINCT; |
4570 | 0 | scratch.d.func.finfo = finfo; |
4571 | 0 | scratch.d.func.fcinfo_data = fcinfo; |
4572 | 0 | scratch.d.func.fn_addr = finfo->fn_addr; |
4573 | 0 | scratch.d.func.nargs = 2; |
4574 | 0 | scratch.resvalue = &state->resvalue; |
4575 | 0 | scratch.resnull = &state->resnull; |
4576 | 0 | ExprEvalPushStep(state, &scratch); |
4577 | | |
4578 | | /* then emit EEOP_QUAL to detect if result is false (or null) */ |
4579 | 0 | scratch.opcode = EEOP_QUAL; |
4580 | 0 | scratch.d.qualexpr.jumpdone = -1; |
4581 | 0 | scratch.resvalue = &state->resvalue; |
4582 | 0 | scratch.resnull = &state->resnull; |
4583 | 0 | ExprEvalPushStep(state, &scratch); |
4584 | 0 | adjust_jumps = lappend_int(adjust_jumps, |
4585 | 0 | state->steps_len - 1); |
4586 | 0 | } |
4587 | | |
4588 | | /* adjust jump targets */ |
4589 | 0 | foreach(lc, adjust_jumps) |
4590 | 0 | { |
4591 | 0 | ExprEvalStep *as = &state->steps[lfirst_int(lc)]; |
4592 | |
|
4593 | 0 | Assert(as->opcode == EEOP_QUAL); |
4594 | 0 | Assert(as->d.qualexpr.jumpdone == -1); |
4595 | 0 | as->d.qualexpr.jumpdone = state->steps_len; |
4596 | 0 | } |
4597 | |
|
4598 | 0 | scratch.resvalue = NULL; |
4599 | 0 | scratch.resnull = NULL; |
4600 | 0 | scratch.opcode = EEOP_DONE_RETURN; |
4601 | 0 | ExprEvalPushStep(state, &scratch); |
4602 | |
|
4603 | 0 | ExecReadyExpr(state); |
4604 | |
|
4605 | 0 | return state; |
4606 | 0 | } |
4607 | | |
4608 | | /* |
4609 | | * Build equality expression that can be evaluated using ExecQual(), returning |
4610 | | * true if the expression context's inner/outer tuples are equal. Datums in |
4611 | | * the inner/outer slots are assumed to be in the same order and quantity as |
4612 | | * the 'eqfunctions' parameter. NULLs are treated as equal. |
4613 | | * |
4614 | | * desc: tuple descriptor of the to-be-compared tuples |
4615 | | * lops: the slot ops for the inner tuple slots |
4616 | | * rops: the slot ops for the outer tuple slots |
4617 | | * eqFunctions: array of function oids of the equality functions to use |
4618 | | * this must be the same length as the 'param_exprs' list. |
4619 | | * collations: collation Oids to use for equality comparison. Must be the |
4620 | | * same length as the 'param_exprs' list. |
4621 | | * parent: parent executor node |
4622 | | */ |
4623 | | ExprState * |
4624 | | ExecBuildParamSetEqual(TupleDesc desc, |
4625 | | const TupleTableSlotOps *lops, |
4626 | | const TupleTableSlotOps *rops, |
4627 | | const Oid *eqfunctions, |
4628 | | const Oid *collations, |
4629 | | const List *param_exprs, |
4630 | | PlanState *parent) |
4631 | 0 | { |
4632 | 0 | ExprState *state = makeNode(ExprState); |
4633 | 0 | ExprEvalStep scratch = {0}; |
4634 | 0 | int maxatt = list_length(param_exprs); |
4635 | 0 | List *adjust_jumps = NIL; |
4636 | 0 | ListCell *lc; |
4637 | |
|
4638 | 0 | state->expr = NULL; |
4639 | 0 | state->flags = EEO_FLAG_IS_QUAL; |
4640 | 0 | state->parent = parent; |
4641 | |
|
4642 | 0 | scratch.resvalue = &state->resvalue; |
4643 | 0 | scratch.resnull = &state->resnull; |
4644 | | |
4645 | | /* push deform steps */ |
4646 | 0 | scratch.opcode = EEOP_INNER_FETCHSOME; |
4647 | 0 | scratch.d.fetch.last_var = maxatt; |
4648 | 0 | scratch.d.fetch.fixed = false; |
4649 | 0 | scratch.d.fetch.known_desc = desc; |
4650 | 0 | scratch.d.fetch.kind = lops; |
4651 | 0 | if (ExecComputeSlotInfo(state, &scratch)) |
4652 | 0 | ExprEvalPushStep(state, &scratch); |
4653 | |
|
4654 | 0 | scratch.opcode = EEOP_OUTER_FETCHSOME; |
4655 | 0 | scratch.d.fetch.last_var = maxatt; |
4656 | 0 | scratch.d.fetch.fixed = false; |
4657 | 0 | scratch.d.fetch.known_desc = desc; |
4658 | 0 | scratch.d.fetch.kind = rops; |
4659 | 0 | if (ExecComputeSlotInfo(state, &scratch)) |
4660 | 0 | ExprEvalPushStep(state, &scratch); |
4661 | |
|
4662 | 0 | for (int attno = 0; attno < maxatt; attno++) |
4663 | 0 | { |
4664 | 0 | Form_pg_attribute att = TupleDescAttr(desc, attno); |
4665 | 0 | Oid foid = eqfunctions[attno]; |
4666 | 0 | Oid collid = collations[attno]; |
4667 | 0 | FmgrInfo *finfo; |
4668 | 0 | FunctionCallInfo fcinfo; |
4669 | 0 | AclResult aclresult; |
4670 | | |
4671 | | /* Check permission to call function */ |
4672 | 0 | aclresult = object_aclcheck(ProcedureRelationId, foid, GetUserId(), ACL_EXECUTE); |
4673 | 0 | if (aclresult != ACLCHECK_OK) |
4674 | 0 | aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(foid)); |
4675 | |
|
4676 | 0 | InvokeFunctionExecuteHook(foid); |
4677 | | |
4678 | | /* Set up the primary fmgr lookup information */ |
4679 | 0 | finfo = palloc0(sizeof(FmgrInfo)); |
4680 | 0 | fcinfo = palloc0(SizeForFunctionCallInfo(2)); |
4681 | 0 | fmgr_info(foid, finfo); |
4682 | 0 | fmgr_info_set_expr(NULL, finfo); |
4683 | 0 | InitFunctionCallInfoData(*fcinfo, finfo, 2, |
4684 | 0 | collid, NULL, NULL); |
4685 | | |
4686 | | /* left arg */ |
4687 | 0 | scratch.opcode = EEOP_INNER_VAR; |
4688 | 0 | scratch.d.var.attnum = attno; |
4689 | 0 | scratch.d.var.vartype = att->atttypid; |
4690 | 0 | scratch.d.var.varreturningtype = VAR_RETURNING_DEFAULT; |
4691 | 0 | scratch.resvalue = &fcinfo->args[0].value; |
4692 | 0 | scratch.resnull = &fcinfo->args[0].isnull; |
4693 | 0 | ExprEvalPushStep(state, &scratch); |
4694 | | |
4695 | | /* right arg */ |
4696 | 0 | scratch.opcode = EEOP_OUTER_VAR; |
4697 | 0 | scratch.d.var.attnum = attno; |
4698 | 0 | scratch.d.var.vartype = att->atttypid; |
4699 | 0 | scratch.d.var.varreturningtype = VAR_RETURNING_DEFAULT; |
4700 | 0 | scratch.resvalue = &fcinfo->args[1].value; |
4701 | 0 | scratch.resnull = &fcinfo->args[1].isnull; |
4702 | 0 | ExprEvalPushStep(state, &scratch); |
4703 | | |
4704 | | /* evaluate distinctness */ |
4705 | 0 | scratch.opcode = EEOP_NOT_DISTINCT; |
4706 | 0 | scratch.d.func.finfo = finfo; |
4707 | 0 | scratch.d.func.fcinfo_data = fcinfo; |
4708 | 0 | scratch.d.func.fn_addr = finfo->fn_addr; |
4709 | 0 | scratch.d.func.nargs = 2; |
4710 | 0 | scratch.resvalue = &state->resvalue; |
4711 | 0 | scratch.resnull = &state->resnull; |
4712 | 0 | ExprEvalPushStep(state, &scratch); |
4713 | | |
4714 | | /* then emit EEOP_QUAL to detect if result is false (or null) */ |
4715 | 0 | scratch.opcode = EEOP_QUAL; |
4716 | 0 | scratch.d.qualexpr.jumpdone = -1; |
4717 | 0 | scratch.resvalue = &state->resvalue; |
4718 | 0 | scratch.resnull = &state->resnull; |
4719 | 0 | ExprEvalPushStep(state, &scratch); |
4720 | 0 | adjust_jumps = lappend_int(adjust_jumps, |
4721 | 0 | state->steps_len - 1); |
4722 | 0 | } |
4723 | | |
4724 | | /* adjust jump targets */ |
4725 | 0 | foreach(lc, adjust_jumps) |
4726 | 0 | { |
4727 | 0 | ExprEvalStep *as = &state->steps[lfirst_int(lc)]; |
4728 | |
|
4729 | 0 | Assert(as->opcode == EEOP_QUAL); |
4730 | 0 | Assert(as->d.qualexpr.jumpdone == -1); |
4731 | 0 | as->d.qualexpr.jumpdone = state->steps_len; |
4732 | 0 | } |
4733 | |
|
4734 | 0 | scratch.resvalue = NULL; |
4735 | 0 | scratch.resnull = NULL; |
4736 | 0 | scratch.opcode = EEOP_DONE_RETURN; |
4737 | 0 | ExprEvalPushStep(state, &scratch); |
4738 | |
|
4739 | 0 | ExecReadyExpr(state); |
4740 | |
|
4741 | 0 | return state; |
4742 | 0 | } |
4743 | | |
4744 | | /* |
4745 | | * Push steps to evaluate a JsonExpr and its various subsidiary expressions. |
4746 | | */ |
4747 | | static void |
4748 | | ExecInitJsonExpr(JsonExpr *jsexpr, ExprState *state, |
4749 | | Datum *resv, bool *resnull, |
4750 | | ExprEvalStep *scratch) |
4751 | 0 | { |
4752 | 0 | JsonExprState *jsestate = palloc0(sizeof(JsonExprState)); |
4753 | 0 | ListCell *argexprlc; |
4754 | 0 | ListCell *argnamelc; |
4755 | 0 | List *jumps_return_null = NIL; |
4756 | 0 | List *jumps_to_end = NIL; |
4757 | 0 | ListCell *lc; |
4758 | 0 | ErrorSaveContext *escontext; |
4759 | 0 | bool returning_domain = |
4760 | 0 | get_typtype(jsexpr->returning->typid) == TYPTYPE_DOMAIN; |
4761 | |
|
4762 | 0 | Assert(jsexpr->on_error != NULL); |
4763 | |
|
4764 | 0 | jsestate->jsexpr = jsexpr; |
4765 | | |
4766 | | /* |
4767 | | * Evaluate formatted_expr storing the result into |
4768 | | * jsestate->formatted_expr. |
4769 | | */ |
4770 | 0 | ExecInitExprRec((Expr *) jsexpr->formatted_expr, state, |
4771 | 0 | &jsestate->formatted_expr.value, |
4772 | 0 | &jsestate->formatted_expr.isnull); |
4773 | | |
4774 | | /* JUMP to return NULL if formatted_expr evaluates to NULL */ |
4775 | 0 | jumps_return_null = lappend_int(jumps_return_null, state->steps_len); |
4776 | 0 | scratch->opcode = EEOP_JUMP_IF_NULL; |
4777 | 0 | scratch->resnull = &jsestate->formatted_expr.isnull; |
4778 | 0 | scratch->d.jump.jumpdone = -1; /* set below */ |
4779 | 0 | ExprEvalPushStep(state, scratch); |
4780 | | |
4781 | | /* |
4782 | | * Evaluate pathspec expression storing the result into |
4783 | | * jsestate->pathspec. |
4784 | | */ |
4785 | 0 | ExecInitExprRec((Expr *) jsexpr->path_spec, state, |
4786 | 0 | &jsestate->pathspec.value, |
4787 | 0 | &jsestate->pathspec.isnull); |
4788 | | |
4789 | | /* JUMP to return NULL if path_spec evaluates to NULL */ |
4790 | 0 | jumps_return_null = lappend_int(jumps_return_null, state->steps_len); |
4791 | 0 | scratch->opcode = EEOP_JUMP_IF_NULL; |
4792 | 0 | scratch->resnull = &jsestate->pathspec.isnull; |
4793 | 0 | scratch->d.jump.jumpdone = -1; /* set below */ |
4794 | 0 | ExprEvalPushStep(state, scratch); |
4795 | | |
4796 | | /* Steps to compute PASSING args. */ |
4797 | 0 | jsestate->args = NIL; |
4798 | 0 | forboth(argexprlc, jsexpr->passing_values, |
4799 | 0 | argnamelc, jsexpr->passing_names) |
4800 | 0 | { |
4801 | 0 | Expr *argexpr = (Expr *) lfirst(argexprlc); |
4802 | 0 | String *argname = lfirst_node(String, argnamelc); |
4803 | 0 | JsonPathVariable *var = palloc(sizeof(*var)); |
4804 | |
|
4805 | 0 | var->name = argname->sval; |
4806 | 0 | var->namelen = strlen(var->name); |
4807 | 0 | var->typid = exprType((Node *) argexpr); |
4808 | 0 | var->typmod = exprTypmod((Node *) argexpr); |
4809 | |
|
4810 | 0 | ExecInitExprRec((Expr *) argexpr, state, &var->value, &var->isnull); |
4811 | |
|
4812 | 0 | jsestate->args = lappend(jsestate->args, var); |
4813 | 0 | } |
4814 | | |
4815 | | /* Step for jsonpath evaluation; see ExecEvalJsonExprPath(). */ |
4816 | 0 | scratch->opcode = EEOP_JSONEXPR_PATH; |
4817 | 0 | scratch->resvalue = resv; |
4818 | 0 | scratch->resnull = resnull; |
4819 | 0 | scratch->d.jsonexpr.jsestate = jsestate; |
4820 | 0 | ExprEvalPushStep(state, scratch); |
4821 | | |
4822 | | /* |
4823 | | * Step to return NULL after jumping to skip the EEOP_JSONEXPR_PATH step |
4824 | | * when either formatted_expr or pathspec is NULL. Adjust jump target |
4825 | | * addresses of JUMPs that we added above. |
4826 | | */ |
4827 | 0 | foreach(lc, jumps_return_null) |
4828 | 0 | { |
4829 | 0 | ExprEvalStep *as = &state->steps[lfirst_int(lc)]; |
4830 | |
|
4831 | 0 | as->d.jump.jumpdone = state->steps_len; |
4832 | 0 | } |
4833 | 0 | scratch->opcode = EEOP_CONST; |
4834 | 0 | scratch->resvalue = resv; |
4835 | 0 | scratch->resnull = resnull; |
4836 | 0 | scratch->d.constval.value = (Datum) 0; |
4837 | 0 | scratch->d.constval.isnull = true; |
4838 | 0 | ExprEvalPushStep(state, scratch); |
4839 | |
|
4840 | 0 | escontext = jsexpr->on_error->btype != JSON_BEHAVIOR_ERROR ? |
4841 | 0 | &jsestate->escontext : NULL; |
4842 | | |
4843 | | /* |
4844 | | * To handle coercion errors softly, use the following ErrorSaveContext to |
4845 | | * pass to ExecInitExprRec() when initializing the coercion expressions |
4846 | | * and in the EEOP_JSONEXPR_COERCION step. |
4847 | | */ |
4848 | 0 | jsestate->escontext.type = T_ErrorSaveContext; |
4849 | | |
4850 | | /* |
4851 | | * Steps to coerce the result value computed by EEOP_JSONEXPR_PATH or the |
4852 | | * NULL returned on NULL input as described above. |
4853 | | */ |
4854 | 0 | jsestate->jump_eval_coercion = -1; |
4855 | 0 | if (jsexpr->use_json_coercion) |
4856 | 0 | { |
4857 | 0 | jsestate->jump_eval_coercion = state->steps_len; |
4858 | |
|
4859 | 0 | ExecInitJsonCoercion(state, jsexpr->returning, escontext, |
4860 | 0 | jsexpr->omit_quotes, |
4861 | 0 | jsexpr->op == JSON_EXISTS_OP, |
4862 | 0 | resv, resnull); |
4863 | 0 | } |
4864 | 0 | else if (jsexpr->use_io_coercion) |
4865 | 0 | { |
4866 | | /* |
4867 | | * Here we only need to initialize the FunctionCallInfo for the target |
4868 | | * type's input function, which is called by ExecEvalJsonExprPath() |
4869 | | * itself, so no additional step is necessary. |
4870 | | */ |
4871 | 0 | Oid typinput; |
4872 | 0 | Oid typioparam; |
4873 | 0 | FmgrInfo *finfo; |
4874 | 0 | FunctionCallInfo fcinfo; |
4875 | |
|
4876 | 0 | getTypeInputInfo(jsexpr->returning->typid, &typinput, &typioparam); |
4877 | 0 | finfo = palloc0(sizeof(FmgrInfo)); |
4878 | 0 | fcinfo = palloc0(SizeForFunctionCallInfo(3)); |
4879 | 0 | fmgr_info(typinput, finfo); |
4880 | 0 | fmgr_info_set_expr((Node *) jsexpr->returning, finfo); |
4881 | 0 | InitFunctionCallInfoData(*fcinfo, finfo, 3, InvalidOid, NULL, NULL); |
4882 | | |
4883 | | /* |
4884 | | * We can preload the second and third arguments for the input |
4885 | | * function, since they're constants. |
4886 | | */ |
4887 | 0 | fcinfo->args[1].value = ObjectIdGetDatum(typioparam); |
4888 | 0 | fcinfo->args[1].isnull = false; |
4889 | 0 | fcinfo->args[2].value = Int32GetDatum(jsexpr->returning->typmod); |
4890 | 0 | fcinfo->args[2].isnull = false; |
4891 | 0 | fcinfo->context = (Node *) escontext; |
4892 | |
|
4893 | 0 | jsestate->input_fcinfo = fcinfo; |
4894 | 0 | } |
4895 | | |
4896 | | /* |
4897 | | * Add a special step, if needed, to check if the coercion evaluation ran |
4898 | | * into an error but was not thrown because the ON ERROR behavior is not |
4899 | | * ERROR. It will set jsestate->error if an error did occur. |
4900 | | */ |
4901 | 0 | if (jsestate->jump_eval_coercion >= 0 && escontext != NULL) |
4902 | 0 | { |
4903 | 0 | scratch->opcode = EEOP_JSONEXPR_COERCION_FINISH; |
4904 | 0 | scratch->d.jsonexpr.jsestate = jsestate; |
4905 | 0 | ExprEvalPushStep(state, scratch); |
4906 | 0 | } |
4907 | |
|
4908 | 0 | jsestate->jump_empty = jsestate->jump_error = -1; |
4909 | | |
4910 | | /* |
4911 | | * Step to check jsestate->error and return the ON ERROR expression if |
4912 | | * there is one. This handles both the errors that occur during jsonpath |
4913 | | * evaluation in EEOP_JSONEXPR_PATH and subsequent coercion evaluation. |
4914 | | * |
4915 | | * Speed up common cases by avoiding extra steps for a NULL-valued ON |
4916 | | * ERROR expression unless RETURNING a domain type, where constraints must |
4917 | | * be checked. ExecEvalJsonExprPath() already returns NULL on error, |
4918 | | * making additional steps unnecessary in typical scenarios. Note that the |
4919 | | * default ON ERROR behavior for JSON_VALUE() and JSON_QUERY() is to |
4920 | | * return NULL. |
4921 | | */ |
4922 | 0 | if (jsexpr->on_error->btype != JSON_BEHAVIOR_ERROR && |
4923 | 0 | (!(IsA(jsexpr->on_error->expr, Const) && |
4924 | 0 | ((Const *) jsexpr->on_error->expr)->constisnull) || |
4925 | 0 | returning_domain)) |
4926 | 0 | { |
4927 | 0 | ErrorSaveContext *saved_escontext; |
4928 | |
|
4929 | 0 | jsestate->jump_error = state->steps_len; |
4930 | | |
4931 | | /* JUMP to end if false, that is, skip the ON ERROR expression. */ |
4932 | 0 | jumps_to_end = lappend_int(jumps_to_end, state->steps_len); |
4933 | 0 | scratch->opcode = EEOP_JUMP_IF_NOT_TRUE; |
4934 | 0 | scratch->resvalue = &jsestate->error.value; |
4935 | 0 | scratch->resnull = &jsestate->error.isnull; |
4936 | 0 | scratch->d.jump.jumpdone = -1; /* set below */ |
4937 | 0 | ExprEvalPushStep(state, scratch); |
4938 | | |
4939 | | /* |
4940 | | * Steps to evaluate the ON ERROR expression; handle errors softly to |
4941 | | * rethrow them in COERCION_FINISH step that will be added later. |
4942 | | */ |
4943 | 0 | saved_escontext = state->escontext; |
4944 | 0 | state->escontext = escontext; |
4945 | 0 | ExecInitExprRec((Expr *) jsexpr->on_error->expr, |
4946 | 0 | state, resv, resnull); |
4947 | 0 | state->escontext = saved_escontext; |
4948 | | |
4949 | | /* Step to coerce the ON ERROR expression if needed */ |
4950 | 0 | if (jsexpr->on_error->coerce) |
4951 | 0 | ExecInitJsonCoercion(state, jsexpr->returning, escontext, |
4952 | 0 | jsexpr->omit_quotes, false, |
4953 | 0 | resv, resnull); |
4954 | | |
4955 | | /* |
4956 | | * Add a COERCION_FINISH step to check for errors that may occur when |
4957 | | * coercing and rethrow them. |
4958 | | */ |
4959 | 0 | if (jsexpr->on_error->coerce || |
4960 | 0 | IsA(jsexpr->on_error->expr, CoerceViaIO) || |
4961 | 0 | IsA(jsexpr->on_error->expr, CoerceToDomain)) |
4962 | 0 | { |
4963 | 0 | scratch->opcode = EEOP_JSONEXPR_COERCION_FINISH; |
4964 | 0 | scratch->resvalue = resv; |
4965 | 0 | scratch->resnull = resnull; |
4966 | 0 | scratch->d.jsonexpr.jsestate = jsestate; |
4967 | 0 | ExprEvalPushStep(state, scratch); |
4968 | 0 | } |
4969 | | |
4970 | | /* JUMP to end to skip the ON EMPTY steps added below. */ |
4971 | 0 | jumps_to_end = lappend_int(jumps_to_end, state->steps_len); |
4972 | 0 | scratch->opcode = EEOP_JUMP; |
4973 | 0 | scratch->d.jump.jumpdone = -1; |
4974 | 0 | ExprEvalPushStep(state, scratch); |
4975 | 0 | } |
4976 | | |
4977 | | /* |
4978 | | * Step to check jsestate->empty and return the ON EMPTY expression if |
4979 | | * there is one. |
4980 | | * |
4981 | | * See the comment above for details on the optimization for NULL-valued |
4982 | | * expressions. |
4983 | | */ |
4984 | 0 | if (jsexpr->on_empty != NULL && |
4985 | 0 | jsexpr->on_empty->btype != JSON_BEHAVIOR_ERROR && |
4986 | 0 | (!(IsA(jsexpr->on_empty->expr, Const) && |
4987 | 0 | ((Const *) jsexpr->on_empty->expr)->constisnull) || |
4988 | 0 | returning_domain)) |
4989 | 0 | { |
4990 | 0 | ErrorSaveContext *saved_escontext; |
4991 | |
|
4992 | 0 | jsestate->jump_empty = state->steps_len; |
4993 | | |
4994 | | /* JUMP to end if false, that is, skip the ON EMPTY expression. */ |
4995 | 0 | jumps_to_end = lappend_int(jumps_to_end, state->steps_len); |
4996 | 0 | scratch->opcode = EEOP_JUMP_IF_NOT_TRUE; |
4997 | 0 | scratch->resvalue = &jsestate->empty.value; |
4998 | 0 | scratch->resnull = &jsestate->empty.isnull; |
4999 | 0 | scratch->d.jump.jumpdone = -1; /* set below */ |
5000 | 0 | ExprEvalPushStep(state, scratch); |
5001 | | |
5002 | | /* |
5003 | | * Steps to evaluate the ON EMPTY expression; handle errors softly to |
5004 | | * rethrow them in COERCION_FINISH step that will be added later. |
5005 | | */ |
5006 | 0 | saved_escontext = state->escontext; |
5007 | 0 | state->escontext = escontext; |
5008 | 0 | ExecInitExprRec((Expr *) jsexpr->on_empty->expr, |
5009 | 0 | state, resv, resnull); |
5010 | 0 | state->escontext = saved_escontext; |
5011 | | |
5012 | | /* Step to coerce the ON EMPTY expression if needed */ |
5013 | 0 | if (jsexpr->on_empty->coerce) |
5014 | 0 | ExecInitJsonCoercion(state, jsexpr->returning, escontext, |
5015 | 0 | jsexpr->omit_quotes, false, |
5016 | 0 | resv, resnull); |
5017 | | |
5018 | | /* |
5019 | | * Add a COERCION_FINISH step to check for errors that may occur when |
5020 | | * coercing and rethrow them. |
5021 | | */ |
5022 | 0 | if (jsexpr->on_empty->coerce || |
5023 | 0 | IsA(jsexpr->on_empty->expr, CoerceViaIO) || |
5024 | 0 | IsA(jsexpr->on_empty->expr, CoerceToDomain)) |
5025 | 0 | { |
5026 | |
|
5027 | 0 | scratch->opcode = EEOP_JSONEXPR_COERCION_FINISH; |
5028 | 0 | scratch->resvalue = resv; |
5029 | 0 | scratch->resnull = resnull; |
5030 | 0 | scratch->d.jsonexpr.jsestate = jsestate; |
5031 | 0 | ExprEvalPushStep(state, scratch); |
5032 | 0 | } |
5033 | 0 | } |
5034 | |
|
5035 | 0 | foreach(lc, jumps_to_end) |
5036 | 0 | { |
5037 | 0 | ExprEvalStep *as = &state->steps[lfirst_int(lc)]; |
5038 | |
|
5039 | 0 | as->d.jump.jumpdone = state->steps_len; |
5040 | 0 | } |
5041 | |
|
5042 | 0 | jsestate->jump_end = state->steps_len; |
5043 | 0 | } |
5044 | | |
5045 | | /* |
5046 | | * Initialize a EEOP_JSONEXPR_COERCION step to coerce the value given in resv |
5047 | | * to the given RETURNING type. |
5048 | | */ |
5049 | | static void |
5050 | | ExecInitJsonCoercion(ExprState *state, JsonReturning *returning, |
5051 | | ErrorSaveContext *escontext, bool omit_quotes, |
5052 | | bool exists_coerce, |
5053 | | Datum *resv, bool *resnull) |
5054 | 0 | { |
5055 | 0 | ExprEvalStep scratch = {0}; |
5056 | | |
5057 | | /* For json_populate_type() */ |
5058 | 0 | scratch.opcode = EEOP_JSONEXPR_COERCION; |
5059 | 0 | scratch.resvalue = resv; |
5060 | 0 | scratch.resnull = resnull; |
5061 | 0 | scratch.d.jsonexpr_coercion.targettype = returning->typid; |
5062 | 0 | scratch.d.jsonexpr_coercion.targettypmod = returning->typmod; |
5063 | 0 | scratch.d.jsonexpr_coercion.json_coercion_cache = NULL; |
5064 | 0 | scratch.d.jsonexpr_coercion.escontext = escontext; |
5065 | 0 | scratch.d.jsonexpr_coercion.omit_quotes = omit_quotes; |
5066 | 0 | scratch.d.jsonexpr_coercion.exists_coerce = exists_coerce; |
5067 | 0 | scratch.d.jsonexpr_coercion.exists_cast_to_int = exists_coerce && |
5068 | 0 | getBaseType(returning->typid) == INT4OID; |
5069 | 0 | scratch.d.jsonexpr_coercion.exists_check_domain = exists_coerce && |
5070 | 0 | DomainHasConstraints(returning->typid); |
5071 | 0 | ExprEvalPushStep(state, &scratch); |
5072 | 0 | } |