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