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