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