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