Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * execExprInterp.c
4 : * Interpreted evaluation of an expression step list.
5 : *
6 : * This file provides either a "direct threaded" (for gcc, clang and
7 : * compatible) or a "switch threaded" (for all compilers) implementation of
8 : * expression evaluation. The former is amongst the fastest known methods
9 : * of interpreting programs without resorting to assembly level work, or
10 : * just-in-time compilation, but it requires support for computed gotos.
11 : * The latter is amongst the fastest approaches doable in standard C.
12 : *
13 : * In either case we use ExprEvalStep->opcode to dispatch to the code block
14 : * within ExecInterpExpr() that implements the specific opcode type.
15 : *
16 : * Switch-threading uses a plain switch() statement to perform the
17 : * dispatch. This has the advantages of being plain C and allowing the
18 : * compiler to warn if implementation of a specific opcode has been forgotten.
19 : * The disadvantage is that dispatches will, as commonly implemented by
20 : * compilers, happen from a single location, requiring more jumps and causing
21 : * bad branch prediction.
22 : *
23 : * In direct threading, we use gcc's label-as-values extension - also adopted
24 : * by some other compilers - to replace ExprEvalStep->opcode with the address
25 : * of the block implementing the instruction. Dispatch to the next instruction
26 : * is done by a "computed goto". This allows for better branch prediction
27 : * (as the jumps are happening from different locations) and fewer jumps
28 : * (as no preparatory jump to a common dispatch location is needed).
29 : *
30 : * When using direct threading, ExecReadyInterpretedExpr will replace
31 : * each step's opcode field with the address of the relevant code block and
32 : * ExprState->flags will contain EEO_FLAG_DIRECT_THREADED to remember that
33 : * that's been done.
34 : *
35 : * For very simple instructions the overhead of the full interpreter
36 : * "startup", as minimal as it is, is noticeable. Therefore
37 : * ExecReadyInterpretedExpr will choose to implement certain simple
38 : * opcode patterns using special fast-path routines (ExecJust*).
39 : *
40 : * Complex or uncommon instructions are not implemented in-line in
41 : * ExecInterpExpr(), rather we call out to a helper function appearing later
42 : * in this file. For one reason, there'd not be a noticeable performance
43 : * benefit, but more importantly those complex routines are intended to be
44 : * shared between different expression evaluation approaches. For instance
45 : * a JIT compiler would generate calls to them. (This is why they are
46 : * exported rather than being "static" in this file.)
47 : *
48 : *
49 : * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
50 : * Portions Copyright (c) 1994, Regents of the University of California
51 : *
52 : * IDENTIFICATION
53 : * src/backend/executor/execExprInterp.c
54 : *
55 : *-------------------------------------------------------------------------
56 : */
57 : #include "postgres.h"
58 :
59 : #include "access/heaptoast.h"
60 : #include "catalog/pg_type.h"
61 : #include "commands/sequence.h"
62 : #include "executor/execExpr.h"
63 : #include "executor/nodeSubplan.h"
64 : #include "funcapi.h"
65 : #include "miscadmin.h"
66 : #include "nodes/miscnodes.h"
67 : #include "nodes/nodeFuncs.h"
68 : #include "pgstat.h"
69 : #include "utils/array.h"
70 : #include "utils/builtins.h"
71 : #include "utils/date.h"
72 : #include "utils/datum.h"
73 : #include "utils/expandedrecord.h"
74 : #include "utils/json.h"
75 : #include "utils/jsonfuncs.h"
76 : #include "utils/jsonpath.h"
77 : #include "utils/lsyscache.h"
78 : #include "utils/memutils.h"
79 : #include "utils/timestamp.h"
80 : #include "utils/typcache.h"
81 : #include "utils/xml.h"
82 :
83 : /*
84 : * Use computed-goto-based opcode dispatch when computed gotos are available.
85 : * But use a separate symbol so that it's easy to adjust locally in this file
86 : * for development and testing.
87 : */
88 : #ifdef HAVE_COMPUTED_GOTO
89 : #define EEO_USE_COMPUTED_GOTO
90 : #endif /* HAVE_COMPUTED_GOTO */
91 :
92 : /*
93 : * Macros for opcode dispatch.
94 : *
95 : * EEO_SWITCH - just hides the switch if not in use.
96 : * EEO_CASE - labels the implementation of named expression step type.
97 : * EEO_DISPATCH - jump to the implementation of the step type for 'op'.
98 : * EEO_OPCODE - compute opcode required by used expression evaluation method.
99 : * EEO_NEXT - increment 'op' and jump to correct next step type.
100 : * EEO_JUMP - jump to the specified step number within the current expression.
101 : */
102 : #if defined(EEO_USE_COMPUTED_GOTO)
103 :
104 : /* struct for jump target -> opcode lookup table */
105 : typedef struct ExprEvalOpLookup
106 : {
107 : const void *opcode;
108 : ExprEvalOp op;
109 : } ExprEvalOpLookup;
110 :
111 : /* to make dispatch_table accessible outside ExecInterpExpr() */
112 : static const void **dispatch_table = NULL;
113 :
114 : /* jump target -> opcode lookup table */
115 : static ExprEvalOpLookup reverse_dispatch_table[EEOP_LAST];
116 :
117 : #define EEO_SWITCH()
118 : #define EEO_CASE(name) CASE_##name:
119 : #define EEO_DISPATCH() goto *((void *) op->opcode)
120 : #define EEO_OPCODE(opcode) ((intptr_t) dispatch_table[opcode])
121 :
122 : #else /* !EEO_USE_COMPUTED_GOTO */
123 :
124 : #define EEO_SWITCH() starteval: switch ((ExprEvalOp) op->opcode)
125 : #define EEO_CASE(name) case name:
126 : #define EEO_DISPATCH() goto starteval
127 : #define EEO_OPCODE(opcode) (opcode)
128 :
129 : #endif /* EEO_USE_COMPUTED_GOTO */
130 :
131 : #define EEO_NEXT() \
132 : do { \
133 : op++; \
134 : EEO_DISPATCH(); \
135 : } while (0)
136 :
137 : #define EEO_JUMP(stepno) \
138 : do { \
139 : op = &state->steps[stepno]; \
140 : EEO_DISPATCH(); \
141 : } while (0)
142 :
143 :
144 : static Datum ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull);
145 : static void ExecInitInterpreter(void);
146 :
147 : /* support functions */
148 : static void CheckVarSlotCompatibility(TupleTableSlot *slot, int attnum, Oid vartype);
149 : static void CheckOpSlotCompatibility(ExprEvalStep *op, TupleTableSlot *slot);
150 : static TupleDesc get_cached_rowtype(Oid type_id, int32 typmod,
151 : ExprEvalRowtypeCache *rowcache,
152 : bool *changed);
153 : static void ExecEvalRowNullInt(ExprState *state, ExprEvalStep *op,
154 : ExprContext *econtext, bool checkisnull);
155 :
156 : /* fast-path evaluation functions */
157 : static Datum ExecJustInnerVar(ExprState *state, ExprContext *econtext, bool *isnull);
158 : static Datum ExecJustOuterVar(ExprState *state, ExprContext *econtext, bool *isnull);
159 : static Datum ExecJustScanVar(ExprState *state, ExprContext *econtext, bool *isnull);
160 : static Datum ExecJustAssignInnerVar(ExprState *state, ExprContext *econtext, bool *isnull);
161 : static Datum ExecJustAssignOuterVar(ExprState *state, ExprContext *econtext, bool *isnull);
162 : static Datum ExecJustAssignScanVar(ExprState *state, ExprContext *econtext, bool *isnull);
163 : static Datum ExecJustApplyFuncToCase(ExprState *state, ExprContext *econtext, bool *isnull);
164 : static Datum ExecJustConst(ExprState *state, ExprContext *econtext, bool *isnull);
165 : static Datum ExecJustInnerVarVirt(ExprState *state, ExprContext *econtext, bool *isnull);
166 : static Datum ExecJustOuterVarVirt(ExprState *state, ExprContext *econtext, bool *isnull);
167 : static Datum ExecJustScanVarVirt(ExprState *state, ExprContext *econtext, bool *isnull);
168 : static Datum ExecJustAssignInnerVarVirt(ExprState *state, ExprContext *econtext, bool *isnull);
169 : static Datum ExecJustAssignOuterVarVirt(ExprState *state, ExprContext *econtext, bool *isnull);
170 : static Datum ExecJustAssignScanVarVirt(ExprState *state, ExprContext *econtext, bool *isnull);
171 : static Datum ExecJustHashInnerVarWithIV(ExprState *state, ExprContext *econtext, bool *isnull);
172 : static Datum ExecJustHashOuterVar(ExprState *state, ExprContext *econtext, bool *isnull);
173 : static Datum ExecJustHashInnerVar(ExprState *state, ExprContext *econtext, bool *isnull);
174 : static Datum ExecJustHashOuterVarVirt(ExprState *state, ExprContext *econtext, bool *isnull);
175 : static Datum ExecJustHashInnerVarVirt(ExprState *state, ExprContext *econtext, bool *isnull);
176 : static Datum ExecJustHashOuterVarStrict(ExprState *state, ExprContext *econtext, bool *isnull);
177 :
178 : /* execution helper functions */
179 : static pg_attribute_always_inline void ExecAggPlainTransByVal(AggState *aggstate,
180 : AggStatePerTrans pertrans,
181 : AggStatePerGroup pergroup,
182 : ExprContext *aggcontext,
183 : int setno);
184 : static pg_attribute_always_inline void ExecAggPlainTransByRef(AggState *aggstate,
185 : AggStatePerTrans pertrans,
186 : AggStatePerGroup pergroup,
187 : ExprContext *aggcontext,
188 : int setno);
189 : static char *ExecGetJsonValueItemString(JsonbValue *item, bool *resnull);
190 :
191 : /*
192 : * ScalarArrayOpExprHashEntry
193 : * Hash table entry type used during EEOP_HASHED_SCALARARRAYOP
194 : */
195 : typedef struct ScalarArrayOpExprHashEntry
196 : {
197 : Datum key;
198 : uint32 status; /* hash status */
199 : uint32 hash; /* hash value (cached) */
200 : } ScalarArrayOpExprHashEntry;
201 :
202 : #define SH_PREFIX saophash
203 : #define SH_ELEMENT_TYPE ScalarArrayOpExprHashEntry
204 : #define SH_KEY_TYPE Datum
205 : #define SH_SCOPE static inline
206 : #define SH_DECLARE
207 : #include "lib/simplehash.h"
208 :
209 : static bool saop_hash_element_match(struct saophash_hash *tb, Datum key1,
210 : Datum key2);
211 : static uint32 saop_element_hash(struct saophash_hash *tb, Datum key);
212 :
213 : /*
214 : * ScalarArrayOpExprHashTable
215 : * Hash table for EEOP_HASHED_SCALARARRAYOP
216 : */
217 : typedef struct ScalarArrayOpExprHashTable
218 : {
219 : saophash_hash *hashtab; /* underlying hash table */
220 : struct ExprEvalStep *op;
221 : FmgrInfo hash_finfo; /* function's lookup data */
222 : FunctionCallInfoBaseData hash_fcinfo_data; /* arguments etc */
223 : } ScalarArrayOpExprHashTable;
224 :
225 : /* Define parameters for ScalarArrayOpExpr hash table code generation. */
226 : #define SH_PREFIX saophash
227 : #define SH_ELEMENT_TYPE ScalarArrayOpExprHashEntry
228 : #define SH_KEY_TYPE Datum
229 : #define SH_KEY key
230 : #define SH_HASH_KEY(tb, key) saop_element_hash(tb, key)
231 : #define SH_EQUAL(tb, a, b) saop_hash_element_match(tb, a, b)
232 : #define SH_SCOPE static inline
233 : #define SH_STORE_HASH
234 : #define SH_GET_HASH(tb, a) a->hash
235 : #define SH_DEFINE
236 : #include "lib/simplehash.h"
237 :
238 : /*
239 : * Prepare ExprState for interpreted execution.
240 : */
241 : void
242 2265644 : ExecReadyInterpretedExpr(ExprState *state)
243 : {
244 : /* Ensure one-time interpreter setup has been done */
245 2265644 : ExecInitInterpreter();
246 :
247 : /* Simple validity checks on expression */
248 : Assert(state->steps_len >= 1);
249 : Assert(state->steps[state->steps_len - 1].opcode == EEOP_DONE);
250 :
251 : /*
252 : * Don't perform redundant initialization. This is unreachable in current
253 : * cases, but might be hit if there's additional expression evaluation
254 : * methods that rely on interpreted execution to work.
255 : */
256 2265644 : if (state->flags & EEO_FLAG_INTERPRETER_INITIALIZED)
257 0 : return;
258 :
259 : /*
260 : * First time through, check whether attribute matches Var. Might not be
261 : * ok anymore, due to schema changes. We do that by setting up a callback
262 : * that does checking on the first call, which then sets the evalfunc
263 : * callback to the actual method of execution.
264 : */
265 2265644 : state->evalfunc = ExecInterpExprStillValid;
266 :
267 : /* DIRECT_THREADED should not already be set */
268 : Assert((state->flags & EEO_FLAG_DIRECT_THREADED) == 0);
269 :
270 : /*
271 : * There shouldn't be any errors before the expression is fully
272 : * initialized, and even if so, it'd lead to the expression being
273 : * abandoned. So we can set the flag now and save some code.
274 : */
275 2265644 : state->flags |= EEO_FLAG_INTERPRETER_INITIALIZED;
276 :
277 : /*
278 : * Select fast-path evalfuncs for very simple expressions. "Starting up"
279 : * the full interpreter is a measurable overhead for these, and these
280 : * patterns occur often enough to be worth optimizing.
281 : */
282 2265644 : if (state->steps_len == 5)
283 : {
284 320872 : ExprEvalOp step0 = state->steps[0].opcode;
285 320872 : ExprEvalOp step1 = state->steps[1].opcode;
286 320872 : ExprEvalOp step2 = state->steps[2].opcode;
287 320872 : ExprEvalOp step3 = state->steps[3].opcode;
288 :
289 320872 : if (step0 == EEOP_INNER_FETCHSOME &&
290 534 : step1 == EEOP_HASHDATUM_SET_INITVAL &&
291 534 : step2 == EEOP_INNER_VAR &&
292 : step3 == EEOP_HASHDATUM_NEXT32)
293 : {
294 534 : state->evalfunc_private = (void *) ExecJustHashInnerVarWithIV;
295 534 : return;
296 : }
297 : }
298 1944772 : else if (state->steps_len == 4)
299 : {
300 119094 : ExprEvalOp step0 = state->steps[0].opcode;
301 119094 : ExprEvalOp step1 = state->steps[1].opcode;
302 119094 : ExprEvalOp step2 = state->steps[2].opcode;
303 :
304 119094 : if (step0 == EEOP_OUTER_FETCHSOME &&
305 21978 : step1 == EEOP_OUTER_VAR &&
306 : step2 == EEOP_HASHDATUM_FIRST)
307 : {
308 1846 : state->evalfunc_private = (void *) ExecJustHashOuterVar;
309 1846 : return;
310 : }
311 117248 : else if (step0 == EEOP_INNER_FETCHSOME &&
312 2376 : step1 == EEOP_INNER_VAR &&
313 : step2 == EEOP_HASHDATUM_FIRST)
314 : {
315 2346 : state->evalfunc_private = (void *) ExecJustHashInnerVar;
316 2346 : return;
317 : }
318 114902 : else if (step0 == EEOP_OUTER_FETCHSOME &&
319 20132 : step1 == EEOP_OUTER_VAR &&
320 : step2 == EEOP_HASHDATUM_FIRST_STRICT)
321 : {
322 16212 : state->evalfunc_private = (void *) ExecJustHashOuterVarStrict;
323 16212 : return;
324 : }
325 : }
326 1825678 : else if (state->steps_len == 3)
327 : {
328 403006 : ExprEvalOp step0 = state->steps[0].opcode;
329 403006 : ExprEvalOp step1 = state->steps[1].opcode;
330 :
331 403006 : if (step0 == EEOP_INNER_FETCHSOME &&
332 : step1 == EEOP_INNER_VAR)
333 : {
334 7338 : state->evalfunc_private = ExecJustInnerVar;
335 7338 : return;
336 : }
337 395668 : else if (step0 == EEOP_OUTER_FETCHSOME &&
338 : step1 == EEOP_OUTER_VAR)
339 : {
340 9390 : state->evalfunc_private = ExecJustOuterVar;
341 9390 : return;
342 : }
343 386278 : else if (step0 == EEOP_SCAN_FETCHSOME &&
344 : step1 == EEOP_SCAN_VAR)
345 : {
346 30 : state->evalfunc_private = ExecJustScanVar;
347 30 : return;
348 : }
349 386248 : else if (step0 == EEOP_INNER_FETCHSOME &&
350 : step1 == EEOP_ASSIGN_INNER_VAR)
351 : {
352 6488 : state->evalfunc_private = ExecJustAssignInnerVar;
353 6488 : return;
354 : }
355 379760 : else if (step0 == EEOP_OUTER_FETCHSOME &&
356 : step1 == EEOP_ASSIGN_OUTER_VAR)
357 : {
358 7906 : state->evalfunc_private = ExecJustAssignOuterVar;
359 7906 : return;
360 : }
361 371854 : else if (step0 == EEOP_SCAN_FETCHSOME &&
362 : step1 == EEOP_ASSIGN_SCAN_VAR)
363 : {
364 39958 : state->evalfunc_private = ExecJustAssignScanVar;
365 39958 : return;
366 : }
367 331896 : else if (step0 == EEOP_CASE_TESTVAL &&
368 552 : step1 == EEOP_FUNCEXPR_STRICT &&
369 552 : state->steps[0].d.casetest.value)
370 : {
371 356 : state->evalfunc_private = ExecJustApplyFuncToCase;
372 356 : return;
373 : }
374 331540 : else if (step0 == EEOP_INNER_VAR &&
375 : step1 == EEOP_HASHDATUM_FIRST)
376 : {
377 1854 : state->evalfunc_private = (void *) ExecJustHashInnerVarVirt;
378 1854 : return;
379 : }
380 329686 : else if (step0 == EEOP_OUTER_VAR &&
381 : step1 == EEOP_HASHDATUM_FIRST)
382 : {
383 7352 : state->evalfunc_private = (void *) ExecJustHashOuterVarVirt;
384 7352 : return;
385 : }
386 : }
387 1422672 : else if (state->steps_len == 2)
388 : {
389 831534 : ExprEvalOp step0 = state->steps[0].opcode;
390 :
391 831534 : if (step0 == EEOP_CONST)
392 : {
393 351390 : state->evalfunc_private = ExecJustConst;
394 351390 : return;
395 : }
396 480144 : else if (step0 == EEOP_INNER_VAR)
397 : {
398 312 : state->evalfunc_private = ExecJustInnerVarVirt;
399 312 : return;
400 : }
401 479832 : else if (step0 == EEOP_OUTER_VAR)
402 : {
403 2570 : state->evalfunc_private = ExecJustOuterVarVirt;
404 2570 : return;
405 : }
406 477262 : else if (step0 == EEOP_SCAN_VAR)
407 : {
408 0 : state->evalfunc_private = ExecJustScanVarVirt;
409 0 : return;
410 : }
411 477262 : else if (step0 == EEOP_ASSIGN_INNER_VAR)
412 : {
413 376 : state->evalfunc_private = ExecJustAssignInnerVarVirt;
414 376 : return;
415 : }
416 476886 : else if (step0 == EEOP_ASSIGN_OUTER_VAR)
417 : {
418 3974 : state->evalfunc_private = ExecJustAssignOuterVarVirt;
419 3974 : return;
420 : }
421 472912 : else if (step0 == EEOP_ASSIGN_SCAN_VAR)
422 : {
423 4218 : state->evalfunc_private = ExecJustAssignScanVarVirt;
424 4218 : return;
425 : }
426 : }
427 :
428 : #if defined(EEO_USE_COMPUTED_GOTO)
429 :
430 : /*
431 : * In the direct-threaded implementation, replace each opcode with the
432 : * address to jump to. (Use ExecEvalStepOp() to get back the opcode.)
433 : */
434 11918898 : for (int off = 0; off < state->steps_len; off++)
435 : {
436 10117704 : ExprEvalStep *op = &state->steps[off];
437 :
438 10117704 : op->opcode = EEO_OPCODE(op->opcode);
439 : }
440 :
441 1801194 : state->flags |= EEO_FLAG_DIRECT_THREADED;
442 : #endif /* EEO_USE_COMPUTED_GOTO */
443 :
444 1801194 : state->evalfunc_private = ExecInterpExpr;
445 : }
446 :
447 :
448 : /*
449 : * Evaluate expression identified by "state" in the execution context
450 : * given by "econtext". *isnull is set to the is-null flag for the result,
451 : * and the Datum value is the function result.
452 : *
453 : * As a special case, return the dispatch table's address if state is NULL.
454 : * This is used by ExecInitInterpreter to set up the dispatch_table global.
455 : * (Only applies when EEO_USE_COMPUTED_GOTO is defined.)
456 : */
457 : static Datum
458 156638074 : ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
459 : {
460 : ExprEvalStep *op;
461 : TupleTableSlot *resultslot;
462 : TupleTableSlot *innerslot;
463 : TupleTableSlot *outerslot;
464 : TupleTableSlot *scanslot;
465 : TupleTableSlot *oldslot;
466 : TupleTableSlot *newslot;
467 :
468 : /*
469 : * This array has to be in the same order as enum ExprEvalOp.
470 : */
471 : #if defined(EEO_USE_COMPUTED_GOTO)
472 : static const void *const dispatch_table[] = {
473 : &&CASE_EEOP_DONE,
474 : &&CASE_EEOP_INNER_FETCHSOME,
475 : &&CASE_EEOP_OUTER_FETCHSOME,
476 : &&CASE_EEOP_SCAN_FETCHSOME,
477 : &&CASE_EEOP_OLD_FETCHSOME,
478 : &&CASE_EEOP_NEW_FETCHSOME,
479 : &&CASE_EEOP_INNER_VAR,
480 : &&CASE_EEOP_OUTER_VAR,
481 : &&CASE_EEOP_SCAN_VAR,
482 : &&CASE_EEOP_OLD_VAR,
483 : &&CASE_EEOP_NEW_VAR,
484 : &&CASE_EEOP_INNER_SYSVAR,
485 : &&CASE_EEOP_OUTER_SYSVAR,
486 : &&CASE_EEOP_SCAN_SYSVAR,
487 : &&CASE_EEOP_OLD_SYSVAR,
488 : &&CASE_EEOP_NEW_SYSVAR,
489 : &&CASE_EEOP_WHOLEROW,
490 : &&CASE_EEOP_ASSIGN_INNER_VAR,
491 : &&CASE_EEOP_ASSIGN_OUTER_VAR,
492 : &&CASE_EEOP_ASSIGN_SCAN_VAR,
493 : &&CASE_EEOP_ASSIGN_OLD_VAR,
494 : &&CASE_EEOP_ASSIGN_NEW_VAR,
495 : &&CASE_EEOP_ASSIGN_TMP,
496 : &&CASE_EEOP_ASSIGN_TMP_MAKE_RO,
497 : &&CASE_EEOP_CONST,
498 : &&CASE_EEOP_FUNCEXPR,
499 : &&CASE_EEOP_FUNCEXPR_STRICT,
500 : &&CASE_EEOP_FUNCEXPR_FUSAGE,
501 : &&CASE_EEOP_FUNCEXPR_STRICT_FUSAGE,
502 : &&CASE_EEOP_BOOL_AND_STEP_FIRST,
503 : &&CASE_EEOP_BOOL_AND_STEP,
504 : &&CASE_EEOP_BOOL_AND_STEP_LAST,
505 : &&CASE_EEOP_BOOL_OR_STEP_FIRST,
506 : &&CASE_EEOP_BOOL_OR_STEP,
507 : &&CASE_EEOP_BOOL_OR_STEP_LAST,
508 : &&CASE_EEOP_BOOL_NOT_STEP,
509 : &&CASE_EEOP_QUAL,
510 : &&CASE_EEOP_JUMP,
511 : &&CASE_EEOP_JUMP_IF_NULL,
512 : &&CASE_EEOP_JUMP_IF_NOT_NULL,
513 : &&CASE_EEOP_JUMP_IF_NOT_TRUE,
514 : &&CASE_EEOP_NULLTEST_ISNULL,
515 : &&CASE_EEOP_NULLTEST_ISNOTNULL,
516 : &&CASE_EEOP_NULLTEST_ROWISNULL,
517 : &&CASE_EEOP_NULLTEST_ROWISNOTNULL,
518 : &&CASE_EEOP_BOOLTEST_IS_TRUE,
519 : &&CASE_EEOP_BOOLTEST_IS_NOT_TRUE,
520 : &&CASE_EEOP_BOOLTEST_IS_FALSE,
521 : &&CASE_EEOP_BOOLTEST_IS_NOT_FALSE,
522 : &&CASE_EEOP_PARAM_EXEC,
523 : &&CASE_EEOP_PARAM_EXTERN,
524 : &&CASE_EEOP_PARAM_CALLBACK,
525 : &&CASE_EEOP_PARAM_SET,
526 : &&CASE_EEOP_CASE_TESTVAL,
527 : &&CASE_EEOP_MAKE_READONLY,
528 : &&CASE_EEOP_IOCOERCE,
529 : &&CASE_EEOP_IOCOERCE_SAFE,
530 : &&CASE_EEOP_DISTINCT,
531 : &&CASE_EEOP_NOT_DISTINCT,
532 : &&CASE_EEOP_NULLIF,
533 : &&CASE_EEOP_SQLVALUEFUNCTION,
534 : &&CASE_EEOP_CURRENTOFEXPR,
535 : &&CASE_EEOP_NEXTVALUEEXPR,
536 : &&CASE_EEOP_RETURNINGEXPR,
537 : &&CASE_EEOP_ARRAYEXPR,
538 : &&CASE_EEOP_ARRAYCOERCE,
539 : &&CASE_EEOP_ROW,
540 : &&CASE_EEOP_ROWCOMPARE_STEP,
541 : &&CASE_EEOP_ROWCOMPARE_FINAL,
542 : &&CASE_EEOP_MINMAX,
543 : &&CASE_EEOP_FIELDSELECT,
544 : &&CASE_EEOP_FIELDSTORE_DEFORM,
545 : &&CASE_EEOP_FIELDSTORE_FORM,
546 : &&CASE_EEOP_SBSREF_SUBSCRIPTS,
547 : &&CASE_EEOP_SBSREF_OLD,
548 : &&CASE_EEOP_SBSREF_ASSIGN,
549 : &&CASE_EEOP_SBSREF_FETCH,
550 : &&CASE_EEOP_DOMAIN_TESTVAL,
551 : &&CASE_EEOP_DOMAIN_NOTNULL,
552 : &&CASE_EEOP_DOMAIN_CHECK,
553 : &&CASE_EEOP_HASHDATUM_SET_INITVAL,
554 : &&CASE_EEOP_HASHDATUM_FIRST,
555 : &&CASE_EEOP_HASHDATUM_FIRST_STRICT,
556 : &&CASE_EEOP_HASHDATUM_NEXT32,
557 : &&CASE_EEOP_HASHDATUM_NEXT32_STRICT,
558 : &&CASE_EEOP_CONVERT_ROWTYPE,
559 : &&CASE_EEOP_SCALARARRAYOP,
560 : &&CASE_EEOP_HASHED_SCALARARRAYOP,
561 : &&CASE_EEOP_XMLEXPR,
562 : &&CASE_EEOP_JSON_CONSTRUCTOR,
563 : &&CASE_EEOP_IS_JSON,
564 : &&CASE_EEOP_JSONEXPR_PATH,
565 : &&CASE_EEOP_JSONEXPR_COERCION,
566 : &&CASE_EEOP_JSONEXPR_COERCION_FINISH,
567 : &&CASE_EEOP_AGGREF,
568 : &&CASE_EEOP_GROUPING_FUNC,
569 : &&CASE_EEOP_WINDOW_FUNC,
570 : &&CASE_EEOP_MERGE_SUPPORT_FUNC,
571 : &&CASE_EEOP_SUBPLAN,
572 : &&CASE_EEOP_AGG_STRICT_DESERIALIZE,
573 : &&CASE_EEOP_AGG_DESERIALIZE,
574 : &&CASE_EEOP_AGG_STRICT_INPUT_CHECK_ARGS,
575 : &&CASE_EEOP_AGG_STRICT_INPUT_CHECK_NULLS,
576 : &&CASE_EEOP_AGG_PLAIN_PERGROUP_NULLCHECK,
577 : &&CASE_EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL,
578 : &&CASE_EEOP_AGG_PLAIN_TRANS_STRICT_BYVAL,
579 : &&CASE_EEOP_AGG_PLAIN_TRANS_BYVAL,
580 : &&CASE_EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYREF,
581 : &&CASE_EEOP_AGG_PLAIN_TRANS_STRICT_BYREF,
582 : &&CASE_EEOP_AGG_PLAIN_TRANS_BYREF,
583 : &&CASE_EEOP_AGG_PRESORTED_DISTINCT_SINGLE,
584 : &&CASE_EEOP_AGG_PRESORTED_DISTINCT_MULTI,
585 : &&CASE_EEOP_AGG_ORDERED_TRANS_DATUM,
586 : &&CASE_EEOP_AGG_ORDERED_TRANS_TUPLE,
587 : &&CASE_EEOP_LAST
588 : };
589 :
590 : StaticAssertDecl(lengthof(dispatch_table) == EEOP_LAST + 1,
591 : "dispatch_table out of whack with ExprEvalOp");
592 :
593 156638074 : if (unlikely(state == NULL))
594 19732 : return PointerGetDatum(dispatch_table);
595 : #else
596 : Assert(state != NULL);
597 : #endif /* EEO_USE_COMPUTED_GOTO */
598 :
599 : /* setup state */
600 156618342 : op = state->steps;
601 156618342 : resultslot = state->resultslot;
602 156618342 : innerslot = econtext->ecxt_innertuple;
603 156618342 : outerslot = econtext->ecxt_outertuple;
604 156618342 : scanslot = econtext->ecxt_scantuple;
605 156618342 : oldslot = econtext->ecxt_oldtuple;
606 156618342 : newslot = econtext->ecxt_newtuple;
607 :
608 : #if defined(EEO_USE_COMPUTED_GOTO)
609 156618342 : EEO_DISPATCH();
610 : #endif
611 :
612 : EEO_SWITCH()
613 : {
614 156600652 : EEO_CASE(EEOP_DONE)
615 : {
616 156600652 : goto out;
617 : }
618 :
619 28750738 : EEO_CASE(EEOP_INNER_FETCHSOME)
620 : {
621 28750738 : CheckOpSlotCompatibility(op, innerslot);
622 :
623 28750738 : slot_getsomeattrs(innerslot, op->d.fetch.last_var);
624 :
625 28750738 : EEO_NEXT();
626 : }
627 :
628 26445368 : EEO_CASE(EEOP_OUTER_FETCHSOME)
629 : {
630 26445368 : CheckOpSlotCompatibility(op, outerslot);
631 :
632 26445368 : slot_getsomeattrs(outerslot, op->d.fetch.last_var);
633 :
634 26445368 : EEO_NEXT();
635 : }
636 :
637 72436102 : EEO_CASE(EEOP_SCAN_FETCHSOME)
638 : {
639 72436102 : CheckOpSlotCompatibility(op, scanslot);
640 :
641 72436102 : slot_getsomeattrs(scanslot, op->d.fetch.last_var);
642 :
643 72436102 : EEO_NEXT();
644 : }
645 :
646 334 : EEO_CASE(EEOP_OLD_FETCHSOME)
647 : {
648 334 : CheckOpSlotCompatibility(op, oldslot);
649 :
650 334 : slot_getsomeattrs(oldslot, op->d.fetch.last_var);
651 :
652 334 : EEO_NEXT();
653 : }
654 :
655 332 : EEO_CASE(EEOP_NEW_FETCHSOME)
656 : {
657 332 : CheckOpSlotCompatibility(op, newslot);
658 :
659 332 : slot_getsomeattrs(newslot, op->d.fetch.last_var);
660 :
661 332 : EEO_NEXT();
662 : }
663 :
664 31961892 : EEO_CASE(EEOP_INNER_VAR)
665 : {
666 31961892 : int attnum = op->d.var.attnum;
667 :
668 : /*
669 : * Since we already extracted all referenced columns from the
670 : * tuple with a FETCHSOME step, we can just grab the value
671 : * directly out of the slot's decomposed-data arrays. But let's
672 : * have an Assert to check that that did happen.
673 : */
674 : Assert(attnum >= 0 && attnum < innerslot->tts_nvalid);
675 31961892 : *op->resvalue = innerslot->tts_values[attnum];
676 31961892 : *op->resnull = innerslot->tts_isnull[attnum];
677 :
678 31961892 : EEO_NEXT();
679 : }
680 :
681 56495168 : EEO_CASE(EEOP_OUTER_VAR)
682 : {
683 56495168 : int attnum = op->d.var.attnum;
684 :
685 : /* See EEOP_INNER_VAR comments */
686 :
687 : Assert(attnum >= 0 && attnum < outerslot->tts_nvalid);
688 56495168 : *op->resvalue = outerslot->tts_values[attnum];
689 56495168 : *op->resnull = outerslot->tts_isnull[attnum];
690 :
691 56495168 : EEO_NEXT();
692 : }
693 :
694 75879174 : EEO_CASE(EEOP_SCAN_VAR)
695 : {
696 75879174 : int attnum = op->d.var.attnum;
697 :
698 : /* See EEOP_INNER_VAR comments */
699 :
700 : Assert(attnum >= 0 && attnum < scanslot->tts_nvalid);
701 75879174 : *op->resvalue = scanslot->tts_values[attnum];
702 75879174 : *op->resnull = scanslot->tts_isnull[attnum];
703 :
704 75879174 : EEO_NEXT();
705 : }
706 :
707 264 : EEO_CASE(EEOP_OLD_VAR)
708 : {
709 264 : int attnum = op->d.var.attnum;
710 :
711 : /* See EEOP_INNER_VAR comments */
712 :
713 : Assert(attnum >= 0 && attnum < oldslot->tts_nvalid);
714 264 : *op->resvalue = oldslot->tts_values[attnum];
715 264 : *op->resnull = oldslot->tts_isnull[attnum];
716 :
717 264 : EEO_NEXT();
718 : }
719 :
720 258 : EEO_CASE(EEOP_NEW_VAR)
721 : {
722 258 : int attnum = op->d.var.attnum;
723 :
724 : /* See EEOP_INNER_VAR comments */
725 :
726 : Assert(attnum >= 0 && attnum < newslot->tts_nvalid);
727 258 : *op->resvalue = newslot->tts_values[attnum];
728 258 : *op->resnull = newslot->tts_isnull[attnum];
729 :
730 258 : EEO_NEXT();
731 : }
732 :
733 6 : EEO_CASE(EEOP_INNER_SYSVAR)
734 : {
735 6 : ExecEvalSysVar(state, op, econtext, innerslot);
736 6 : EEO_NEXT();
737 : }
738 :
739 12 : EEO_CASE(EEOP_OUTER_SYSVAR)
740 : {
741 12 : ExecEvalSysVar(state, op, econtext, outerslot);
742 12 : EEO_NEXT();
743 : }
744 :
745 6793246 : EEO_CASE(EEOP_SCAN_SYSVAR)
746 : {
747 6793246 : ExecEvalSysVar(state, op, econtext, scanslot);
748 6793234 : EEO_NEXT();
749 : }
750 :
751 228 : EEO_CASE(EEOP_OLD_SYSVAR)
752 : {
753 228 : ExecEvalSysVar(state, op, econtext, oldslot);
754 228 : EEO_NEXT();
755 : }
756 :
757 228 : EEO_CASE(EEOP_NEW_SYSVAR)
758 : {
759 228 : ExecEvalSysVar(state, op, econtext, newslot);
760 228 : EEO_NEXT();
761 : }
762 :
763 44066 : EEO_CASE(EEOP_WHOLEROW)
764 : {
765 : /* too complex for an inline implementation */
766 44066 : ExecEvalWholeRowVar(state, op, econtext);
767 :
768 44066 : EEO_NEXT();
769 : }
770 :
771 7277990 : EEO_CASE(EEOP_ASSIGN_INNER_VAR)
772 : {
773 7277990 : int resultnum = op->d.assign_var.resultnum;
774 7277990 : int attnum = op->d.assign_var.attnum;
775 :
776 : /*
777 : * We do not need CheckVarSlotCompatibility here; that was taken
778 : * care of at compilation time. But see EEOP_INNER_VAR comments.
779 : */
780 : Assert(attnum >= 0 && attnum < innerslot->tts_nvalid);
781 : Assert(resultnum >= 0 && resultnum < resultslot->tts_tupleDescriptor->natts);
782 7277990 : resultslot->tts_values[resultnum] = innerslot->tts_values[attnum];
783 7277990 : resultslot->tts_isnull[resultnum] = innerslot->tts_isnull[attnum];
784 :
785 7277990 : EEO_NEXT();
786 : }
787 :
788 23854088 : EEO_CASE(EEOP_ASSIGN_OUTER_VAR)
789 : {
790 23854088 : int resultnum = op->d.assign_var.resultnum;
791 23854088 : int attnum = op->d.assign_var.attnum;
792 :
793 : /*
794 : * We do not need CheckVarSlotCompatibility here; that was taken
795 : * care of at compilation time. But see EEOP_INNER_VAR comments.
796 : */
797 : Assert(attnum >= 0 && attnum < outerslot->tts_nvalid);
798 : Assert(resultnum >= 0 && resultnum < resultslot->tts_tupleDescriptor->natts);
799 23854088 : resultslot->tts_values[resultnum] = outerslot->tts_values[attnum];
800 23854088 : resultslot->tts_isnull[resultnum] = outerslot->tts_isnull[attnum];
801 :
802 23854088 : EEO_NEXT();
803 : }
804 :
805 57416104 : EEO_CASE(EEOP_ASSIGN_SCAN_VAR)
806 : {
807 57416104 : int resultnum = op->d.assign_var.resultnum;
808 57416104 : int attnum = op->d.assign_var.attnum;
809 :
810 : /*
811 : * We do not need CheckVarSlotCompatibility here; that was taken
812 : * care of at compilation time. But see EEOP_INNER_VAR comments.
813 : */
814 : Assert(attnum >= 0 && attnum < scanslot->tts_nvalid);
815 : Assert(resultnum >= 0 && resultnum < resultslot->tts_tupleDescriptor->natts);
816 57416104 : resultslot->tts_values[resultnum] = scanslot->tts_values[attnum];
817 57416104 : resultslot->tts_isnull[resultnum] = scanslot->tts_isnull[attnum];
818 :
819 57416104 : EEO_NEXT();
820 : }
821 :
822 738 : EEO_CASE(EEOP_ASSIGN_OLD_VAR)
823 : {
824 738 : int resultnum = op->d.assign_var.resultnum;
825 738 : int attnum = op->d.assign_var.attnum;
826 :
827 : /*
828 : * We do not need CheckVarSlotCompatibility here; that was taken
829 : * care of at compilation time. But see EEOP_INNER_VAR comments.
830 : */
831 : Assert(attnum >= 0 && attnum < oldslot->tts_nvalid);
832 : Assert(resultnum >= 0 && resultnum < resultslot->tts_tupleDescriptor->natts);
833 738 : resultslot->tts_values[resultnum] = oldslot->tts_values[attnum];
834 738 : resultslot->tts_isnull[resultnum] = oldslot->tts_isnull[attnum];
835 :
836 738 : EEO_NEXT();
837 : }
838 :
839 736 : EEO_CASE(EEOP_ASSIGN_NEW_VAR)
840 : {
841 736 : int resultnum = op->d.assign_var.resultnum;
842 736 : int attnum = op->d.assign_var.attnum;
843 :
844 : /*
845 : * We do not need CheckVarSlotCompatibility here; that was taken
846 : * care of at compilation time. But see EEOP_INNER_VAR comments.
847 : */
848 : Assert(attnum >= 0 && attnum < newslot->tts_nvalid);
849 : Assert(resultnum >= 0 && resultnum < resultslot->tts_tupleDescriptor->natts);
850 736 : resultslot->tts_values[resultnum] = newslot->tts_values[attnum];
851 736 : resultslot->tts_isnull[resultnum] = newslot->tts_isnull[attnum];
852 :
853 736 : EEO_NEXT();
854 : }
855 :
856 25598598 : EEO_CASE(EEOP_ASSIGN_TMP)
857 : {
858 25598598 : int resultnum = op->d.assign_tmp.resultnum;
859 :
860 : Assert(resultnum >= 0 && resultnum < resultslot->tts_tupleDescriptor->natts);
861 25598598 : resultslot->tts_values[resultnum] = state->resvalue;
862 25598598 : resultslot->tts_isnull[resultnum] = state->resnull;
863 :
864 25598598 : EEO_NEXT();
865 : }
866 :
867 10601290 : EEO_CASE(EEOP_ASSIGN_TMP_MAKE_RO)
868 : {
869 10601290 : int resultnum = op->d.assign_tmp.resultnum;
870 :
871 : Assert(resultnum >= 0 && resultnum < resultslot->tts_tupleDescriptor->natts);
872 10601290 : resultslot->tts_isnull[resultnum] = state->resnull;
873 10601290 : if (!resultslot->tts_isnull[resultnum])
874 7490016 : resultslot->tts_values[resultnum] =
875 7490016 : MakeExpandedObjectReadOnlyInternal(state->resvalue);
876 : else
877 3111274 : resultslot->tts_values[resultnum] = state->resvalue;
878 :
879 10601290 : EEO_NEXT();
880 : }
881 :
882 18901966 : EEO_CASE(EEOP_CONST)
883 : {
884 18901966 : *op->resnull = op->d.constval.isnull;
885 18901966 : *op->resvalue = op->d.constval.value;
886 :
887 18901966 : EEO_NEXT();
888 : }
889 :
890 : /*
891 : * Function-call implementations. Arguments have previously been
892 : * evaluated directly into fcinfo->args.
893 : *
894 : * As both STRICT checks and function-usage are noticeable performance
895 : * wise, and function calls are a very hot-path (they also back
896 : * operators!), it's worth having so many separate opcodes.
897 : *
898 : * Note: the reason for using a temporary variable "d", here and in
899 : * other places, is that some compilers think "*op->resvalue = f();"
900 : * requires them to evaluate op->resvalue into a register before
901 : * calling f(), just in case f() is able to modify op->resvalue
902 : * somehow. The extra line of code can save a useless register spill
903 : * and reload across the function call.
904 : */
905 1872216 : EEO_CASE(EEOP_FUNCEXPR)
906 : {
907 1872216 : FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
908 : Datum d;
909 :
910 1872216 : fcinfo->isnull = false;
911 1872216 : d = op->d.func.fn_addr(fcinfo);
912 1862608 : *op->resvalue = d;
913 1862608 : *op->resnull = fcinfo->isnull;
914 :
915 1862608 : EEO_NEXT();
916 : }
917 :
918 99407440 : EEO_CASE(EEOP_FUNCEXPR_STRICT)
919 : {
920 99407440 : FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
921 99407440 : NullableDatum *args = fcinfo->args;
922 99407440 : int nargs = op->d.func.nargs;
923 : Datum d;
924 :
925 : /* strict function, so check for NULL args */
926 284499888 : for (int argno = 0; argno < nargs; argno++)
927 : {
928 186219746 : if (args[argno].isnull)
929 : {
930 1127298 : *op->resnull = true;
931 1127298 : goto strictfail;
932 : }
933 : }
934 98280142 : fcinfo->isnull = false;
935 98280142 : d = op->d.func.fn_addr(fcinfo);
936 98273540 : *op->resvalue = d;
937 98273540 : *op->resnull = fcinfo->isnull;
938 :
939 99400838 : strictfail:
940 99400838 : EEO_NEXT();
941 : }
942 :
943 208 : EEO_CASE(EEOP_FUNCEXPR_FUSAGE)
944 : {
945 : /* not common enough to inline */
946 208 : ExecEvalFuncExprFusage(state, op, econtext);
947 :
948 208 : EEO_NEXT();
949 : }
950 :
951 6 : EEO_CASE(EEOP_FUNCEXPR_STRICT_FUSAGE)
952 : {
953 : /* not common enough to inline */
954 6 : ExecEvalFuncExprStrictFusage(state, op, econtext);
955 :
956 6 : EEO_NEXT();
957 : }
958 :
959 : /*
960 : * If any of its clauses is FALSE, an AND's result is FALSE regardless
961 : * of the states of the rest of the clauses, so we can stop evaluating
962 : * and return FALSE immediately. If none are FALSE and one or more is
963 : * NULL, we return NULL; otherwise we return TRUE. This makes sense
964 : * when you interpret NULL as "don't know": perhaps one of the "don't
965 : * knows" would have been FALSE if we'd known its value. Only when
966 : * all the inputs are known to be TRUE can we state confidently that
967 : * the AND's result is TRUE.
968 : */
969 1033494 : EEO_CASE(EEOP_BOOL_AND_STEP_FIRST)
970 : {
971 1033494 : *op->d.boolexpr.anynull = false;
972 :
973 : /*
974 : * EEOP_BOOL_AND_STEP_FIRST resets anynull, otherwise it's the
975 : * same as EEOP_BOOL_AND_STEP - so fall through to that.
976 : */
977 :
978 : /* FALL THROUGH */
979 : }
980 :
981 1170668 : EEO_CASE(EEOP_BOOL_AND_STEP)
982 : {
983 1170668 : if (*op->resnull)
984 : {
985 1216 : *op->d.boolexpr.anynull = true;
986 : }
987 1169452 : else if (!DatumGetBool(*op->resvalue))
988 : {
989 : /* result is already set to FALSE, need not change it */
990 : /* bail out early */
991 777954 : EEO_JUMP(op->d.boolexpr.jumpdone);
992 : }
993 :
994 392714 : EEO_NEXT();
995 : }
996 :
997 255540 : EEO_CASE(EEOP_BOOL_AND_STEP_LAST)
998 : {
999 255540 : if (*op->resnull)
1000 : {
1001 : /* result is already set to NULL, need not change it */
1002 : }
1003 254662 : else if (!DatumGetBool(*op->resvalue))
1004 : {
1005 : /* result is already set to FALSE, need not change it */
1006 :
1007 : /*
1008 : * No point jumping early to jumpdone - would be same target
1009 : * (as this is the last argument to the AND expression),
1010 : * except more expensive.
1011 : */
1012 : }
1013 184726 : else if (*op->d.boolexpr.anynull)
1014 : {
1015 372 : *op->resvalue = (Datum) 0;
1016 372 : *op->resnull = true;
1017 : }
1018 : else
1019 : {
1020 : /* result is already set to TRUE, need not change it */
1021 : }
1022 :
1023 255540 : EEO_NEXT();
1024 : }
1025 :
1026 : /*
1027 : * If any of its clauses is TRUE, an OR's result is TRUE regardless of
1028 : * the states of the rest of the clauses, so we can stop evaluating
1029 : * and return TRUE immediately. If none are TRUE and one or more is
1030 : * NULL, we return NULL; otherwise we return FALSE. This makes sense
1031 : * when you interpret NULL as "don't know": perhaps one of the "don't
1032 : * knows" would have been TRUE if we'd known its value. Only when all
1033 : * the inputs are known to be FALSE can we state confidently that the
1034 : * OR's result is FALSE.
1035 : */
1036 3608776 : EEO_CASE(EEOP_BOOL_OR_STEP_FIRST)
1037 : {
1038 3608776 : *op->d.boolexpr.anynull = false;
1039 :
1040 : /*
1041 : * EEOP_BOOL_OR_STEP_FIRST resets anynull, otherwise it's the same
1042 : * as EEOP_BOOL_OR_STEP - so fall through to that.
1043 : */
1044 :
1045 : /* FALL THROUGH */
1046 : }
1047 :
1048 7040106 : EEO_CASE(EEOP_BOOL_OR_STEP)
1049 : {
1050 7040106 : if (*op->resnull)
1051 : {
1052 163200 : *op->d.boolexpr.anynull = true;
1053 : }
1054 6876906 : else if (DatumGetBool(*op->resvalue))
1055 : {
1056 : /* result is already set to TRUE, need not change it */
1057 : /* bail out early */
1058 444182 : EEO_JUMP(op->d.boolexpr.jumpdone);
1059 : }
1060 :
1061 6595924 : EEO_NEXT();
1062 : }
1063 :
1064 3164594 : EEO_CASE(EEOP_BOOL_OR_STEP_LAST)
1065 : {
1066 3164594 : if (*op->resnull)
1067 : {
1068 : /* result is already set to NULL, need not change it */
1069 : }
1070 3067314 : else if (DatumGetBool(*op->resvalue))
1071 : {
1072 : /* result is already set to TRUE, need not change it */
1073 :
1074 : /*
1075 : * No point jumping to jumpdone - would be same target (as
1076 : * this is the last argument to the AND expression), except
1077 : * more expensive.
1078 : */
1079 : }
1080 2998048 : else if (*op->d.boolexpr.anynull)
1081 : {
1082 6450 : *op->resvalue = (Datum) 0;
1083 6450 : *op->resnull = true;
1084 : }
1085 : else
1086 : {
1087 : /* result is already set to FALSE, need not change it */
1088 : }
1089 :
1090 3164594 : EEO_NEXT();
1091 : }
1092 :
1093 1851464 : EEO_CASE(EEOP_BOOL_NOT_STEP)
1094 : {
1095 : /*
1096 : * Evaluation of 'not' is simple... if expr is false, then return
1097 : * 'true' and vice versa. It's safe to do this even on a
1098 : * nominally null value, so we ignore resnull; that means that
1099 : * NULL in produces NULL out, which is what we want.
1100 : */
1101 1851464 : *op->resvalue = BoolGetDatum(!DatumGetBool(*op->resvalue));
1102 :
1103 1851464 : EEO_NEXT();
1104 : }
1105 :
1106 78473150 : EEO_CASE(EEOP_QUAL)
1107 : {
1108 : /* simplified version of BOOL_AND_STEP for use by ExecQual() */
1109 :
1110 : /* If argument (also result) is false or null ... */
1111 78473150 : if (*op->resnull ||
1112 77595730 : !DatumGetBool(*op->resvalue))
1113 : {
1114 : /* ... bail out early, returning FALSE */
1115 39026328 : *op->resnull = false;
1116 39026328 : *op->resvalue = BoolGetDatum(false);
1117 39026328 : EEO_JUMP(op->d.qualexpr.jumpdone);
1118 : }
1119 :
1120 : /*
1121 : * Otherwise, leave the TRUE value in place, in case this is the
1122 : * last qual. Then, TRUE is the correct answer.
1123 : */
1124 :
1125 39446822 : EEO_NEXT();
1126 : }
1127 :
1128 323184 : EEO_CASE(EEOP_JUMP)
1129 : {
1130 : /* Unconditionally jump to target step */
1131 323184 : EEO_JUMP(op->d.jump.jumpdone);
1132 : }
1133 :
1134 673402 : EEO_CASE(EEOP_JUMP_IF_NULL)
1135 : {
1136 : /* Transfer control if current result is null */
1137 673402 : if (*op->resnull)
1138 3330 : EEO_JUMP(op->d.jump.jumpdone);
1139 :
1140 670072 : EEO_NEXT();
1141 : }
1142 :
1143 263924 : EEO_CASE(EEOP_JUMP_IF_NOT_NULL)
1144 : {
1145 : /* Transfer control if current result is non-null */
1146 263924 : if (!*op->resnull)
1147 192232 : EEO_JUMP(op->d.jump.jumpdone);
1148 :
1149 71692 : EEO_NEXT();
1150 : }
1151 :
1152 1918650 : EEO_CASE(EEOP_JUMP_IF_NOT_TRUE)
1153 : {
1154 : /* Transfer control if current result is null or false */
1155 1918650 : if (*op->resnull || !DatumGetBool(*op->resvalue))
1156 1478674 : EEO_JUMP(op->d.jump.jumpdone);
1157 :
1158 439976 : EEO_NEXT();
1159 : }
1160 :
1161 991928 : EEO_CASE(EEOP_NULLTEST_ISNULL)
1162 : {
1163 991928 : *op->resvalue = BoolGetDatum(*op->resnull);
1164 991928 : *op->resnull = false;
1165 :
1166 991928 : EEO_NEXT();
1167 : }
1168 :
1169 3138906 : EEO_CASE(EEOP_NULLTEST_ISNOTNULL)
1170 : {
1171 3138906 : *op->resvalue = BoolGetDatum(!*op->resnull);
1172 3138906 : *op->resnull = false;
1173 :
1174 3138906 : EEO_NEXT();
1175 : }
1176 :
1177 696 : EEO_CASE(EEOP_NULLTEST_ROWISNULL)
1178 : {
1179 : /* out of line implementation: too large */
1180 696 : ExecEvalRowNull(state, op, econtext);
1181 :
1182 696 : EEO_NEXT();
1183 : }
1184 :
1185 554 : EEO_CASE(EEOP_NULLTEST_ROWISNOTNULL)
1186 : {
1187 : /* out of line implementation: too large */
1188 554 : ExecEvalRowNotNull(state, op, econtext);
1189 :
1190 554 : EEO_NEXT();
1191 : }
1192 :
1193 : /* BooleanTest implementations for all booltesttypes */
1194 :
1195 81164 : EEO_CASE(EEOP_BOOLTEST_IS_TRUE)
1196 : {
1197 81164 : if (*op->resnull)
1198 : {
1199 80290 : *op->resvalue = BoolGetDatum(false);
1200 80290 : *op->resnull = false;
1201 : }
1202 : /* else, input value is the correct output as well */
1203 :
1204 81164 : EEO_NEXT();
1205 : }
1206 :
1207 1052 : EEO_CASE(EEOP_BOOLTEST_IS_NOT_TRUE)
1208 : {
1209 1052 : if (*op->resnull)
1210 : {
1211 174 : *op->resvalue = BoolGetDatum(true);
1212 174 : *op->resnull = false;
1213 : }
1214 : else
1215 878 : *op->resvalue = BoolGetDatum(!DatumGetBool(*op->resvalue));
1216 :
1217 1052 : EEO_NEXT();
1218 : }
1219 :
1220 826 : EEO_CASE(EEOP_BOOLTEST_IS_FALSE)
1221 : {
1222 826 : if (*op->resnull)
1223 : {
1224 162 : *op->resvalue = BoolGetDatum(false);
1225 162 : *op->resnull = false;
1226 : }
1227 : else
1228 664 : *op->resvalue = BoolGetDatum(!DatumGetBool(*op->resvalue));
1229 :
1230 826 : EEO_NEXT();
1231 : }
1232 :
1233 542 : EEO_CASE(EEOP_BOOLTEST_IS_NOT_FALSE)
1234 : {
1235 542 : if (*op->resnull)
1236 : {
1237 42 : *op->resvalue = BoolGetDatum(true);
1238 42 : *op->resnull = false;
1239 : }
1240 : /* else, input value is the correct output as well */
1241 :
1242 542 : EEO_NEXT();
1243 : }
1244 :
1245 6771756 : EEO_CASE(EEOP_PARAM_EXEC)
1246 : {
1247 : /* out of line implementation: too large */
1248 6771756 : ExecEvalParamExec(state, op, econtext);
1249 :
1250 6771738 : EEO_NEXT();
1251 : }
1252 :
1253 517592 : EEO_CASE(EEOP_PARAM_EXTERN)
1254 : {
1255 : /* out of line implementation: too large */
1256 517592 : ExecEvalParamExtern(state, op, econtext);
1257 517592 : EEO_NEXT();
1258 : }
1259 :
1260 393600 : EEO_CASE(EEOP_PARAM_CALLBACK)
1261 : {
1262 : /* allow an extension module to supply a PARAM_EXTERN value */
1263 393600 : op->d.cparam.paramfunc(state, op, econtext);
1264 393594 : EEO_NEXT();
1265 : }
1266 :
1267 1382704 : EEO_CASE(EEOP_PARAM_SET)
1268 : {
1269 : /* out of line, unlikely to matter performance-wise */
1270 1382704 : ExecEvalParamSet(state, op, econtext);
1271 1382704 : EEO_NEXT();
1272 : }
1273 :
1274 49894 : EEO_CASE(EEOP_CASE_TESTVAL)
1275 : {
1276 : /*
1277 : * Normally upper parts of the expression tree have setup the
1278 : * values to be returned here, but some parts of the system
1279 : * currently misuse {caseValue,domainValue}_{datum,isNull} to set
1280 : * run-time data. So if no values have been set-up, use
1281 : * ExprContext's. This isn't pretty, but also not *that* ugly,
1282 : * and this is unlikely to be performance sensitive enough to
1283 : * worry about an extra branch.
1284 : */
1285 49894 : if (op->d.casetest.value)
1286 : {
1287 43408 : *op->resvalue = *op->d.casetest.value;
1288 43408 : *op->resnull = *op->d.casetest.isnull;
1289 : }
1290 : else
1291 : {
1292 6486 : *op->resvalue = econtext->caseValue_datum;
1293 6486 : *op->resnull = econtext->caseValue_isNull;
1294 : }
1295 :
1296 49894 : EEO_NEXT();
1297 : }
1298 :
1299 82204 : EEO_CASE(EEOP_DOMAIN_TESTVAL)
1300 : {
1301 : /*
1302 : * See EEOP_CASE_TESTVAL comment.
1303 : */
1304 82204 : if (op->d.casetest.value)
1305 : {
1306 13568 : *op->resvalue = *op->d.casetest.value;
1307 13568 : *op->resnull = *op->d.casetest.isnull;
1308 : }
1309 : else
1310 : {
1311 68636 : *op->resvalue = econtext->domainValue_datum;
1312 68636 : *op->resnull = econtext->domainValue_isNull;
1313 : }
1314 :
1315 82204 : EEO_NEXT();
1316 : }
1317 :
1318 4776 : EEO_CASE(EEOP_MAKE_READONLY)
1319 : {
1320 : /*
1321 : * Force a varlena value that might be read multiple times to R/O
1322 : */
1323 4776 : if (!*op->d.make_readonly.isnull)
1324 4712 : *op->resvalue =
1325 4712 : MakeExpandedObjectReadOnlyInternal(*op->d.make_readonly.value);
1326 4776 : *op->resnull = *op->d.make_readonly.isnull;
1327 :
1328 4776 : EEO_NEXT();
1329 : }
1330 :
1331 6031796 : EEO_CASE(EEOP_IOCOERCE)
1332 : {
1333 : /*
1334 : * Evaluate a CoerceViaIO node. This can be quite a hot path, so
1335 : * inline as much work as possible. The source value is in our
1336 : * result variable.
1337 : *
1338 : * Also look at ExecEvalCoerceViaIOSafe() if you change anything
1339 : * here.
1340 : */
1341 : char *str;
1342 :
1343 : /* call output function (similar to OutputFunctionCall) */
1344 6031796 : if (*op->resnull)
1345 : {
1346 : /* output functions are not called on nulls */
1347 62616 : str = NULL;
1348 : }
1349 : else
1350 : {
1351 : FunctionCallInfo fcinfo_out;
1352 :
1353 5969180 : fcinfo_out = op->d.iocoerce.fcinfo_data_out;
1354 5969180 : fcinfo_out->args[0].value = *op->resvalue;
1355 5969180 : fcinfo_out->args[0].isnull = false;
1356 :
1357 5969180 : fcinfo_out->isnull = false;
1358 5969180 : str = DatumGetCString(FunctionCallInvoke(fcinfo_out));
1359 :
1360 : /* OutputFunctionCall assumes result isn't null */
1361 : Assert(!fcinfo_out->isnull);
1362 : }
1363 :
1364 : /* call input function (similar to InputFunctionCall) */
1365 6031796 : if (!op->d.iocoerce.finfo_in->fn_strict || str != NULL)
1366 : {
1367 : FunctionCallInfo fcinfo_in;
1368 : Datum d;
1369 :
1370 5969296 : fcinfo_in = op->d.iocoerce.fcinfo_data_in;
1371 5969296 : fcinfo_in->args[0].value = PointerGetDatum(str);
1372 5969296 : fcinfo_in->args[0].isnull = *op->resnull;
1373 : /* second and third arguments are already set up */
1374 :
1375 5969296 : fcinfo_in->isnull = false;
1376 5969296 : d = FunctionCallInvoke(fcinfo_in);
1377 5969256 : *op->resvalue = d;
1378 :
1379 : /* Should get null result if and only if str is NULL */
1380 : if (str == NULL)
1381 : {
1382 : Assert(*op->resnull);
1383 : Assert(fcinfo_in->isnull);
1384 : }
1385 : else
1386 : {
1387 : Assert(!*op->resnull);
1388 : Assert(!fcinfo_in->isnull);
1389 : }
1390 : }
1391 :
1392 6031756 : EEO_NEXT();
1393 : }
1394 :
1395 0 : EEO_CASE(EEOP_IOCOERCE_SAFE)
1396 : {
1397 0 : ExecEvalCoerceViaIOSafe(state, op);
1398 0 : EEO_NEXT();
1399 : }
1400 :
1401 1351392 : EEO_CASE(EEOP_DISTINCT)
1402 : {
1403 : /*
1404 : * IS DISTINCT FROM must evaluate arguments (already done into
1405 : * fcinfo->args) to determine whether they are NULL; if either is
1406 : * NULL then the result is determined. If neither is NULL, then
1407 : * proceed to evaluate the comparison function, which is just the
1408 : * type's standard equality operator. We need not care whether
1409 : * that function is strict. Because the handling of nulls is
1410 : * different, we can't just reuse EEOP_FUNCEXPR.
1411 : */
1412 1351392 : FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
1413 :
1414 : /* check function arguments for NULLness */
1415 1351392 : if (fcinfo->args[0].isnull && fcinfo->args[1].isnull)
1416 : {
1417 : /* Both NULL? Then is not distinct... */
1418 1011182 : *op->resvalue = BoolGetDatum(false);
1419 1011182 : *op->resnull = false;
1420 : }
1421 340210 : else if (fcinfo->args[0].isnull || fcinfo->args[1].isnull)
1422 : {
1423 : /* Only one is NULL? Then is distinct... */
1424 290 : *op->resvalue = BoolGetDatum(true);
1425 290 : *op->resnull = false;
1426 : }
1427 : else
1428 : {
1429 : /* Neither null, so apply the equality function */
1430 : Datum eqresult;
1431 :
1432 339920 : fcinfo->isnull = false;
1433 339920 : eqresult = op->d.func.fn_addr(fcinfo);
1434 : /* Must invert result of "="; safe to do even if null */
1435 339920 : *op->resvalue = BoolGetDatum(!DatumGetBool(eqresult));
1436 339920 : *op->resnull = fcinfo->isnull;
1437 : }
1438 :
1439 1351392 : EEO_NEXT();
1440 : }
1441 :
1442 : /* see EEOP_DISTINCT for comments, this is just inverted */
1443 11540048 : EEO_CASE(EEOP_NOT_DISTINCT)
1444 : {
1445 11540048 : FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
1446 :
1447 11540048 : if (fcinfo->args[0].isnull && fcinfo->args[1].isnull)
1448 : {
1449 72904 : *op->resvalue = BoolGetDatum(true);
1450 72904 : *op->resnull = false;
1451 : }
1452 11467144 : else if (fcinfo->args[0].isnull || fcinfo->args[1].isnull)
1453 : {
1454 292 : *op->resvalue = BoolGetDatum(false);
1455 292 : *op->resnull = false;
1456 : }
1457 : else
1458 : {
1459 : Datum eqresult;
1460 :
1461 11466852 : fcinfo->isnull = false;
1462 11466852 : eqresult = op->d.func.fn_addr(fcinfo);
1463 11466852 : *op->resvalue = eqresult;
1464 11466852 : *op->resnull = fcinfo->isnull;
1465 : }
1466 :
1467 11540048 : EEO_NEXT();
1468 : }
1469 :
1470 6722 : EEO_CASE(EEOP_NULLIF)
1471 : {
1472 : /*
1473 : * The arguments are already evaluated into fcinfo->args.
1474 : */
1475 6722 : FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
1476 6722 : Datum save_arg0 = fcinfo->args[0].value;
1477 :
1478 : /* if either argument is NULL they can't be equal */
1479 6722 : if (!fcinfo->args[0].isnull && !fcinfo->args[1].isnull)
1480 : {
1481 : Datum result;
1482 :
1483 : /*
1484 : * If first argument is of varlena type, it might be an
1485 : * expanded datum. We need to ensure that the value passed to
1486 : * the comparison function is a read-only pointer. However,
1487 : * if we end by returning the first argument, that will be the
1488 : * original read-write pointer if it was read-write.
1489 : */
1490 6668 : if (op->d.func.make_ro)
1491 242 : fcinfo->args[0].value =
1492 242 : MakeExpandedObjectReadOnlyInternal(save_arg0);
1493 :
1494 6668 : fcinfo->isnull = false;
1495 6668 : result = op->d.func.fn_addr(fcinfo);
1496 :
1497 : /* if the arguments are equal return null */
1498 6668 : if (!fcinfo->isnull && DatumGetBool(result))
1499 : {
1500 138 : *op->resvalue = (Datum) 0;
1501 138 : *op->resnull = true;
1502 :
1503 138 : EEO_NEXT();
1504 : }
1505 : }
1506 :
1507 : /* Arguments aren't equal, so return the first one */
1508 6584 : *op->resvalue = save_arg0;
1509 6584 : *op->resnull = fcinfo->args[0].isnull;
1510 :
1511 6584 : EEO_NEXT();
1512 : }
1513 :
1514 18594 : EEO_CASE(EEOP_SQLVALUEFUNCTION)
1515 : {
1516 : /*
1517 : * Doesn't seem worthwhile to have an inline implementation
1518 : * efficiency-wise.
1519 : */
1520 18594 : ExecEvalSQLValueFunction(state, op);
1521 :
1522 18594 : EEO_NEXT();
1523 : }
1524 :
1525 2 : EEO_CASE(EEOP_CURRENTOFEXPR)
1526 : {
1527 : /* error invocation uses space, and shouldn't ever occur */
1528 2 : ExecEvalCurrentOfExpr(state, op);
1529 :
1530 0 : EEO_NEXT();
1531 : }
1532 :
1533 912 : EEO_CASE(EEOP_NEXTVALUEEXPR)
1534 : {
1535 : /*
1536 : * Doesn't seem worthwhile to have an inline implementation
1537 : * efficiency-wise.
1538 : */
1539 912 : ExecEvalNextValueExpr(state, op);
1540 :
1541 912 : EEO_NEXT();
1542 : }
1543 :
1544 642 : EEO_CASE(EEOP_RETURNINGEXPR)
1545 : {
1546 : /*
1547 : * The next op actually evaluates the expression. If the OLD/NEW
1548 : * row doesn't exist, skip that and return NULL.
1549 : */
1550 642 : if (state->flags & op->d.returningexpr.nullflag)
1551 : {
1552 120 : *op->resvalue = (Datum) 0;
1553 120 : *op->resnull = true;
1554 :
1555 120 : EEO_JUMP(op->d.returningexpr.jumpdone);
1556 : }
1557 :
1558 522 : EEO_NEXT();
1559 : }
1560 :
1561 760890 : EEO_CASE(EEOP_ARRAYEXPR)
1562 : {
1563 : /* too complex for an inline implementation */
1564 760890 : ExecEvalArrayExpr(state, op);
1565 :
1566 760890 : EEO_NEXT();
1567 : }
1568 :
1569 67366 : EEO_CASE(EEOP_ARRAYCOERCE)
1570 : {
1571 : /* too complex for an inline implementation */
1572 67366 : ExecEvalArrayCoerce(state, op, econtext);
1573 :
1574 67334 : EEO_NEXT();
1575 : }
1576 :
1577 27652 : EEO_CASE(EEOP_ROW)
1578 : {
1579 : /* too complex for an inline implementation */
1580 27652 : ExecEvalRow(state, op);
1581 :
1582 27652 : EEO_NEXT();
1583 : }
1584 :
1585 208692 : EEO_CASE(EEOP_ROWCOMPARE_STEP)
1586 : {
1587 208692 : FunctionCallInfo fcinfo = op->d.rowcompare_step.fcinfo_data;
1588 : Datum d;
1589 :
1590 : /* force NULL result if strict fn and NULL input */
1591 208692 : if (op->d.rowcompare_step.finfo->fn_strict &&
1592 208692 : (fcinfo->args[0].isnull || fcinfo->args[1].isnull))
1593 : {
1594 18 : *op->resnull = true;
1595 18 : EEO_JUMP(op->d.rowcompare_step.jumpnull);
1596 : }
1597 :
1598 : /* Apply comparison function */
1599 208674 : fcinfo->isnull = false;
1600 208674 : d = op->d.rowcompare_step.fn_addr(fcinfo);
1601 208674 : *op->resvalue = d;
1602 :
1603 : /* force NULL result if NULL function result */
1604 208674 : if (fcinfo->isnull)
1605 : {
1606 0 : *op->resnull = true;
1607 0 : EEO_JUMP(op->d.rowcompare_step.jumpnull);
1608 : }
1609 208674 : *op->resnull = false;
1610 :
1611 : /* If unequal, no need to compare remaining columns */
1612 208674 : if (DatumGetInt32(*op->resvalue) != 0)
1613 : {
1614 94512 : EEO_JUMP(op->d.rowcompare_step.jumpdone);
1615 : }
1616 :
1617 114162 : EEO_NEXT();
1618 : }
1619 :
1620 94512 : EEO_CASE(EEOP_ROWCOMPARE_FINAL)
1621 : {
1622 94512 : int32 cmpresult = DatumGetInt32(*op->resvalue);
1623 94512 : CompareType cmptype = op->d.rowcompare_final.cmptype;
1624 :
1625 94512 : *op->resnull = false;
1626 94512 : switch (cmptype)
1627 : {
1628 : /* EQ and NE cases aren't allowed here */
1629 34404 : case COMPARE_LT:
1630 34404 : *op->resvalue = BoolGetDatum(cmpresult < 0);
1631 34404 : break;
1632 60000 : case COMPARE_LE:
1633 60000 : *op->resvalue = BoolGetDatum(cmpresult <= 0);
1634 60000 : break;
1635 6 : case COMPARE_GE:
1636 6 : *op->resvalue = BoolGetDatum(cmpresult >= 0);
1637 6 : break;
1638 102 : case COMPARE_GT:
1639 102 : *op->resvalue = BoolGetDatum(cmpresult > 0);
1640 102 : break;
1641 0 : default:
1642 : Assert(false);
1643 0 : break;
1644 : }
1645 :
1646 94512 : EEO_NEXT();
1647 : }
1648 :
1649 23276 : EEO_CASE(EEOP_MINMAX)
1650 : {
1651 : /* too complex for an inline implementation */
1652 23276 : ExecEvalMinMax(state, op);
1653 :
1654 23276 : EEO_NEXT();
1655 : }
1656 :
1657 110492 : EEO_CASE(EEOP_FIELDSELECT)
1658 : {
1659 : /* too complex for an inline implementation */
1660 110492 : ExecEvalFieldSelect(state, op, econtext);
1661 :
1662 110492 : EEO_NEXT();
1663 : }
1664 :
1665 520 : EEO_CASE(EEOP_FIELDSTORE_DEFORM)
1666 : {
1667 : /* too complex for an inline implementation */
1668 520 : ExecEvalFieldStoreDeForm(state, op, econtext);
1669 :
1670 520 : EEO_NEXT();
1671 : }
1672 :
1673 520 : EEO_CASE(EEOP_FIELDSTORE_FORM)
1674 : {
1675 : /* too complex for an inline implementation */
1676 520 : ExecEvalFieldStoreForm(state, op, econtext);
1677 :
1678 520 : EEO_NEXT();
1679 : }
1680 :
1681 661162 : EEO_CASE(EEOP_SBSREF_SUBSCRIPTS)
1682 : {
1683 : /* Precheck SubscriptingRef subscript(s) */
1684 661162 : if (op->d.sbsref_subscript.subscriptfunc(state, op, econtext))
1685 : {
1686 661108 : EEO_NEXT();
1687 : }
1688 : else
1689 : {
1690 : /* Subscript is null, short-circuit SubscriptingRef to NULL */
1691 30 : EEO_JUMP(op->d.sbsref_subscript.jumpdone);
1692 : }
1693 : }
1694 :
1695 276 : EEO_CASE(EEOP_SBSREF_OLD)
1696 1902 : EEO_CASE(EEOP_SBSREF_ASSIGN)
1697 661380 : EEO_CASE(EEOP_SBSREF_FETCH)
1698 : {
1699 : /* Perform a SubscriptingRef fetch or assignment */
1700 661380 : op->d.sbsref.subscriptfunc(state, op, econtext);
1701 :
1702 661254 : EEO_NEXT();
1703 : }
1704 :
1705 12116 : EEO_CASE(EEOP_CONVERT_ROWTYPE)
1706 : {
1707 : /* too complex for an inline implementation */
1708 12116 : ExecEvalConvertRowtype(state, op, econtext);
1709 :
1710 12116 : EEO_NEXT();
1711 : }
1712 :
1713 4073022 : EEO_CASE(EEOP_SCALARARRAYOP)
1714 : {
1715 : /* too complex for an inline implementation */
1716 4073022 : ExecEvalScalarArrayOp(state, op);
1717 :
1718 4073022 : EEO_NEXT();
1719 : }
1720 :
1721 4676 : EEO_CASE(EEOP_HASHED_SCALARARRAYOP)
1722 : {
1723 : /* too complex for an inline implementation */
1724 4676 : ExecEvalHashedScalarArrayOp(state, op, econtext);
1725 :
1726 4676 : EEO_NEXT();
1727 : }
1728 :
1729 378 : EEO_CASE(EEOP_DOMAIN_NOTNULL)
1730 : {
1731 : /* too complex for an inline implementation */
1732 378 : ExecEvalConstraintNotNull(state, op);
1733 :
1734 272 : EEO_NEXT();
1735 : }
1736 :
1737 13024 : EEO_CASE(EEOP_DOMAIN_CHECK)
1738 : {
1739 : /* too complex for an inline implementation */
1740 13024 : ExecEvalConstraintCheck(state, op);
1741 :
1742 12602 : EEO_NEXT();
1743 : }
1744 :
1745 0 : EEO_CASE(EEOP_HASHDATUM_SET_INITVAL)
1746 : {
1747 0 : *op->resvalue = op->d.hashdatum_initvalue.init_value;
1748 0 : *op->resnull = false;
1749 :
1750 0 : EEO_NEXT();
1751 : }
1752 :
1753 2720446 : EEO_CASE(EEOP_HASHDATUM_FIRST)
1754 : {
1755 2720446 : FunctionCallInfo fcinfo = op->d.hashdatum.fcinfo_data;
1756 :
1757 : /*
1758 : * Save the Datum on non-null inputs, otherwise store 0 so that
1759 : * subsequent NEXT32 operations combine with an initialized value.
1760 : */
1761 2720446 : if (!fcinfo->args[0].isnull)
1762 2709324 : *op->resvalue = op->d.hashdatum.fn_addr(fcinfo);
1763 : else
1764 11122 : *op->resvalue = (Datum) 0;
1765 :
1766 2720440 : *op->resnull = false;
1767 :
1768 2720440 : EEO_NEXT();
1769 : }
1770 :
1771 9373330 : EEO_CASE(EEOP_HASHDATUM_FIRST_STRICT)
1772 : {
1773 9373330 : FunctionCallInfo fcinfo = op->d.hashdatum.fcinfo_data;
1774 :
1775 9373330 : if (fcinfo->args[0].isnull)
1776 : {
1777 : /*
1778 : * With strict we have the expression return NULL instead of
1779 : * ignoring NULL input values. We've nothing more to do after
1780 : * finding a NULL.
1781 : */
1782 522 : *op->resnull = true;
1783 522 : *op->resvalue = (Datum) 0;
1784 522 : EEO_JUMP(op->d.hashdatum.jumpdone);
1785 : }
1786 :
1787 : /* execute the hash function and save the resulting value */
1788 9372808 : *op->resvalue = op->d.hashdatum.fn_addr(fcinfo);
1789 9372808 : *op->resnull = false;
1790 :
1791 9372808 : EEO_NEXT();
1792 : }
1793 :
1794 4010456 : EEO_CASE(EEOP_HASHDATUM_NEXT32)
1795 : {
1796 4010456 : FunctionCallInfo fcinfo = op->d.hashdatum.fcinfo_data;
1797 : uint32 existinghash;
1798 :
1799 4010456 : existinghash = DatumGetUInt32(op->d.hashdatum.iresult->value);
1800 : /* combine successive hash values by rotating */
1801 4010456 : existinghash = pg_rotate_left32(existinghash, 1);
1802 :
1803 : /* leave the hash value alone on NULL inputs */
1804 4010456 : if (!fcinfo->args[0].isnull)
1805 : {
1806 : uint32 hashvalue;
1807 :
1808 : /* execute hash func and combine with previous hash value */
1809 3905714 : hashvalue = DatumGetUInt32(op->d.hashdatum.fn_addr(fcinfo));
1810 3905714 : existinghash = existinghash ^ hashvalue;
1811 : }
1812 :
1813 4010456 : *op->resvalue = UInt32GetDatum(existinghash);
1814 4010456 : *op->resnull = false;
1815 :
1816 4010456 : EEO_NEXT();
1817 : }
1818 :
1819 1468610 : EEO_CASE(EEOP_HASHDATUM_NEXT32_STRICT)
1820 : {
1821 1468610 : FunctionCallInfo fcinfo = op->d.hashdatum.fcinfo_data;
1822 :
1823 1468610 : if (fcinfo->args[0].isnull)
1824 : {
1825 : /*
1826 : * With strict we have the expression return NULL instead of
1827 : * ignoring NULL input values. We've nothing more to do after
1828 : * finding a NULL.
1829 : */
1830 42 : *op->resnull = true;
1831 42 : *op->resvalue = (Datum) 0;
1832 42 : EEO_JUMP(op->d.hashdatum.jumpdone);
1833 : }
1834 : else
1835 : {
1836 : uint32 existinghash;
1837 : uint32 hashvalue;
1838 :
1839 1468568 : existinghash = DatumGetUInt32(op->d.hashdatum.iresult->value);
1840 : /* combine successive hash values by rotating */
1841 1468568 : existinghash = pg_rotate_left32(existinghash, 1);
1842 :
1843 : /* execute hash func and combine with previous hash value */
1844 1468568 : hashvalue = DatumGetUInt32(op->d.hashdatum.fn_addr(fcinfo));
1845 1468568 : *op->resvalue = UInt32GetDatum(existinghash ^ hashvalue);
1846 1468568 : *op->resnull = false;
1847 : }
1848 :
1849 1468568 : EEO_NEXT();
1850 : }
1851 :
1852 44618 : EEO_CASE(EEOP_XMLEXPR)
1853 : {
1854 : /* too complex for an inline implementation */
1855 44618 : ExecEvalXmlExpr(state, op);
1856 :
1857 44516 : EEO_NEXT();
1858 : }
1859 :
1860 696 : EEO_CASE(EEOP_JSON_CONSTRUCTOR)
1861 : {
1862 : /* too complex for an inline implementation */
1863 696 : ExecEvalJsonConstructor(state, op, econtext);
1864 616 : EEO_NEXT();
1865 : }
1866 :
1867 2750 : EEO_CASE(EEOP_IS_JSON)
1868 : {
1869 : /* too complex for an inline implementation */
1870 2750 : ExecEvalJsonIsPredicate(state, op);
1871 :
1872 2750 : EEO_NEXT();
1873 : }
1874 :
1875 5282 : EEO_CASE(EEOP_JSONEXPR_PATH)
1876 : {
1877 : /* too complex for an inline implementation */
1878 5282 : EEO_JUMP(ExecEvalJsonExprPath(state, op, econtext));
1879 : }
1880 :
1881 1806 : EEO_CASE(EEOP_JSONEXPR_COERCION)
1882 : {
1883 : /* too complex for an inline implementation */
1884 1806 : ExecEvalJsonCoercion(state, op, econtext);
1885 :
1886 1650 : EEO_NEXT();
1887 : }
1888 :
1889 1698 : EEO_CASE(EEOP_JSONEXPR_COERCION_FINISH)
1890 : {
1891 : /* too complex for an inline implementation */
1892 1698 : ExecEvalJsonCoercionFinish(state, op);
1893 :
1894 1620 : EEO_NEXT();
1895 : }
1896 :
1897 498544 : EEO_CASE(EEOP_AGGREF)
1898 : {
1899 : /*
1900 : * Returns a Datum whose value is the precomputed aggregate value
1901 : * found in the given expression context.
1902 : */
1903 498544 : int aggno = op->d.aggref.aggno;
1904 :
1905 : Assert(econtext->ecxt_aggvalues != NULL);
1906 :
1907 498544 : *op->resvalue = econtext->ecxt_aggvalues[aggno];
1908 498544 : *op->resnull = econtext->ecxt_aggnulls[aggno];
1909 :
1910 498544 : EEO_NEXT();
1911 : }
1912 :
1913 1670 : EEO_CASE(EEOP_GROUPING_FUNC)
1914 : {
1915 : /* too complex/uncommon for an inline implementation */
1916 1670 : ExecEvalGroupingFunc(state, op);
1917 :
1918 1670 : EEO_NEXT();
1919 : }
1920 :
1921 1030882 : EEO_CASE(EEOP_WINDOW_FUNC)
1922 : {
1923 : /*
1924 : * Like Aggref, just return a precomputed value from the econtext.
1925 : */
1926 1030882 : WindowFuncExprState *wfunc = op->d.window_func.wfstate;
1927 :
1928 : Assert(econtext->ecxt_aggvalues != NULL);
1929 :
1930 1030882 : *op->resvalue = econtext->ecxt_aggvalues[wfunc->wfuncno];
1931 1030882 : *op->resnull = econtext->ecxt_aggnulls[wfunc->wfuncno];
1932 :
1933 1030882 : EEO_NEXT();
1934 : }
1935 :
1936 410 : EEO_CASE(EEOP_MERGE_SUPPORT_FUNC)
1937 : {
1938 : /* too complex/uncommon for an inline implementation */
1939 410 : ExecEvalMergeSupportFunc(state, op, econtext);
1940 :
1941 410 : EEO_NEXT();
1942 : }
1943 :
1944 2859710 : EEO_CASE(EEOP_SUBPLAN)
1945 : {
1946 : /* too complex for an inline implementation */
1947 2859710 : ExecEvalSubPlan(state, op, econtext);
1948 :
1949 2859704 : EEO_NEXT();
1950 : }
1951 :
1952 : /* evaluate a strict aggregate deserialization function */
1953 426 : EEO_CASE(EEOP_AGG_STRICT_DESERIALIZE)
1954 : {
1955 : /* Don't call a strict deserialization function with NULL input */
1956 426 : if (op->d.agg_deserialize.fcinfo_data->args[0].isnull)
1957 128 : EEO_JUMP(op->d.agg_deserialize.jumpnull);
1958 :
1959 : /* fallthrough */
1960 : }
1961 :
1962 : /* evaluate aggregate deserialization function (non-strict portion) */
1963 298 : EEO_CASE(EEOP_AGG_DESERIALIZE)
1964 : {
1965 298 : FunctionCallInfo fcinfo = op->d.agg_deserialize.fcinfo_data;
1966 298 : AggState *aggstate = castNode(AggState, state->parent);
1967 : MemoryContext oldContext;
1968 :
1969 : /*
1970 : * We run the deserialization functions in per-input-tuple memory
1971 : * context.
1972 : */
1973 298 : oldContext = MemoryContextSwitchTo(aggstate->tmpcontext->ecxt_per_tuple_memory);
1974 298 : fcinfo->isnull = false;
1975 298 : *op->resvalue = FunctionCallInvoke(fcinfo);
1976 298 : *op->resnull = fcinfo->isnull;
1977 298 : MemoryContextSwitchTo(oldContext);
1978 :
1979 298 : EEO_NEXT();
1980 : }
1981 :
1982 : /*
1983 : * Check that a strict aggregate transition / combination function's
1984 : * input is not NULL.
1985 : */
1986 :
1987 4969558 : EEO_CASE(EEOP_AGG_STRICT_INPUT_CHECK_ARGS)
1988 : {
1989 4969558 : NullableDatum *args = op->d.agg_strict_input_check.args;
1990 4969558 : int nargs = op->d.agg_strict_input_check.nargs;
1991 :
1992 10021360 : for (int argno = 0; argno < nargs; argno++)
1993 : {
1994 5210266 : if (args[argno].isnull)
1995 158464 : EEO_JUMP(op->d.agg_strict_input_check.jumpnull);
1996 : }
1997 4811094 : EEO_NEXT();
1998 : }
1999 :
2000 376704 : EEO_CASE(EEOP_AGG_STRICT_INPUT_CHECK_NULLS)
2001 : {
2002 376704 : bool *nulls = op->d.agg_strict_input_check.nulls;
2003 376704 : int nargs = op->d.agg_strict_input_check.nargs;
2004 :
2005 708408 : for (int argno = 0; argno < nargs; argno++)
2006 : {
2007 376704 : if (nulls[argno])
2008 45000 : EEO_JUMP(op->d.agg_strict_input_check.jumpnull);
2009 : }
2010 331704 : EEO_NEXT();
2011 : }
2012 :
2013 : /*
2014 : * Check for a NULL pointer to the per-group states.
2015 : */
2016 :
2017 72492 : EEO_CASE(EEOP_AGG_PLAIN_PERGROUP_NULLCHECK)
2018 : {
2019 72492 : AggState *aggstate = castNode(AggState, state->parent);
2020 72492 : AggStatePerGroup pergroup_allaggs =
2021 72492 : aggstate->all_pergroups[op->d.agg_plain_pergroup_nullcheck.setoff];
2022 :
2023 72492 : if (pergroup_allaggs == NULL)
2024 37404 : EEO_JUMP(op->d.agg_plain_pergroup_nullcheck.jumpnull);
2025 :
2026 35088 : EEO_NEXT();
2027 : }
2028 :
2029 : /*
2030 : * Different types of aggregate transition functions are implemented
2031 : * as different types of steps, to avoid incurring unnecessary
2032 : * overhead. There's a step type for each valid combination of having
2033 : * a by value / by reference transition type, [not] needing to the
2034 : * initialize the transition value for the first row in a group from
2035 : * input, and [not] strict transition function.
2036 : *
2037 : * Could optimize further by splitting off by-reference for
2038 : * fixed-length types, but currently that doesn't seem worth it.
2039 : */
2040 :
2041 648170 : EEO_CASE(EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL)
2042 : {
2043 648170 : AggState *aggstate = castNode(AggState, state->parent);
2044 648170 : AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
2045 648170 : AggStatePerGroup pergroup =
2046 648170 : &aggstate->all_pergroups[op->d.agg_trans.setoff][op->d.agg_trans.transno];
2047 :
2048 : Assert(pertrans->transtypeByVal);
2049 :
2050 648170 : if (pergroup->noTransValue)
2051 : {
2052 : /* If transValue has not yet been initialized, do so now. */
2053 8780 : ExecAggInitGroup(aggstate, pertrans, pergroup,
2054 : op->d.agg_trans.aggcontext);
2055 : /* copied trans value from input, done this round */
2056 : }
2057 639390 : else if (likely(!pergroup->transValueIsNull))
2058 : {
2059 : /* invoke transition function, unless prevented by strictness */
2060 639390 : ExecAggPlainTransByVal(aggstate, pertrans, pergroup,
2061 : op->d.agg_trans.aggcontext,
2062 : op->d.agg_trans.setno);
2063 : }
2064 :
2065 648170 : EEO_NEXT();
2066 : }
2067 :
2068 : /* see comments above EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL */
2069 17981456 : EEO_CASE(EEOP_AGG_PLAIN_TRANS_STRICT_BYVAL)
2070 : {
2071 17981456 : AggState *aggstate = castNode(AggState, state->parent);
2072 17981456 : AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
2073 17981456 : AggStatePerGroup pergroup =
2074 17981456 : &aggstate->all_pergroups[op->d.agg_trans.setoff][op->d.agg_trans.transno];
2075 :
2076 : Assert(pertrans->transtypeByVal);
2077 :
2078 17981456 : if (likely(!pergroup->transValueIsNull))
2079 17921438 : ExecAggPlainTransByVal(aggstate, pertrans, pergroup,
2080 : op->d.agg_trans.aggcontext,
2081 : op->d.agg_trans.setno);
2082 :
2083 17981456 : EEO_NEXT();
2084 : }
2085 :
2086 : /* see comments above EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL */
2087 9882526 : EEO_CASE(EEOP_AGG_PLAIN_TRANS_BYVAL)
2088 : {
2089 9882526 : AggState *aggstate = castNode(AggState, state->parent);
2090 9882526 : AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
2091 9882526 : AggStatePerGroup pergroup =
2092 9882526 : &aggstate->all_pergroups[op->d.agg_trans.setoff][op->d.agg_trans.transno];
2093 :
2094 : Assert(pertrans->transtypeByVal);
2095 :
2096 9882526 : ExecAggPlainTransByVal(aggstate, pertrans, pergroup,
2097 : op->d.agg_trans.aggcontext,
2098 : op->d.agg_trans.setno);
2099 :
2100 9882454 : EEO_NEXT();
2101 : }
2102 :
2103 : /* see comments above EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL */
2104 195656 : EEO_CASE(EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYREF)
2105 : {
2106 195656 : AggState *aggstate = castNode(AggState, state->parent);
2107 195656 : AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
2108 195656 : AggStatePerGroup pergroup =
2109 195656 : &aggstate->all_pergroups[op->d.agg_trans.setoff][op->d.agg_trans.transno];
2110 :
2111 : Assert(!pertrans->transtypeByVal);
2112 :
2113 195656 : if (pergroup->noTransValue)
2114 878 : ExecAggInitGroup(aggstate, pertrans, pergroup,
2115 : op->d.agg_trans.aggcontext);
2116 194778 : else if (likely(!pergroup->transValueIsNull))
2117 194778 : ExecAggPlainTransByRef(aggstate, pertrans, pergroup,
2118 : op->d.agg_trans.aggcontext,
2119 : op->d.agg_trans.setno);
2120 :
2121 195650 : EEO_NEXT();
2122 : }
2123 :
2124 : /* see comments above EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL */
2125 2617542 : EEO_CASE(EEOP_AGG_PLAIN_TRANS_STRICT_BYREF)
2126 : {
2127 2617542 : AggState *aggstate = castNode(AggState, state->parent);
2128 2617542 : AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
2129 2617542 : AggStatePerGroup pergroup =
2130 2617542 : &aggstate->all_pergroups[op->d.agg_trans.setoff][op->d.agg_trans.transno];
2131 :
2132 : Assert(!pertrans->transtypeByVal);
2133 :
2134 2617542 : if (likely(!pergroup->transValueIsNull))
2135 2617542 : ExecAggPlainTransByRef(aggstate, pertrans, pergroup,
2136 : op->d.agg_trans.aggcontext,
2137 : op->d.agg_trans.setno);
2138 2617542 : EEO_NEXT();
2139 : }
2140 :
2141 : /* see comments above EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL */
2142 23820 : EEO_CASE(EEOP_AGG_PLAIN_TRANS_BYREF)
2143 : {
2144 23820 : AggState *aggstate = castNode(AggState, state->parent);
2145 23820 : AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
2146 23820 : AggStatePerGroup pergroup =
2147 23820 : &aggstate->all_pergroups[op->d.agg_trans.setoff][op->d.agg_trans.transno];
2148 :
2149 : Assert(!pertrans->transtypeByVal);
2150 :
2151 23820 : ExecAggPlainTransByRef(aggstate, pertrans, pergroup,
2152 : op->d.agg_trans.aggcontext,
2153 : op->d.agg_trans.setno);
2154 :
2155 23820 : EEO_NEXT();
2156 : }
2157 :
2158 365850 : EEO_CASE(EEOP_AGG_PRESORTED_DISTINCT_SINGLE)
2159 : {
2160 365850 : AggStatePerTrans pertrans = op->d.agg_presorted_distinctcheck.pertrans;
2161 365850 : AggState *aggstate = castNode(AggState, state->parent);
2162 :
2163 365850 : if (ExecEvalPreOrderedDistinctSingle(aggstate, pertrans))
2164 101956 : EEO_NEXT();
2165 : else
2166 263894 : EEO_JUMP(op->d.agg_presorted_distinctcheck.jumpdistinct);
2167 : }
2168 :
2169 720 : EEO_CASE(EEOP_AGG_PRESORTED_DISTINCT_MULTI)
2170 : {
2171 720 : AggState *aggstate = castNode(AggState, state->parent);
2172 720 : AggStatePerTrans pertrans = op->d.agg_presorted_distinctcheck.pertrans;
2173 :
2174 720 : if (ExecEvalPreOrderedDistinctMulti(aggstate, pertrans))
2175 312 : EEO_NEXT();
2176 : else
2177 408 : EEO_JUMP(op->d.agg_presorted_distinctcheck.jumpdistinct);
2178 : }
2179 :
2180 : /* process single-column ordered aggregate datum */
2181 844384 : EEO_CASE(EEOP_AGG_ORDERED_TRANS_DATUM)
2182 : {
2183 : /* too complex for an inline implementation */
2184 844384 : ExecEvalAggOrderedTransDatum(state, op, econtext);
2185 :
2186 844384 : EEO_NEXT();
2187 : }
2188 :
2189 : /* process multi-column ordered aggregate tuple */
2190 180 : EEO_CASE(EEOP_AGG_ORDERED_TRANS_TUPLE)
2191 : {
2192 : /* too complex for an inline implementation */
2193 180 : ExecEvalAggOrderedTransTuple(state, op, econtext);
2194 :
2195 180 : EEO_NEXT();
2196 : }
2197 :
2198 0 : EEO_CASE(EEOP_LAST)
2199 : {
2200 : /* unreachable */
2201 : Assert(false);
2202 0 : goto out;
2203 : }
2204 : }
2205 :
2206 156600652 : out:
2207 156600652 : *isnull = state->resnull;
2208 156600652 : return state->resvalue;
2209 : }
2210 :
2211 : /*
2212 : * Expression evaluation callback that performs extra checks before executing
2213 : * the expression. Declared extern so other methods of execution can use it
2214 : * too.
2215 : */
2216 : Datum
2217 1761072 : ExecInterpExprStillValid(ExprState *state, ExprContext *econtext, bool *isNull)
2218 : {
2219 : /*
2220 : * First time through, check whether attribute matches Var. Might not be
2221 : * ok anymore, due to schema changes.
2222 : */
2223 1761072 : CheckExprStillValid(state, econtext);
2224 :
2225 : /* skip the check during further executions */
2226 1761048 : state->evalfunc = (ExprStateEvalFunc) state->evalfunc_private;
2227 :
2228 : /* and actually execute */
2229 1761048 : return state->evalfunc(state, econtext, isNull);
2230 : }
2231 :
2232 : /*
2233 : * Check that an expression is still valid in the face of potential schema
2234 : * changes since the plan has been created.
2235 : */
2236 : void
2237 1766568 : CheckExprStillValid(ExprState *state, ExprContext *econtext)
2238 : {
2239 : TupleTableSlot *innerslot;
2240 : TupleTableSlot *outerslot;
2241 : TupleTableSlot *scanslot;
2242 : TupleTableSlot *oldslot;
2243 : TupleTableSlot *newslot;
2244 :
2245 1766568 : innerslot = econtext->ecxt_innertuple;
2246 1766568 : outerslot = econtext->ecxt_outertuple;
2247 1766568 : scanslot = econtext->ecxt_scantuple;
2248 1766568 : oldslot = econtext->ecxt_oldtuple;
2249 1766568 : newslot = econtext->ecxt_newtuple;
2250 :
2251 9911616 : for (int i = 0; i < state->steps_len; i++)
2252 : {
2253 8145072 : ExprEvalStep *op = &state->steps[i];
2254 :
2255 8145072 : switch (ExecEvalStepOp(state, op))
2256 : {
2257 85890 : case EEOP_INNER_VAR:
2258 : {
2259 85890 : int attnum = op->d.var.attnum;
2260 :
2261 85890 : CheckVarSlotCompatibility(innerslot, attnum + 1, op->d.var.vartype);
2262 85890 : break;
2263 : }
2264 :
2265 215064 : case EEOP_OUTER_VAR:
2266 : {
2267 215064 : int attnum = op->d.var.attnum;
2268 :
2269 215064 : CheckVarSlotCompatibility(outerslot, attnum + 1, op->d.var.vartype);
2270 215064 : break;
2271 : }
2272 :
2273 325828 : case EEOP_SCAN_VAR:
2274 : {
2275 325828 : int attnum = op->d.var.attnum;
2276 :
2277 325828 : CheckVarSlotCompatibility(scanslot, attnum + 1, op->d.var.vartype);
2278 325804 : break;
2279 : }
2280 :
2281 156 : case EEOP_OLD_VAR:
2282 : {
2283 156 : int attnum = op->d.var.attnum;
2284 :
2285 156 : CheckVarSlotCompatibility(oldslot, attnum + 1, op->d.var.vartype);
2286 156 : break;
2287 : }
2288 :
2289 156 : case EEOP_NEW_VAR:
2290 : {
2291 156 : int attnum = op->d.var.attnum;
2292 :
2293 156 : CheckVarSlotCompatibility(newslot, attnum + 1, op->d.var.vartype);
2294 156 : break;
2295 : }
2296 7517978 : default:
2297 7517978 : break;
2298 : }
2299 : }
2300 1766544 : }
2301 :
2302 : /*
2303 : * Check whether a user attribute in a slot can be referenced by a Var
2304 : * expression. This should succeed unless there have been schema changes
2305 : * since the expression tree has been created.
2306 : */
2307 : static void
2308 627094 : CheckVarSlotCompatibility(TupleTableSlot *slot, int attnum, Oid vartype)
2309 : {
2310 : /*
2311 : * What we have to check for here is the possibility of an attribute
2312 : * having been dropped or changed in type since the plan tree was created.
2313 : * Ideally the plan will get invalidated and not re-used, but just in
2314 : * case, we keep these defenses. Fortunately it's sufficient to check
2315 : * once on the first time through.
2316 : *
2317 : * Note: ideally we'd check typmod as well as typid, but that seems
2318 : * impractical at the moment: in many cases the tupdesc will have been
2319 : * generated by ExecTypeFromTL(), and that can't guarantee to generate an
2320 : * accurate typmod in all cases, because some expression node types don't
2321 : * carry typmod. Fortunately, for precisely that reason, there should be
2322 : * no places with a critical dependency on the typmod of a value.
2323 : *
2324 : * System attributes don't require checking since their types never
2325 : * change.
2326 : */
2327 627094 : if (attnum > 0)
2328 : {
2329 627094 : TupleDesc slot_tupdesc = slot->tts_tupleDescriptor;
2330 : Form_pg_attribute attr;
2331 :
2332 627094 : if (attnum > slot_tupdesc->natts) /* should never happen */
2333 0 : elog(ERROR, "attribute number %d exceeds number of columns %d",
2334 : attnum, slot_tupdesc->natts);
2335 :
2336 627094 : attr = TupleDescAttr(slot_tupdesc, attnum - 1);
2337 :
2338 627094 : if (attr->attisdropped)
2339 12 : ereport(ERROR,
2340 : (errcode(ERRCODE_UNDEFINED_COLUMN),
2341 : errmsg("attribute %d of type %s has been dropped",
2342 : attnum, format_type_be(slot_tupdesc->tdtypeid))));
2343 :
2344 627082 : if (vartype != attr->atttypid)
2345 12 : ereport(ERROR,
2346 : (errcode(ERRCODE_DATATYPE_MISMATCH),
2347 : errmsg("attribute %d of type %s has wrong type",
2348 : attnum, format_type_be(slot_tupdesc->tdtypeid)),
2349 : errdetail("Table has type %s, but query expects %s.",
2350 : format_type_be(attr->atttypid),
2351 : format_type_be(vartype))));
2352 : }
2353 627070 : }
2354 :
2355 : /*
2356 : * Verify that the slot is compatible with a EEOP_*_FETCHSOME operation.
2357 : */
2358 : static void
2359 153756454 : CheckOpSlotCompatibility(ExprEvalStep *op, TupleTableSlot *slot)
2360 : {
2361 : #ifdef USE_ASSERT_CHECKING
2362 : /* there's nothing to check */
2363 : if (!op->d.fetch.fixed)
2364 : return;
2365 :
2366 : /*
2367 : * Should probably fixed at some point, but for now it's easier to allow
2368 : * buffer and heap tuples to be used interchangeably.
2369 : */
2370 : if (slot->tts_ops == &TTSOpsBufferHeapTuple &&
2371 : op->d.fetch.kind == &TTSOpsHeapTuple)
2372 : return;
2373 : if (slot->tts_ops == &TTSOpsHeapTuple &&
2374 : op->d.fetch.kind == &TTSOpsBufferHeapTuple)
2375 : return;
2376 :
2377 : /*
2378 : * At the moment we consider it OK if a virtual slot is used instead of a
2379 : * specific type of slot, as a virtual slot never needs to be deformed.
2380 : */
2381 : if (slot->tts_ops == &TTSOpsVirtual)
2382 : return;
2383 :
2384 : Assert(op->d.fetch.kind == slot->tts_ops);
2385 : #endif
2386 153756454 : }
2387 :
2388 : /*
2389 : * get_cached_rowtype: utility function to lookup a rowtype tupdesc
2390 : *
2391 : * type_id, typmod: identity of the rowtype
2392 : * rowcache: space for caching identity info
2393 : * (rowcache->cacheptr must be initialized to NULL)
2394 : * changed: if not NULL, *changed is set to true on any update
2395 : *
2396 : * The returned TupleDesc is not guaranteed pinned; caller must pin it
2397 : * to use it across any operation that might incur cache invalidation,
2398 : * including for example detoasting of input tuples.
2399 : * (The TupleDesc is always refcounted, so just use IncrTupleDescRefCount.)
2400 : *
2401 : * NOTE: because composite types can change contents, we must be prepared
2402 : * to re-do this during any node execution; cannot call just once during
2403 : * expression initialization.
2404 : */
2405 : static TupleDesc
2406 136504 : get_cached_rowtype(Oid type_id, int32 typmod,
2407 : ExprEvalRowtypeCache *rowcache,
2408 : bool *changed)
2409 : {
2410 136504 : if (type_id != RECORDOID)
2411 : {
2412 : /*
2413 : * It's a named composite type, so use the regular typcache. Do a
2414 : * lookup first time through, or if the composite type changed. Note:
2415 : * "tupdesc_id == 0" may look redundant, but it protects against the
2416 : * admittedly-theoretical possibility that type_id was RECORDOID the
2417 : * last time through, so that the cacheptr isn't TypeCacheEntry *.
2418 : */
2419 44404 : TypeCacheEntry *typentry = (TypeCacheEntry *) rowcache->cacheptr;
2420 :
2421 44404 : if (unlikely(typentry == NULL ||
2422 : rowcache->tupdesc_id == 0 ||
2423 : typentry->tupDesc_identifier != rowcache->tupdesc_id))
2424 : {
2425 6740 : typentry = lookup_type_cache(type_id, TYPECACHE_TUPDESC);
2426 6740 : if (typentry->tupDesc == NULL)
2427 0 : ereport(ERROR,
2428 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2429 : errmsg("type %s is not composite",
2430 : format_type_be(type_id))));
2431 6740 : rowcache->cacheptr = typentry;
2432 6740 : rowcache->tupdesc_id = typentry->tupDesc_identifier;
2433 6740 : if (changed)
2434 960 : *changed = true;
2435 : }
2436 44404 : return typentry->tupDesc;
2437 : }
2438 : else
2439 : {
2440 : /*
2441 : * A RECORD type, once registered, doesn't change for the life of the
2442 : * backend. So we don't need a typcache entry as such, which is good
2443 : * because there isn't one. It's possible that the caller is asking
2444 : * about a different type than before, though.
2445 : */
2446 92100 : TupleDesc tupDesc = (TupleDesc) rowcache->cacheptr;
2447 :
2448 92100 : if (unlikely(tupDesc == NULL ||
2449 : rowcache->tupdesc_id != 0 ||
2450 : type_id != tupDesc->tdtypeid ||
2451 : typmod != tupDesc->tdtypmod))
2452 : {
2453 2120 : tupDesc = lookup_rowtype_tupdesc(type_id, typmod);
2454 : /* Drop pin acquired by lookup_rowtype_tupdesc */
2455 2120 : ReleaseTupleDesc(tupDesc);
2456 2120 : rowcache->cacheptr = tupDesc;
2457 2120 : rowcache->tupdesc_id = 0; /* not a valid value for non-RECORD */
2458 2120 : if (changed)
2459 0 : *changed = true;
2460 : }
2461 92100 : return tupDesc;
2462 : }
2463 : }
2464 :
2465 :
2466 : /*
2467 : * Fast-path functions, for very simple expressions
2468 : */
2469 :
2470 : /* implementation of ExecJust(Inner|Outer|Scan)Var */
2471 : static pg_attribute_always_inline Datum
2472 6236944 : ExecJustVarImpl(ExprState *state, TupleTableSlot *slot, bool *isnull)
2473 : {
2474 6236944 : ExprEvalStep *op = &state->steps[1];
2475 6236944 : int attnum = op->d.var.attnum + 1;
2476 :
2477 6236944 : CheckOpSlotCompatibility(&state->steps[0], slot);
2478 :
2479 : /*
2480 : * Since we use slot_getattr(), we don't need to implement the FETCHSOME
2481 : * step explicitly, and we also needn't Assert that the attnum is in range
2482 : * --- slot_getattr() will take care of any problems.
2483 : */
2484 6236944 : return slot_getattr(slot, attnum, isnull);
2485 : }
2486 :
2487 : /* Simple reference to inner Var */
2488 : static Datum
2489 4530582 : ExecJustInnerVar(ExprState *state, ExprContext *econtext, bool *isnull)
2490 : {
2491 4530582 : return ExecJustVarImpl(state, econtext->ecxt_innertuple, isnull);
2492 : }
2493 :
2494 : /* Simple reference to outer Var */
2495 : static Datum
2496 1704330 : ExecJustOuterVar(ExprState *state, ExprContext *econtext, bool *isnull)
2497 : {
2498 1704330 : return ExecJustVarImpl(state, econtext->ecxt_outertuple, isnull);
2499 : }
2500 :
2501 : /* Simple reference to scan Var */
2502 : static Datum
2503 2032 : ExecJustScanVar(ExprState *state, ExprContext *econtext, bool *isnull)
2504 : {
2505 2032 : return ExecJustVarImpl(state, econtext->ecxt_scantuple, isnull);
2506 : }
2507 :
2508 : /* implementation of ExecJustAssign(Inner|Outer|Scan)Var */
2509 : static pg_attribute_always_inline Datum
2510 8769710 : ExecJustAssignVarImpl(ExprState *state, TupleTableSlot *inslot, bool *isnull)
2511 : {
2512 8769710 : ExprEvalStep *op = &state->steps[1];
2513 8769710 : int attnum = op->d.assign_var.attnum + 1;
2514 8769710 : int resultnum = op->d.assign_var.resultnum;
2515 8769710 : TupleTableSlot *outslot = state->resultslot;
2516 :
2517 8769710 : CheckOpSlotCompatibility(&state->steps[0], inslot);
2518 :
2519 : /*
2520 : * We do not need CheckVarSlotCompatibility here; that was taken care of
2521 : * at compilation time.
2522 : *
2523 : * Since we use slot_getattr(), we don't need to implement the FETCHSOME
2524 : * step explicitly, and we also needn't Assert that the attnum is in range
2525 : * --- slot_getattr() will take care of any problems. Nonetheless, check
2526 : * that resultnum is in range.
2527 : */
2528 : Assert(resultnum >= 0 && resultnum < outslot->tts_tupleDescriptor->natts);
2529 17539420 : outslot->tts_values[resultnum] =
2530 8769710 : slot_getattr(inslot, attnum, &outslot->tts_isnull[resultnum]);
2531 8769710 : return 0;
2532 : }
2533 :
2534 : /* Evaluate inner Var and assign to appropriate column of result tuple */
2535 : static Datum
2536 65720 : ExecJustAssignInnerVar(ExprState *state, ExprContext *econtext, bool *isnull)
2537 : {
2538 65720 : return ExecJustAssignVarImpl(state, econtext->ecxt_innertuple, isnull);
2539 : }
2540 :
2541 : /* Evaluate outer Var and assign to appropriate column of result tuple */
2542 : static Datum
2543 335338 : ExecJustAssignOuterVar(ExprState *state, ExprContext *econtext, bool *isnull)
2544 : {
2545 335338 : return ExecJustAssignVarImpl(state, econtext->ecxt_outertuple, isnull);
2546 : }
2547 :
2548 : /* Evaluate scan Var and assign to appropriate column of result tuple */
2549 : static Datum
2550 8368652 : ExecJustAssignScanVar(ExprState *state, ExprContext *econtext, bool *isnull)
2551 : {
2552 8368652 : return ExecJustAssignVarImpl(state, econtext->ecxt_scantuple, isnull);
2553 : }
2554 :
2555 : /* Evaluate CASE_TESTVAL and apply a strict function to it */
2556 : static Datum
2557 21078 : ExecJustApplyFuncToCase(ExprState *state, ExprContext *econtext, bool *isnull)
2558 : {
2559 21078 : ExprEvalStep *op = &state->steps[0];
2560 : FunctionCallInfo fcinfo;
2561 : NullableDatum *args;
2562 : int nargs;
2563 : Datum d;
2564 :
2565 : /*
2566 : * XXX with some redesign of the CaseTestExpr mechanism, maybe we could
2567 : * get rid of this data shuffling?
2568 : */
2569 21078 : *op->resvalue = *op->d.casetest.value;
2570 21078 : *op->resnull = *op->d.casetest.isnull;
2571 :
2572 21078 : op++;
2573 :
2574 21078 : nargs = op->d.func.nargs;
2575 21078 : fcinfo = op->d.func.fcinfo_data;
2576 21078 : args = fcinfo->args;
2577 :
2578 : /* strict function, so check for NULL args */
2579 42468 : for (int argno = 0; argno < nargs; argno++)
2580 : {
2581 21402 : if (args[argno].isnull)
2582 : {
2583 12 : *isnull = true;
2584 12 : return (Datum) 0;
2585 : }
2586 : }
2587 21066 : fcinfo->isnull = false;
2588 21066 : d = op->d.func.fn_addr(fcinfo);
2589 21048 : *isnull = fcinfo->isnull;
2590 21048 : return d;
2591 : }
2592 :
2593 : /* Simple Const expression */
2594 : static Datum
2595 1741976 : ExecJustConst(ExprState *state, ExprContext *econtext, bool *isnull)
2596 : {
2597 1741976 : ExprEvalStep *op = &state->steps[0];
2598 :
2599 1741976 : *isnull = op->d.constval.isnull;
2600 1741976 : return op->d.constval.value;
2601 : }
2602 :
2603 : /* implementation of ExecJust(Inner|Outer|Scan)VarVirt */
2604 : static pg_attribute_always_inline Datum
2605 1686782 : ExecJustVarVirtImpl(ExprState *state, TupleTableSlot *slot, bool *isnull)
2606 : {
2607 1686782 : ExprEvalStep *op = &state->steps[0];
2608 1686782 : int attnum = op->d.var.attnum;
2609 :
2610 : /*
2611 : * As it is guaranteed that a virtual slot is used, there never is a need
2612 : * to perform tuple deforming (nor would it be possible). Therefore
2613 : * execExpr.c has not emitted an EEOP_*_FETCHSOME step. Verify, as much as
2614 : * possible, that that determination was accurate.
2615 : */
2616 : Assert(TTS_IS_VIRTUAL(slot));
2617 : Assert(TTS_FIXED(slot));
2618 : Assert(attnum >= 0 && attnum < slot->tts_nvalid);
2619 :
2620 1686782 : *isnull = slot->tts_isnull[attnum];
2621 :
2622 1686782 : return slot->tts_values[attnum];
2623 : }
2624 :
2625 : /* Like ExecJustInnerVar, optimized for virtual slots */
2626 : static Datum
2627 557776 : ExecJustInnerVarVirt(ExprState *state, ExprContext *econtext, bool *isnull)
2628 : {
2629 557776 : return ExecJustVarVirtImpl(state, econtext->ecxt_innertuple, isnull);
2630 : }
2631 :
2632 : /* Like ExecJustOuterVar, optimized for virtual slots */
2633 : static Datum
2634 1129006 : ExecJustOuterVarVirt(ExprState *state, ExprContext *econtext, bool *isnull)
2635 : {
2636 1129006 : return ExecJustVarVirtImpl(state, econtext->ecxt_outertuple, isnull);
2637 : }
2638 :
2639 : /* Like ExecJustScanVar, optimized for virtual slots */
2640 : static Datum
2641 0 : ExecJustScanVarVirt(ExprState *state, ExprContext *econtext, bool *isnull)
2642 : {
2643 0 : return ExecJustVarVirtImpl(state, econtext->ecxt_scantuple, isnull);
2644 : }
2645 :
2646 : /* implementation of ExecJustAssign(Inner|Outer|Scan)VarVirt */
2647 : static pg_attribute_always_inline Datum
2648 987468 : ExecJustAssignVarVirtImpl(ExprState *state, TupleTableSlot *inslot, bool *isnull)
2649 : {
2650 987468 : ExprEvalStep *op = &state->steps[0];
2651 987468 : int attnum = op->d.assign_var.attnum;
2652 987468 : int resultnum = op->d.assign_var.resultnum;
2653 987468 : TupleTableSlot *outslot = state->resultslot;
2654 :
2655 : /* see ExecJustVarVirtImpl for comments */
2656 :
2657 : Assert(TTS_IS_VIRTUAL(inslot));
2658 : Assert(TTS_FIXED(inslot));
2659 : Assert(attnum >= 0 && attnum < inslot->tts_nvalid);
2660 : Assert(resultnum >= 0 && resultnum < outslot->tts_tupleDescriptor->natts);
2661 :
2662 987468 : outslot->tts_values[resultnum] = inslot->tts_values[attnum];
2663 987468 : outslot->tts_isnull[resultnum] = inslot->tts_isnull[attnum];
2664 :
2665 987468 : return 0;
2666 : }
2667 :
2668 : /* Like ExecJustAssignInnerVar, optimized for virtual slots */
2669 : static Datum
2670 121274 : ExecJustAssignInnerVarVirt(ExprState *state, ExprContext *econtext, bool *isnull)
2671 : {
2672 121274 : return ExecJustAssignVarVirtImpl(state, econtext->ecxt_innertuple, isnull);
2673 : }
2674 :
2675 : /* Like ExecJustAssignOuterVar, optimized for virtual slots */
2676 : static Datum
2677 681692 : ExecJustAssignOuterVarVirt(ExprState *state, ExprContext *econtext, bool *isnull)
2678 : {
2679 681692 : return ExecJustAssignVarVirtImpl(state, econtext->ecxt_outertuple, isnull);
2680 : }
2681 :
2682 : /* Like ExecJustAssignScanVar, optimized for virtual slots */
2683 : static Datum
2684 184502 : ExecJustAssignScanVarVirt(ExprState *state, ExprContext *econtext, bool *isnull)
2685 : {
2686 184502 : return ExecJustAssignVarVirtImpl(state, econtext->ecxt_scantuple, isnull);
2687 : }
2688 :
2689 : /*
2690 : * implementation for hashing an inner Var, seeding with an initial value.
2691 : */
2692 : static Datum
2693 1860412 : ExecJustHashInnerVarWithIV(ExprState *state, ExprContext *econtext,
2694 : bool *isnull)
2695 : {
2696 1860412 : ExprEvalStep *fetchop = &state->steps[0];
2697 1860412 : ExprEvalStep *setivop = &state->steps[1];
2698 1860412 : ExprEvalStep *innervar = &state->steps[2];
2699 1860412 : ExprEvalStep *hashop = &state->steps[3];
2700 1860412 : FunctionCallInfo fcinfo = hashop->d.hashdatum.fcinfo_data;
2701 1860412 : int attnum = innervar->d.var.attnum;
2702 : uint32 hashkey;
2703 :
2704 1860412 : CheckOpSlotCompatibility(fetchop, econtext->ecxt_innertuple);
2705 1860412 : slot_getsomeattrs(econtext->ecxt_innertuple, fetchop->d.fetch.last_var);
2706 :
2707 1860412 : fcinfo->args[0].value = econtext->ecxt_innertuple->tts_values[attnum];
2708 1860412 : fcinfo->args[0].isnull = econtext->ecxt_innertuple->tts_isnull[attnum];
2709 :
2710 1860412 : hashkey = DatumGetUInt32(setivop->d.hashdatum_initvalue.init_value);
2711 1860412 : hashkey = pg_rotate_left32(hashkey, 1);
2712 :
2713 1860412 : if (!fcinfo->args[0].isnull)
2714 : {
2715 : uint32 hashvalue;
2716 :
2717 1859512 : hashvalue = DatumGetUInt32(hashop->d.hashdatum.fn_addr(fcinfo));
2718 1859512 : hashkey = hashkey ^ hashvalue;
2719 : }
2720 :
2721 1860412 : *isnull = false;
2722 1860412 : return UInt32GetDatum(hashkey);
2723 : }
2724 :
2725 : /* implementation of ExecJustHash(Inner|Outer)Var */
2726 : static pg_attribute_always_inline Datum
2727 3091220 : ExecJustHashVarImpl(ExprState *state, TupleTableSlot *slot, bool *isnull)
2728 : {
2729 3091220 : ExprEvalStep *fetchop = &state->steps[0];
2730 3091220 : ExprEvalStep *var = &state->steps[1];
2731 3091220 : ExprEvalStep *hashop = &state->steps[2];
2732 3091220 : FunctionCallInfo fcinfo = hashop->d.hashdatum.fcinfo_data;
2733 3091220 : int attnum = var->d.var.attnum;
2734 :
2735 3091220 : CheckOpSlotCompatibility(fetchop, slot);
2736 3091220 : slot_getsomeattrs(slot, fetchop->d.fetch.last_var);
2737 :
2738 3091220 : fcinfo->args[0].value = slot->tts_values[attnum];
2739 3091220 : fcinfo->args[0].isnull = slot->tts_isnull[attnum];
2740 :
2741 3091220 : *isnull = false;
2742 :
2743 3091220 : if (!fcinfo->args[0].isnull)
2744 3087962 : return DatumGetUInt32(hashop->d.hashdatum.fn_addr(fcinfo));
2745 : else
2746 3258 : return (Datum) 0;
2747 : }
2748 :
2749 : /* implementation for hashing an outer Var */
2750 : static Datum
2751 1268298 : ExecJustHashOuterVar(ExprState *state, ExprContext *econtext, bool *isnull)
2752 : {
2753 1268298 : return ExecJustHashVarImpl(state, econtext->ecxt_outertuple, isnull);
2754 : }
2755 :
2756 : /* implementation for hashing an inner Var */
2757 : static Datum
2758 1822922 : ExecJustHashInnerVar(ExprState *state, ExprContext *econtext, bool *isnull)
2759 : {
2760 1822922 : return ExecJustHashVarImpl(state, econtext->ecxt_innertuple, isnull);
2761 : }
2762 :
2763 : /* implementation of ExecJustHash(Inner|Outer)VarVirt */
2764 : static pg_attribute_always_inline Datum
2765 4848406 : ExecJustHashVarVirtImpl(ExprState *state, TupleTableSlot *slot, bool *isnull)
2766 : {
2767 4848406 : ExprEvalStep *var = &state->steps[0];
2768 4848406 : ExprEvalStep *hashop = &state->steps[1];
2769 4848406 : FunctionCallInfo fcinfo = hashop->d.hashdatum.fcinfo_data;
2770 4848406 : int attnum = var->d.var.attnum;
2771 :
2772 4848406 : fcinfo->args[0].value = slot->tts_values[attnum];
2773 4848406 : fcinfo->args[0].isnull = slot->tts_isnull[attnum];
2774 :
2775 4848406 : *isnull = false;
2776 :
2777 4848406 : if (!fcinfo->args[0].isnull)
2778 4844910 : return DatumGetUInt32(hashop->d.hashdatum.fn_addr(fcinfo));
2779 : else
2780 3496 : return (Datum) 0;
2781 : }
2782 :
2783 : /* Like ExecJustHashInnerVar, optimized for virtual slots */
2784 : static Datum
2785 1151698 : ExecJustHashInnerVarVirt(ExprState *state, ExprContext *econtext,
2786 : bool *isnull)
2787 : {
2788 1151698 : return ExecJustHashVarVirtImpl(state, econtext->ecxt_innertuple, isnull);
2789 : }
2790 :
2791 : /* Like ExecJustHashOuterVar, optimized for virtual slots */
2792 : static Datum
2793 3696708 : ExecJustHashOuterVarVirt(ExprState *state, ExprContext *econtext,
2794 : bool *isnull)
2795 : {
2796 3696708 : return ExecJustHashVarVirtImpl(state, econtext->ecxt_outertuple, isnull);
2797 : }
2798 :
2799 : /*
2800 : * implementation for hashing an outer Var. Returns NULL on NULL input.
2801 : */
2802 : static Datum
2803 6165294 : ExecJustHashOuterVarStrict(ExprState *state, ExprContext *econtext,
2804 : bool *isnull)
2805 : {
2806 6165294 : ExprEvalStep *fetchop = &state->steps[0];
2807 6165294 : ExprEvalStep *var = &state->steps[1];
2808 6165294 : ExprEvalStep *hashop = &state->steps[2];
2809 6165294 : FunctionCallInfo fcinfo = hashop->d.hashdatum.fcinfo_data;
2810 6165294 : int attnum = var->d.var.attnum;
2811 :
2812 6165294 : CheckOpSlotCompatibility(fetchop, econtext->ecxt_outertuple);
2813 6165294 : slot_getsomeattrs(econtext->ecxt_outertuple, fetchop->d.fetch.last_var);
2814 :
2815 6165294 : fcinfo->args[0].value = econtext->ecxt_outertuple->tts_values[attnum];
2816 6165294 : fcinfo->args[0].isnull = econtext->ecxt_outertuple->tts_isnull[attnum];
2817 :
2818 6165294 : if (!fcinfo->args[0].isnull)
2819 : {
2820 6164996 : *isnull = false;
2821 6164996 : return DatumGetUInt32(hashop->d.hashdatum.fn_addr(fcinfo));
2822 : }
2823 : else
2824 : {
2825 : /* return NULL on NULL input */
2826 298 : *isnull = true;
2827 298 : return (Datum) 0;
2828 : }
2829 : }
2830 :
2831 : #if defined(EEO_USE_COMPUTED_GOTO)
2832 : /*
2833 : * Comparator used when building address->opcode lookup table for
2834 : * ExecEvalStepOp() in the threaded dispatch case.
2835 : */
2836 : static int
2837 61418198 : dispatch_compare_ptr(const void *a, const void *b)
2838 : {
2839 61418198 : const ExprEvalOpLookup *la = (const ExprEvalOpLookup *) a;
2840 61418198 : const ExprEvalOpLookup *lb = (const ExprEvalOpLookup *) b;
2841 :
2842 61418198 : if (la->opcode < lb->opcode)
2843 36485072 : return -1;
2844 24933126 : else if (la->opcode > lb->opcode)
2845 17706346 : return 1;
2846 7226780 : return 0;
2847 : }
2848 : #endif
2849 :
2850 : /*
2851 : * Do one-time initialization of interpretation machinery.
2852 : */
2853 : static void
2854 2265644 : ExecInitInterpreter(void)
2855 : {
2856 : #if defined(EEO_USE_COMPUTED_GOTO)
2857 : /* Set up externally-visible pointer to dispatch table */
2858 2265644 : if (dispatch_table == NULL)
2859 : {
2860 19732 : dispatch_table = (const void **)
2861 19732 : DatumGetPointer(ExecInterpExpr(NULL, NULL, NULL));
2862 :
2863 : /* build reverse lookup table */
2864 2269180 : for (int i = 0; i < EEOP_LAST; i++)
2865 : {
2866 2249448 : reverse_dispatch_table[i].opcode = dispatch_table[i];
2867 2249448 : reverse_dispatch_table[i].op = (ExprEvalOp) i;
2868 : }
2869 :
2870 : /* make it bsearch()able */
2871 19732 : qsort(reverse_dispatch_table,
2872 : EEOP_LAST /* nmembers */ ,
2873 : sizeof(ExprEvalOpLookup),
2874 : dispatch_compare_ptr);
2875 : }
2876 : #endif
2877 2265644 : }
2878 :
2879 : /*
2880 : * Function to return the opcode of an expression step.
2881 : *
2882 : * When direct-threading is in use, ExprState->opcode isn't easily
2883 : * decipherable. This function returns the appropriate enum member.
2884 : */
2885 : ExprEvalOp
2886 8192994 : ExecEvalStepOp(ExprState *state, ExprEvalStep *op)
2887 : {
2888 : #if defined(EEO_USE_COMPUTED_GOTO)
2889 8192994 : if (state->flags & EEO_FLAG_DIRECT_THREADED)
2890 : {
2891 : ExprEvalOpLookup key;
2892 : ExprEvalOpLookup *res;
2893 :
2894 7226780 : key.opcode = (void *) op->opcode;
2895 7226780 : res = bsearch(&key,
2896 : reverse_dispatch_table,
2897 : EEOP_LAST /* nmembers */ ,
2898 : sizeof(ExprEvalOpLookup),
2899 : dispatch_compare_ptr);
2900 : Assert(res); /* unknown ops shouldn't get looked up */
2901 7226780 : return res->op;
2902 : }
2903 : #endif
2904 966214 : return (ExprEvalOp) op->opcode;
2905 : }
2906 :
2907 :
2908 : /*
2909 : * Out-of-line helper functions for complex instructions.
2910 : */
2911 :
2912 : /*
2913 : * Evaluate EEOP_FUNCEXPR_FUSAGE
2914 : */
2915 : void
2916 208 : ExecEvalFuncExprFusage(ExprState *state, ExprEvalStep *op,
2917 : ExprContext *econtext)
2918 : {
2919 208 : FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
2920 : PgStat_FunctionCallUsage fcusage;
2921 : Datum d;
2922 :
2923 208 : pgstat_init_function_usage(fcinfo, &fcusage);
2924 :
2925 208 : fcinfo->isnull = false;
2926 208 : d = op->d.func.fn_addr(fcinfo);
2927 208 : *op->resvalue = d;
2928 208 : *op->resnull = fcinfo->isnull;
2929 :
2930 208 : pgstat_end_function_usage(&fcusage, true);
2931 208 : }
2932 :
2933 : /*
2934 : * Evaluate EEOP_FUNCEXPR_STRICT_FUSAGE
2935 : */
2936 : void
2937 6 : ExecEvalFuncExprStrictFusage(ExprState *state, ExprEvalStep *op,
2938 : ExprContext *econtext)
2939 : {
2940 :
2941 6 : FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
2942 : PgStat_FunctionCallUsage fcusage;
2943 6 : NullableDatum *args = fcinfo->args;
2944 6 : int nargs = op->d.func.nargs;
2945 : Datum d;
2946 :
2947 : /* strict function, so check for NULL args */
2948 18 : for (int argno = 0; argno < nargs; argno++)
2949 : {
2950 12 : if (args[argno].isnull)
2951 : {
2952 0 : *op->resnull = true;
2953 0 : return;
2954 : }
2955 : }
2956 :
2957 6 : pgstat_init_function_usage(fcinfo, &fcusage);
2958 :
2959 6 : fcinfo->isnull = false;
2960 6 : d = op->d.func.fn_addr(fcinfo);
2961 6 : *op->resvalue = d;
2962 6 : *op->resnull = fcinfo->isnull;
2963 :
2964 6 : pgstat_end_function_usage(&fcusage, true);
2965 : }
2966 :
2967 : /*
2968 : * Evaluate a PARAM_EXEC parameter.
2969 : *
2970 : * PARAM_EXEC params (internal executor parameters) are stored in the
2971 : * ecxt_param_exec_vals array, and can be accessed by array index.
2972 : */
2973 : void
2974 7087970 : ExecEvalParamExec(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
2975 : {
2976 : ParamExecData *prm;
2977 :
2978 7087970 : prm = &(econtext->ecxt_param_exec_vals[op->d.param.paramid]);
2979 7087970 : if (unlikely(prm->execPlan != NULL))
2980 : {
2981 : /* Parameter not evaluated yet, so go do it */
2982 8768 : ExecSetParamPlan(prm->execPlan, econtext);
2983 : /* ExecSetParamPlan should have processed this param... */
2984 : Assert(prm->execPlan == NULL);
2985 : }
2986 7087952 : *op->resvalue = prm->value;
2987 7087952 : *op->resnull = prm->isnull;
2988 7087952 : }
2989 :
2990 : /*
2991 : * Evaluate a PARAM_EXTERN parameter.
2992 : *
2993 : * PARAM_EXTERN parameters must be sought in ecxt_param_list_info.
2994 : */
2995 : void
2996 517592 : ExecEvalParamExtern(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
2997 : {
2998 517592 : ParamListInfo paramInfo = econtext->ecxt_param_list_info;
2999 517592 : int paramId = op->d.param.paramid;
3000 :
3001 517592 : if (likely(paramInfo &&
3002 : paramId > 0 && paramId <= paramInfo->numParams))
3003 : {
3004 : ParamExternData *prm;
3005 : ParamExternData prmdata;
3006 :
3007 : /* give hook a chance in case parameter is dynamic */
3008 517592 : if (paramInfo->paramFetch != NULL)
3009 186 : prm = paramInfo->paramFetch(paramInfo, paramId, false, &prmdata);
3010 : else
3011 517406 : prm = ¶mInfo->params[paramId - 1];
3012 :
3013 517592 : if (likely(OidIsValid(prm->ptype)))
3014 : {
3015 : /* safety check in case hook did something unexpected */
3016 517592 : if (unlikely(prm->ptype != op->d.param.paramtype))
3017 0 : ereport(ERROR,
3018 : (errcode(ERRCODE_DATATYPE_MISMATCH),
3019 : errmsg("type of parameter %d (%s) does not match that when preparing the plan (%s)",
3020 : paramId,
3021 : format_type_be(prm->ptype),
3022 : format_type_be(op->d.param.paramtype))));
3023 517592 : *op->resvalue = prm->value;
3024 517592 : *op->resnull = prm->isnull;
3025 517592 : return;
3026 : }
3027 : }
3028 :
3029 0 : ereport(ERROR,
3030 : (errcode(ERRCODE_UNDEFINED_OBJECT),
3031 : errmsg("no value found for parameter %d", paramId)));
3032 : }
3033 :
3034 : /*
3035 : * Set value of a param (currently always PARAM_EXEC) from
3036 : * state->res{value,null}.
3037 : */
3038 : void
3039 1383076 : ExecEvalParamSet(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
3040 : {
3041 : ParamExecData *prm;
3042 :
3043 1383076 : prm = &(econtext->ecxt_param_exec_vals[op->d.param.paramid]);
3044 :
3045 : /* Shouldn't have a pending evaluation anymore */
3046 : Assert(prm->execPlan == NULL);
3047 :
3048 1383076 : prm->value = state->resvalue;
3049 1383076 : prm->isnull = state->resnull;
3050 1383076 : }
3051 :
3052 : /*
3053 : * Evaluate a CoerceViaIO node in soft-error mode.
3054 : *
3055 : * The source value is in op's result variable.
3056 : *
3057 : * Note: This implements EEOP_IOCOERCE_SAFE. If you change anything here,
3058 : * also look at the inline code for EEOP_IOCOERCE.
3059 : */
3060 : void
3061 0 : ExecEvalCoerceViaIOSafe(ExprState *state, ExprEvalStep *op)
3062 : {
3063 : char *str;
3064 :
3065 : /* call output function (similar to OutputFunctionCall) */
3066 0 : if (*op->resnull)
3067 : {
3068 : /* output functions are not called on nulls */
3069 0 : str = NULL;
3070 : }
3071 : else
3072 : {
3073 : FunctionCallInfo fcinfo_out;
3074 :
3075 0 : fcinfo_out = op->d.iocoerce.fcinfo_data_out;
3076 0 : fcinfo_out->args[0].value = *op->resvalue;
3077 0 : fcinfo_out->args[0].isnull = false;
3078 :
3079 0 : fcinfo_out->isnull = false;
3080 0 : str = DatumGetCString(FunctionCallInvoke(fcinfo_out));
3081 :
3082 : /* OutputFunctionCall assumes result isn't null */
3083 : Assert(!fcinfo_out->isnull);
3084 : }
3085 :
3086 : /* call input function (similar to InputFunctionCallSafe) */
3087 0 : if (!op->d.iocoerce.finfo_in->fn_strict || str != NULL)
3088 : {
3089 : FunctionCallInfo fcinfo_in;
3090 :
3091 0 : fcinfo_in = op->d.iocoerce.fcinfo_data_in;
3092 0 : fcinfo_in->args[0].value = PointerGetDatum(str);
3093 0 : fcinfo_in->args[0].isnull = *op->resnull;
3094 : /* second and third arguments are already set up */
3095 :
3096 : /* ErrorSaveContext must be present. */
3097 : Assert(IsA(fcinfo_in->context, ErrorSaveContext));
3098 :
3099 0 : fcinfo_in->isnull = false;
3100 0 : *op->resvalue = FunctionCallInvoke(fcinfo_in);
3101 :
3102 0 : if (SOFT_ERROR_OCCURRED(fcinfo_in->context))
3103 : {
3104 0 : *op->resnull = true;
3105 0 : *op->resvalue = (Datum) 0;
3106 0 : return;
3107 : }
3108 :
3109 : /* Should get null result if and only if str is NULL */
3110 : if (str == NULL)
3111 : Assert(*op->resnull);
3112 : else
3113 : Assert(!*op->resnull);
3114 : }
3115 : }
3116 :
3117 : /*
3118 : * Evaluate a SQLValueFunction expression.
3119 : */
3120 : void
3121 18594 : ExecEvalSQLValueFunction(ExprState *state, ExprEvalStep *op)
3122 : {
3123 18594 : LOCAL_FCINFO(fcinfo, 0);
3124 18594 : SQLValueFunction *svf = op->d.sqlvaluefunction.svf;
3125 :
3126 18594 : *op->resnull = false;
3127 :
3128 : /*
3129 : * Note: current_schema() can return NULL. current_user() etc currently
3130 : * cannot, but might as well code those cases the same way for safety.
3131 : */
3132 18594 : switch (svf->op)
3133 : {
3134 50 : case SVFOP_CURRENT_DATE:
3135 50 : *op->resvalue = DateADTGetDatum(GetSQLCurrentDate());
3136 50 : break;
3137 24 : case SVFOP_CURRENT_TIME:
3138 : case SVFOP_CURRENT_TIME_N:
3139 24 : *op->resvalue = TimeTzADTPGetDatum(GetSQLCurrentTime(svf->typmod));
3140 24 : break;
3141 288 : case SVFOP_CURRENT_TIMESTAMP:
3142 : case SVFOP_CURRENT_TIMESTAMP_N:
3143 288 : *op->resvalue = TimestampTzGetDatum(GetSQLCurrentTimestamp(svf->typmod));
3144 288 : break;
3145 24 : case SVFOP_LOCALTIME:
3146 : case SVFOP_LOCALTIME_N:
3147 24 : *op->resvalue = TimeADTGetDatum(GetSQLLocalTime(svf->typmod));
3148 24 : break;
3149 66 : case SVFOP_LOCALTIMESTAMP:
3150 : case SVFOP_LOCALTIMESTAMP_N:
3151 66 : *op->resvalue = TimestampGetDatum(GetSQLLocalTimestamp(svf->typmod));
3152 66 : break;
3153 17516 : case SVFOP_CURRENT_ROLE:
3154 : case SVFOP_CURRENT_USER:
3155 : case SVFOP_USER:
3156 17516 : InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL);
3157 17516 : *op->resvalue = current_user(fcinfo);
3158 17516 : *op->resnull = fcinfo->isnull;
3159 17516 : break;
3160 566 : case SVFOP_SESSION_USER:
3161 566 : InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL);
3162 566 : *op->resvalue = session_user(fcinfo);
3163 566 : *op->resnull = fcinfo->isnull;
3164 566 : break;
3165 42 : case SVFOP_CURRENT_CATALOG:
3166 42 : InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL);
3167 42 : *op->resvalue = current_database(fcinfo);
3168 42 : *op->resnull = fcinfo->isnull;
3169 42 : break;
3170 18 : case SVFOP_CURRENT_SCHEMA:
3171 18 : InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL);
3172 18 : *op->resvalue = current_schema(fcinfo);
3173 18 : *op->resnull = fcinfo->isnull;
3174 18 : break;
3175 : }
3176 18594 : }
3177 :
3178 : /*
3179 : * Raise error if a CURRENT OF expression is evaluated.
3180 : *
3181 : * The planner should convert CURRENT OF into a TidScan qualification, or some
3182 : * other special handling in a ForeignScan node. So we have to be able to do
3183 : * ExecInitExpr on a CurrentOfExpr, but we shouldn't ever actually execute it.
3184 : * If we get here, we suppose we must be dealing with CURRENT OF on a foreign
3185 : * table whose FDW doesn't handle it, and complain accordingly.
3186 : */
3187 : void
3188 2 : ExecEvalCurrentOfExpr(ExprState *state, ExprEvalStep *op)
3189 : {
3190 2 : ereport(ERROR,
3191 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3192 : errmsg("WHERE CURRENT OF is not supported for this table type")));
3193 : }
3194 :
3195 : /*
3196 : * Evaluate NextValueExpr.
3197 : */
3198 : void
3199 912 : ExecEvalNextValueExpr(ExprState *state, ExprEvalStep *op)
3200 : {
3201 912 : int64 newval = nextval_internal(op->d.nextvalueexpr.seqid, false);
3202 :
3203 912 : switch (op->d.nextvalueexpr.seqtypid)
3204 : {
3205 30 : case INT2OID:
3206 30 : *op->resvalue = Int16GetDatum((int16) newval);
3207 30 : break;
3208 804 : case INT4OID:
3209 804 : *op->resvalue = Int32GetDatum((int32) newval);
3210 804 : break;
3211 78 : case INT8OID:
3212 78 : *op->resvalue = Int64GetDatum((int64) newval);
3213 78 : break;
3214 0 : default:
3215 0 : elog(ERROR, "unsupported sequence type %u",
3216 : op->d.nextvalueexpr.seqtypid);
3217 : }
3218 912 : *op->resnull = false;
3219 912 : }
3220 :
3221 : /*
3222 : * Evaluate NullTest / IS NULL for rows.
3223 : */
3224 : void
3225 696 : ExecEvalRowNull(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
3226 : {
3227 696 : ExecEvalRowNullInt(state, op, econtext, true);
3228 696 : }
3229 :
3230 : /*
3231 : * Evaluate NullTest / IS NOT NULL for rows.
3232 : */
3233 : void
3234 554 : ExecEvalRowNotNull(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
3235 : {
3236 554 : ExecEvalRowNullInt(state, op, econtext, false);
3237 554 : }
3238 :
3239 : /* Common code for IS [NOT] NULL on a row value */
3240 : static void
3241 1250 : ExecEvalRowNullInt(ExprState *state, ExprEvalStep *op,
3242 : ExprContext *econtext, bool checkisnull)
3243 : {
3244 1250 : Datum value = *op->resvalue;
3245 1250 : bool isnull = *op->resnull;
3246 : HeapTupleHeader tuple;
3247 : Oid tupType;
3248 : int32 tupTypmod;
3249 : TupleDesc tupDesc;
3250 : HeapTupleData tmptup;
3251 :
3252 1250 : *op->resnull = false;
3253 :
3254 : /* NULL row variables are treated just as NULL scalar columns */
3255 1250 : if (isnull)
3256 : {
3257 156 : *op->resvalue = BoolGetDatum(checkisnull);
3258 742 : return;
3259 : }
3260 :
3261 : /*
3262 : * The SQL standard defines IS [NOT] NULL for a non-null rowtype argument
3263 : * as:
3264 : *
3265 : * "R IS NULL" is true if every field is the null value.
3266 : *
3267 : * "R IS NOT NULL" is true if no field is the null value.
3268 : *
3269 : * This definition is (apparently intentionally) not recursive; so our
3270 : * tests on the fields are primitive attisnull tests, not recursive checks
3271 : * to see if they are all-nulls or no-nulls rowtypes.
3272 : *
3273 : * The standard does not consider the possibility of zero-field rows, but
3274 : * here we consider them to vacuously satisfy both predicates.
3275 : */
3276 :
3277 1094 : tuple = DatumGetHeapTupleHeader(value);
3278 :
3279 1094 : tupType = HeapTupleHeaderGetTypeId(tuple);
3280 1094 : tupTypmod = HeapTupleHeaderGetTypMod(tuple);
3281 :
3282 : /* Lookup tupdesc if first time through or if type changes */
3283 1094 : tupDesc = get_cached_rowtype(tupType, tupTypmod,
3284 : &op->d.nulltest_row.rowcache, NULL);
3285 :
3286 : /*
3287 : * heap_attisnull needs a HeapTuple not a bare HeapTupleHeader.
3288 : */
3289 1094 : tmptup.t_len = HeapTupleHeaderGetDatumLength(tuple);
3290 1094 : tmptup.t_data = tuple;
3291 :
3292 2636 : for (int att = 1; att <= tupDesc->natts; att++)
3293 : {
3294 : /* ignore dropped columns */
3295 2128 : if (TupleDescCompactAttr(tupDesc, att - 1)->attisdropped)
3296 0 : continue;
3297 2128 : if (heap_attisnull(&tmptup, att, tupDesc))
3298 : {
3299 : /* null field disproves IS NOT NULL */
3300 56 : if (!checkisnull)
3301 : {
3302 32 : *op->resvalue = BoolGetDatum(false);
3303 32 : return;
3304 : }
3305 : }
3306 : else
3307 : {
3308 : /* non-null field disproves IS NULL */
3309 2072 : if (checkisnull)
3310 : {
3311 554 : *op->resvalue = BoolGetDatum(false);
3312 554 : return;
3313 : }
3314 : }
3315 : }
3316 :
3317 508 : *op->resvalue = BoolGetDatum(true);
3318 : }
3319 :
3320 : /*
3321 : * Evaluate an ARRAY[] expression.
3322 : *
3323 : * The individual array elements (or subarrays) have already been evaluated
3324 : * into op->d.arrayexpr.elemvalues[]/elemnulls[].
3325 : */
3326 : void
3327 761016 : ExecEvalArrayExpr(ExprState *state, ExprEvalStep *op)
3328 : {
3329 : ArrayType *result;
3330 761016 : Oid element_type = op->d.arrayexpr.elemtype;
3331 761016 : int nelems = op->d.arrayexpr.nelems;
3332 761016 : int ndims = 0;
3333 : int dims[MAXDIM];
3334 : int lbs[MAXDIM];
3335 :
3336 : /* Set non-null as default */
3337 761016 : *op->resnull = false;
3338 :
3339 761016 : if (!op->d.arrayexpr.multidims)
3340 : {
3341 : /* Elements are presumably of scalar type */
3342 760538 : Datum *dvalues = op->d.arrayexpr.elemvalues;
3343 760538 : bool *dnulls = op->d.arrayexpr.elemnulls;
3344 :
3345 : /* setup for 1-D array of the given length */
3346 760538 : ndims = 1;
3347 760538 : dims[0] = nelems;
3348 760538 : lbs[0] = 1;
3349 :
3350 760538 : result = construct_md_array(dvalues, dnulls, ndims, dims, lbs,
3351 : element_type,
3352 760538 : op->d.arrayexpr.elemlength,
3353 760538 : op->d.arrayexpr.elembyval,
3354 760538 : op->d.arrayexpr.elemalign);
3355 : }
3356 : else
3357 : {
3358 : /* Must be nested array expressions */
3359 478 : int nbytes = 0;
3360 : int nitems;
3361 478 : int outer_nelems = 0;
3362 478 : int elem_ndims = 0;
3363 478 : int *elem_dims = NULL;
3364 478 : int *elem_lbs = NULL;
3365 478 : bool firstone = true;
3366 478 : bool havenulls = false;
3367 478 : bool haveempty = false;
3368 : char **subdata;
3369 : bits8 **subbitmaps;
3370 : int *subbytes;
3371 : int *subnitems;
3372 : int32 dataoffset;
3373 : char *dat;
3374 : int iitem;
3375 :
3376 478 : subdata = (char **) palloc(nelems * sizeof(char *));
3377 478 : subbitmaps = (bits8 **) palloc(nelems * sizeof(bits8 *));
3378 478 : subbytes = (int *) palloc(nelems * sizeof(int));
3379 478 : subnitems = (int *) palloc(nelems * sizeof(int));
3380 :
3381 : /* loop through and get data area from each element */
3382 1334 : for (int elemoff = 0; elemoff < nelems; elemoff++)
3383 : {
3384 : Datum arraydatum;
3385 : bool eisnull;
3386 : ArrayType *array;
3387 : int this_ndims;
3388 :
3389 856 : arraydatum = op->d.arrayexpr.elemvalues[elemoff];
3390 856 : eisnull = op->d.arrayexpr.elemnulls[elemoff];
3391 :
3392 : /* temporarily ignore null subarrays */
3393 856 : if (eisnull)
3394 : {
3395 0 : haveempty = true;
3396 0 : continue;
3397 : }
3398 :
3399 856 : array = DatumGetArrayTypeP(arraydatum);
3400 :
3401 : /* run-time double-check on element type */
3402 856 : if (element_type != ARR_ELEMTYPE(array))
3403 0 : ereport(ERROR,
3404 : (errcode(ERRCODE_DATATYPE_MISMATCH),
3405 : errmsg("cannot merge incompatible arrays"),
3406 : errdetail("Array with element type %s cannot be "
3407 : "included in ARRAY construct with element type %s.",
3408 : format_type_be(ARR_ELEMTYPE(array)),
3409 : format_type_be(element_type))));
3410 :
3411 856 : this_ndims = ARR_NDIM(array);
3412 : /* temporarily ignore zero-dimensional subarrays */
3413 856 : if (this_ndims <= 0)
3414 : {
3415 0 : haveempty = true;
3416 0 : continue;
3417 : }
3418 :
3419 856 : if (firstone)
3420 : {
3421 : /* Get sub-array details from first member */
3422 478 : elem_ndims = this_ndims;
3423 478 : ndims = elem_ndims + 1;
3424 478 : if (ndims <= 0 || ndims > MAXDIM)
3425 0 : ereport(ERROR,
3426 : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
3427 : errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
3428 : ndims, MAXDIM)));
3429 :
3430 478 : elem_dims = (int *) palloc(elem_ndims * sizeof(int));
3431 478 : memcpy(elem_dims, ARR_DIMS(array), elem_ndims * sizeof(int));
3432 478 : elem_lbs = (int *) palloc(elem_ndims * sizeof(int));
3433 478 : memcpy(elem_lbs, ARR_LBOUND(array), elem_ndims * sizeof(int));
3434 :
3435 478 : firstone = false;
3436 : }
3437 : else
3438 : {
3439 : /* Check other sub-arrays are compatible */
3440 378 : if (elem_ndims != this_ndims ||
3441 378 : memcmp(elem_dims, ARR_DIMS(array),
3442 378 : elem_ndims * sizeof(int)) != 0 ||
3443 378 : memcmp(elem_lbs, ARR_LBOUND(array),
3444 : elem_ndims * sizeof(int)) != 0)
3445 0 : ereport(ERROR,
3446 : (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
3447 : errmsg("multidimensional arrays must have array "
3448 : "expressions with matching dimensions")));
3449 : }
3450 :
3451 856 : subdata[outer_nelems] = ARR_DATA_PTR(array);
3452 856 : subbitmaps[outer_nelems] = ARR_NULLBITMAP(array);
3453 856 : subbytes[outer_nelems] = ARR_SIZE(array) - ARR_DATA_OFFSET(array);
3454 856 : nbytes += subbytes[outer_nelems];
3455 : /* check for overflow of total request */
3456 856 : if (!AllocSizeIsValid(nbytes))
3457 0 : ereport(ERROR,
3458 : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
3459 : errmsg("array size exceeds the maximum allowed (%d)",
3460 : (int) MaxAllocSize)));
3461 856 : subnitems[outer_nelems] = ArrayGetNItems(this_ndims,
3462 : ARR_DIMS(array));
3463 856 : havenulls |= ARR_HASNULL(array);
3464 856 : outer_nelems++;
3465 : }
3466 :
3467 : /*
3468 : * If all items were null or empty arrays, return an empty array;
3469 : * otherwise, if some were and some weren't, raise error. (Note: we
3470 : * must special-case this somehow to avoid trying to generate a 1-D
3471 : * array formed from empty arrays. It's not ideal...)
3472 : */
3473 478 : if (haveempty)
3474 : {
3475 0 : if (ndims == 0) /* didn't find any nonempty array */
3476 : {
3477 0 : *op->resvalue = PointerGetDatum(construct_empty_array(element_type));
3478 0 : return;
3479 : }
3480 0 : ereport(ERROR,
3481 : (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
3482 : errmsg("multidimensional arrays must have array "
3483 : "expressions with matching dimensions")));
3484 : }
3485 :
3486 : /* setup for multi-D array */
3487 478 : dims[0] = outer_nelems;
3488 478 : lbs[0] = 1;
3489 1188 : for (int i = 1; i < ndims; i++)
3490 : {
3491 710 : dims[i] = elem_dims[i - 1];
3492 710 : lbs[i] = elem_lbs[i - 1];
3493 : }
3494 :
3495 : /* check for subscript overflow */
3496 478 : nitems = ArrayGetNItems(ndims, dims);
3497 478 : ArrayCheckBounds(ndims, dims, lbs);
3498 :
3499 478 : if (havenulls)
3500 : {
3501 30 : dataoffset = ARR_OVERHEAD_WITHNULLS(ndims, nitems);
3502 30 : nbytes += dataoffset;
3503 : }
3504 : else
3505 : {
3506 448 : dataoffset = 0; /* marker for no null bitmap */
3507 448 : nbytes += ARR_OVERHEAD_NONULLS(ndims);
3508 : }
3509 :
3510 478 : result = (ArrayType *) palloc0(nbytes);
3511 478 : SET_VARSIZE(result, nbytes);
3512 478 : result->ndim = ndims;
3513 478 : result->dataoffset = dataoffset;
3514 478 : result->elemtype = element_type;
3515 478 : memcpy(ARR_DIMS(result), dims, ndims * sizeof(int));
3516 478 : memcpy(ARR_LBOUND(result), lbs, ndims * sizeof(int));
3517 :
3518 478 : dat = ARR_DATA_PTR(result);
3519 478 : iitem = 0;
3520 1334 : for (int i = 0; i < outer_nelems; i++)
3521 : {
3522 856 : memcpy(dat, subdata[i], subbytes[i]);
3523 856 : dat += subbytes[i];
3524 856 : if (havenulls)
3525 60 : array_bitmap_copy(ARR_NULLBITMAP(result), iitem,
3526 60 : subbitmaps[i], 0,
3527 60 : subnitems[i]);
3528 856 : iitem += subnitems[i];
3529 : }
3530 : }
3531 :
3532 761016 : *op->resvalue = PointerGetDatum(result);
3533 : }
3534 :
3535 : /*
3536 : * Evaluate an ArrayCoerceExpr expression.
3537 : *
3538 : * Source array is in step's result variable.
3539 : */
3540 : void
3541 67366 : ExecEvalArrayCoerce(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
3542 : {
3543 : Datum arraydatum;
3544 :
3545 : /* NULL array -> NULL result */
3546 67366 : if (*op->resnull)
3547 300 : return;
3548 :
3549 67066 : arraydatum = *op->resvalue;
3550 :
3551 : /*
3552 : * If it's binary-compatible, modify the element type in the array header,
3553 : * but otherwise leave the array as we received it.
3554 : */
3555 67066 : if (op->d.arraycoerce.elemexprstate == NULL)
3556 : {
3557 : /* Detoast input array if necessary, and copy in any case */
3558 66440 : ArrayType *array = DatumGetArrayTypePCopy(arraydatum);
3559 :
3560 66440 : ARR_ELEMTYPE(array) = op->d.arraycoerce.resultelemtype;
3561 66440 : *op->resvalue = PointerGetDatum(array);
3562 66440 : return;
3563 : }
3564 :
3565 : /*
3566 : * Use array_map to apply the sub-expression to each array element.
3567 : */
3568 594 : *op->resvalue = array_map(arraydatum,
3569 626 : op->d.arraycoerce.elemexprstate,
3570 : econtext,
3571 : op->d.arraycoerce.resultelemtype,
3572 626 : op->d.arraycoerce.amstate);
3573 : }
3574 :
3575 : /*
3576 : * Evaluate a ROW() expression.
3577 : *
3578 : * The individual columns have already been evaluated into
3579 : * op->d.row.elemvalues[]/elemnulls[].
3580 : */
3581 : void
3582 27844 : ExecEvalRow(ExprState *state, ExprEvalStep *op)
3583 : {
3584 : HeapTuple tuple;
3585 :
3586 : /* build tuple from evaluated field values */
3587 27844 : tuple = heap_form_tuple(op->d.row.tupdesc,
3588 27844 : op->d.row.elemvalues,
3589 27844 : op->d.row.elemnulls);
3590 :
3591 27844 : *op->resvalue = HeapTupleGetDatum(tuple);
3592 27844 : *op->resnull = false;
3593 27844 : }
3594 :
3595 : /*
3596 : * Evaluate GREATEST() or LEAST() expression (note this is *not* MIN()/MAX()).
3597 : *
3598 : * All of the to-be-compared expressions have already been evaluated into
3599 : * op->d.minmax.values[]/nulls[].
3600 : */
3601 : void
3602 23276 : ExecEvalMinMax(ExprState *state, ExprEvalStep *op)
3603 : {
3604 23276 : Datum *values = op->d.minmax.values;
3605 23276 : bool *nulls = op->d.minmax.nulls;
3606 23276 : FunctionCallInfo fcinfo = op->d.minmax.fcinfo_data;
3607 23276 : MinMaxOp operator = op->d.minmax.op;
3608 :
3609 : /* set at initialization */
3610 : Assert(fcinfo->args[0].isnull == false);
3611 : Assert(fcinfo->args[1].isnull == false);
3612 :
3613 : /* default to null result */
3614 23276 : *op->resnull = true;
3615 :
3616 70122 : for (int off = 0; off < op->d.minmax.nelems; off++)
3617 : {
3618 : /* ignore NULL inputs */
3619 46846 : if (nulls[off])
3620 122 : continue;
3621 :
3622 46724 : if (*op->resnull)
3623 : {
3624 : /* first nonnull input, adopt value */
3625 23276 : *op->resvalue = values[off];
3626 23276 : *op->resnull = false;
3627 : }
3628 : else
3629 : {
3630 : int cmpresult;
3631 :
3632 : /* apply comparison function */
3633 23448 : fcinfo->args[0].value = *op->resvalue;
3634 23448 : fcinfo->args[1].value = values[off];
3635 :
3636 23448 : fcinfo->isnull = false;
3637 23448 : cmpresult = DatumGetInt32(FunctionCallInvoke(fcinfo));
3638 23448 : if (fcinfo->isnull) /* probably should not happen */
3639 0 : continue;
3640 :
3641 23448 : if (cmpresult > 0 && operator == IS_LEAST)
3642 248 : *op->resvalue = values[off];
3643 23200 : else if (cmpresult < 0 && operator == IS_GREATEST)
3644 196 : *op->resvalue = values[off];
3645 : }
3646 : }
3647 23276 : }
3648 :
3649 : /*
3650 : * Evaluate a FieldSelect node.
3651 : *
3652 : * Source record is in step's result variable.
3653 : */
3654 : void
3655 111044 : ExecEvalFieldSelect(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
3656 : {
3657 111044 : AttrNumber fieldnum = op->d.fieldselect.fieldnum;
3658 : Datum tupDatum;
3659 : HeapTupleHeader tuple;
3660 : Oid tupType;
3661 : int32 tupTypmod;
3662 : TupleDesc tupDesc;
3663 : Form_pg_attribute attr;
3664 : HeapTupleData tmptup;
3665 :
3666 : /* NULL record -> NULL result */
3667 111044 : if (*op->resnull)
3668 188 : return;
3669 :
3670 110856 : tupDatum = *op->resvalue;
3671 :
3672 : /* We can special-case expanded records for speed */
3673 110856 : if (VARATT_IS_EXTERNAL_EXPANDED(DatumGetPointer(tupDatum)))
3674 662 : {
3675 662 : ExpandedRecordHeader *erh = (ExpandedRecordHeader *) DatumGetEOHP(tupDatum);
3676 :
3677 : Assert(erh->er_magic == ER_MAGIC);
3678 :
3679 : /* Extract record's TupleDesc */
3680 662 : tupDesc = expanded_record_get_tupdesc(erh);
3681 :
3682 : /*
3683 : * Find field's attr record. Note we don't support system columns
3684 : * here: a datum tuple doesn't have valid values for most of the
3685 : * interesting system columns anyway.
3686 : */
3687 662 : if (fieldnum <= 0) /* should never happen */
3688 0 : elog(ERROR, "unsupported reference to system column %d in FieldSelect",
3689 : fieldnum);
3690 662 : if (fieldnum > tupDesc->natts) /* should never happen */
3691 0 : elog(ERROR, "attribute number %d exceeds number of columns %d",
3692 : fieldnum, tupDesc->natts);
3693 662 : attr = TupleDescAttr(tupDesc, fieldnum - 1);
3694 :
3695 : /* Check for dropped column, and force a NULL result if so */
3696 662 : if (attr->attisdropped)
3697 : {
3698 0 : *op->resnull = true;
3699 0 : return;
3700 : }
3701 :
3702 : /* Check for type mismatch --- possible after ALTER COLUMN TYPE? */
3703 : /* As in CheckVarSlotCompatibility, we should but can't check typmod */
3704 662 : if (op->d.fieldselect.resulttype != attr->atttypid)
3705 0 : ereport(ERROR,
3706 : (errcode(ERRCODE_DATATYPE_MISMATCH),
3707 : errmsg("attribute %d has wrong type", fieldnum),
3708 : errdetail("Table has type %s, but query expects %s.",
3709 : format_type_be(attr->atttypid),
3710 : format_type_be(op->d.fieldselect.resulttype))));
3711 :
3712 : /* extract the field */
3713 662 : *op->resvalue = expanded_record_get_field(erh, fieldnum,
3714 : op->resnull);
3715 : }
3716 : else
3717 : {
3718 : /* Get the composite datum and extract its type fields */
3719 110194 : tuple = DatumGetHeapTupleHeader(tupDatum);
3720 :
3721 110194 : tupType = HeapTupleHeaderGetTypeId(tuple);
3722 110194 : tupTypmod = HeapTupleHeaderGetTypMod(tuple);
3723 :
3724 : /* Lookup tupdesc if first time through or if type changes */
3725 110194 : tupDesc = get_cached_rowtype(tupType, tupTypmod,
3726 : &op->d.fieldselect.rowcache, NULL);
3727 :
3728 : /*
3729 : * Find field's attr record. Note we don't support system columns
3730 : * here: a datum tuple doesn't have valid values for most of the
3731 : * interesting system columns anyway.
3732 : */
3733 110194 : if (fieldnum <= 0) /* should never happen */
3734 0 : elog(ERROR, "unsupported reference to system column %d in FieldSelect",
3735 : fieldnum);
3736 110194 : if (fieldnum > tupDesc->natts) /* should never happen */
3737 0 : elog(ERROR, "attribute number %d exceeds number of columns %d",
3738 : fieldnum, tupDesc->natts);
3739 110194 : attr = TupleDescAttr(tupDesc, fieldnum - 1);
3740 :
3741 : /* Check for dropped column, and force a NULL result if so */
3742 110194 : if (attr->attisdropped)
3743 : {
3744 0 : *op->resnull = true;
3745 0 : return;
3746 : }
3747 :
3748 : /* Check for type mismatch --- possible after ALTER COLUMN TYPE? */
3749 : /* As in CheckVarSlotCompatibility, we should but can't check typmod */
3750 110194 : if (op->d.fieldselect.resulttype != attr->atttypid)
3751 0 : ereport(ERROR,
3752 : (errcode(ERRCODE_DATATYPE_MISMATCH),
3753 : errmsg("attribute %d has wrong type", fieldnum),
3754 : errdetail("Table has type %s, but query expects %s.",
3755 : format_type_be(attr->atttypid),
3756 : format_type_be(op->d.fieldselect.resulttype))));
3757 :
3758 : /* heap_getattr needs a HeapTuple not a bare HeapTupleHeader */
3759 110194 : tmptup.t_len = HeapTupleHeaderGetDatumLength(tuple);
3760 110194 : tmptup.t_data = tuple;
3761 :
3762 : /* extract the field */
3763 110194 : *op->resvalue = heap_getattr(&tmptup,
3764 : fieldnum,
3765 : tupDesc,
3766 : op->resnull);
3767 : }
3768 : }
3769 :
3770 : /*
3771 : * Deform source tuple, filling in the step's values/nulls arrays, before
3772 : * evaluating individual new values as part of a FieldStore expression.
3773 : * Subsequent steps will overwrite individual elements of the values/nulls
3774 : * arrays with the new field values, and then FIELDSTORE_FORM will build the
3775 : * new tuple value.
3776 : *
3777 : * Source record is in step's result variable.
3778 : */
3779 : void
3780 520 : ExecEvalFieldStoreDeForm(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
3781 : {
3782 520 : if (*op->resnull)
3783 : {
3784 : /* Convert null input tuple into an all-nulls row */
3785 256 : memset(op->d.fieldstore.nulls, true,
3786 256 : op->d.fieldstore.ncolumns * sizeof(bool));
3787 : }
3788 : else
3789 : {
3790 : /*
3791 : * heap_deform_tuple needs a HeapTuple not a bare HeapTupleHeader. We
3792 : * set all the fields in the struct just in case.
3793 : */
3794 264 : Datum tupDatum = *op->resvalue;
3795 : HeapTupleHeader tuphdr;
3796 : HeapTupleData tmptup;
3797 : TupleDesc tupDesc;
3798 :
3799 264 : tuphdr = DatumGetHeapTupleHeader(tupDatum);
3800 264 : tmptup.t_len = HeapTupleHeaderGetDatumLength(tuphdr);
3801 264 : ItemPointerSetInvalid(&(tmptup.t_self));
3802 264 : tmptup.t_tableOid = InvalidOid;
3803 264 : tmptup.t_data = tuphdr;
3804 :
3805 : /*
3806 : * Lookup tupdesc if first time through or if type changes. Because
3807 : * we don't pin the tupdesc, we must not do this lookup until after
3808 : * doing DatumGetHeapTupleHeader: that could do database access while
3809 : * detoasting the datum.
3810 : */
3811 264 : tupDesc = get_cached_rowtype(op->d.fieldstore.fstore->resulttype, -1,
3812 : op->d.fieldstore.rowcache, NULL);
3813 :
3814 : /* Check that current tupdesc doesn't have more fields than allocated */
3815 264 : if (unlikely(tupDesc->natts > op->d.fieldstore.ncolumns))
3816 0 : elog(ERROR, "too many columns in composite type %u",
3817 : op->d.fieldstore.fstore->resulttype);
3818 :
3819 264 : heap_deform_tuple(&tmptup, tupDesc,
3820 : op->d.fieldstore.values,
3821 : op->d.fieldstore.nulls);
3822 : }
3823 520 : }
3824 :
3825 : /*
3826 : * Compute the new composite datum after each individual field value of a
3827 : * FieldStore expression has been evaluated.
3828 : */
3829 : void
3830 520 : ExecEvalFieldStoreForm(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
3831 : {
3832 : TupleDesc tupDesc;
3833 : HeapTuple tuple;
3834 :
3835 : /* Lookup tupdesc (should be valid already) */
3836 520 : tupDesc = get_cached_rowtype(op->d.fieldstore.fstore->resulttype, -1,
3837 : op->d.fieldstore.rowcache, NULL);
3838 :
3839 520 : tuple = heap_form_tuple(tupDesc,
3840 520 : op->d.fieldstore.values,
3841 520 : op->d.fieldstore.nulls);
3842 :
3843 520 : *op->resvalue = HeapTupleGetDatum(tuple);
3844 520 : *op->resnull = false;
3845 520 : }
3846 :
3847 : /*
3848 : * Evaluate a rowtype coercion operation.
3849 : * This may require rearranging field positions.
3850 : *
3851 : * Source record is in step's result variable.
3852 : */
3853 : void
3854 12260 : ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
3855 : {
3856 : HeapTuple result;
3857 : Datum tupDatum;
3858 : HeapTupleHeader tuple;
3859 : HeapTupleData tmptup;
3860 : TupleDesc indesc,
3861 : outdesc;
3862 12260 : bool changed = false;
3863 :
3864 : /* NULL in -> NULL out */
3865 12260 : if (*op->resnull)
3866 44 : return;
3867 :
3868 12216 : tupDatum = *op->resvalue;
3869 12216 : tuple = DatumGetHeapTupleHeader(tupDatum);
3870 :
3871 : /*
3872 : * Lookup tupdescs if first time through or if type changes. We'd better
3873 : * pin them since type conversion functions could do catalog lookups and
3874 : * hence cause cache invalidation.
3875 : */
3876 12216 : indesc = get_cached_rowtype(op->d.convert_rowtype.inputtype, -1,
3877 : op->d.convert_rowtype.incache,
3878 : &changed);
3879 12216 : IncrTupleDescRefCount(indesc);
3880 12216 : outdesc = get_cached_rowtype(op->d.convert_rowtype.outputtype, -1,
3881 : op->d.convert_rowtype.outcache,
3882 : &changed);
3883 12216 : IncrTupleDescRefCount(outdesc);
3884 :
3885 : /*
3886 : * We used to be able to assert that incoming tuples are marked with
3887 : * exactly the rowtype of indesc. However, now that ExecEvalWholeRowVar
3888 : * might change the tuples' marking to plain RECORD due to inserting
3889 : * aliases, we can only make this weak test:
3890 : */
3891 : Assert(HeapTupleHeaderGetTypeId(tuple) == indesc->tdtypeid ||
3892 : HeapTupleHeaderGetTypeId(tuple) == RECORDOID);
3893 :
3894 : /* if first time through, or after change, initialize conversion map */
3895 12216 : if (changed)
3896 : {
3897 : MemoryContext old_cxt;
3898 :
3899 : /* allocate map in long-lived memory context */
3900 480 : old_cxt = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
3901 :
3902 : /* prepare map from old to new attribute numbers */
3903 480 : op->d.convert_rowtype.map = convert_tuples_by_name(indesc, outdesc);
3904 :
3905 480 : MemoryContextSwitchTo(old_cxt);
3906 : }
3907 :
3908 : /* Following steps need a HeapTuple not a bare HeapTupleHeader */
3909 12216 : tmptup.t_len = HeapTupleHeaderGetDatumLength(tuple);
3910 12216 : tmptup.t_data = tuple;
3911 :
3912 12216 : if (op->d.convert_rowtype.map != NULL)
3913 : {
3914 : /* Full conversion with attribute rearrangement needed */
3915 576 : result = execute_attr_map_tuple(&tmptup, op->d.convert_rowtype.map);
3916 : /* Result already has appropriate composite-datum header fields */
3917 576 : *op->resvalue = HeapTupleGetDatum(result);
3918 : }
3919 : else
3920 : {
3921 : /*
3922 : * The tuple is physically compatible as-is, but we need to insert the
3923 : * destination rowtype OID in its composite-datum header field, so we
3924 : * have to copy it anyway. heap_copy_tuple_as_datum() is convenient
3925 : * for this since it will both make the physical copy and insert the
3926 : * correct composite header fields. Note that we aren't expecting to
3927 : * have to flatten any toasted fields: the input was a composite
3928 : * datum, so it shouldn't contain any. So heap_copy_tuple_as_datum()
3929 : * is overkill here, but its check for external fields is cheap.
3930 : */
3931 11640 : *op->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc);
3932 : }
3933 :
3934 12216 : DecrTupleDescRefCount(indesc);
3935 12216 : DecrTupleDescRefCount(outdesc);
3936 : }
3937 :
3938 : /*
3939 : * Evaluate "scalar op ANY/ALL (array)".
3940 : *
3941 : * Source array is in our result area, scalar arg is already evaluated into
3942 : * fcinfo->args[0].
3943 : *
3944 : * The operator always yields boolean, and we combine the results across all
3945 : * array elements using OR and AND (for ANY and ALL respectively). Of course
3946 : * we short-circuit as soon as the result is known.
3947 : */
3948 : void
3949 4081256 : ExecEvalScalarArrayOp(ExprState *state, ExprEvalStep *op)
3950 : {
3951 4081256 : FunctionCallInfo fcinfo = op->d.scalararrayop.fcinfo_data;
3952 4081256 : bool useOr = op->d.scalararrayop.useOr;
3953 4081256 : bool strictfunc = op->d.scalararrayop.finfo->fn_strict;
3954 : ArrayType *arr;
3955 : int nitems;
3956 : Datum result;
3957 : bool resultnull;
3958 : int16 typlen;
3959 : bool typbyval;
3960 : char typalign;
3961 : char *s;
3962 : bits8 *bitmap;
3963 : int bitmask;
3964 :
3965 : /*
3966 : * If the array is NULL then we return NULL --- it's not very meaningful
3967 : * to do anything else, even if the operator isn't strict.
3968 : */
3969 4081256 : if (*op->resnull)
3970 159664 : return;
3971 :
3972 : /* Else okay to fetch and detoast the array */
3973 3921592 : arr = DatumGetArrayTypeP(*op->resvalue);
3974 :
3975 : /*
3976 : * If the array is empty, we return either FALSE or TRUE per the useOr
3977 : * flag. This is correct even if the scalar is NULL; since we would
3978 : * evaluate the operator zero times, it matters not whether it would want
3979 : * to return NULL.
3980 : */
3981 3921592 : nitems = ArrayGetNItems(ARR_NDIM(arr), ARR_DIMS(arr));
3982 3921592 : if (nitems <= 0)
3983 : {
3984 12438 : *op->resvalue = BoolGetDatum(!useOr);
3985 12438 : *op->resnull = false;
3986 12438 : return;
3987 : }
3988 :
3989 : /*
3990 : * If the scalar is NULL, and the function is strict, return NULL; no
3991 : * point in iterating the loop.
3992 : */
3993 3909154 : if (fcinfo->args[0].isnull && strictfunc)
3994 : {
3995 986 : *op->resnull = true;
3996 986 : return;
3997 : }
3998 :
3999 : /*
4000 : * We arrange to look up info about the element type only once per series
4001 : * of calls, assuming the element type doesn't change underneath us.
4002 : */
4003 3908168 : if (op->d.scalararrayop.element_type != ARR_ELEMTYPE(arr))
4004 : {
4005 14320 : get_typlenbyvalalign(ARR_ELEMTYPE(arr),
4006 : &op->d.scalararrayop.typlen,
4007 : &op->d.scalararrayop.typbyval,
4008 : &op->d.scalararrayop.typalign);
4009 14320 : op->d.scalararrayop.element_type = ARR_ELEMTYPE(arr);
4010 : }
4011 :
4012 3908168 : typlen = op->d.scalararrayop.typlen;
4013 3908168 : typbyval = op->d.scalararrayop.typbyval;
4014 3908168 : typalign = op->d.scalararrayop.typalign;
4015 :
4016 : /* Initialize result appropriately depending on useOr */
4017 3908168 : result = BoolGetDatum(!useOr);
4018 3908168 : resultnull = false;
4019 :
4020 : /* Loop over the array elements */
4021 3908168 : s = (char *) ARR_DATA_PTR(arr);
4022 3908168 : bitmap = ARR_NULLBITMAP(arr);
4023 3908168 : bitmask = 1;
4024 :
4025 10554324 : for (int i = 0; i < nitems; i++)
4026 : {
4027 : Datum elt;
4028 : Datum thisresult;
4029 :
4030 : /* Get array element, checking for NULL */
4031 8342204 : if (bitmap && (*bitmap & bitmask) == 0)
4032 : {
4033 215264 : fcinfo->args[1].value = (Datum) 0;
4034 215264 : fcinfo->args[1].isnull = true;
4035 : }
4036 : else
4037 : {
4038 8126940 : elt = fetch_att(s, typbyval, typlen);
4039 8126940 : s = att_addlength_pointer(s, typlen, s);
4040 8126940 : s = (char *) att_align_nominal(s, typalign);
4041 8126940 : fcinfo->args[1].value = elt;
4042 8126940 : fcinfo->args[1].isnull = false;
4043 : }
4044 :
4045 : /* Call comparison function */
4046 8342204 : if (fcinfo->args[1].isnull && strictfunc)
4047 : {
4048 215240 : fcinfo->isnull = true;
4049 215240 : thisresult = (Datum) 0;
4050 : }
4051 : else
4052 : {
4053 8126964 : fcinfo->isnull = false;
4054 8126964 : thisresult = op->d.scalararrayop.fn_addr(fcinfo);
4055 : }
4056 :
4057 : /* Combine results per OR or AND semantics */
4058 8342204 : if (fcinfo->isnull)
4059 215336 : resultnull = true;
4060 8126868 : else if (useOr)
4061 : {
4062 7329768 : if (DatumGetBool(thisresult))
4063 : {
4064 1121338 : result = BoolGetDatum(true);
4065 1121338 : resultnull = false;
4066 1121338 : break; /* needn't look at any more elements */
4067 : }
4068 : }
4069 : else
4070 : {
4071 797100 : if (!DatumGetBool(thisresult))
4072 : {
4073 574710 : result = BoolGetDatum(false);
4074 574710 : resultnull = false;
4075 574710 : break; /* needn't look at any more elements */
4076 : }
4077 : }
4078 :
4079 : /* advance bitmap pointer if any */
4080 6646156 : if (bitmap)
4081 : {
4082 767988 : bitmask <<= 1;
4083 767988 : if (bitmask == 0x100)
4084 : {
4085 776 : bitmap++;
4086 776 : bitmask = 1;
4087 : }
4088 : }
4089 : }
4090 :
4091 3908168 : *op->resvalue = result;
4092 3908168 : *op->resnull = resultnull;
4093 : }
4094 :
4095 : /*
4096 : * Hash function for scalar array hash op elements.
4097 : *
4098 : * We use the element type's default hash opclass, and the column collation
4099 : * if the type is collation-sensitive.
4100 : */
4101 : static uint32
4102 6522 : saop_element_hash(struct saophash_hash *tb, Datum key)
4103 : {
4104 6522 : ScalarArrayOpExprHashTable *elements_tab = (ScalarArrayOpExprHashTable *) tb->private_data;
4105 6522 : FunctionCallInfo fcinfo = &elements_tab->hash_fcinfo_data;
4106 : Datum hash;
4107 :
4108 6522 : fcinfo->args[0].value = key;
4109 6522 : fcinfo->args[0].isnull = false;
4110 :
4111 6522 : hash = elements_tab->hash_finfo.fn_addr(fcinfo);
4112 :
4113 6522 : return DatumGetUInt32(hash);
4114 : }
4115 :
4116 : /*
4117 : * Matching function for scalar array hash op elements, to be used in hashtable
4118 : * lookups.
4119 : */
4120 : static bool
4121 4464 : saop_hash_element_match(struct saophash_hash *tb, Datum key1, Datum key2)
4122 : {
4123 : Datum result;
4124 :
4125 4464 : ScalarArrayOpExprHashTable *elements_tab = (ScalarArrayOpExprHashTable *) tb->private_data;
4126 4464 : FunctionCallInfo fcinfo = elements_tab->op->d.hashedscalararrayop.fcinfo_data;
4127 :
4128 4464 : fcinfo->args[0].value = key1;
4129 4464 : fcinfo->args[0].isnull = false;
4130 4464 : fcinfo->args[1].value = key2;
4131 4464 : fcinfo->args[1].isnull = false;
4132 :
4133 4464 : result = elements_tab->op->d.hashedscalararrayop.finfo->fn_addr(fcinfo);
4134 :
4135 4464 : return DatumGetBool(result);
4136 : }
4137 :
4138 : /*
4139 : * Evaluate "scalar op ANY (const array)".
4140 : *
4141 : * Similar to ExecEvalScalarArrayOp, but optimized for faster repeat lookups
4142 : * by building a hashtable on the first lookup. This hashtable will be reused
4143 : * by subsequent lookups. Unlike ExecEvalScalarArrayOp, this version only
4144 : * supports OR semantics.
4145 : *
4146 : * Source array is in our result area, scalar arg is already evaluated into
4147 : * fcinfo->args[0].
4148 : *
4149 : * The operator always yields boolean.
4150 : */
4151 : void
4152 4676 : ExecEvalHashedScalarArrayOp(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
4153 : {
4154 4676 : ScalarArrayOpExprHashTable *elements_tab = op->d.hashedscalararrayop.elements_tab;
4155 4676 : FunctionCallInfo fcinfo = op->d.hashedscalararrayop.fcinfo_data;
4156 4676 : bool inclause = op->d.hashedscalararrayop.inclause;
4157 4676 : bool strictfunc = op->d.hashedscalararrayop.finfo->fn_strict;
4158 4676 : Datum scalar = fcinfo->args[0].value;
4159 4676 : bool scalar_isnull = fcinfo->args[0].isnull;
4160 : Datum result;
4161 : bool resultnull;
4162 : bool hashfound;
4163 :
4164 : /* We don't setup a hashed scalar array op if the array const is null. */
4165 : Assert(!*op->resnull);
4166 :
4167 : /*
4168 : * If the scalar is NULL, and the function is strict, return NULL; no
4169 : * point in executing the search.
4170 : */
4171 4676 : if (fcinfo->args[0].isnull && strictfunc)
4172 : {
4173 68 : *op->resnull = true;
4174 68 : return;
4175 : }
4176 :
4177 : /* Build the hash table on first evaluation */
4178 4608 : if (elements_tab == NULL)
4179 : {
4180 : ScalarArrayOpExpr *saop;
4181 : int16 typlen;
4182 : bool typbyval;
4183 : char typalign;
4184 : int nitems;
4185 152 : bool has_nulls = false;
4186 : char *s;
4187 : bits8 *bitmap;
4188 : int bitmask;
4189 : MemoryContext oldcontext;
4190 : ArrayType *arr;
4191 :
4192 152 : saop = op->d.hashedscalararrayop.saop;
4193 :
4194 152 : arr = DatumGetArrayTypeP(*op->resvalue);
4195 152 : nitems = ArrayGetNItems(ARR_NDIM(arr), ARR_DIMS(arr));
4196 :
4197 152 : get_typlenbyvalalign(ARR_ELEMTYPE(arr),
4198 : &typlen,
4199 : &typbyval,
4200 : &typalign);
4201 :
4202 152 : oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
4203 :
4204 : elements_tab = (ScalarArrayOpExprHashTable *)
4205 152 : palloc0(offsetof(ScalarArrayOpExprHashTable, hash_fcinfo_data) +
4206 : SizeForFunctionCallInfo(1));
4207 152 : op->d.hashedscalararrayop.elements_tab = elements_tab;
4208 152 : elements_tab->op = op;
4209 :
4210 152 : fmgr_info(saop->hashfuncid, &elements_tab->hash_finfo);
4211 152 : fmgr_info_set_expr((Node *) saop, &elements_tab->hash_finfo);
4212 :
4213 152 : InitFunctionCallInfoData(elements_tab->hash_fcinfo_data,
4214 : &elements_tab->hash_finfo,
4215 : 1,
4216 : saop->inputcollid,
4217 : NULL,
4218 : NULL);
4219 :
4220 : /*
4221 : * Create the hash table sizing it according to the number of elements
4222 : * in the array. This does assume that the array has no duplicates.
4223 : * If the array happens to contain many duplicate values then it'll
4224 : * just mean that we sized the table a bit on the large side.
4225 : */
4226 152 : elements_tab->hashtab = saophash_create(CurrentMemoryContext, nitems,
4227 : elements_tab);
4228 :
4229 152 : MemoryContextSwitchTo(oldcontext);
4230 :
4231 152 : s = (char *) ARR_DATA_PTR(arr);
4232 152 : bitmap = ARR_NULLBITMAP(arr);
4233 152 : bitmask = 1;
4234 2240 : for (int i = 0; i < nitems; i++)
4235 : {
4236 : /* Get array element, checking for NULL. */
4237 2088 : if (bitmap && (*bitmap & bitmask) == 0)
4238 : {
4239 174 : has_nulls = true;
4240 : }
4241 : else
4242 : {
4243 : Datum element;
4244 :
4245 1914 : element = fetch_att(s, typbyval, typlen);
4246 1914 : s = att_addlength_pointer(s, typlen, s);
4247 1914 : s = (char *) att_align_nominal(s, typalign);
4248 :
4249 1914 : saophash_insert(elements_tab->hashtab, element, &hashfound);
4250 : }
4251 :
4252 : /* Advance bitmap pointer if any. */
4253 2088 : if (bitmap)
4254 : {
4255 570 : bitmask <<= 1;
4256 570 : if (bitmask == 0x100)
4257 : {
4258 54 : bitmap++;
4259 54 : bitmask = 1;
4260 : }
4261 : }
4262 : }
4263 :
4264 : /*
4265 : * Remember if we had any nulls so that we know if we need to execute
4266 : * non-strict functions with a null lhs value if no match is found.
4267 : */
4268 152 : op->d.hashedscalararrayop.has_nulls = has_nulls;
4269 : }
4270 :
4271 : /* Check the hash to see if we have a match. */
4272 4608 : hashfound = NULL != saophash_lookup(elements_tab->hashtab, scalar);
4273 :
4274 : /* the result depends on if the clause is an IN or NOT IN clause */
4275 4608 : if (inclause)
4276 854 : result = BoolGetDatum(hashfound); /* IN */
4277 : else
4278 3754 : result = BoolGetDatum(!hashfound); /* NOT IN */
4279 :
4280 4608 : resultnull = false;
4281 :
4282 : /*
4283 : * If we didn't find a match in the array, we still might need to handle
4284 : * the possibility of null values. We didn't put any NULLs into the
4285 : * hashtable, but instead marked if we found any when building the table
4286 : * in has_nulls.
4287 : */
4288 4608 : if (!hashfound && op->d.hashedscalararrayop.has_nulls)
4289 : {
4290 42 : if (strictfunc)
4291 : {
4292 :
4293 : /*
4294 : * We have nulls in the array so a non-null lhs and no match must
4295 : * yield NULL.
4296 : */
4297 24 : result = (Datum) 0;
4298 24 : resultnull = true;
4299 : }
4300 : else
4301 : {
4302 : /*
4303 : * Execute function will null rhs just once.
4304 : *
4305 : * The hash lookup path will have scribbled on the lhs argument so
4306 : * we need to set it up also (even though we entered this function
4307 : * with it already set).
4308 : */
4309 18 : fcinfo->args[0].value = scalar;
4310 18 : fcinfo->args[0].isnull = scalar_isnull;
4311 18 : fcinfo->args[1].value = (Datum) 0;
4312 18 : fcinfo->args[1].isnull = true;
4313 :
4314 18 : result = op->d.hashedscalararrayop.finfo->fn_addr(fcinfo);
4315 18 : resultnull = fcinfo->isnull;
4316 :
4317 : /*
4318 : * Reverse the result for NOT IN clauses since the above function
4319 : * is the equality function and we need not-equals.
4320 : */
4321 18 : if (!inclause)
4322 12 : result = !result;
4323 : }
4324 : }
4325 :
4326 4608 : *op->resvalue = result;
4327 4608 : *op->resnull = resultnull;
4328 : }
4329 :
4330 : /*
4331 : * Evaluate a NOT NULL domain constraint.
4332 : */
4333 : void
4334 378 : ExecEvalConstraintNotNull(ExprState *state, ExprEvalStep *op)
4335 : {
4336 378 : if (*op->resnull)
4337 106 : errsave((Node *) op->d.domaincheck.escontext,
4338 : (errcode(ERRCODE_NOT_NULL_VIOLATION),
4339 : errmsg("domain %s does not allow null values",
4340 : format_type_be(op->d.domaincheck.resulttype)),
4341 : errdatatype(op->d.domaincheck.resulttype)));
4342 272 : }
4343 :
4344 : /*
4345 : * Evaluate a CHECK domain constraint.
4346 : */
4347 : void
4348 13024 : ExecEvalConstraintCheck(ExprState *state, ExprEvalStep *op)
4349 : {
4350 13024 : if (!*op->d.domaincheck.checknull &&
4351 11854 : !DatumGetBool(*op->d.domaincheck.checkvalue))
4352 452 : errsave((Node *) op->d.domaincheck.escontext,
4353 : (errcode(ERRCODE_CHECK_VIOLATION),
4354 : errmsg("value for domain %s violates check constraint \"%s\"",
4355 : format_type_be(op->d.domaincheck.resulttype),
4356 : op->d.domaincheck.constraintname),
4357 : errdomainconstraint(op->d.domaincheck.resulttype,
4358 : op->d.domaincheck.constraintname)));
4359 12602 : }
4360 :
4361 : /*
4362 : * Evaluate the various forms of XmlExpr.
4363 : *
4364 : * Arguments have been evaluated into named_argvalue/named_argnull
4365 : * and/or argvalue/argnull arrays.
4366 : */
4367 : void
4368 44618 : ExecEvalXmlExpr(ExprState *state, ExprEvalStep *op)
4369 : {
4370 44618 : XmlExpr *xexpr = op->d.xmlexpr.xexpr;
4371 : Datum value;
4372 :
4373 44618 : *op->resnull = true; /* until we get a result */
4374 44618 : *op->resvalue = (Datum) 0;
4375 :
4376 44618 : switch (xexpr->op)
4377 : {
4378 54 : case IS_XMLCONCAT:
4379 : {
4380 54 : Datum *argvalue = op->d.xmlexpr.argvalue;
4381 54 : bool *argnull = op->d.xmlexpr.argnull;
4382 54 : List *values = NIL;
4383 :
4384 174 : for (int i = 0; i < list_length(xexpr->args); i++)
4385 : {
4386 120 : if (!argnull[i])
4387 90 : values = lappend(values, DatumGetPointer(argvalue[i]));
4388 : }
4389 :
4390 54 : if (values != NIL)
4391 : {
4392 42 : *op->resvalue = PointerGetDatum(xmlconcat(values));
4393 42 : *op->resnull = false;
4394 : }
4395 : }
4396 54 : break;
4397 :
4398 21964 : case IS_XMLFOREST:
4399 : {
4400 21964 : Datum *argvalue = op->d.xmlexpr.named_argvalue;
4401 21964 : bool *argnull = op->d.xmlexpr.named_argnull;
4402 : StringInfoData buf;
4403 : ListCell *lc;
4404 : ListCell *lc2;
4405 : int i;
4406 :
4407 21964 : initStringInfo(&buf);
4408 :
4409 21964 : i = 0;
4410 153628 : forboth(lc, xexpr->named_args, lc2, xexpr->arg_names)
4411 : {
4412 131664 : Expr *e = (Expr *) lfirst(lc);
4413 131664 : char *argname = strVal(lfirst(lc2));
4414 :
4415 131664 : if (!argnull[i])
4416 : {
4417 109946 : value = argvalue[i];
4418 109946 : appendStringInfo(&buf, "<%s>%s</%s>",
4419 : argname,
4420 : map_sql_value_to_xml_value(value,
4421 : exprType((Node *) e), true),
4422 : argname);
4423 109946 : *op->resnull = false;
4424 : }
4425 131664 : i++;
4426 : }
4427 :
4428 21964 : if (!*op->resnull)
4429 : {
4430 : text *result;
4431 :
4432 21964 : result = cstring_to_text_with_len(buf.data, buf.len);
4433 21964 : *op->resvalue = PointerGetDatum(result);
4434 : }
4435 :
4436 21964 : pfree(buf.data);
4437 : }
4438 21964 : break;
4439 :
4440 22120 : case IS_XMLELEMENT:
4441 22120 : *op->resvalue = PointerGetDatum(xmlelement(xexpr,
4442 : op->d.xmlexpr.named_argvalue,
4443 : op->d.xmlexpr.named_argnull,
4444 : op->d.xmlexpr.argvalue,
4445 : op->d.xmlexpr.argnull));
4446 22114 : *op->resnull = false;
4447 22114 : break;
4448 :
4449 132 : case IS_XMLPARSE:
4450 : {
4451 132 : Datum *argvalue = op->d.xmlexpr.argvalue;
4452 132 : bool *argnull = op->d.xmlexpr.argnull;
4453 : text *data;
4454 : bool preserve_whitespace;
4455 :
4456 : /* arguments are known to be text, bool */
4457 : Assert(list_length(xexpr->args) == 2);
4458 :
4459 132 : if (argnull[0])
4460 0 : return;
4461 132 : value = argvalue[0];
4462 132 : data = DatumGetTextPP(value);
4463 :
4464 132 : if (argnull[1]) /* probably can't happen */
4465 0 : return;
4466 132 : value = argvalue[1];
4467 132 : preserve_whitespace = DatumGetBool(value);
4468 :
4469 132 : *op->resvalue = PointerGetDatum(xmlparse(data,
4470 : xexpr->xmloption,
4471 : preserve_whitespace));
4472 84 : *op->resnull = false;
4473 : }
4474 84 : break;
4475 :
4476 72 : case IS_XMLPI:
4477 : {
4478 : text *arg;
4479 : bool isnull;
4480 :
4481 : /* optional argument is known to be text */
4482 : Assert(list_length(xexpr->args) <= 1);
4483 :
4484 72 : if (xexpr->args)
4485 : {
4486 42 : isnull = op->d.xmlexpr.argnull[0];
4487 42 : if (isnull)
4488 18 : arg = NULL;
4489 : else
4490 24 : arg = DatumGetTextPP(op->d.xmlexpr.argvalue[0]);
4491 : }
4492 : else
4493 : {
4494 30 : arg = NULL;
4495 30 : isnull = false;
4496 : }
4497 :
4498 72 : *op->resvalue = PointerGetDatum(xmlpi(xexpr->name,
4499 : arg,
4500 : isnull,
4501 : op->resnull));
4502 : }
4503 54 : break;
4504 :
4505 60 : case IS_XMLROOT:
4506 : {
4507 60 : Datum *argvalue = op->d.xmlexpr.argvalue;
4508 60 : bool *argnull = op->d.xmlexpr.argnull;
4509 : xmltype *data;
4510 : text *version;
4511 : int standalone;
4512 :
4513 : /* arguments are known to be xml, text, int */
4514 : Assert(list_length(xexpr->args) == 3);
4515 :
4516 60 : if (argnull[0])
4517 0 : return;
4518 60 : data = DatumGetXmlP(argvalue[0]);
4519 :
4520 60 : if (argnull[1])
4521 36 : version = NULL;
4522 : else
4523 24 : version = DatumGetTextPP(argvalue[1]);
4524 :
4525 : Assert(!argnull[2]); /* always present */
4526 60 : standalone = DatumGetInt32(argvalue[2]);
4527 :
4528 60 : *op->resvalue = PointerGetDatum(xmlroot(data,
4529 : version,
4530 : standalone));
4531 60 : *op->resnull = false;
4532 : }
4533 60 : break;
4534 :
4535 192 : case IS_XMLSERIALIZE:
4536 : {
4537 192 : Datum *argvalue = op->d.xmlexpr.argvalue;
4538 192 : bool *argnull = op->d.xmlexpr.argnull;
4539 :
4540 : /* argument type is known to be xml */
4541 : Assert(list_length(xexpr->args) == 1);
4542 :
4543 192 : if (argnull[0])
4544 12 : return;
4545 180 : value = argvalue[0];
4546 :
4547 300 : *op->resvalue =
4548 180 : PointerGetDatum(xmltotext_with_options(DatumGetXmlP(value),
4549 : xexpr->xmloption,
4550 180 : xexpr->indent));
4551 150 : *op->resnull = false;
4552 : }
4553 150 : break;
4554 :
4555 24 : case IS_DOCUMENT:
4556 : {
4557 24 : Datum *argvalue = op->d.xmlexpr.argvalue;
4558 24 : bool *argnull = op->d.xmlexpr.argnull;
4559 :
4560 : /* optional argument is known to be xml */
4561 : Assert(list_length(xexpr->args) == 1);
4562 :
4563 24 : if (argnull[0])
4564 0 : return;
4565 24 : value = argvalue[0];
4566 :
4567 48 : *op->resvalue =
4568 24 : BoolGetDatum(xml_is_document(DatumGetXmlP(value)));
4569 24 : *op->resnull = false;
4570 : }
4571 24 : break;
4572 :
4573 0 : default:
4574 0 : elog(ERROR, "unrecognized XML operation");
4575 : break;
4576 : }
4577 : }
4578 :
4579 : /*
4580 : * Evaluate a JSON constructor expression.
4581 : */
4582 : void
4583 696 : ExecEvalJsonConstructor(ExprState *state, ExprEvalStep *op,
4584 : ExprContext *econtext)
4585 : {
4586 : Datum res;
4587 696 : JsonConstructorExprState *jcstate = op->d.json_constructor.jcstate;
4588 696 : JsonConstructorExpr *ctor = jcstate->constructor;
4589 696 : bool is_jsonb = ctor->returning->format->format_type == JS_FORMAT_JSONB;
4590 696 : bool isnull = false;
4591 :
4592 696 : if (ctor->type == JSCTOR_JSON_ARRAY)
4593 : res = (is_jsonb ?
4594 218 : jsonb_build_array_worker :
4595 : json_build_array_worker) (jcstate->nargs,
4596 218 : jcstate->arg_values,
4597 218 : jcstate->arg_nulls,
4598 218 : jcstate->arg_types,
4599 218 : jcstate->constructor->absent_on_null);
4600 478 : else if (ctor->type == JSCTOR_JSON_OBJECT)
4601 : res = (is_jsonb ?
4602 368 : jsonb_build_object_worker :
4603 : json_build_object_worker) (jcstate->nargs,
4604 368 : jcstate->arg_values,
4605 368 : jcstate->arg_nulls,
4606 368 : jcstate->arg_types,
4607 368 : jcstate->constructor->absent_on_null,
4608 368 : jcstate->constructor->unique);
4609 110 : else if (ctor->type == JSCTOR_JSON_SCALAR)
4610 : {
4611 100 : if (jcstate->arg_nulls[0])
4612 : {
4613 20 : res = (Datum) 0;
4614 20 : isnull = true;
4615 : }
4616 : else
4617 : {
4618 80 : Datum value = jcstate->arg_values[0];
4619 80 : Oid outfuncid = jcstate->arg_type_cache[0].outfuncid;
4620 80 : JsonTypeCategory category = (JsonTypeCategory)
4621 80 : jcstate->arg_type_cache[0].category;
4622 :
4623 80 : if (is_jsonb)
4624 0 : res = datum_to_jsonb(value, category, outfuncid);
4625 : else
4626 80 : res = datum_to_json(value, category, outfuncid);
4627 : }
4628 : }
4629 10 : else if (ctor->type == JSCTOR_JSON_PARSE)
4630 : {
4631 10 : if (jcstate->arg_nulls[0])
4632 : {
4633 0 : res = (Datum) 0;
4634 0 : isnull = true;
4635 : }
4636 : else
4637 : {
4638 10 : Datum value = jcstate->arg_values[0];
4639 10 : text *js = DatumGetTextP(value);
4640 :
4641 10 : if (is_jsonb)
4642 0 : res = jsonb_from_text(js, true);
4643 : else
4644 : {
4645 10 : (void) json_validate(js, true, true);
4646 0 : res = value;
4647 : }
4648 : }
4649 : }
4650 : else
4651 0 : elog(ERROR, "invalid JsonConstructorExpr type %d", ctor->type);
4652 :
4653 616 : *op->resvalue = res;
4654 616 : *op->resnull = isnull;
4655 616 : }
4656 :
4657 : /*
4658 : * Evaluate a IS JSON predicate.
4659 : */
4660 : void
4661 2750 : ExecEvalJsonIsPredicate(ExprState *state, ExprEvalStep *op)
4662 : {
4663 2750 : JsonIsPredicate *pred = op->d.is_json.pred;
4664 2750 : Datum js = *op->resvalue;
4665 : Oid exprtype;
4666 : bool res;
4667 :
4668 2750 : if (*op->resnull)
4669 : {
4670 102 : *op->resvalue = BoolGetDatum(false);
4671 102 : return;
4672 : }
4673 :
4674 2648 : exprtype = exprType(pred->expr);
4675 :
4676 2648 : if (exprtype == TEXTOID || exprtype == JSONOID)
4677 2120 : {
4678 2120 : text *json = DatumGetTextP(js);
4679 :
4680 2120 : if (pred->item_type == JS_TYPE_ANY)
4681 1442 : res = true;
4682 : else
4683 : {
4684 678 : switch (json_get_first_token(json, false))
4685 : {
4686 300 : case JSON_TOKEN_OBJECT_START:
4687 300 : res = pred->item_type == JS_TYPE_OBJECT;
4688 300 : break;
4689 126 : case JSON_TOKEN_ARRAY_START:
4690 126 : res = pred->item_type == JS_TYPE_ARRAY;
4691 126 : break;
4692 216 : case JSON_TOKEN_STRING:
4693 : case JSON_TOKEN_NUMBER:
4694 : case JSON_TOKEN_TRUE:
4695 : case JSON_TOKEN_FALSE:
4696 : case JSON_TOKEN_NULL:
4697 216 : res = pred->item_type == JS_TYPE_SCALAR;
4698 216 : break;
4699 36 : default:
4700 36 : res = false;
4701 36 : break;
4702 : }
4703 : }
4704 :
4705 : /*
4706 : * Do full parsing pass only for uniqueness check or for JSON text
4707 : * validation.
4708 : */
4709 2120 : if (res && (pred->unique_keys || exprtype == TEXTOID))
4710 1326 : res = json_validate(json, pred->unique_keys, false);
4711 : }
4712 528 : else if (exprtype == JSONBOID)
4713 : {
4714 528 : if (pred->item_type == JS_TYPE_ANY)
4715 330 : res = true;
4716 : else
4717 : {
4718 198 : Jsonb *jb = DatumGetJsonbP(js);
4719 :
4720 198 : switch (pred->item_type)
4721 : {
4722 66 : case JS_TYPE_OBJECT:
4723 66 : res = JB_ROOT_IS_OBJECT(jb);
4724 66 : break;
4725 66 : case JS_TYPE_ARRAY:
4726 66 : res = JB_ROOT_IS_ARRAY(jb) && !JB_ROOT_IS_SCALAR(jb);
4727 66 : break;
4728 66 : case JS_TYPE_SCALAR:
4729 66 : res = JB_ROOT_IS_ARRAY(jb) && JB_ROOT_IS_SCALAR(jb);
4730 66 : break;
4731 0 : default:
4732 0 : res = false;
4733 0 : break;
4734 : }
4735 : }
4736 :
4737 : /* Key uniqueness check is redundant for jsonb */
4738 : }
4739 : else
4740 0 : res = false;
4741 :
4742 2648 : *op->resvalue = BoolGetDatum(res);
4743 : }
4744 :
4745 : /*
4746 : * Evaluate a jsonpath against a document, both of which must have been
4747 : * evaluated and their values saved in op->d.jsonexpr.jsestate.
4748 : *
4749 : * If an error occurs during JsonPath* evaluation or when coercing its result
4750 : * to the RETURNING type, JsonExprState.error is set to true, provided the
4751 : * ON ERROR behavior is not ERROR. Similarly, if JsonPath{Query|Value}() found
4752 : * no matching items, JsonExprState.empty is set to true, provided the ON EMPTY
4753 : * behavior is not ERROR. That is to signal to the subsequent steps that check
4754 : * those flags to return the ON ERROR / ON EMPTY expression.
4755 : *
4756 : * Return value is the step address to be performed next. It will be one of
4757 : * jump_error, jump_empty, jump_eval_coercion, or jump_end, all given in
4758 : * op->d.jsonexpr.jsestate.
4759 : */
4760 : int
4761 5282 : ExecEvalJsonExprPath(ExprState *state, ExprEvalStep *op,
4762 : ExprContext *econtext)
4763 : {
4764 5282 : JsonExprState *jsestate = op->d.jsonexpr.jsestate;
4765 5282 : JsonExpr *jsexpr = jsestate->jsexpr;
4766 : Datum item;
4767 : JsonPath *path;
4768 5282 : bool throw_error = jsexpr->on_error->btype == JSON_BEHAVIOR_ERROR;
4769 5282 : bool error = false,
4770 5282 : empty = false;
4771 5282 : int jump_eval_coercion = jsestate->jump_eval_coercion;
4772 5282 : char *val_string = NULL;
4773 :
4774 5282 : item = jsestate->formatted_expr.value;
4775 5282 : path = DatumGetJsonPathP(jsestate->pathspec.value);
4776 :
4777 : /* Set error/empty to false. */
4778 5282 : memset(&jsestate->error, 0, sizeof(NullableDatum));
4779 5282 : memset(&jsestate->empty, 0, sizeof(NullableDatum));
4780 :
4781 : /* Also reset ErrorSaveContext contents for the next row. */
4782 5282 : if (jsestate->escontext.details_wanted)
4783 : {
4784 912 : jsestate->escontext.error_data = NULL;
4785 912 : jsestate->escontext.details_wanted = false;
4786 : }
4787 5282 : jsestate->escontext.error_occurred = false;
4788 :
4789 5282 : switch (jsexpr->op)
4790 : {
4791 582 : case JSON_EXISTS_OP:
4792 : {
4793 582 : bool exists = JsonPathExists(item, path,
4794 582 : !throw_error ? &error : NULL,
4795 : jsestate->args);
4796 :
4797 576 : if (!error)
4798 : {
4799 420 : *op->resnull = false;
4800 420 : *op->resvalue = BoolGetDatum(exists);
4801 : }
4802 : }
4803 576 : break;
4804 :
4805 2460 : case JSON_QUERY_OP:
4806 2460 : *op->resvalue = JsonPathQuery(item, path, jsexpr->wrapper, &empty,
4807 2460 : !throw_error ? &error : NULL,
4808 : jsestate->args,
4809 2460 : jsexpr->column_name);
4810 :
4811 2430 : *op->resnull = (DatumGetPointer(*op->resvalue) == NULL);
4812 2430 : break;
4813 :
4814 2240 : case JSON_VALUE_OP:
4815 : {
4816 2240 : JsonbValue *jbv = JsonPathValue(item, path, &empty,
4817 2240 : !throw_error ? &error : NULL,
4818 : jsestate->args,
4819 2240 : jsexpr->column_name);
4820 :
4821 2210 : if (jbv == NULL)
4822 : {
4823 : /* Will be coerced with json_populate_type(), if needed. */
4824 516 : *op->resvalue = (Datum) 0;
4825 516 : *op->resnull = true;
4826 : }
4827 1694 : else if (!error && !empty)
4828 : {
4829 1694 : if (jsexpr->returning->typid == JSONOID ||
4830 1664 : jsexpr->returning->typid == JSONBOID)
4831 : {
4832 54 : val_string = DatumGetCString(DirectFunctionCall1(jsonb_out,
4833 : JsonbPGetDatum(JsonbValueToJsonb(jbv))));
4834 : }
4835 1640 : else if (jsexpr->use_json_coercion)
4836 : {
4837 102 : *op->resvalue = JsonbPGetDatum(JsonbValueToJsonb(jbv));
4838 102 : *op->resnull = false;
4839 : }
4840 : else
4841 : {
4842 1538 : val_string = ExecGetJsonValueItemString(jbv, op->resnull);
4843 :
4844 : /*
4845 : * Simply convert to the default RETURNING type (text)
4846 : * if no coercion needed.
4847 : */
4848 1538 : if (!jsexpr->use_io_coercion)
4849 114 : *op->resvalue = DirectFunctionCall1(textin,
4850 : CStringGetDatum(val_string));
4851 : }
4852 : }
4853 2210 : break;
4854 : }
4855 :
4856 : /* JSON_TABLE_OP can't happen here */
4857 :
4858 0 : default:
4859 0 : elog(ERROR, "unrecognized SQL/JSON expression op %d",
4860 : (int) jsexpr->op);
4861 : return false;
4862 : }
4863 :
4864 : /*
4865 : * Coerce the result value to the RETURNING type by calling its input
4866 : * function.
4867 : */
4868 5216 : if (!*op->resnull && jsexpr->use_io_coercion)
4869 : {
4870 : FunctionCallInfo fcinfo;
4871 :
4872 : Assert(jump_eval_coercion == -1);
4873 1478 : fcinfo = jsestate->input_fcinfo;
4874 : Assert(fcinfo != NULL);
4875 : Assert(val_string != NULL);
4876 1478 : fcinfo->args[0].value = PointerGetDatum(val_string);
4877 1478 : fcinfo->args[0].isnull = *op->resnull;
4878 :
4879 : /*
4880 : * Second and third arguments are already set up in
4881 : * ExecInitJsonExpr().
4882 : */
4883 :
4884 1478 : fcinfo->isnull = false;
4885 1478 : *op->resvalue = FunctionCallInvoke(fcinfo);
4886 1418 : if (SOFT_ERROR_OCCURRED(&jsestate->escontext))
4887 186 : error = true;
4888 : }
4889 :
4890 : /*
4891 : * When setting up the ErrorSaveContext (if needed) for capturing the
4892 : * errors that occur when coercing the JsonBehavior expression, set
4893 : * details_wanted to be able to show the actual error message as the
4894 : * DETAIL of the error message that tells that it is the JsonBehavior
4895 : * expression that caused the error; see ExecEvalJsonCoercionFinish().
4896 : */
4897 :
4898 : /* Handle ON EMPTY. */
4899 5156 : if (empty)
4900 : {
4901 540 : *op->resvalue = (Datum) 0;
4902 540 : *op->resnull = true;
4903 540 : if (jsexpr->on_empty)
4904 : {
4905 540 : if (jsexpr->on_empty->btype != JSON_BEHAVIOR_ERROR)
4906 : {
4907 480 : jsestate->empty.value = BoolGetDatum(true);
4908 : /* Set up to catch coercion errors of the ON EMPTY value. */
4909 480 : jsestate->escontext.error_occurred = false;
4910 480 : jsestate->escontext.details_wanted = true;
4911 : /* Jump to end if the ON EMPTY behavior is to return NULL */
4912 480 : return jsestate->jump_empty >= 0 ? jsestate->jump_empty : jsestate->jump_end;
4913 : }
4914 : }
4915 0 : else if (jsexpr->on_error->btype != JSON_BEHAVIOR_ERROR)
4916 : {
4917 0 : jsestate->error.value = BoolGetDatum(true);
4918 : /* Set up to catch coercion errors of the ON ERROR value. */
4919 0 : jsestate->escontext.error_occurred = false;
4920 0 : jsestate->escontext.details_wanted = true;
4921 : Assert(!throw_error);
4922 : /* Jump to end if the ON ERROR behavior is to return NULL */
4923 0 : return jsestate->jump_error >= 0 ? jsestate->jump_error : jsestate->jump_end;
4924 : }
4925 :
4926 60 : if (jsexpr->column_name)
4927 12 : ereport(ERROR,
4928 : errcode(ERRCODE_NO_SQL_JSON_ITEM),
4929 : errmsg("no SQL/JSON item found for specified path of column \"%s\"",
4930 : jsexpr->column_name));
4931 : else
4932 48 : ereport(ERROR,
4933 : errcode(ERRCODE_NO_SQL_JSON_ITEM),
4934 : errmsg("no SQL/JSON item found for specified path"));
4935 : }
4936 :
4937 : /*
4938 : * ON ERROR. Wouldn't get here if the behavior is ERROR, because they
4939 : * would have already been thrown.
4940 : */
4941 4616 : if (error)
4942 : {
4943 : Assert(!throw_error);
4944 534 : *op->resvalue = (Datum) 0;
4945 534 : *op->resnull = true;
4946 534 : jsestate->error.value = BoolGetDatum(true);
4947 : /* Set up to catch coercion errors of the ON ERROR value. */
4948 534 : jsestate->escontext.error_occurred = false;
4949 534 : jsestate->escontext.details_wanted = true;
4950 : /* Jump to end if the ON ERROR behavior is to return NULL */
4951 534 : return jsestate->jump_error >= 0 ? jsestate->jump_error : jsestate->jump_end;
4952 : }
4953 :
4954 4082 : return jump_eval_coercion >= 0 ? jump_eval_coercion : jsestate->jump_end;
4955 : }
4956 :
4957 : /*
4958 : * Convert the given JsonbValue to its C string representation
4959 : *
4960 : * *resnull is set if the JsonbValue is a jbvNull.
4961 : */
4962 : static char *
4963 1538 : ExecGetJsonValueItemString(JsonbValue *item, bool *resnull)
4964 : {
4965 1538 : *resnull = false;
4966 :
4967 : /* get coercion state reference and datum of the corresponding SQL type */
4968 1538 : switch (item->type)
4969 : {
4970 0 : case jbvNull:
4971 0 : *resnull = true;
4972 0 : return NULL;
4973 :
4974 304 : case jbvString:
4975 : {
4976 304 : char *str = palloc(item->val.string.len + 1);
4977 :
4978 304 : memcpy(str, item->val.string.val, item->val.string.len);
4979 304 : str[item->val.string.len] = '\0';
4980 304 : return str;
4981 : }
4982 :
4983 1120 : case jbvNumeric:
4984 1120 : return DatumGetCString(DirectFunctionCall1(numeric_out,
4985 : NumericGetDatum(item->val.numeric)));
4986 :
4987 72 : case jbvBool:
4988 72 : return DatumGetCString(DirectFunctionCall1(boolout,
4989 : BoolGetDatum(item->val.boolean)));
4990 :
4991 42 : case jbvDatetime:
4992 42 : switch (item->val.datetime.typid)
4993 : {
4994 6 : case DATEOID:
4995 6 : return DatumGetCString(DirectFunctionCall1(date_out,
4996 : item->val.datetime.value));
4997 6 : case TIMEOID:
4998 6 : return DatumGetCString(DirectFunctionCall1(time_out,
4999 : item->val.datetime.value));
5000 6 : case TIMETZOID:
5001 6 : return DatumGetCString(DirectFunctionCall1(timetz_out,
5002 : item->val.datetime.value));
5003 6 : case TIMESTAMPOID:
5004 6 : return DatumGetCString(DirectFunctionCall1(timestamp_out,
5005 : item->val.datetime.value));
5006 18 : case TIMESTAMPTZOID:
5007 18 : return DatumGetCString(DirectFunctionCall1(timestamptz_out,
5008 : item->val.datetime.value));
5009 0 : default:
5010 0 : elog(ERROR, "unexpected jsonb datetime type oid %u",
5011 : item->val.datetime.typid);
5012 : }
5013 : break;
5014 :
5015 0 : case jbvArray:
5016 : case jbvObject:
5017 : case jbvBinary:
5018 0 : return DatumGetCString(DirectFunctionCall1(jsonb_out,
5019 : JsonbPGetDatum(JsonbValueToJsonb(item))));
5020 :
5021 0 : default:
5022 0 : elog(ERROR, "unexpected jsonb value type %d", item->type);
5023 : }
5024 :
5025 : Assert(false);
5026 : *resnull = true;
5027 : return NULL;
5028 : }
5029 :
5030 : /*
5031 : * Coerce a jsonb value produced by ExecEvalJsonExprPath() or an ON ERROR /
5032 : * ON EMPTY behavior expression to the target type.
5033 : *
5034 : * Any soft errors that occur here will be checked by
5035 : * EEOP_JSONEXPR_COERCION_FINISH that will run after this.
5036 : */
5037 : void
5038 1806 : ExecEvalJsonCoercion(ExprState *state, ExprEvalStep *op,
5039 : ExprContext *econtext)
5040 : {
5041 1806 : ErrorSaveContext *escontext = op->d.jsonexpr_coercion.escontext;
5042 :
5043 : /*
5044 : * Prepare to call json_populate_type() to coerce the boolean result of
5045 : * JSON_EXISTS_OP to the target type. If the target type is integer or a
5046 : * domain over integer, call the boolean-to-integer cast function instead,
5047 : * because the integer's input function (which is what
5048 : * json_populate_type() calls to coerce to scalar target types) doesn't
5049 : * accept boolean literals as valid input. We only have a special case
5050 : * for integer and domains thereof as it seems common to use those types
5051 : * for EXISTS columns in JSON_TABLE().
5052 : */
5053 1806 : if (op->d.jsonexpr_coercion.exists_coerce)
5054 : {
5055 180 : if (op->d.jsonexpr_coercion.exists_cast_to_int)
5056 : {
5057 : /* Check domain constraints if any. */
5058 126 : if (op->d.jsonexpr_coercion.exists_check_domain &&
5059 24 : !domain_check_safe(*op->resvalue, *op->resnull,
5060 : op->d.jsonexpr_coercion.targettype,
5061 : &op->d.jsonexpr_coercion.json_coercion_cache,
5062 : econtext->ecxt_per_query_memory,
5063 : (Node *) escontext))
5064 : {
5065 18 : *op->resnull = true;
5066 18 : *op->resvalue = (Datum) 0;
5067 : }
5068 : else
5069 102 : *op->resvalue = DirectFunctionCall1(bool_int4, *op->resvalue);
5070 120 : return;
5071 : }
5072 :
5073 54 : *op->resvalue = DirectFunctionCall1(jsonb_in,
5074 : DatumGetBool(*op->resvalue) ?
5075 : CStringGetDatum("true") :
5076 : CStringGetDatum("false"));
5077 : }
5078 :
5079 1530 : *op->resvalue = json_populate_type(*op->resvalue, JSONBOID,
5080 : op->d.jsonexpr_coercion.targettype,
5081 : op->d.jsonexpr_coercion.targettypmod,
5082 : &op->d.jsonexpr_coercion.json_coercion_cache,
5083 : econtext->ecxt_per_query_memory,
5084 : op->resnull,
5085 1680 : op->d.jsonexpr_coercion.omit_quotes,
5086 : (Node *) escontext);
5087 : }
5088 :
5089 : static char *
5090 78 : GetJsonBehaviorValueString(JsonBehavior *behavior)
5091 : {
5092 : /*
5093 : * The order of array elements must correspond to the order of
5094 : * JsonBehaviorType members.
5095 : */
5096 78 : const char *behavior_names[] =
5097 : {
5098 : "NULL",
5099 : "ERROR",
5100 : "EMPTY",
5101 : "TRUE",
5102 : "FALSE",
5103 : "UNKNOWN",
5104 : "EMPTY ARRAY",
5105 : "EMPTY OBJECT",
5106 : "DEFAULT"
5107 : };
5108 :
5109 78 : return pstrdup(behavior_names[behavior->btype]);
5110 : }
5111 :
5112 : /*
5113 : * Checks if an error occurred in ExecEvalJsonCoercion(). If so, this sets
5114 : * JsonExprState.error to trigger the ON ERROR handling steps, unless the
5115 : * error is thrown when coercing a JsonBehavior value.
5116 : */
5117 : void
5118 1698 : ExecEvalJsonCoercionFinish(ExprState *state, ExprEvalStep *op)
5119 : {
5120 1698 : JsonExprState *jsestate = op->d.jsonexpr.jsestate;
5121 :
5122 1698 : if (SOFT_ERROR_OCCURRED(&jsestate->escontext))
5123 : {
5124 : /*
5125 : * jsestate->error or jsestate->empty being set means that the error
5126 : * occurred when coercing the JsonBehavior value. Throw the error in
5127 : * that case with the actual coercion error message shown in the
5128 : * DETAIL part.
5129 : */
5130 552 : if (DatumGetBool(jsestate->error.value))
5131 60 : ereport(ERROR,
5132 : (errcode(ERRCODE_DATATYPE_MISMATCH),
5133 : /*- translator: first %s is a SQL/JSON clause (e.g. ON ERROR) */
5134 : errmsg("could not coerce %s expression (%s) to the RETURNING type",
5135 : "ON ERROR",
5136 : GetJsonBehaviorValueString(jsestate->jsexpr->on_error)),
5137 : errdetail("%s", jsestate->escontext.error_data->message)));
5138 492 : else if (DatumGetBool(jsestate->empty.value))
5139 18 : ereport(ERROR,
5140 : (errcode(ERRCODE_DATATYPE_MISMATCH),
5141 : /*- translator: first %s is a SQL/JSON clause (e.g. ON ERROR) */
5142 : errmsg("could not coerce %s expression (%s) to the RETURNING type",
5143 : "ON EMPTY",
5144 : GetJsonBehaviorValueString(jsestate->jsexpr->on_empty)),
5145 : errdetail("%s", jsestate->escontext.error_data->message)));
5146 :
5147 474 : *op->resvalue = (Datum) 0;
5148 474 : *op->resnull = true;
5149 :
5150 474 : jsestate->error.value = BoolGetDatum(true);
5151 :
5152 : /*
5153 : * Reset for next use such as for catching errors when coercing a
5154 : * JsonBehavior expression.
5155 : */
5156 474 : jsestate->escontext.error_occurred = false;
5157 474 : jsestate->escontext.error_occurred = false;
5158 474 : jsestate->escontext.details_wanted = true;
5159 : }
5160 1620 : }
5161 :
5162 : /*
5163 : * ExecEvalGroupingFunc
5164 : *
5165 : * Computes a bitmask with a bit for each (unevaluated) argument expression
5166 : * (rightmost arg is least significant bit).
5167 : *
5168 : * A bit is set if the corresponding expression is NOT part of the set of
5169 : * grouping expressions in the current grouping set.
5170 : */
5171 : void
5172 1928 : ExecEvalGroupingFunc(ExprState *state, ExprEvalStep *op)
5173 : {
5174 1928 : AggState *aggstate = castNode(AggState, state->parent);
5175 1928 : int result = 0;
5176 1928 : Bitmapset *grouped_cols = aggstate->grouped_cols;
5177 : ListCell *lc;
5178 :
5179 4658 : foreach(lc, op->d.grouping_func.clauses)
5180 : {
5181 2730 : int attnum = lfirst_int(lc);
5182 :
5183 2730 : result <<= 1;
5184 :
5185 2730 : if (!bms_is_member(attnum, grouped_cols))
5186 1092 : result |= 1;
5187 : }
5188 :
5189 1928 : *op->resvalue = Int32GetDatum(result);
5190 1928 : *op->resnull = false;
5191 1928 : }
5192 :
5193 : /*
5194 : * ExecEvalMergeSupportFunc
5195 : *
5196 : * Returns information about the current MERGE action for its RETURNING list.
5197 : */
5198 : void
5199 428 : ExecEvalMergeSupportFunc(ExprState *state, ExprEvalStep *op,
5200 : ExprContext *econtext)
5201 : {
5202 428 : ModifyTableState *mtstate = castNode(ModifyTableState, state->parent);
5203 428 : MergeActionState *relaction = mtstate->mt_merge_action;
5204 :
5205 428 : if (!relaction)
5206 0 : elog(ERROR, "no merge action in progress");
5207 :
5208 : /* Return the MERGE action ("INSERT", "UPDATE", or "DELETE") */
5209 428 : switch (relaction->mas_action->commandType)
5210 : {
5211 132 : case CMD_INSERT:
5212 132 : *op->resvalue = PointerGetDatum(cstring_to_text_with_len("INSERT", 6));
5213 132 : *op->resnull = false;
5214 132 : break;
5215 176 : case CMD_UPDATE:
5216 176 : *op->resvalue = PointerGetDatum(cstring_to_text_with_len("UPDATE", 6));
5217 176 : *op->resnull = false;
5218 176 : break;
5219 120 : case CMD_DELETE:
5220 120 : *op->resvalue = PointerGetDatum(cstring_to_text_with_len("DELETE", 6));
5221 120 : *op->resnull = false;
5222 120 : break;
5223 0 : case CMD_NOTHING:
5224 0 : elog(ERROR, "unexpected merge action: DO NOTHING");
5225 : break;
5226 0 : default:
5227 0 : elog(ERROR, "unrecognized commandType: %d",
5228 : (int) relaction->mas_action->commandType);
5229 : }
5230 428 : }
5231 :
5232 : /*
5233 : * Hand off evaluation of a subplan to nodeSubplan.c
5234 : */
5235 : void
5236 2860022 : ExecEvalSubPlan(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
5237 : {
5238 2860022 : SubPlanState *sstate = op->d.subplan.sstate;
5239 :
5240 : /* could potentially be nested, so make sure there's enough stack */
5241 2860022 : check_stack_depth();
5242 :
5243 2860022 : *op->resvalue = ExecSubPlan(sstate, econtext, op->resnull);
5244 2860016 : }
5245 :
5246 : /*
5247 : * Evaluate a wholerow Var expression.
5248 : *
5249 : * Returns a Datum whose value is the value of a whole-row range variable
5250 : * with respect to given expression context.
5251 : */
5252 : void
5253 46154 : ExecEvalWholeRowVar(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
5254 : {
5255 46154 : Var *variable = op->d.wholerow.var;
5256 46154 : TupleTableSlot *slot = NULL;
5257 : TupleDesc output_tupdesc;
5258 : MemoryContext oldcontext;
5259 : HeapTupleHeader dtuple;
5260 : HeapTuple tuple;
5261 :
5262 : /* This was checked by ExecInitExpr */
5263 : Assert(variable->varattno == InvalidAttrNumber);
5264 :
5265 : /* Get the input slot we want */
5266 46154 : switch (variable->varno)
5267 : {
5268 90 : case INNER_VAR:
5269 : /* get the tuple from the inner node */
5270 90 : slot = econtext->ecxt_innertuple;
5271 90 : break;
5272 :
5273 18 : case OUTER_VAR:
5274 : /* get the tuple from the outer node */
5275 18 : slot = econtext->ecxt_outertuple;
5276 18 : break;
5277 :
5278 : /* INDEX_VAR is handled by default case */
5279 :
5280 46046 : default:
5281 :
5282 : /*
5283 : * Get the tuple from the relation being scanned.
5284 : *
5285 : * By default, this uses the "scan" tuple slot, but a wholerow Var
5286 : * in the RETURNING list may explicitly refer to OLD/NEW. If the
5287 : * OLD/NEW row doesn't exist, we just return NULL.
5288 : */
5289 46046 : switch (variable->varreturningtype)
5290 : {
5291 45582 : case VAR_RETURNING_DEFAULT:
5292 45582 : slot = econtext->ecxt_scantuple;
5293 45582 : break;
5294 :
5295 232 : case VAR_RETURNING_OLD:
5296 232 : if (state->flags & EEO_FLAG_OLD_IS_NULL)
5297 : {
5298 60 : *op->resvalue = (Datum) 0;
5299 60 : *op->resnull = true;
5300 60 : return;
5301 : }
5302 172 : slot = econtext->ecxt_oldtuple;
5303 172 : break;
5304 :
5305 232 : case VAR_RETURNING_NEW:
5306 232 : if (state->flags & EEO_FLAG_NEW_IS_NULL)
5307 : {
5308 30 : *op->resvalue = (Datum) 0;
5309 30 : *op->resnull = true;
5310 30 : return;
5311 : }
5312 202 : slot = econtext->ecxt_newtuple;
5313 202 : break;
5314 : }
5315 45956 : break;
5316 : }
5317 :
5318 : /* Apply the junkfilter if any */
5319 46064 : if (op->d.wholerow.junkFilter != NULL)
5320 60 : slot = ExecFilterJunk(op->d.wholerow.junkFilter, slot);
5321 :
5322 : /*
5323 : * If first time through, obtain tuple descriptor and check compatibility.
5324 : *
5325 : * XXX: It'd be great if this could be moved to the expression
5326 : * initialization phase, but due to using slots that's currently not
5327 : * feasible.
5328 : */
5329 46064 : if (op->d.wholerow.first)
5330 : {
5331 : /* optimistically assume we don't need slow path */
5332 2870 : op->d.wholerow.slow = false;
5333 :
5334 : /*
5335 : * If the Var identifies a named composite type, we must check that
5336 : * the actual tuple type is compatible with it.
5337 : */
5338 2870 : if (variable->vartype != RECORDOID)
5339 : {
5340 : TupleDesc var_tupdesc;
5341 : TupleDesc slot_tupdesc;
5342 :
5343 : /*
5344 : * We really only care about numbers of attributes and data types.
5345 : * Also, we can ignore type mismatch on columns that are dropped
5346 : * in the destination type, so long as (1) the physical storage
5347 : * matches or (2) the actual column value is NULL. Case (1) is
5348 : * helpful in some cases involving out-of-date cached plans, while
5349 : * case (2) is expected behavior in situations such as an INSERT
5350 : * into a table with dropped columns (the planner typically
5351 : * generates an INT4 NULL regardless of the dropped column type).
5352 : * If we find a dropped column and cannot verify that case (1)
5353 : * holds, we have to use the slow path to check (2) for each row.
5354 : *
5355 : * If vartype is a domain over composite, just look through that
5356 : * to the base composite type.
5357 : */
5358 1756 : var_tupdesc = lookup_rowtype_tupdesc_domain(variable->vartype,
5359 : -1, false);
5360 :
5361 1756 : slot_tupdesc = slot->tts_tupleDescriptor;
5362 :
5363 1756 : if (var_tupdesc->natts != slot_tupdesc->natts)
5364 0 : ereport(ERROR,
5365 : (errcode(ERRCODE_DATATYPE_MISMATCH),
5366 : errmsg("table row type and query-specified row type do not match"),
5367 : errdetail_plural("Table row contains %d attribute, but query expects %d.",
5368 : "Table row contains %d attributes, but query expects %d.",
5369 : slot_tupdesc->natts,
5370 : slot_tupdesc->natts,
5371 : var_tupdesc->natts)));
5372 :
5373 7006 : for (int i = 0; i < var_tupdesc->natts; i++)
5374 : {
5375 5250 : Form_pg_attribute vattr = TupleDescAttr(var_tupdesc, i);
5376 5250 : Form_pg_attribute sattr = TupleDescAttr(slot_tupdesc, i);
5377 :
5378 5250 : if (vattr->atttypid == sattr->atttypid)
5379 5250 : continue; /* no worries */
5380 0 : if (!vattr->attisdropped)
5381 0 : ereport(ERROR,
5382 : (errcode(ERRCODE_DATATYPE_MISMATCH),
5383 : errmsg("table row type and query-specified row type do not match"),
5384 : errdetail("Table has type %s at ordinal position %d, but query expects %s.",
5385 : format_type_be(sattr->atttypid),
5386 : i + 1,
5387 : format_type_be(vattr->atttypid))));
5388 :
5389 0 : if (vattr->attlen != sattr->attlen ||
5390 0 : vattr->attalign != sattr->attalign)
5391 0 : op->d.wholerow.slow = true; /* need to check for nulls */
5392 : }
5393 :
5394 : /*
5395 : * Use the variable's declared rowtype as the descriptor for the
5396 : * output values. In particular, we *must* absorb any
5397 : * attisdropped markings.
5398 : */
5399 1756 : oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
5400 1756 : output_tupdesc = CreateTupleDescCopy(var_tupdesc);
5401 1756 : MemoryContextSwitchTo(oldcontext);
5402 :
5403 1756 : ReleaseTupleDesc(var_tupdesc);
5404 : }
5405 : else
5406 : {
5407 : /*
5408 : * In the RECORD case, we use the input slot's rowtype as the
5409 : * descriptor for the output values, modulo possibly assigning new
5410 : * column names below.
5411 : */
5412 1114 : oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
5413 1114 : output_tupdesc = CreateTupleDescCopy(slot->tts_tupleDescriptor);
5414 1114 : MemoryContextSwitchTo(oldcontext);
5415 :
5416 : /*
5417 : * It's possible that the input slot is a relation scan slot and
5418 : * so is marked with that relation's rowtype. But we're supposed
5419 : * to be returning RECORD, so reset to that.
5420 : */
5421 1114 : output_tupdesc->tdtypeid = RECORDOID;
5422 1114 : output_tupdesc->tdtypmod = -1;
5423 :
5424 : /*
5425 : * We already got the correct physical datatype info above, but
5426 : * now we should try to find the source RTE and adopt its column
5427 : * aliases, since it's unlikely that the input slot has the
5428 : * desired names.
5429 : *
5430 : * If we can't locate the RTE, assume the column names we've got
5431 : * are OK. (As of this writing, the only cases where we can't
5432 : * locate the RTE are in execution of trigger WHEN clauses, and
5433 : * then the Var will have the trigger's relation's rowtype, so its
5434 : * names are fine.) Also, if the creator of the RTE didn't bother
5435 : * to fill in an eref field, assume our column names are OK. (This
5436 : * happens in COPY, and perhaps other places.)
5437 : */
5438 1114 : if (econtext->ecxt_estate &&
5439 1114 : variable->varno <= econtext->ecxt_estate->es_range_table_size)
5440 : {
5441 1114 : RangeTblEntry *rte = exec_rt_fetch(variable->varno,
5442 1114 : econtext->ecxt_estate);
5443 :
5444 1114 : if (rte->eref)
5445 1114 : ExecTypeSetColNames(output_tupdesc, rte->eref->colnames);
5446 : }
5447 : }
5448 :
5449 : /* Bless the tupdesc if needed, and save it in the execution state */
5450 2870 : op->d.wholerow.tupdesc = BlessTupleDesc(output_tupdesc);
5451 :
5452 2870 : op->d.wholerow.first = false;
5453 : }
5454 :
5455 : /*
5456 : * Make sure all columns of the slot are accessible in the slot's
5457 : * Datum/isnull arrays.
5458 : */
5459 46064 : slot_getallattrs(slot);
5460 :
5461 46064 : if (op->d.wholerow.slow)
5462 : {
5463 : /* Check to see if any dropped attributes are non-null */
5464 0 : TupleDesc tupleDesc = slot->tts_tupleDescriptor;
5465 0 : TupleDesc var_tupdesc = op->d.wholerow.tupdesc;
5466 :
5467 : Assert(var_tupdesc->natts == tupleDesc->natts);
5468 :
5469 0 : for (int i = 0; i < var_tupdesc->natts; i++)
5470 : {
5471 0 : CompactAttribute *vattr = TupleDescCompactAttr(var_tupdesc, i);
5472 0 : CompactAttribute *sattr = TupleDescCompactAttr(tupleDesc, i);
5473 :
5474 0 : if (!vattr->attisdropped)
5475 0 : continue; /* already checked non-dropped cols */
5476 0 : if (slot->tts_isnull[i])
5477 0 : continue; /* null is always okay */
5478 0 : if (vattr->attlen != sattr->attlen ||
5479 0 : vattr->attalignby != sattr->attalignby)
5480 0 : ereport(ERROR,
5481 : (errcode(ERRCODE_DATATYPE_MISMATCH),
5482 : errmsg("table row type and query-specified row type do not match"),
5483 : errdetail("Physical storage mismatch on dropped attribute at ordinal position %d.",
5484 : i + 1)));
5485 : }
5486 : }
5487 :
5488 : /*
5489 : * Build a composite datum, making sure any toasted fields get detoasted.
5490 : *
5491 : * (Note: it is critical that we not change the slot's state here.)
5492 : */
5493 46064 : tuple = toast_build_flattened_tuple(slot->tts_tupleDescriptor,
5494 : slot->tts_values,
5495 : slot->tts_isnull);
5496 46064 : dtuple = tuple->t_data;
5497 :
5498 : /*
5499 : * Label the datum with the composite type info we identified before.
5500 : *
5501 : * (Note: we could skip doing this by passing op->d.wholerow.tupdesc to
5502 : * the tuple build step; but that seems a tad risky so let's not.)
5503 : */
5504 46064 : HeapTupleHeaderSetTypeId(dtuple, op->d.wholerow.tupdesc->tdtypeid);
5505 46064 : HeapTupleHeaderSetTypMod(dtuple, op->d.wholerow.tupdesc->tdtypmod);
5506 :
5507 46064 : *op->resvalue = PointerGetDatum(dtuple);
5508 46064 : *op->resnull = false;
5509 : }
5510 :
5511 : void
5512 6793786 : ExecEvalSysVar(ExprState *state, ExprEvalStep *op, ExprContext *econtext,
5513 : TupleTableSlot *slot)
5514 : {
5515 : Datum d;
5516 :
5517 : /* OLD/NEW system attribute is NULL if OLD/NEW row is NULL */
5518 6793786 : if ((op->d.var.varreturningtype == VAR_RETURNING_OLD &&
5519 228 : state->flags & EEO_FLAG_OLD_IS_NULL) ||
5520 6793702 : (op->d.var.varreturningtype == VAR_RETURNING_NEW &&
5521 228 : state->flags & EEO_FLAG_NEW_IS_NULL))
5522 : {
5523 156 : *op->resvalue = (Datum) 0;
5524 156 : *op->resnull = true;
5525 156 : return;
5526 : }
5527 :
5528 : /* slot_getsysattr has sufficient defenses against bad attnums */
5529 6793630 : d = slot_getsysattr(slot,
5530 : op->d.var.attnum,
5531 : op->resnull);
5532 6793618 : *op->resvalue = d;
5533 : /* this ought to be unreachable, but it's cheap enough to check */
5534 6793618 : if (unlikely(*op->resnull))
5535 0 : elog(ERROR, "failed to fetch attribute from slot");
5536 : }
5537 :
5538 : /*
5539 : * Transition value has not been initialized. This is the first non-NULL input
5540 : * value for a group. We use it as the initial value for transValue.
5541 : */
5542 : void
5543 60190 : ExecAggInitGroup(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroup,
5544 : ExprContext *aggcontext)
5545 : {
5546 60190 : FunctionCallInfo fcinfo = pertrans->transfn_fcinfo;
5547 : MemoryContext oldContext;
5548 :
5549 : /*
5550 : * We must copy the datum into aggcontext if it is pass-by-ref. We do not
5551 : * need to pfree the old transValue, since it's NULL. (We already checked
5552 : * that the agg's input type is binary-compatible with its transtype, so
5553 : * straight copy here is OK.)
5554 : */
5555 60190 : oldContext = MemoryContextSwitchTo(aggcontext->ecxt_per_tuple_memory);
5556 120380 : pergroup->transValue = datumCopy(fcinfo->args[1].value,
5557 60190 : pertrans->transtypeByVal,
5558 60190 : pertrans->transtypeLen);
5559 60190 : pergroup->transValueIsNull = false;
5560 60190 : pergroup->noTransValue = false;
5561 60190 : MemoryContextSwitchTo(oldContext);
5562 60190 : }
5563 :
5564 : /*
5565 : * Ensure that the new transition value is stored in the aggcontext,
5566 : * rather than the per-tuple context. This should be invoked only when
5567 : * we know (a) the transition data type is pass-by-reference, and (b)
5568 : * the newValue is distinct from the oldValue.
5569 : *
5570 : * NB: This can change the current memory context.
5571 : *
5572 : * We copy the presented newValue into the aggcontext, except when the datum
5573 : * points to a R/W expanded object that is already a child of the aggcontext,
5574 : * in which case we need not copy. We then delete the oldValue, if not null.
5575 : *
5576 : * If the presented datum points to a R/W expanded object that is a child of
5577 : * some other context, ideally we would just reparent it under the aggcontext.
5578 : * Unfortunately, that doesn't work easily, and it wouldn't help anyway for
5579 : * aggregate-aware transfns. We expect that a transfn that deals in expanded
5580 : * objects and is aware of the memory management conventions for aggregate
5581 : * transition values will (1) on first call, return a R/W expanded object that
5582 : * is already in the right context, allowing us to do nothing here, and (2) on
5583 : * subsequent calls, modify and return that same object, so that control
5584 : * doesn't even reach here. However, if we have a generic transfn that
5585 : * returns a new R/W expanded object (probably in the per-tuple context),
5586 : * reparenting that result would cause problems. We'd pass that R/W object to
5587 : * the next invocation of the transfn, and then it would be at liberty to
5588 : * change or delete that object, and if it deletes it then our own attempt to
5589 : * delete the now-old transvalue afterwards would be a double free. We avoid
5590 : * this problem by forcing the stored transvalue to always be a flat
5591 : * non-expanded object unless the transfn is visibly doing aggregate-aware
5592 : * memory management. This is somewhat inefficient, but the best answer to
5593 : * that is to write a smarter transfn.
5594 : */
5595 : Datum
5596 62046 : ExecAggCopyTransValue(AggState *aggstate, AggStatePerTrans pertrans,
5597 : Datum newValue, bool newValueIsNull,
5598 : Datum oldValue, bool oldValueIsNull)
5599 : {
5600 : Assert(newValue != oldValue);
5601 :
5602 62046 : if (!newValueIsNull)
5603 : {
5604 62046 : MemoryContextSwitchTo(aggstate->curaggcontext->ecxt_per_tuple_memory);
5605 62214 : if (DatumIsReadWriteExpandedObject(newValue,
5606 : false,
5607 62040 : pertrans->transtypeLen) &&
5608 168 : MemoryContextGetParent(DatumGetEOHP(newValue)->eoh_context) == CurrentMemoryContext)
5609 : /* do nothing */ ;
5610 : else
5611 62040 : newValue = datumCopy(newValue,
5612 62040 : pertrans->transtypeByVal,
5613 62040 : pertrans->transtypeLen);
5614 : }
5615 : else
5616 : {
5617 : /*
5618 : * Ensure that AggStatePerGroup->transValue ends up being 0, so
5619 : * callers can safely compare newValue/oldValue without having to
5620 : * check their respective nullness.
5621 : */
5622 0 : newValue = (Datum) 0;
5623 : }
5624 :
5625 62046 : if (!oldValueIsNull)
5626 : {
5627 61932 : if (DatumIsReadWriteExpandedObject(oldValue,
5628 : false,
5629 : pertrans->transtypeLen))
5630 0 : DeleteExpandedObject(oldValue);
5631 : else
5632 61932 : pfree(DatumGetPointer(oldValue));
5633 : }
5634 :
5635 62046 : return newValue;
5636 : }
5637 :
5638 : /*
5639 : * ExecEvalPreOrderedDistinctSingle
5640 : * Returns true when the aggregate transition value Datum is distinct
5641 : * from the previous input Datum and returns false when the input Datum
5642 : * matches the previous input Datum.
5643 : */
5644 : bool
5645 365850 : ExecEvalPreOrderedDistinctSingle(AggState *aggstate, AggStatePerTrans pertrans)
5646 : {
5647 365850 : Datum value = pertrans->transfn_fcinfo->args[1].value;
5648 365850 : bool isnull = pertrans->transfn_fcinfo->args[1].isnull;
5649 :
5650 365850 : if (!pertrans->haslast ||
5651 347586 : pertrans->lastisnull != isnull ||
5652 347556 : (!isnull && !DatumGetBool(FunctionCall2Coll(&pertrans->equalfnOne,
5653 : pertrans->aggCollation,
5654 : pertrans->lastdatum, value))))
5655 : {
5656 101956 : if (pertrans->haslast && !pertrans->inputtypeByVal &&
5657 25982 : !pertrans->lastisnull)
5658 25982 : pfree(DatumGetPointer(pertrans->lastdatum));
5659 :
5660 101956 : pertrans->haslast = true;
5661 101956 : if (!isnull)
5662 : {
5663 : MemoryContext oldContext;
5664 :
5665 101920 : oldContext = MemoryContextSwitchTo(aggstate->curaggcontext->ecxt_per_tuple_memory);
5666 :
5667 203840 : pertrans->lastdatum = datumCopy(value, pertrans->inputtypeByVal,
5668 101920 : pertrans->inputtypeLen);
5669 :
5670 101920 : MemoryContextSwitchTo(oldContext);
5671 : }
5672 : else
5673 36 : pertrans->lastdatum = (Datum) 0;
5674 101956 : pertrans->lastisnull = isnull;
5675 101956 : return true;
5676 : }
5677 :
5678 263894 : return false;
5679 : }
5680 :
5681 : /*
5682 : * ExecEvalPreOrderedDistinctMulti
5683 : * Returns true when the aggregate input is distinct from the previous
5684 : * input and returns false when the input matches the previous input, or
5685 : * when there was no previous input.
5686 : */
5687 : bool
5688 720 : ExecEvalPreOrderedDistinctMulti(AggState *aggstate, AggStatePerTrans pertrans)
5689 : {
5690 720 : ExprContext *tmpcontext = aggstate->tmpcontext;
5691 720 : bool isdistinct = false; /* for now */
5692 : TupleTableSlot *save_outer;
5693 : TupleTableSlot *save_inner;
5694 :
5695 2820 : for (int i = 0; i < pertrans->numTransInputs; i++)
5696 : {
5697 2100 : pertrans->sortslot->tts_values[i] = pertrans->transfn_fcinfo->args[i + 1].value;
5698 2100 : pertrans->sortslot->tts_isnull[i] = pertrans->transfn_fcinfo->args[i + 1].isnull;
5699 : }
5700 :
5701 720 : ExecClearTuple(pertrans->sortslot);
5702 720 : pertrans->sortslot->tts_nvalid = pertrans->numInputs;
5703 720 : ExecStoreVirtualTuple(pertrans->sortslot);
5704 :
5705 : /* save the previous slots before we overwrite them */
5706 720 : save_outer = tmpcontext->ecxt_outertuple;
5707 720 : save_inner = tmpcontext->ecxt_innertuple;
5708 :
5709 720 : tmpcontext->ecxt_outertuple = pertrans->sortslot;
5710 720 : tmpcontext->ecxt_innertuple = pertrans->uniqslot;
5711 :
5712 720 : if (!pertrans->haslast ||
5713 624 : !ExecQual(pertrans->equalfnMulti, tmpcontext))
5714 : {
5715 312 : if (pertrans->haslast)
5716 216 : ExecClearTuple(pertrans->uniqslot);
5717 :
5718 312 : pertrans->haslast = true;
5719 312 : ExecCopySlot(pertrans->uniqslot, pertrans->sortslot);
5720 :
5721 312 : isdistinct = true;
5722 : }
5723 :
5724 : /* restore the original slots */
5725 720 : tmpcontext->ecxt_outertuple = save_outer;
5726 720 : tmpcontext->ecxt_innertuple = save_inner;
5727 :
5728 720 : return isdistinct;
5729 : }
5730 :
5731 : /*
5732 : * Invoke ordered transition function, with a datum argument.
5733 : */
5734 : void
5735 844384 : ExecEvalAggOrderedTransDatum(ExprState *state, ExprEvalStep *op,
5736 : ExprContext *econtext)
5737 : {
5738 844384 : AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
5739 844384 : int setno = op->d.agg_trans.setno;
5740 :
5741 844384 : tuplesort_putdatum(pertrans->sortstates[setno],
5742 844384 : *op->resvalue, *op->resnull);
5743 844384 : }
5744 :
5745 : /*
5746 : * Invoke ordered transition function, with a tuple argument.
5747 : */
5748 : void
5749 180 : ExecEvalAggOrderedTransTuple(ExprState *state, ExprEvalStep *op,
5750 : ExprContext *econtext)
5751 : {
5752 180 : AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
5753 180 : int setno = op->d.agg_trans.setno;
5754 :
5755 180 : ExecClearTuple(pertrans->sortslot);
5756 180 : pertrans->sortslot->tts_nvalid = pertrans->numInputs;
5757 180 : ExecStoreVirtualTuple(pertrans->sortslot);
5758 180 : tuplesort_puttupleslot(pertrans->sortstates[setno], pertrans->sortslot);
5759 180 : }
5760 :
5761 : /* implementation of transition function invocation for byval types */
5762 : static pg_attribute_always_inline void
5763 28443354 : ExecAggPlainTransByVal(AggState *aggstate, AggStatePerTrans pertrans,
5764 : AggStatePerGroup pergroup,
5765 : ExprContext *aggcontext, int setno)
5766 : {
5767 28443354 : FunctionCallInfo fcinfo = pertrans->transfn_fcinfo;
5768 : MemoryContext oldContext;
5769 : Datum newVal;
5770 :
5771 : /* cf. select_current_set() */
5772 28443354 : aggstate->curaggcontext = aggcontext;
5773 28443354 : aggstate->current_set = setno;
5774 :
5775 : /* set up aggstate->curpertrans for AggGetAggref() */
5776 28443354 : aggstate->curpertrans = pertrans;
5777 :
5778 : /* invoke transition function in per-tuple context */
5779 28443354 : oldContext = MemoryContextSwitchTo(aggstate->tmpcontext->ecxt_per_tuple_memory);
5780 :
5781 28443354 : fcinfo->args[0].value = pergroup->transValue;
5782 28443354 : fcinfo->args[0].isnull = pergroup->transValueIsNull;
5783 28443354 : fcinfo->isnull = false; /* just in case transfn doesn't set it */
5784 :
5785 28443354 : newVal = FunctionCallInvoke(fcinfo);
5786 :
5787 28443282 : pergroup->transValue = newVal;
5788 28443282 : pergroup->transValueIsNull = fcinfo->isnull;
5789 :
5790 28443282 : MemoryContextSwitchTo(oldContext);
5791 28443282 : }
5792 :
5793 : /* implementation of transition function invocation for byref types */
5794 : static pg_attribute_always_inline void
5795 2836140 : ExecAggPlainTransByRef(AggState *aggstate, AggStatePerTrans pertrans,
5796 : AggStatePerGroup pergroup,
5797 : ExprContext *aggcontext, int setno)
5798 : {
5799 2836140 : FunctionCallInfo fcinfo = pertrans->transfn_fcinfo;
5800 : MemoryContext oldContext;
5801 : Datum newVal;
5802 :
5803 : /* cf. select_current_set() */
5804 2836140 : aggstate->curaggcontext = aggcontext;
5805 2836140 : aggstate->current_set = setno;
5806 :
5807 : /* set up aggstate->curpertrans for AggGetAggref() */
5808 2836140 : aggstate->curpertrans = pertrans;
5809 :
5810 : /* invoke transition function in per-tuple context */
5811 2836140 : oldContext = MemoryContextSwitchTo(aggstate->tmpcontext->ecxt_per_tuple_memory);
5812 :
5813 2836140 : fcinfo->args[0].value = pergroup->transValue;
5814 2836140 : fcinfo->args[0].isnull = pergroup->transValueIsNull;
5815 2836140 : fcinfo->isnull = false; /* just in case transfn doesn't set it */
5816 :
5817 2836140 : newVal = FunctionCallInvoke(fcinfo);
5818 :
5819 : /*
5820 : * For pass-by-ref datatype, must copy the new value into aggcontext and
5821 : * free the prior transValue. But if transfn returned a pointer to its
5822 : * first input, we don't need to do anything.
5823 : *
5824 : * It's safe to compare newVal with pergroup->transValue without regard
5825 : * for either being NULL, because ExecAggCopyTransValue takes care to set
5826 : * transValue to 0 when NULL. Otherwise we could end up accidentally not
5827 : * reparenting, when the transValue has the same numerical value as
5828 : * newValue, despite being NULL. This is a somewhat hot path, making it
5829 : * undesirable to instead solve this with another branch for the common
5830 : * case of the transition function returning its (modified) input
5831 : * argument.
5832 : */
5833 2836134 : if (DatumGetPointer(newVal) != DatumGetPointer(pergroup->transValue))
5834 38850 : newVal = ExecAggCopyTransValue(aggstate, pertrans,
5835 38850 : newVal, fcinfo->isnull,
5836 : pergroup->transValue,
5837 38850 : pergroup->transValueIsNull);
5838 :
5839 2836134 : pergroup->transValue = newVal;
5840 2836134 : pergroup->transValueIsNull = fcinfo->isnull;
5841 :
5842 2836134 : MemoryContextSwitchTo(oldContext);
5843 2836134 : }
|