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