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 2164666 : ExecReadyInterpretedExpr(ExprState *state)
236 : {
237 : /* Ensure one-time interpreter setup has been done */
238 2164666 : 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 2164666 : 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 2164666 : 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 2164666 : 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 2164666 : if (state->steps_len == 3)
276 : {
277 383864 : ExprEvalOp step0 = state->steps[0].opcode;
278 383864 : ExprEvalOp step1 = state->steps[1].opcode;
279 :
280 383864 : if (step0 == EEOP_INNER_FETCHSOME &&
281 : step1 == EEOP_INNER_VAR)
282 : {
283 5722 : state->evalfunc_private = (void *) ExecJustInnerVar;
284 5722 : return;
285 : }
286 378142 : else if (step0 == EEOP_OUTER_FETCHSOME &&
287 : step1 == EEOP_OUTER_VAR)
288 : {
289 28712 : state->evalfunc_private = (void *) ExecJustOuterVar;
290 28712 : return;
291 : }
292 349430 : else if (step0 == EEOP_SCAN_FETCHSOME &&
293 : step1 == EEOP_SCAN_VAR)
294 : {
295 19056 : state->evalfunc_private = (void *) ExecJustScanVar;
296 19056 : return;
297 : }
298 330374 : else if (step0 == EEOP_INNER_FETCHSOME &&
299 : step1 == EEOP_ASSIGN_INNER_VAR)
300 : {
301 5372 : state->evalfunc_private = (void *) ExecJustAssignInnerVar;
302 5372 : return;
303 : }
304 325002 : else if (step0 == EEOP_OUTER_FETCHSOME &&
305 : step1 == EEOP_ASSIGN_OUTER_VAR)
306 : {
307 7622 : state->evalfunc_private = (void *) ExecJustAssignOuterVar;
308 7622 : return;
309 : }
310 317380 : else if (step0 == EEOP_SCAN_FETCHSOME &&
311 : step1 == EEOP_ASSIGN_SCAN_VAR)
312 : {
313 41696 : state->evalfunc_private = (void *) ExecJustAssignScanVar;
314 41696 : return;
315 : }
316 275684 : 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 1780802 : else if (state->steps_len == 2)
325 : {
326 944586 : ExprEvalOp step0 = state->steps[0].opcode;
327 :
328 944586 : if (step0 == EEOP_CONST)
329 : {
330 455712 : state->evalfunc_private = (void *) ExecJustConst;
331 455712 : return;
332 : }
333 488874 : else if (step0 == EEOP_INNER_VAR)
334 : {
335 374 : state->evalfunc_private = (void *) ExecJustInnerVarVirt;
336 374 : return;
337 : }
338 488500 : else if (step0 == EEOP_OUTER_VAR)
339 : {
340 45550 : state->evalfunc_private = (void *) ExecJustOuterVarVirt;
341 45550 : return;
342 : }
343 442950 : else if (step0 == EEOP_SCAN_VAR)
344 : {
345 72 : state->evalfunc_private = (void *) ExecJustScanVarVirt;
346 72 : return;
347 : }
348 442878 : else if (step0 == EEOP_ASSIGN_INNER_VAR)
349 : {
350 236 : state->evalfunc_private = (void *) ExecJustAssignInnerVarVirt;
351 236 : return;
352 : }
353 442642 : else if (step0 == EEOP_ASSIGN_OUTER_VAR)
354 : {
355 2972 : state->evalfunc_private = (void *) ExecJustAssignOuterVarVirt;
356 2972 : return;
357 : }
358 439670 : else if (step0 == EEOP_ASSIGN_SCAN_VAR)
359 : {
360 3522 : state->evalfunc_private = (void *) ExecJustAssignScanVarVirt;
361 3522 : 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 9586510 : for (int off = 0; off < state->steps_len; off++)
372 : {
373 8038810 : ExprEvalStep *op = &state->steps[off];
374 :
375 8038810 : op->opcode = EEO_OPCODE(op->opcode);
376 : }
377 :
378 1547700 : state->flags |= EEO_FLAG_DIRECT_THREADED;
379 : #endif /* EEO_USE_COMPUTED_GOTO */
380 :
381 1547700 : 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 140494496 : 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 140494496 : if (unlikely(state == NULL))
509 16374 : return PointerGetDatum(dispatch_table);
510 : #else
511 : Assert(state != NULL);
512 : #endif /* EEO_USE_COMPUTED_GOTO */
513 :
514 : /* setup state */
515 140478122 : op = state->steps;
516 140478122 : resultslot = state->resultslot;
517 140478122 : innerslot = econtext->ecxt_innertuple;
518 140478122 : outerslot = econtext->ecxt_outertuple;
519 140478122 : scanslot = econtext->ecxt_scantuple;
520 :
521 : #if defined(EEO_USE_COMPUTED_GOTO)
522 140478122 : EEO_DISPATCH();
523 : #endif
524 :
525 : EEO_SWITCH()
526 : {
527 140461646 : EEO_CASE(EEOP_DONE)
528 : {
529 140461646 : goto out;
530 : }
531 :
532 27821138 : EEO_CASE(EEOP_INNER_FETCHSOME)
533 : {
534 27821138 : CheckOpSlotCompatibility(op, innerslot);
535 :
536 27821138 : slot_getsomeattrs(innerslot, op->d.fetch.last_var);
537 :
538 27821138 : EEO_NEXT();
539 : }
540 :
541 25906096 : EEO_CASE(EEOP_OUTER_FETCHSOME)
542 : {
543 25906096 : CheckOpSlotCompatibility(op, outerslot);
544 :
545 25906096 : slot_getsomeattrs(outerslot, op->d.fetch.last_var);
546 :
547 25906096 : EEO_NEXT();
548 : }
549 :
550 68686360 : EEO_CASE(EEOP_SCAN_FETCHSOME)
551 : {
552 68686360 : CheckOpSlotCompatibility(op, scanslot);
553 :
554 68686360 : slot_getsomeattrs(scanslot, op->d.fetch.last_var);
555 :
556 68686360 : EEO_NEXT();
557 : }
558 :
559 27061546 : EEO_CASE(EEOP_INNER_VAR)
560 : {
561 27061546 : 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 27061546 : *op->resvalue = innerslot->tts_values[attnum];
571 27061546 : *op->resnull = innerslot->tts_isnull[attnum];
572 :
573 27061546 : EEO_NEXT();
574 : }
575 :
576 44543814 : EEO_CASE(EEOP_OUTER_VAR)
577 : {
578 44543814 : int attnum = op->d.var.attnum;
579 :
580 : /* See EEOP_INNER_VAR comments */
581 :
582 : Assert(attnum >= 0 && attnum < outerslot->tts_nvalid);
583 44543814 : *op->resvalue = outerslot->tts_values[attnum];
584 44543814 : *op->resnull = outerslot->tts_isnull[attnum];
585 :
586 44543814 : EEO_NEXT();
587 : }
588 :
589 71665924 : EEO_CASE(EEOP_SCAN_VAR)
590 : {
591 71665924 : int attnum = op->d.var.attnum;
592 :
593 : /* See EEOP_INNER_VAR comments */
594 :
595 : Assert(attnum >= 0 && attnum < scanslot->tts_nvalid);
596 71665924 : *op->resvalue = scanslot->tts_values[attnum];
597 71665924 : *op->resnull = scanslot->tts_isnull[attnum];
598 :
599 71665924 : 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 6147160 : EEO_CASE(EEOP_SCAN_SYSVAR)
615 : {
616 6147160 : ExecEvalSysVar(state, op, econtext, scanslot);
617 6147148 : EEO_NEXT();
618 : }
619 :
620 35700 : EEO_CASE(EEOP_WHOLEROW)
621 : {
622 : /* too complex for an inline implementation */
623 35700 : ExecEvalWholeRowVar(state, op, econtext);
624 :
625 35700 : EEO_NEXT();
626 : }
627 :
628 7834178 : EEO_CASE(EEOP_ASSIGN_INNER_VAR)
629 : {
630 7834178 : int resultnum = op->d.assign_var.resultnum;
631 7834178 : 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 7834178 : resultslot->tts_values[resultnum] = innerslot->tts_values[attnum];
640 7834178 : resultslot->tts_isnull[resultnum] = innerslot->tts_isnull[attnum];
641 :
642 7834178 : EEO_NEXT();
643 : }
644 :
645 18840350 : EEO_CASE(EEOP_ASSIGN_OUTER_VAR)
646 : {
647 18840350 : int resultnum = op->d.assign_var.resultnum;
648 18840350 : 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 18840350 : resultslot->tts_values[resultnum] = outerslot->tts_values[attnum];
657 18840350 : resultslot->tts_isnull[resultnum] = outerslot->tts_isnull[attnum];
658 :
659 18840350 : EEO_NEXT();
660 : }
661 :
662 53157898 : EEO_CASE(EEOP_ASSIGN_SCAN_VAR)
663 : {
664 53157898 : int resultnum = op->d.assign_var.resultnum;
665 53157898 : 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 53157898 : resultslot->tts_values[resultnum] = scanslot->tts_values[attnum];
674 53157898 : resultslot->tts_isnull[resultnum] = scanslot->tts_isnull[attnum];
675 :
676 53157898 : EEO_NEXT();
677 : }
678 :
679 26307940 : EEO_CASE(EEOP_ASSIGN_TMP)
680 : {
681 26307940 : int resultnum = op->d.assign_tmp.resultnum;
682 :
683 : Assert(resultnum >= 0 && resultnum < resultslot->tts_tupleDescriptor->natts);
684 26307940 : resultslot->tts_values[resultnum] = state->resvalue;
685 26307940 : resultslot->tts_isnull[resultnum] = state->resnull;
686 :
687 26307940 : EEO_NEXT();
688 : }
689 :
690 10543572 : EEO_CASE(EEOP_ASSIGN_TMP_MAKE_RO)
691 : {
692 10543572 : int resultnum = op->d.assign_tmp.resultnum;
693 :
694 : Assert(resultnum >= 0 && resultnum < resultslot->tts_tupleDescriptor->natts);
695 10543572 : resultslot->tts_isnull[resultnum] = state->resnull;
696 10543572 : if (!resultslot->tts_isnull[resultnum])
697 7488404 : resultslot->tts_values[resultnum] =
698 7488404 : MakeExpandedObjectReadOnlyInternal(state->resvalue);
699 : else
700 3055168 : resultslot->tts_values[resultnum] = state->resvalue;
701 :
702 10543572 : EEO_NEXT();
703 : }
704 :
705 20901428 : EEO_CASE(EEOP_CONST)
706 : {
707 20901428 : *op->resnull = op->d.constval.isnull;
708 20901428 : *op->resvalue = op->d.constval.value;
709 :
710 20901428 : 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 1448978 : EEO_CASE(EEOP_FUNCEXPR)
729 : {
730 1448978 : FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
731 : Datum d;
732 :
733 1448978 : fcinfo->isnull = false;
734 1448978 : d = op->d.func.fn_addr(fcinfo);
735 1439096 : *op->resvalue = d;
736 1439096 : *op->resnull = fcinfo->isnull;
737 :
738 1439096 : EEO_NEXT();
739 : }
740 :
741 94203582 : EEO_CASE(EEOP_FUNCEXPR_STRICT)
742 : {
743 94203582 : FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
744 94203582 : NullableDatum *args = fcinfo->args;
745 94203582 : int nargs = op->d.func.nargs;
746 : Datum d;
747 :
748 : /* strict function, so check for NULL args */
749 268664326 : for (int argno = 0; argno < nargs; argno++)
750 : {
751 175903782 : if (args[argno].isnull)
752 : {
753 1443038 : *op->resnull = true;
754 1443038 : goto strictfail;
755 : }
756 : }
757 92760544 : fcinfo->isnull = false;
758 92760544 : d = op->d.func.fn_addr(fcinfo);
759 92754872 : *op->resvalue = d;
760 92754872 : *op->resnull = fcinfo->isnull;
761 :
762 94197910 : strictfail:
763 94197910 : 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 0 : EEO_CASE(EEOP_FUNCEXPR_STRICT_FUSAGE)
775 : {
776 : /* not common enough to inline */
777 0 : ExecEvalFuncExprStrictFusage(state, op, econtext);
778 :
779 0 : 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 891226 : EEO_CASE(EEOP_BOOL_AND_STEP_FIRST)
793 : {
794 891226 : *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 999806 : EEO_CASE(EEOP_BOOL_AND_STEP)
805 : {
806 999806 : if (*op->resnull)
807 : {
808 1216 : *op->d.boolexpr.anynull = true;
809 : }
810 998590 : else if (!DatumGetBool(*op->resvalue))
811 : {
812 : /* result is already set to FALSE, need not change it */
813 : /* bail out early */
814 680618 : EEO_JUMP(op->d.boolexpr.jumpdone);
815 : }
816 :
817 319188 : EEO_NEXT();
818 : }
819 :
820 210608 : EEO_CASE(EEOP_BOOL_AND_STEP_LAST)
821 : {
822 210608 : if (*op->resnull)
823 : {
824 : /* result is already set to NULL, need not change it */
825 : }
826 209730 : 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 151128 : 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 210608 : 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 3078830 : EEO_CASE(EEOP_BOOL_OR_STEP_FIRST)
860 : {
861 3078830 : *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 5943868 : EEO_CASE(EEOP_BOOL_OR_STEP)
872 : {
873 5943868 : if (*op->resnull)
874 : {
875 159514 : *op->d.boolexpr.anynull = true;
876 : }
877 5784354 : else if (DatumGetBool(*op->resvalue))
878 : {
879 : /* result is already set to TRUE, need not change it */
880 : /* bail out early */
881 387248 : EEO_JUMP(op->d.boolexpr.jumpdone);
882 : }
883 :
884 5556620 : EEO_NEXT();
885 : }
886 :
887 2691582 : EEO_CASE(EEOP_BOOL_OR_STEP_LAST)
888 : {
889 2691582 : if (*op->resnull)
890 : {
891 : /* result is already set to NULL, need not change it */
892 : }
893 2597634 : 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 2550864 : else if (*op->d.boolexpr.anynull)
904 : {
905 6266 : *op->resvalue = (Datum) 0;
906 6266 : *op->resnull = true;
907 : }
908 : else
909 : {
910 : /* result is already set to FALSE, need not change it */
911 : }
912 :
913 2691582 : EEO_NEXT();
914 : }
915 :
916 1490546 : 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 1490546 : *op->resvalue = BoolGetDatum(!DatumGetBool(*op->resvalue));
925 :
926 1490546 : EEO_NEXT();
927 : }
928 :
929 76243632 : 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 76243632 : if (*op->resnull ||
935 74984636 : !DatumGetBool(*op->resvalue))
936 : {
937 : /* ... bail out early, returning FALSE */
938 35107604 : *op->resnull = false;
939 35107604 : *op->resvalue = BoolGetDatum(false);
940 35107604 : 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 41136028 : EEO_NEXT();
949 : }
950 :
951 231514 : EEO_CASE(EEOP_JUMP)
952 : {
953 : /* Unconditionally jump to target step */
954 231514 : EEO_JUMP(op->d.jump.jumpdone);
955 : }
956 :
957 567990 : EEO_CASE(EEOP_JUMP_IF_NULL)
958 : {
959 : /* Transfer control if current result is null */
960 567990 : if (*op->resnull)
961 3306 : EEO_JUMP(op->d.jump.jumpdone);
962 :
963 564684 : EEO_NEXT();
964 : }
965 :
966 259856 : EEO_CASE(EEOP_JUMP_IF_NOT_NULL)
967 : {
968 : /* Transfer control if current result is non-null */
969 259856 : if (!*op->resnull)
970 188348 : EEO_JUMP(op->d.jump.jumpdone);
971 :
972 71508 : EEO_NEXT();
973 : }
974 :
975 1499156 : EEO_CASE(EEOP_JUMP_IF_NOT_TRUE)
976 : {
977 : /* Transfer control if current result is null or false */
978 1499156 : if (*op->resnull || !DatumGetBool(*op->resvalue))
979 1152316 : EEO_JUMP(op->d.jump.jumpdone);
980 :
981 346840 : EEO_NEXT();
982 : }
983 :
984 684134 : EEO_CASE(EEOP_NULLTEST_ISNULL)
985 : {
986 684134 : *op->resvalue = BoolGetDatum(*op->resnull);
987 684134 : *op->resnull = false;
988 :
989 684134 : EEO_NEXT();
990 : }
991 :
992 6126990 : EEO_CASE(EEOP_NULLTEST_ISNOTNULL)
993 : {
994 6126990 : *op->resvalue = BoolGetDatum(!*op->resnull);
995 6126990 : *op->resnull = false;
996 :
997 6126990 : 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 524 : EEO_CASE(EEOP_NULLTEST_ROWISNOTNULL)
1009 : {
1010 : /* out of line implementation: too large */
1011 524 : ExecEvalRowNotNull(state, op, econtext);
1012 :
1013 524 : EEO_NEXT();
1014 : }
1015 :
1016 : /* BooleanTest implementations for all booltesttypes */
1017 :
1018 60098 : EEO_CASE(EEOP_BOOLTEST_IS_TRUE)
1019 : {
1020 60098 : if (*op->resnull)
1021 : {
1022 59436 : *op->resvalue = BoolGetDatum(false);
1023 59436 : *op->resnull = false;
1024 : }
1025 : /* else, input value is the correct output as well */
1026 :
1027 60098 : 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 806 : EEO_CASE(EEOP_BOOLTEST_IS_FALSE)
1044 : {
1045 806 : if (*op->resnull)
1046 : {
1047 162 : *op->resvalue = BoolGetDatum(false);
1048 162 : *op->resnull = false;
1049 : }
1050 : else
1051 644 : *op->resvalue = BoolGetDatum(!DatumGetBool(*op->resvalue));
1052 :
1053 806 : 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 3554230 : EEO_CASE(EEOP_PARAM_EXEC)
1069 : {
1070 : /* out of line implementation: too large */
1071 3554230 : ExecEvalParamExec(state, op, econtext);
1072 :
1073 3554218 : EEO_NEXT();
1074 : }
1075 :
1076 294004 : EEO_CASE(EEOP_PARAM_EXTERN)
1077 : {
1078 : /* out of line implementation: too large */
1079 294004 : ExecEvalParamExtern(state, op, econtext);
1080 294004 : EEO_NEXT();
1081 : }
1082 :
1083 318998 : EEO_CASE(EEOP_PARAM_CALLBACK)
1084 : {
1085 : /* allow an extension module to supply a PARAM_EXTERN value */
1086 318998 : op->d.cparam.paramfunc(state, op, econtext);
1087 318992 : EEO_NEXT();
1088 : }
1089 :
1090 45838 : 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 45838 : if (op->d.casetest.value)
1102 : {
1103 42802 : *op->resvalue = *op->d.casetest.value;
1104 42802 : *op->resnull = *op->d.casetest.isnull;
1105 : }
1106 : else
1107 : {
1108 3036 : *op->resvalue = econtext->caseValue_datum;
1109 3036 : *op->resnull = econtext->caseValue_isNull;
1110 : }
1111 :
1112 45838 : EEO_NEXT();
1113 : }
1114 :
1115 511692 : EEO_CASE(EEOP_DOMAIN_TESTVAL)
1116 : {
1117 : /*
1118 : * See EEOP_CASE_TESTVAL comment.
1119 : */
1120 511692 : if (op->d.casetest.value)
1121 : {
1122 53054 : *op->resvalue = *op->d.casetest.value;
1123 53054 : *op->resnull = *op->d.casetest.isnull;
1124 : }
1125 : else
1126 : {
1127 458638 : *op->resvalue = econtext->domainValue_datum;
1128 458638 : *op->resnull = econtext->domainValue_isNull;
1129 : }
1130 :
1131 511692 : EEO_NEXT();
1132 : }
1133 :
1134 9984 : EEO_CASE(EEOP_MAKE_READONLY)
1135 : {
1136 : /*
1137 : * Force a varlena value that might be read multiple times to R/O
1138 : */
1139 9984 : if (!*op->d.make_readonly.isnull)
1140 9920 : *op->resvalue =
1141 9920 : MakeExpandedObjectReadOnlyInternal(*op->d.make_readonly.value);
1142 9984 : *op->resnull = *op->d.make_readonly.isnull;
1143 :
1144 9984 : EEO_NEXT();
1145 : }
1146 :
1147 5046934 : 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 5046934 : if (*op->resnull)
1158 : {
1159 : /* output functions are not called on nulls */
1160 61158 : str = NULL;
1161 : }
1162 : else
1163 : {
1164 : FunctionCallInfo fcinfo_out;
1165 :
1166 4985776 : fcinfo_out = op->d.iocoerce.fcinfo_data_out;
1167 4985776 : fcinfo_out->args[0].value = *op->resvalue;
1168 4985776 : fcinfo_out->args[0].isnull = false;
1169 :
1170 4985776 : fcinfo_out->isnull = false;
1171 4985776 : 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 5046934 : if (!op->d.iocoerce.finfo_in->fn_strict || str != NULL)
1179 : {
1180 : FunctionCallInfo fcinfo_in;
1181 : Datum d;
1182 :
1183 4985886 : fcinfo_in = op->d.iocoerce.fcinfo_data_in;
1184 4985886 : fcinfo_in->args[0].value = PointerGetDatum(str);
1185 4985886 : fcinfo_in->args[0].isnull = *op->resnull;
1186 : /* second and third arguments are already set up */
1187 :
1188 4985886 : fcinfo_in->isnull = false;
1189 4985886 : d = FunctionCallInvoke(fcinfo_in);
1190 4985846 : *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 5046894 : EEO_NEXT();
1206 : }
1207 :
1208 798502 : 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 798502 : FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
1220 :
1221 : /* check function arguments for NULLness */
1222 798502 : if (fcinfo->args[0].isnull && fcinfo->args[1].isnull)
1223 : {
1224 : /* Both NULL? Then is not distinct... */
1225 741388 : *op->resvalue = BoolGetDatum(false);
1226 741388 : *op->resnull = false;
1227 : }
1228 57114 : else if (fcinfo->args[0].isnull || fcinfo->args[1].isnull)
1229 : {
1230 : /* Only one is NULL? Then is distinct... */
1231 276 : *op->resvalue = BoolGetDatum(true);
1232 276 : *op->resnull = false;
1233 : }
1234 : else
1235 : {
1236 : /* Neither null, so apply the equality function */
1237 : Datum eqresult;
1238 :
1239 56838 : fcinfo->isnull = false;
1240 56838 : eqresult = op->d.func.fn_addr(fcinfo);
1241 : /* Must invert result of "="; safe to do even if null */
1242 56838 : *op->resvalue = BoolGetDatum(!DatumGetBool(eqresult));
1243 56838 : *op->resnull = fcinfo->isnull;
1244 : }
1245 :
1246 798502 : EEO_NEXT();
1247 : }
1248 :
1249 : /* see EEOP_DISTINCT for comments, this is just inverted */
1250 11225334 : EEO_CASE(EEOP_NOT_DISTINCT)
1251 : {
1252 11225334 : FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
1253 :
1254 11225334 : if (fcinfo->args[0].isnull && fcinfo->args[1].isnull)
1255 : {
1256 71642 : *op->resvalue = BoolGetDatum(true);
1257 71642 : *op->resnull = false;
1258 : }
1259 11153692 : 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 11153434 : fcinfo->isnull = false;
1269 11153434 : eqresult = op->d.func.fn_addr(fcinfo);
1270 11153434 : *op->resvalue = eqresult;
1271 11153434 : *op->resnull = fcinfo->isnull;
1272 : }
1273 :
1274 11225334 : EEO_NEXT();
1275 : }
1276 :
1277 6716 : EEO_CASE(EEOP_NULLIF)
1278 : {
1279 : /*
1280 : * The arguments are already evaluated into fcinfo->args.
1281 : */
1282 6716 : FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
1283 :
1284 : /* if either argument is NULL they can't be equal */
1285 6716 : if (!fcinfo->args[0].isnull && !fcinfo->args[1].isnull)
1286 : {
1287 : Datum result;
1288 :
1289 6662 : fcinfo->isnull = false;
1290 6662 : result = op->d.func.fn_addr(fcinfo);
1291 :
1292 : /* if the arguments are equal return null */
1293 6662 : if (!fcinfo->isnull && DatumGetBool(result))
1294 : {
1295 138 : *op->resvalue = (Datum) 0;
1296 138 : *op->resnull = true;
1297 :
1298 138 : EEO_NEXT();
1299 : }
1300 : }
1301 :
1302 : /* Arguments aren't equal, so return the first one */
1303 6578 : *op->resvalue = fcinfo->args[0].value;
1304 6578 : *op->resnull = fcinfo->args[0].isnull;
1305 :
1306 6578 : EEO_NEXT();
1307 : }
1308 :
1309 16826 : EEO_CASE(EEOP_SQLVALUEFUNCTION)
1310 : {
1311 : /*
1312 : * Doesn't seem worthwhile to have an inline implementation
1313 : * efficiency-wise.
1314 : */
1315 16826 : ExecEvalSQLValueFunction(state, op);
1316 :
1317 16826 : 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 792 : EEO_CASE(EEOP_NEXTVALUEEXPR)
1329 : {
1330 : /*
1331 : * Doesn't seem worthwhile to have an inline implementation
1332 : * efficiency-wise.
1333 : */
1334 792 : ExecEvalNextValueExpr(state, op);
1335 :
1336 792 : EEO_NEXT();
1337 : }
1338 :
1339 717778 : EEO_CASE(EEOP_ARRAYEXPR)
1340 : {
1341 : /* too complex for an inline implementation */
1342 717778 : ExecEvalArrayExpr(state, op);
1343 :
1344 717778 : EEO_NEXT();
1345 : }
1346 :
1347 65356 : EEO_CASE(EEOP_ARRAYCOERCE)
1348 : {
1349 : /* too complex for an inline implementation */
1350 65356 : ExecEvalArrayCoerce(state, op, econtext);
1351 :
1352 65324 : EEO_NEXT();
1353 : }
1354 :
1355 26722 : EEO_CASE(EEOP_ROW)
1356 : {
1357 : /* too complex for an inline implementation */
1358 26722 : ExecEvalRow(state, op);
1359 :
1360 26722 : 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 3058 : EEO_CASE(EEOP_MINMAX)
1428 : {
1429 : /* too complex for an inline implementation */
1430 3058 : ExecEvalMinMax(state, op);
1431 :
1432 3058 : EEO_NEXT();
1433 : }
1434 :
1435 90512 : EEO_CASE(EEOP_FIELDSELECT)
1436 : {
1437 : /* too complex for an inline implementation */
1438 90512 : ExecEvalFieldSelect(state, op, econtext);
1439 :
1440 90512 : EEO_NEXT();
1441 : }
1442 :
1443 382 : EEO_CASE(EEOP_FIELDSTORE_DEFORM)
1444 : {
1445 : /* too complex for an inline implementation */
1446 382 : ExecEvalFieldStoreDeForm(state, op, econtext);
1447 :
1448 382 : EEO_NEXT();
1449 : }
1450 :
1451 382 : EEO_CASE(EEOP_FIELDSTORE_FORM)
1452 : {
1453 : /* too complex for an inline implementation */
1454 382 : ExecEvalFieldStoreForm(state, op, econtext);
1455 :
1456 382 : EEO_NEXT();
1457 : }
1458 :
1459 566062 : EEO_CASE(EEOP_SBSREF_SUBSCRIPTS)
1460 : {
1461 : /* Precheck SubscriptingRef subscript(s) */
1462 566062 : if (op->d.sbsref_subscript.subscriptfunc(state, op, econtext))
1463 : {
1464 566008 : 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 1554 : EEO_CASE(EEOP_SBSREF_ASSIGN)
1475 566208 : EEO_CASE(EEOP_SBSREF_FETCH)
1476 : {
1477 : /* Perform a SubscriptingRef fetch or assignment */
1478 566208 : op->d.sbsref.subscriptfunc(state, op, econtext);
1479 :
1480 566112 : 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 4609408 : EEO_CASE(EEOP_SCALARARRAYOP)
1492 : {
1493 : /* too complex for an inline implementation */
1494 4609408 : ExecEvalScalarArrayOp(state, op);
1495 :
1496 4609408 : EEO_NEXT();
1497 : }
1498 :
1499 4598 : EEO_CASE(EEOP_HASHED_SCALARARRAYOP)
1500 : {
1501 : /* too complex for an inline implementation */
1502 4598 : ExecEvalHashedScalarArrayOp(state, op, econtext);
1503 :
1504 4598 : 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 52534 : EEO_CASE(EEOP_DOMAIN_CHECK)
1516 : {
1517 : /* too complex for an inline implementation */
1518 52534 : ExecEvalConstraintCheck(state, op);
1519 :
1520 52166 : EEO_NEXT();
1521 : }
1522 :
1523 43114 : EEO_CASE(EEOP_XMLEXPR)
1524 : {
1525 : /* too complex for an inline implementation */
1526 43114 : ExecEvalXmlExpr(state, op);
1527 :
1528 43012 : EEO_NEXT();
1529 : }
1530 :
1531 496 : EEO_CASE(EEOP_JSON_CONSTRUCTOR)
1532 : {
1533 : /* too complex for an inline implementation */
1534 496 : ExecEvalJsonConstructor(state, op, econtext);
1535 432 : 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 435498 : 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 435498 : int aggno = op->d.aggref.aggno;
1553 :
1554 : Assert(econtext->ecxt_aggvalues != NULL);
1555 :
1556 435498 : *op->resvalue = econtext->ecxt_aggvalues[aggno];
1557 435498 : *op->resnull = econtext->ecxt_aggnulls[aggno];
1558 :
1559 435498 : 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 973986 : EEO_CASE(EEOP_WINDOW_FUNC)
1571 : {
1572 : /*
1573 : * Like Aggref, just return a precomputed value from the econtext.
1574 : */
1575 973986 : WindowFuncExprState *wfunc = op->d.window_func.wfstate;
1576 :
1577 : Assert(econtext->ecxt_aggvalues != NULL);
1578 :
1579 973986 : *op->resvalue = econtext->ecxt_aggvalues[wfunc->wfuncno];
1580 973986 : *op->resnull = econtext->ecxt_aggnulls[wfunc->wfuncno];
1581 :
1582 973986 : EEO_NEXT();
1583 : }
1584 :
1585 2273822 : EEO_CASE(EEOP_SUBPLAN)
1586 : {
1587 : /* too complex for an inline implementation */
1588 2273822 : ExecEvalSubPlan(state, op, econtext);
1589 :
1590 2273816 : EEO_NEXT();
1591 : }
1592 :
1593 : /* evaluate a strict aggregate deserialization function */
1594 506 : EEO_CASE(EEOP_AGG_STRICT_DESERIALIZE)
1595 : {
1596 : /* Don't call a strict deserialization function with NULL input */
1597 506 : 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 382 : EEO_CASE(EEOP_AGG_DESERIALIZE)
1605 : {
1606 382 : FunctionCallInfo fcinfo = op->d.agg_deserialize.fcinfo_data;
1607 382 : 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 382 : oldContext = MemoryContextSwitchTo(aggstate->tmpcontext->ecxt_per_tuple_memory);
1615 382 : fcinfo->isnull = false;
1616 382 : *op->resvalue = FunctionCallInvoke(fcinfo);
1617 382 : *op->resnull = fcinfo->isnull;
1618 382 : MemoryContextSwitchTo(oldContext);
1619 :
1620 382 : EEO_NEXT();
1621 : }
1622 :
1623 : /*
1624 : * Check that a strict aggregate transition / combination function's
1625 : * input is not NULL.
1626 : */
1627 :
1628 4900488 : EEO_CASE(EEOP_AGG_STRICT_INPUT_CHECK_ARGS)
1629 : {
1630 4900488 : NullableDatum *args = op->d.agg_strict_input_check.args;
1631 4900488 : int nargs = op->d.agg_strict_input_check.nargs;
1632 :
1633 9883340 : for (int argno = 0; argno < nargs; argno++)
1634 : {
1635 5141196 : if (args[argno].isnull)
1636 158344 : EEO_JUMP(op->d.agg_strict_input_check.jumpnull);
1637 : }
1638 4742144 : 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 645324 : EEO_CASE(EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL)
1683 : {
1684 645324 : AggState *aggstate = castNode(AggState, state->parent);
1685 645324 : AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
1686 645324 : AggStatePerGroup pergroup =
1687 645324 : &aggstate->all_pergroups[op->d.agg_trans.setoff][op->d.agg_trans.transno];
1688 :
1689 : Assert(pertrans->transtypeByVal);
1690 :
1691 645324 : if (pergroup->noTransValue)
1692 : {
1693 : /* If transValue has not yet been initialized, do so now. */
1694 8714 : ExecAggInitGroup(aggstate, pertrans, pergroup,
1695 : op->d.agg_trans.aggcontext);
1696 : /* copied trans value from input, done this round */
1697 : }
1698 636610 : else if (likely(!pergroup->transValueIsNull))
1699 : {
1700 : /* invoke transition function, unless prevented by strictness */
1701 636610 : ExecAggPlainTransByVal(aggstate, pertrans, pergroup,
1702 : op->d.agg_trans.aggcontext,
1703 : op->d.agg_trans.setno);
1704 : }
1705 :
1706 645324 : EEO_NEXT();
1707 : }
1708 :
1709 : /* see comments above EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL */
1710 17148120 : EEO_CASE(EEOP_AGG_PLAIN_TRANS_STRICT_BYVAL)
1711 : {
1712 17148120 : AggState *aggstate = castNode(AggState, state->parent);
1713 17148120 : AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
1714 17148120 : AggStatePerGroup pergroup =
1715 17148120 : &aggstate->all_pergroups[op->d.agg_trans.setoff][op->d.agg_trans.transno];
1716 :
1717 : Assert(pertrans->transtypeByVal);
1718 :
1719 17148120 : if (likely(!pergroup->transValueIsNull))
1720 17088102 : ExecAggPlainTransByVal(aggstate, pertrans, pergroup,
1721 : op->d.agg_trans.aggcontext,
1722 : op->d.agg_trans.setno);
1723 :
1724 17148120 : EEO_NEXT();
1725 : }
1726 :
1727 : /* see comments above EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL */
1728 9373142 : EEO_CASE(EEOP_AGG_PLAIN_TRANS_BYVAL)
1729 : {
1730 9373142 : AggState *aggstate = castNode(AggState, state->parent);
1731 9373142 : AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
1732 9373142 : AggStatePerGroup pergroup =
1733 9373142 : &aggstate->all_pergroups[op->d.agg_trans.setoff][op->d.agg_trans.transno];
1734 :
1735 : Assert(pertrans->transtypeByVal);
1736 :
1737 9373142 : ExecAggPlainTransByVal(aggstate, pertrans, pergroup,
1738 : op->d.agg_trans.aggcontext,
1739 : op->d.agg_trans.setno);
1740 :
1741 9373082 : EEO_NEXT();
1742 : }
1743 :
1744 : /* see comments above EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL */
1745 176288 : EEO_CASE(EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYREF)
1746 : {
1747 176288 : AggState *aggstate = castNode(AggState, state->parent);
1748 176288 : AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
1749 176288 : AggStatePerGroup pergroup =
1750 176288 : &aggstate->all_pergroups[op->d.agg_trans.setoff][op->d.agg_trans.transno];
1751 :
1752 : Assert(!pertrans->transtypeByVal);
1753 :
1754 176288 : if (pergroup->noTransValue)
1755 800 : ExecAggInitGroup(aggstate, pertrans, pergroup,
1756 : op->d.agg_trans.aggcontext);
1757 175488 : else if (likely(!pergroup->transValueIsNull))
1758 175488 : ExecAggPlainTransByRef(aggstate, pertrans, pergroup,
1759 : op->d.agg_trans.aggcontext,
1760 : op->d.agg_trans.setno);
1761 :
1762 176282 : EEO_NEXT();
1763 : }
1764 :
1765 : /* see comments above EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL */
1766 2587286 : EEO_CASE(EEOP_AGG_PLAIN_TRANS_STRICT_BYREF)
1767 : {
1768 2587286 : AggState *aggstate = castNode(AggState, state->parent);
1769 2587286 : AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
1770 2587286 : AggStatePerGroup pergroup =
1771 2587286 : &aggstate->all_pergroups[op->d.agg_trans.setoff][op->d.agg_trans.transno];
1772 :
1773 : Assert(!pertrans->transtypeByVal);
1774 :
1775 2587286 : if (likely(!pergroup->transValueIsNull))
1776 2587286 : ExecAggPlainTransByRef(aggstate, pertrans, pergroup,
1777 : op->d.agg_trans.aggcontext,
1778 : op->d.agg_trans.setno);
1779 2587286 : EEO_NEXT();
1780 : }
1781 :
1782 : /* see comments above EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL */
1783 23074 : EEO_CASE(EEOP_AGG_PLAIN_TRANS_BYREF)
1784 : {
1785 23074 : AggState *aggstate = castNode(AggState, state->parent);
1786 23074 : AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
1787 23074 : AggStatePerGroup pergroup =
1788 23074 : &aggstate->all_pergroups[op->d.agg_trans.setoff][op->d.agg_trans.transno];
1789 :
1790 : Assert(!pertrans->transtypeByVal);
1791 :
1792 23074 : ExecAggPlainTransByRef(aggstate, pertrans, pergroup,
1793 : op->d.agg_trans.aggcontext,
1794 : op->d.agg_trans.setno);
1795 :
1796 23074 : EEO_NEXT();
1797 : }
1798 :
1799 363800 : EEO_CASE(EEOP_AGG_PRESORTED_DISTINCT_SINGLE)
1800 : {
1801 363800 : AggStatePerTrans pertrans = op->d.agg_presorted_distinctcheck.pertrans;
1802 363800 : AggState *aggstate = castNode(AggState, state->parent);
1803 :
1804 363800 : if (ExecEvalPreOrderedDistinctSingle(aggstate, pertrans))
1805 100138 : EEO_NEXT();
1806 : else
1807 263662 : EEO_JUMP(op->d.agg_presorted_distinctcheck.jumpdistinct);
1808 : }
1809 :
1810 708 : EEO_CASE(EEOP_AGG_PRESORTED_DISTINCT_MULTI)
1811 : {
1812 708 : AggState *aggstate = castNode(AggState, state->parent);
1813 708 : AggStatePerTrans pertrans = op->d.agg_presorted_distinctcheck.pertrans;
1814 :
1815 708 : if (ExecEvalPreOrderedDistinctMulti(aggstate, pertrans))
1816 300 : 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 140461646 : out:
1848 140461646 : *isnull = state->resnull;
1849 140461646 : 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 1748672 : 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 1748672 : CheckExprStillValid(state, econtext);
1865 :
1866 : /* skip the check during further executions */
1867 1748648 : state->evalfunc = (ExprStateEvalFunc) state->evalfunc_private;
1868 :
1869 : /* and actually execute */
1870 1748648 : 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 1754644 : CheckExprStillValid(ExprState *state, ExprContext *econtext)
1879 : {
1880 : TupleTableSlot *innerslot;
1881 : TupleTableSlot *outerslot;
1882 : TupleTableSlot *scanslot;
1883 :
1884 1754644 : innerslot = econtext->ecxt_innertuple;
1885 1754644 : outerslot = econtext->ecxt_outertuple;
1886 1754644 : scanslot = econtext->ecxt_scantuple;
1887 :
1888 8766710 : for (int i = 0; i < state->steps_len; i++)
1889 : {
1890 7012090 : ExprEvalStep *op = &state->steps[i];
1891 :
1892 7012090 : switch (ExecEvalStepOp(state, op))
1893 : {
1894 68460 : case EEOP_INNER_VAR:
1895 : {
1896 68460 : int attnum = op->d.var.attnum;
1897 :
1898 68460 : CheckVarSlotCompatibility(innerslot, attnum + 1, op->d.var.vartype);
1899 68460 : break;
1900 : }
1901 :
1902 174778 : case EEOP_OUTER_VAR:
1903 : {
1904 174778 : int attnum = op->d.var.attnum;
1905 :
1906 174778 : CheckVarSlotCompatibility(outerslot, attnum + 1, op->d.var.vartype);
1907 174778 : break;
1908 : }
1909 :
1910 251120 : case EEOP_SCAN_VAR:
1911 : {
1912 251120 : int attnum = op->d.var.attnum;
1913 :
1914 251120 : CheckVarSlotCompatibility(scanslot, attnum + 1, op->d.var.vartype);
1915 251096 : break;
1916 : }
1917 6517732 : default:
1918 6517732 : break;
1919 : }
1920 : }
1921 1754620 : }
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 494358 : 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 494358 : if (attnum > 0)
1949 : {
1950 494358 : TupleDesc slot_tupdesc = slot->tts_tupleDescriptor;
1951 : Form_pg_attribute attr;
1952 :
1953 494358 : 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 494358 : attr = TupleDescAttr(slot_tupdesc, attnum - 1);
1958 :
1959 494358 : 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 494346 : 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 494334 : }
1975 :
1976 : /*
1977 : * Verify that the slot is compatible with a EEOP_*_FETCHSOME operation.
1978 : */
1979 : static void
1980 148456474 : 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 148456474 : }
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 : * (The TupleDesc is always refcounted, so just use IncrTupleDescRefCount.)
2020 : *
2021 : * NOTE: because composite types can change contents, we must be prepared
2022 : * to re-do this during any node execution; cannot call just once during
2023 : * expression initialization.
2024 : */
2025 : static TupleDesc
2026 135194 : get_cached_rowtype(Oid type_id, int32 typmod,
2027 : ExprEvalRowtypeCache *rowcache,
2028 : bool *changed)
2029 : {
2030 135194 : if (type_id != RECORDOID)
2031 : {
2032 : /*
2033 : * It's a named composite type, so use the regular typcache. Do a
2034 : * lookup first time through, or if the composite type changed. Note:
2035 : * "tupdesc_id == 0" may look redundant, but it protects against the
2036 : * admittedly-theoretical possibility that type_id was RECORDOID the
2037 : * last time through, so that the cacheptr isn't TypeCacheEntry *.
2038 : */
2039 43346 : TypeCacheEntry *typentry = (TypeCacheEntry *) rowcache->cacheptr;
2040 :
2041 43346 : if (unlikely(typentry == NULL ||
2042 : rowcache->tupdesc_id == 0 ||
2043 : typentry->tupDesc_identifier != rowcache->tupdesc_id))
2044 : {
2045 6016 : typentry = lookup_type_cache(type_id, TYPECACHE_TUPDESC);
2046 6016 : if (typentry->tupDesc == NULL)
2047 0 : ereport(ERROR,
2048 : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2049 : errmsg("type %s is not composite",
2050 : format_type_be(type_id))));
2051 6016 : rowcache->cacheptr = (void *) typentry;
2052 6016 : rowcache->tupdesc_id = typentry->tupDesc_identifier;
2053 6016 : if (changed)
2054 716 : *changed = true;
2055 : }
2056 43346 : return typentry->tupDesc;
2057 : }
2058 : else
2059 : {
2060 : /*
2061 : * A RECORD type, once registered, doesn't change for the life of the
2062 : * backend. So we don't need a typcache entry as such, which is good
2063 : * because there isn't one. It's possible that the caller is asking
2064 : * about a different type than before, though.
2065 : */
2066 91848 : TupleDesc tupDesc = (TupleDesc) rowcache->cacheptr;
2067 :
2068 91848 : if (unlikely(tupDesc == NULL ||
2069 : rowcache->tupdesc_id != 0 ||
2070 : type_id != tupDesc->tdtypeid ||
2071 : typmod != tupDesc->tdtypmod))
2072 : {
2073 1936 : tupDesc = lookup_rowtype_tupdesc(type_id, typmod);
2074 : /* Drop pin acquired by lookup_rowtype_tupdesc */
2075 1936 : ReleaseTupleDesc(tupDesc);
2076 1936 : rowcache->cacheptr = (void *) tupDesc;
2077 1936 : rowcache->tupdesc_id = 0; /* not a valid value for non-RECORD */
2078 1936 : if (changed)
2079 0 : *changed = true;
2080 : }
2081 91848 : return tupDesc;
2082 : }
2083 : }
2084 :
2085 :
2086 : /*
2087 : * Fast-path functions, for very simple expressions
2088 : */
2089 :
2090 : /* implementation of ExecJust(Inner|Outer|Scan)Var */
2091 : static pg_attribute_always_inline Datum
2092 15442118 : ExecJustVarImpl(ExprState *state, TupleTableSlot *slot, bool *isnull)
2093 : {
2094 15442118 : ExprEvalStep *op = &state->steps[1];
2095 15442118 : int attnum = op->d.var.attnum + 1;
2096 :
2097 15442118 : CheckOpSlotCompatibility(&state->steps[0], slot);
2098 :
2099 : /*
2100 : * Since we use slot_getattr(), we don't need to implement the FETCHSOME
2101 : * step explicitly, and we also needn't Assert that the attnum is in range
2102 : * --- slot_getattr() will take care of any problems.
2103 : */
2104 15442118 : return slot_getattr(slot, attnum, isnull);
2105 : }
2106 :
2107 : /* Simple reference to inner Var */
2108 : static Datum
2109 3817658 : ExecJustInnerVar(ExprState *state, ExprContext *econtext, bool *isnull)
2110 : {
2111 3817658 : return ExecJustVarImpl(state, econtext->ecxt_innertuple, isnull);
2112 : }
2113 :
2114 : /* Simple reference to outer Var */
2115 : static Datum
2116 11358174 : ExecJustOuterVar(ExprState *state, ExprContext *econtext, bool *isnull)
2117 : {
2118 11358174 : return ExecJustVarImpl(state, econtext->ecxt_outertuple, isnull);
2119 : }
2120 :
2121 : /* Simple reference to scan Var */
2122 : static Datum
2123 266286 : ExecJustScanVar(ExprState *state, ExprContext *econtext, bool *isnull)
2124 : {
2125 266286 : return ExecJustVarImpl(state, econtext->ecxt_scantuple, isnull);
2126 : }
2127 :
2128 : /* implementation of ExecJustAssign(Inner|Outer|Scan)Var */
2129 : static pg_attribute_always_inline Datum
2130 10600762 : ExecJustAssignVarImpl(ExprState *state, TupleTableSlot *inslot, bool *isnull)
2131 : {
2132 10600762 : ExprEvalStep *op = &state->steps[1];
2133 10600762 : int attnum = op->d.assign_var.attnum + 1;
2134 10600762 : int resultnum = op->d.assign_var.resultnum;
2135 10600762 : TupleTableSlot *outslot = state->resultslot;
2136 :
2137 10600762 : CheckOpSlotCompatibility(&state->steps[0], inslot);
2138 :
2139 : /*
2140 : * We do not need CheckVarSlotCompatibility here; that was taken care of
2141 : * at compilation time.
2142 : *
2143 : * Since we use slot_getattr(), we don't need to implement the FETCHSOME
2144 : * step explicitly, and we also needn't Assert that the attnum is in range
2145 : * --- slot_getattr() will take care of any problems. Nonetheless, check
2146 : * that resultnum is in range.
2147 : */
2148 : Assert(resultnum >= 0 && resultnum < outslot->tts_tupleDescriptor->natts);
2149 21201524 : outslot->tts_values[resultnum] =
2150 10600762 : slot_getattr(inslot, attnum, &outslot->tts_isnull[resultnum]);
2151 10600762 : return 0;
2152 : }
2153 :
2154 : /* Evaluate inner Var and assign to appropriate column of result tuple */
2155 : static Datum
2156 43500 : ExecJustAssignInnerVar(ExprState *state, ExprContext *econtext, bool *isnull)
2157 : {
2158 43500 : return ExecJustAssignVarImpl(state, econtext->ecxt_innertuple, isnull);
2159 : }
2160 :
2161 : /* Evaluate outer Var and assign to appropriate column of result tuple */
2162 : static Datum
2163 525290 : ExecJustAssignOuterVar(ExprState *state, ExprContext *econtext, bool *isnull)
2164 : {
2165 525290 : return ExecJustAssignVarImpl(state, econtext->ecxt_outertuple, isnull);
2166 : }
2167 :
2168 : /* Evaluate scan Var and assign to appropriate column of result tuple */
2169 : static Datum
2170 10031972 : ExecJustAssignScanVar(ExprState *state, ExprContext *econtext, bool *isnull)
2171 : {
2172 10031972 : return ExecJustAssignVarImpl(state, econtext->ecxt_scantuple, isnull);
2173 : }
2174 :
2175 : /* Evaluate CASE_TESTVAL and apply a strict function to it */
2176 : static Datum
2177 2658 : ExecJustApplyFuncToCase(ExprState *state, ExprContext *econtext, bool *isnull)
2178 : {
2179 2658 : ExprEvalStep *op = &state->steps[0];
2180 : FunctionCallInfo fcinfo;
2181 : NullableDatum *args;
2182 : int nargs;
2183 : Datum d;
2184 :
2185 : /*
2186 : * XXX with some redesign of the CaseTestExpr mechanism, maybe we could
2187 : * get rid of this data shuffling?
2188 : */
2189 2658 : *op->resvalue = *op->d.casetest.value;
2190 2658 : *op->resnull = *op->d.casetest.isnull;
2191 :
2192 2658 : op++;
2193 :
2194 2658 : nargs = op->d.func.nargs;
2195 2658 : fcinfo = op->d.func.fcinfo_data;
2196 2658 : args = fcinfo->args;
2197 :
2198 : /* strict function, so check for NULL args */
2199 5628 : for (int argno = 0; argno < nargs; argno++)
2200 : {
2201 2982 : if (args[argno].isnull)
2202 : {
2203 12 : *isnull = true;
2204 12 : return (Datum) 0;
2205 : }
2206 : }
2207 2646 : fcinfo->isnull = false;
2208 2646 : d = op->d.func.fn_addr(fcinfo);
2209 2628 : *isnull = fcinfo->isnull;
2210 2628 : return d;
2211 : }
2212 :
2213 : /* Simple Const expression */
2214 : static Datum
2215 1758920 : ExecJustConst(ExprState *state, ExprContext *econtext, bool *isnull)
2216 : {
2217 1758920 : ExprEvalStep *op = &state->steps[0];
2218 :
2219 1758920 : *isnull = op->d.constval.isnull;
2220 1758920 : return op->d.constval.value;
2221 : }
2222 :
2223 : /* implementation of ExecJust(Inner|Outer|Scan)VarVirt */
2224 : static pg_attribute_always_inline Datum
2225 16010162 : ExecJustVarVirtImpl(ExprState *state, TupleTableSlot *slot, bool *isnull)
2226 : {
2227 16010162 : ExprEvalStep *op = &state->steps[0];
2228 16010162 : int attnum = op->d.var.attnum;
2229 :
2230 : /*
2231 : * As it is guaranteed that a virtual slot is used, there never is a need
2232 : * to perform tuple deforming (nor would it be possible). Therefore
2233 : * execExpr.c has not emitted an EEOP_*_FETCHSOME step. Verify, as much as
2234 : * possible, that that determination was accurate.
2235 : */
2236 : Assert(TTS_IS_VIRTUAL(slot));
2237 : Assert(TTS_FIXED(slot));
2238 : Assert(attnum >= 0 && attnum < slot->tts_nvalid);
2239 :
2240 16010162 : *isnull = slot->tts_isnull[attnum];
2241 :
2242 16010162 : return slot->tts_values[attnum];
2243 : }
2244 :
2245 : /* Like ExecJustInnerVar, optimized for virtual slots */
2246 : static Datum
2247 498592 : ExecJustInnerVarVirt(ExprState *state, ExprContext *econtext, bool *isnull)
2248 : {
2249 498592 : return ExecJustVarVirtImpl(state, econtext->ecxt_innertuple, isnull);
2250 : }
2251 :
2252 : /* Like ExecJustOuterVar, optimized for virtual slots */
2253 : static Datum
2254 15511384 : ExecJustOuterVarVirt(ExprState *state, ExprContext *econtext, bool *isnull)
2255 : {
2256 15511384 : return ExecJustVarVirtImpl(state, econtext->ecxt_outertuple, isnull);
2257 : }
2258 :
2259 : /* Like ExecJustScanVar, optimized for virtual slots */
2260 : static Datum
2261 186 : ExecJustScanVarVirt(ExprState *state, ExprContext *econtext, bool *isnull)
2262 : {
2263 186 : return ExecJustVarVirtImpl(state, econtext->ecxt_scantuple, isnull);
2264 : }
2265 :
2266 : /* implementation of ExecJustAssign(Inner|Outer|Scan)VarVirt */
2267 : static pg_attribute_always_inline Datum
2268 815626 : ExecJustAssignVarVirtImpl(ExprState *state, TupleTableSlot *inslot, bool *isnull)
2269 : {
2270 815626 : ExprEvalStep *op = &state->steps[0];
2271 815626 : int attnum = op->d.assign_var.attnum;
2272 815626 : int resultnum = op->d.assign_var.resultnum;
2273 815626 : TupleTableSlot *outslot = state->resultslot;
2274 :
2275 : /* see ExecJustVarVirtImpl for comments */
2276 :
2277 : Assert(TTS_IS_VIRTUAL(inslot));
2278 : Assert(TTS_FIXED(inslot));
2279 : Assert(attnum >= 0 && attnum < inslot->tts_nvalid);
2280 : Assert(resultnum >= 0 && resultnum < outslot->tts_tupleDescriptor->natts);
2281 :
2282 815626 : outslot->tts_values[resultnum] = inslot->tts_values[attnum];
2283 815626 : outslot->tts_isnull[resultnum] = inslot->tts_isnull[attnum];
2284 :
2285 815626 : return 0;
2286 : }
2287 :
2288 : /* Like ExecJustAssignInnerVar, optimized for virtual slots */
2289 : static Datum
2290 121148 : ExecJustAssignInnerVarVirt(ExprState *state, ExprContext *econtext, bool *isnull)
2291 : {
2292 121148 : return ExecJustAssignVarVirtImpl(state, econtext->ecxt_innertuple, isnull);
2293 : }
2294 :
2295 : /* Like ExecJustAssignOuterVar, optimized for virtual slots */
2296 : static Datum
2297 510790 : ExecJustAssignOuterVarVirt(ExprState *state, ExprContext *econtext, bool *isnull)
2298 : {
2299 510790 : return ExecJustAssignVarVirtImpl(state, econtext->ecxt_outertuple, isnull);
2300 : }
2301 :
2302 : /* Like ExecJustAssignScanVar, optimized for virtual slots */
2303 : static Datum
2304 183688 : ExecJustAssignScanVarVirt(ExprState *state, ExprContext *econtext, bool *isnull)
2305 : {
2306 183688 : return ExecJustAssignVarVirtImpl(state, econtext->ecxt_scantuple, isnull);
2307 : }
2308 :
2309 : #if defined(EEO_USE_COMPUTED_GOTO)
2310 : /*
2311 : * Comparator used when building address->opcode lookup table for
2312 : * ExecEvalStepOp() in the threaded dispatch case.
2313 : */
2314 : static int
2315 47206990 : dispatch_compare_ptr(const void *a, const void *b)
2316 : {
2317 47206990 : const ExprEvalOpLookup *la = (const ExprEvalOpLookup *) a;
2318 47206990 : const ExprEvalOpLookup *lb = (const ExprEvalOpLookup *) b;
2319 :
2320 47206990 : if (la->opcode < lb->opcode)
2321 30214928 : return -1;
2322 16992062 : else if (la->opcode > lb->opcode)
2323 11174084 : return 1;
2324 5817978 : return 0;
2325 : }
2326 : #endif
2327 :
2328 : /*
2329 : * Do one-time initialization of interpretation machinery.
2330 : */
2331 : static void
2332 2164666 : ExecInitInterpreter(void)
2333 : {
2334 : #if defined(EEO_USE_COMPUTED_GOTO)
2335 : /* Set up externally-visible pointer to dispatch table */
2336 2164666 : if (dispatch_table == NULL)
2337 : {
2338 16374 : dispatch_table = (const void **)
2339 16374 : DatumGetPointer(ExecInterpExpr(NULL, NULL, NULL));
2340 :
2341 : /* build reverse lookup table */
2342 1555530 : for (int i = 0; i < EEOP_LAST; i++)
2343 : {
2344 1539156 : reverse_dispatch_table[i].opcode = dispatch_table[i];
2345 1539156 : reverse_dispatch_table[i].op = (ExprEvalOp) i;
2346 : }
2347 :
2348 : /* make it bsearch()able */
2349 16374 : qsort(reverse_dispatch_table,
2350 : EEOP_LAST /* nmembers */ ,
2351 : sizeof(ExprEvalOpLookup),
2352 : dispatch_compare_ptr);
2353 : }
2354 : #endif
2355 2164666 : }
2356 :
2357 : /*
2358 : * Function to return the opcode of an expression step.
2359 : *
2360 : * When direct-threading is in use, ExprState->opcode isn't easily
2361 : * decipherable. This function returns the appropriate enum member.
2362 : */
2363 : ExprEvalOp
2364 7058492 : ExecEvalStepOp(ExprState *state, ExprEvalStep *op)
2365 : {
2366 : #if defined(EEO_USE_COMPUTED_GOTO)
2367 7058492 : if (state->flags & EEO_FLAG_DIRECT_THREADED)
2368 : {
2369 : ExprEvalOpLookup key;
2370 : ExprEvalOpLookup *res;
2371 :
2372 5817978 : key.opcode = (void *) op->opcode;
2373 5817978 : res = bsearch(&key,
2374 : reverse_dispatch_table,
2375 : EEOP_LAST /* nmembers */ ,
2376 : sizeof(ExprEvalOpLookup),
2377 : dispatch_compare_ptr);
2378 : Assert(res); /* unknown ops shouldn't get looked up */
2379 5817978 : return res->op;
2380 : }
2381 : #endif
2382 1240514 : return (ExprEvalOp) op->opcode;
2383 : }
2384 :
2385 :
2386 : /*
2387 : * Out-of-line helper functions for complex instructions.
2388 : */
2389 :
2390 : /*
2391 : * Evaluate EEOP_FUNCEXPR_FUSAGE
2392 : */
2393 : void
2394 208 : ExecEvalFuncExprFusage(ExprState *state, ExprEvalStep *op,
2395 : ExprContext *econtext)
2396 : {
2397 208 : FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
2398 : PgStat_FunctionCallUsage fcusage;
2399 : Datum d;
2400 :
2401 208 : pgstat_init_function_usage(fcinfo, &fcusage);
2402 :
2403 208 : fcinfo->isnull = false;
2404 208 : d = op->d.func.fn_addr(fcinfo);
2405 208 : *op->resvalue = d;
2406 208 : *op->resnull = fcinfo->isnull;
2407 :
2408 208 : pgstat_end_function_usage(&fcusage, true);
2409 208 : }
2410 :
2411 : /*
2412 : * Evaluate EEOP_FUNCEXPR_STRICT_FUSAGE
2413 : */
2414 : void
2415 0 : ExecEvalFuncExprStrictFusage(ExprState *state, ExprEvalStep *op,
2416 : ExprContext *econtext)
2417 : {
2418 :
2419 0 : FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
2420 : PgStat_FunctionCallUsage fcusage;
2421 0 : NullableDatum *args = fcinfo->args;
2422 0 : int nargs = op->d.func.nargs;
2423 : Datum d;
2424 :
2425 : /* strict function, so check for NULL args */
2426 0 : for (int argno = 0; argno < nargs; argno++)
2427 : {
2428 0 : if (args[argno].isnull)
2429 : {
2430 0 : *op->resnull = true;
2431 0 : return;
2432 : }
2433 : }
2434 :
2435 0 : pgstat_init_function_usage(fcinfo, &fcusage);
2436 :
2437 0 : fcinfo->isnull = false;
2438 0 : d = op->d.func.fn_addr(fcinfo);
2439 0 : *op->resvalue = d;
2440 0 : *op->resnull = fcinfo->isnull;
2441 :
2442 0 : pgstat_end_function_usage(&fcusage, true);
2443 : }
2444 :
2445 : /*
2446 : * Evaluate a PARAM_EXEC parameter.
2447 : *
2448 : * PARAM_EXEC params (internal executor parameters) are stored in the
2449 : * ecxt_param_exec_vals array, and can be accessed by array index.
2450 : */
2451 : void
2452 3867178 : ExecEvalParamExec(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
2453 : {
2454 : ParamExecData *prm;
2455 :
2456 3867178 : prm = &(econtext->ecxt_param_exec_vals[op->d.param.paramid]);
2457 3867178 : if (unlikely(prm->execPlan != NULL))
2458 : {
2459 : /* Parameter not evaluated yet, so go do it */
2460 11638 : ExecSetParamPlan(prm->execPlan, econtext);
2461 : /* ExecSetParamPlan should have processed this param... */
2462 : Assert(prm->execPlan == NULL);
2463 : }
2464 3867166 : *op->resvalue = prm->value;
2465 3867166 : *op->resnull = prm->isnull;
2466 3867166 : }
2467 :
2468 : /*
2469 : * Evaluate a PARAM_EXTERN parameter.
2470 : *
2471 : * PARAM_EXTERN parameters must be sought in ecxt_param_list_info.
2472 : */
2473 : void
2474 294004 : ExecEvalParamExtern(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
2475 : {
2476 294004 : ParamListInfo paramInfo = econtext->ecxt_param_list_info;
2477 294004 : int paramId = op->d.param.paramid;
2478 :
2479 294004 : if (likely(paramInfo &&
2480 : paramId > 0 && paramId <= paramInfo->numParams))
2481 : {
2482 : ParamExternData *prm;
2483 : ParamExternData prmdata;
2484 :
2485 : /* give hook a chance in case parameter is dynamic */
2486 294004 : if (paramInfo->paramFetch != NULL)
2487 176 : prm = paramInfo->paramFetch(paramInfo, paramId, false, &prmdata);
2488 : else
2489 293828 : prm = ¶mInfo->params[paramId - 1];
2490 :
2491 294004 : if (likely(OidIsValid(prm->ptype)))
2492 : {
2493 : /* safety check in case hook did something unexpected */
2494 294004 : if (unlikely(prm->ptype != op->d.param.paramtype))
2495 0 : ereport(ERROR,
2496 : (errcode(ERRCODE_DATATYPE_MISMATCH),
2497 : errmsg("type of parameter %d (%s) does not match that when preparing the plan (%s)",
2498 : paramId,
2499 : format_type_be(prm->ptype),
2500 : format_type_be(op->d.param.paramtype))));
2501 294004 : *op->resvalue = prm->value;
2502 294004 : *op->resnull = prm->isnull;
2503 294004 : return;
2504 : }
2505 : }
2506 :
2507 0 : ereport(ERROR,
2508 : (errcode(ERRCODE_UNDEFINED_OBJECT),
2509 : errmsg("no value found for parameter %d", paramId)));
2510 : }
2511 :
2512 : /*
2513 : * Evaluate a SQLValueFunction expression.
2514 : */
2515 : void
2516 16826 : ExecEvalSQLValueFunction(ExprState *state, ExprEvalStep *op)
2517 : {
2518 16826 : LOCAL_FCINFO(fcinfo, 0);
2519 16826 : SQLValueFunction *svf = op->d.sqlvaluefunction.svf;
2520 :
2521 16826 : *op->resnull = false;
2522 :
2523 : /*
2524 : * Note: current_schema() can return NULL. current_user() etc currently
2525 : * cannot, but might as well code those cases the same way for safety.
2526 : */
2527 16826 : switch (svf->op)
2528 : {
2529 26 : case SVFOP_CURRENT_DATE:
2530 26 : *op->resvalue = DateADTGetDatum(GetSQLCurrentDate());
2531 26 : break;
2532 24 : case SVFOP_CURRENT_TIME:
2533 : case SVFOP_CURRENT_TIME_N:
2534 24 : *op->resvalue = TimeTzADTPGetDatum(GetSQLCurrentTime(svf->typmod));
2535 24 : break;
2536 278 : case SVFOP_CURRENT_TIMESTAMP:
2537 : case SVFOP_CURRENT_TIMESTAMP_N:
2538 278 : *op->resvalue = TimestampTzGetDatum(GetSQLCurrentTimestamp(svf->typmod));
2539 278 : break;
2540 24 : case SVFOP_LOCALTIME:
2541 : case SVFOP_LOCALTIME_N:
2542 24 : *op->resvalue = TimeADTGetDatum(GetSQLLocalTime(svf->typmod));
2543 24 : break;
2544 66 : case SVFOP_LOCALTIMESTAMP:
2545 : case SVFOP_LOCALTIMESTAMP_N:
2546 66 : *op->resvalue = TimestampGetDatum(GetSQLLocalTimestamp(svf->typmod));
2547 66 : break;
2548 16310 : case SVFOP_CURRENT_ROLE:
2549 : case SVFOP_CURRENT_USER:
2550 : case SVFOP_USER:
2551 16310 : InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL);
2552 16310 : *op->resvalue = current_user(fcinfo);
2553 16310 : *op->resnull = fcinfo->isnull;
2554 16310 : break;
2555 68 : case SVFOP_SESSION_USER:
2556 68 : InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL);
2557 68 : *op->resvalue = session_user(fcinfo);
2558 68 : *op->resnull = fcinfo->isnull;
2559 68 : break;
2560 12 : case SVFOP_CURRENT_CATALOG:
2561 12 : InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL);
2562 12 : *op->resvalue = current_database(fcinfo);
2563 12 : *op->resnull = fcinfo->isnull;
2564 12 : break;
2565 18 : case SVFOP_CURRENT_SCHEMA:
2566 18 : InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL);
2567 18 : *op->resvalue = current_schema(fcinfo);
2568 18 : *op->resnull = fcinfo->isnull;
2569 18 : break;
2570 : }
2571 16826 : }
2572 :
2573 : /*
2574 : * Raise error if a CURRENT OF expression is evaluated.
2575 : *
2576 : * The planner should convert CURRENT OF into a TidScan qualification, or some
2577 : * other special handling in a ForeignScan node. So we have to be able to do
2578 : * ExecInitExpr on a CurrentOfExpr, but we shouldn't ever actually execute it.
2579 : * If we get here, we suppose we must be dealing with CURRENT OF on a foreign
2580 : * table whose FDW doesn't handle it, and complain accordingly.
2581 : */
2582 : void
2583 2 : ExecEvalCurrentOfExpr(ExprState *state, ExprEvalStep *op)
2584 : {
2585 2 : ereport(ERROR,
2586 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2587 : errmsg("WHERE CURRENT OF is not supported for this table type")));
2588 : }
2589 :
2590 : /*
2591 : * Evaluate NextValueExpr.
2592 : */
2593 : void
2594 792 : ExecEvalNextValueExpr(ExprState *state, ExprEvalStep *op)
2595 : {
2596 792 : int64 newval = nextval_internal(op->d.nextvalueexpr.seqid, false);
2597 :
2598 792 : switch (op->d.nextvalueexpr.seqtypid)
2599 : {
2600 30 : case INT2OID:
2601 30 : *op->resvalue = Int16GetDatum((int16) newval);
2602 30 : break;
2603 714 : case INT4OID:
2604 714 : *op->resvalue = Int32GetDatum((int32) newval);
2605 714 : break;
2606 48 : case INT8OID:
2607 48 : *op->resvalue = Int64GetDatum((int64) newval);
2608 48 : break;
2609 0 : default:
2610 0 : elog(ERROR, "unsupported sequence type %u",
2611 : op->d.nextvalueexpr.seqtypid);
2612 : }
2613 792 : *op->resnull = false;
2614 792 : }
2615 :
2616 : /*
2617 : * Evaluate NullTest / IS NULL for rows.
2618 : */
2619 : void
2620 696 : ExecEvalRowNull(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
2621 : {
2622 696 : ExecEvalRowNullInt(state, op, econtext, true);
2623 696 : }
2624 :
2625 : /*
2626 : * Evaluate NullTest / IS NOT NULL for rows.
2627 : */
2628 : void
2629 524 : ExecEvalRowNotNull(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
2630 : {
2631 524 : ExecEvalRowNullInt(state, op, econtext, false);
2632 524 : }
2633 :
2634 : /* Common code for IS [NOT] NULL on a row value */
2635 : static void
2636 1220 : ExecEvalRowNullInt(ExprState *state, ExprEvalStep *op,
2637 : ExprContext *econtext, bool checkisnull)
2638 : {
2639 1220 : Datum value = *op->resvalue;
2640 1220 : bool isnull = *op->resnull;
2641 : HeapTupleHeader tuple;
2642 : Oid tupType;
2643 : int32 tupTypmod;
2644 : TupleDesc tupDesc;
2645 : HeapTupleData tmptup;
2646 :
2647 1220 : *op->resnull = false;
2648 :
2649 : /* NULL row variables are treated just as NULL scalar columns */
2650 1220 : if (isnull)
2651 : {
2652 152 : *op->resvalue = BoolGetDatum(checkisnull);
2653 738 : return;
2654 : }
2655 :
2656 : /*
2657 : * The SQL standard defines IS [NOT] NULL for a non-null rowtype argument
2658 : * as:
2659 : *
2660 : * "R IS NULL" is true if every field is the null value.
2661 : *
2662 : * "R IS NOT NULL" is true if no field is the null value.
2663 : *
2664 : * This definition is (apparently intentionally) not recursive; so our
2665 : * tests on the fields are primitive attisnull tests, not recursive checks
2666 : * to see if they are all-nulls or no-nulls rowtypes.
2667 : *
2668 : * The standard does not consider the possibility of zero-field rows, but
2669 : * here we consider them to vacuously satisfy both predicates.
2670 : */
2671 :
2672 1068 : tuple = DatumGetHeapTupleHeader(value);
2673 :
2674 1068 : tupType = HeapTupleHeaderGetTypeId(tuple);
2675 1068 : tupTypmod = HeapTupleHeaderGetTypMod(tuple);
2676 :
2677 : /* Lookup tupdesc if first time through or if type changes */
2678 1068 : tupDesc = get_cached_rowtype(tupType, tupTypmod,
2679 : &op->d.nulltest_row.rowcache, NULL);
2680 :
2681 : /*
2682 : * heap_attisnull needs a HeapTuple not a bare HeapTupleHeader.
2683 : */
2684 1068 : tmptup.t_len = HeapTupleHeaderGetDatumLength(tuple);
2685 1068 : tmptup.t_data = tuple;
2686 :
2687 2578 : for (int att = 1; att <= tupDesc->natts; att++)
2688 : {
2689 : /* ignore dropped columns */
2690 2096 : if (TupleDescAttr(tupDesc, att - 1)->attisdropped)
2691 0 : continue;
2692 2096 : if (heap_attisnull(&tmptup, att, tupDesc))
2693 : {
2694 : /* null field disproves IS NOT NULL */
2695 56 : if (!checkisnull)
2696 : {
2697 32 : *op->resvalue = BoolGetDatum(false);
2698 32 : return;
2699 : }
2700 : }
2701 : else
2702 : {
2703 : /* non-null field disproves IS NULL */
2704 2040 : if (checkisnull)
2705 : {
2706 554 : *op->resvalue = BoolGetDatum(false);
2707 554 : return;
2708 : }
2709 : }
2710 : }
2711 :
2712 482 : *op->resvalue = BoolGetDatum(true);
2713 : }
2714 :
2715 : /*
2716 : * Evaluate an ARRAY[] expression.
2717 : *
2718 : * The individual array elements (or subarrays) have already been evaluated
2719 : * into op->d.arrayexpr.elemvalues[]/elemnulls[].
2720 : */
2721 : void
2722 717904 : ExecEvalArrayExpr(ExprState *state, ExprEvalStep *op)
2723 : {
2724 : ArrayType *result;
2725 717904 : Oid element_type = op->d.arrayexpr.elemtype;
2726 717904 : int nelems = op->d.arrayexpr.nelems;
2727 717904 : int ndims = 0;
2728 : int dims[MAXDIM];
2729 : int lbs[MAXDIM];
2730 :
2731 : /* Set non-null as default */
2732 717904 : *op->resnull = false;
2733 :
2734 717904 : if (!op->d.arrayexpr.multidims)
2735 : {
2736 : /* Elements are presumably of scalar type */
2737 717426 : Datum *dvalues = op->d.arrayexpr.elemvalues;
2738 717426 : bool *dnulls = op->d.arrayexpr.elemnulls;
2739 :
2740 : /* setup for 1-D array of the given length */
2741 717426 : ndims = 1;
2742 717426 : dims[0] = nelems;
2743 717426 : lbs[0] = 1;
2744 :
2745 717426 : result = construct_md_array(dvalues, dnulls, ndims, dims, lbs,
2746 : element_type,
2747 717426 : op->d.arrayexpr.elemlength,
2748 717426 : op->d.arrayexpr.elembyval,
2749 717426 : op->d.arrayexpr.elemalign);
2750 : }
2751 : else
2752 : {
2753 : /* Must be nested array expressions */
2754 478 : int nbytes = 0;
2755 : int nitems;
2756 478 : int outer_nelems = 0;
2757 478 : int elem_ndims = 0;
2758 478 : int *elem_dims = NULL;
2759 478 : int *elem_lbs = NULL;
2760 478 : bool firstone = true;
2761 478 : bool havenulls = false;
2762 478 : bool haveempty = false;
2763 : char **subdata;
2764 : bits8 **subbitmaps;
2765 : int *subbytes;
2766 : int *subnitems;
2767 : int32 dataoffset;
2768 : char *dat;
2769 : int iitem;
2770 :
2771 478 : subdata = (char **) palloc(nelems * sizeof(char *));
2772 478 : subbitmaps = (bits8 **) palloc(nelems * sizeof(bits8 *));
2773 478 : subbytes = (int *) palloc(nelems * sizeof(int));
2774 478 : subnitems = (int *) palloc(nelems * sizeof(int));
2775 :
2776 : /* loop through and get data area from each element */
2777 1334 : for (int elemoff = 0; elemoff < nelems; elemoff++)
2778 : {
2779 : Datum arraydatum;
2780 : bool eisnull;
2781 : ArrayType *array;
2782 : int this_ndims;
2783 :
2784 856 : arraydatum = op->d.arrayexpr.elemvalues[elemoff];
2785 856 : eisnull = op->d.arrayexpr.elemnulls[elemoff];
2786 :
2787 : /* temporarily ignore null subarrays */
2788 856 : if (eisnull)
2789 : {
2790 0 : haveempty = true;
2791 0 : continue;
2792 : }
2793 :
2794 856 : array = DatumGetArrayTypeP(arraydatum);
2795 :
2796 : /* run-time double-check on element type */
2797 856 : if (element_type != ARR_ELEMTYPE(array))
2798 0 : ereport(ERROR,
2799 : (errcode(ERRCODE_DATATYPE_MISMATCH),
2800 : errmsg("cannot merge incompatible arrays"),
2801 : errdetail("Array with element type %s cannot be "
2802 : "included in ARRAY construct with element type %s.",
2803 : format_type_be(ARR_ELEMTYPE(array)),
2804 : format_type_be(element_type))));
2805 :
2806 856 : this_ndims = ARR_NDIM(array);
2807 : /* temporarily ignore zero-dimensional subarrays */
2808 856 : if (this_ndims <= 0)
2809 : {
2810 0 : haveempty = true;
2811 0 : continue;
2812 : }
2813 :
2814 856 : if (firstone)
2815 : {
2816 : /* Get sub-array details from first member */
2817 478 : elem_ndims = this_ndims;
2818 478 : ndims = elem_ndims + 1;
2819 478 : if (ndims <= 0 || ndims > MAXDIM)
2820 0 : ereport(ERROR,
2821 : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
2822 : errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
2823 : ndims, MAXDIM)));
2824 :
2825 478 : elem_dims = (int *) palloc(elem_ndims * sizeof(int));
2826 478 : memcpy(elem_dims, ARR_DIMS(array), elem_ndims * sizeof(int));
2827 478 : elem_lbs = (int *) palloc(elem_ndims * sizeof(int));
2828 478 : memcpy(elem_lbs, ARR_LBOUND(array), elem_ndims * sizeof(int));
2829 :
2830 478 : firstone = false;
2831 : }
2832 : else
2833 : {
2834 : /* Check other sub-arrays are compatible */
2835 378 : if (elem_ndims != this_ndims ||
2836 378 : memcmp(elem_dims, ARR_DIMS(array),
2837 378 : elem_ndims * sizeof(int)) != 0 ||
2838 378 : memcmp(elem_lbs, ARR_LBOUND(array),
2839 : elem_ndims * sizeof(int)) != 0)
2840 0 : ereport(ERROR,
2841 : (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
2842 : errmsg("multidimensional arrays must have array "
2843 : "expressions with matching dimensions")));
2844 : }
2845 :
2846 856 : subdata[outer_nelems] = ARR_DATA_PTR(array);
2847 856 : subbitmaps[outer_nelems] = ARR_NULLBITMAP(array);
2848 856 : subbytes[outer_nelems] = ARR_SIZE(array) - ARR_DATA_OFFSET(array);
2849 856 : nbytes += subbytes[outer_nelems];
2850 : /* check for overflow of total request */
2851 856 : if (!AllocSizeIsValid(nbytes))
2852 0 : ereport(ERROR,
2853 : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
2854 : errmsg("array size exceeds the maximum allowed (%d)",
2855 : (int) MaxAllocSize)));
2856 856 : subnitems[outer_nelems] = ArrayGetNItems(this_ndims,
2857 : ARR_DIMS(array));
2858 856 : havenulls |= ARR_HASNULL(array);
2859 856 : outer_nelems++;
2860 : }
2861 :
2862 : /*
2863 : * If all items were null or empty arrays, return an empty array;
2864 : * otherwise, if some were and some weren't, raise error. (Note: we
2865 : * must special-case this somehow to avoid trying to generate a 1-D
2866 : * array formed from empty arrays. It's not ideal...)
2867 : */
2868 478 : if (haveempty)
2869 : {
2870 0 : if (ndims == 0) /* didn't find any nonempty array */
2871 : {
2872 0 : *op->resvalue = PointerGetDatum(construct_empty_array(element_type));
2873 0 : return;
2874 : }
2875 0 : ereport(ERROR,
2876 : (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
2877 : errmsg("multidimensional arrays must have array "
2878 : "expressions with matching dimensions")));
2879 : }
2880 :
2881 : /* setup for multi-D array */
2882 478 : dims[0] = outer_nelems;
2883 478 : lbs[0] = 1;
2884 1188 : for (int i = 1; i < ndims; i++)
2885 : {
2886 710 : dims[i] = elem_dims[i - 1];
2887 710 : lbs[i] = elem_lbs[i - 1];
2888 : }
2889 :
2890 : /* check for subscript overflow */
2891 478 : nitems = ArrayGetNItems(ndims, dims);
2892 478 : ArrayCheckBounds(ndims, dims, lbs);
2893 :
2894 478 : if (havenulls)
2895 : {
2896 30 : dataoffset = ARR_OVERHEAD_WITHNULLS(ndims, nitems);
2897 30 : nbytes += dataoffset;
2898 : }
2899 : else
2900 : {
2901 448 : dataoffset = 0; /* marker for no null bitmap */
2902 448 : nbytes += ARR_OVERHEAD_NONULLS(ndims);
2903 : }
2904 :
2905 478 : result = (ArrayType *) palloc0(nbytes);
2906 478 : SET_VARSIZE(result, nbytes);
2907 478 : result->ndim = ndims;
2908 478 : result->dataoffset = dataoffset;
2909 478 : result->elemtype = element_type;
2910 478 : memcpy(ARR_DIMS(result), dims, ndims * sizeof(int));
2911 478 : memcpy(ARR_LBOUND(result), lbs, ndims * sizeof(int));
2912 :
2913 478 : dat = ARR_DATA_PTR(result);
2914 478 : iitem = 0;
2915 1334 : for (int i = 0; i < outer_nelems; i++)
2916 : {
2917 856 : memcpy(dat, subdata[i], subbytes[i]);
2918 856 : dat += subbytes[i];
2919 856 : if (havenulls)
2920 60 : array_bitmap_copy(ARR_NULLBITMAP(result), iitem,
2921 60 : subbitmaps[i], 0,
2922 60 : subnitems[i]);
2923 856 : iitem += subnitems[i];
2924 : }
2925 : }
2926 :
2927 717904 : *op->resvalue = PointerGetDatum(result);
2928 : }
2929 :
2930 : /*
2931 : * Evaluate an ArrayCoerceExpr expression.
2932 : *
2933 : * Source array is in step's result variable.
2934 : */
2935 : void
2936 65356 : ExecEvalArrayCoerce(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
2937 : {
2938 : Datum arraydatum;
2939 :
2940 : /* NULL array -> NULL result */
2941 65356 : if (*op->resnull)
2942 210 : return;
2943 :
2944 65146 : arraydatum = *op->resvalue;
2945 :
2946 : /*
2947 : * If it's binary-compatible, modify the element type in the array header,
2948 : * but otherwise leave the array as we received it.
2949 : */
2950 65146 : if (op->d.arraycoerce.elemexprstate == NULL)
2951 : {
2952 : /* Detoast input array if necessary, and copy in any case */
2953 64738 : ArrayType *array = DatumGetArrayTypePCopy(arraydatum);
2954 :
2955 64738 : ARR_ELEMTYPE(array) = op->d.arraycoerce.resultelemtype;
2956 64738 : *op->resvalue = PointerGetDatum(array);
2957 64738 : return;
2958 : }
2959 :
2960 : /*
2961 : * Use array_map to apply the sub-expression to each array element.
2962 : */
2963 376 : *op->resvalue = array_map(arraydatum,
2964 408 : op->d.arraycoerce.elemexprstate,
2965 : econtext,
2966 : op->d.arraycoerce.resultelemtype,
2967 408 : op->d.arraycoerce.amstate);
2968 : }
2969 :
2970 : /*
2971 : * Evaluate a ROW() expression.
2972 : *
2973 : * The individual columns have already been evaluated into
2974 : * op->d.row.elemvalues[]/elemnulls[].
2975 : */
2976 : void
2977 26890 : ExecEvalRow(ExprState *state, ExprEvalStep *op)
2978 : {
2979 : HeapTuple tuple;
2980 :
2981 : /* build tuple from evaluated field values */
2982 26890 : tuple = heap_form_tuple(op->d.row.tupdesc,
2983 : op->d.row.elemvalues,
2984 : op->d.row.elemnulls);
2985 :
2986 26890 : *op->resvalue = HeapTupleGetDatum(tuple);
2987 26890 : *op->resnull = false;
2988 26890 : }
2989 :
2990 : /*
2991 : * Evaluate GREATEST() or LEAST() expression (note this is *not* MIN()/MAX()).
2992 : *
2993 : * All of the to-be-compared expressions have already been evaluated into
2994 : * op->d.minmax.values[]/nulls[].
2995 : */
2996 : void
2997 3058 : ExecEvalMinMax(ExprState *state, ExprEvalStep *op)
2998 : {
2999 3058 : Datum *values = op->d.minmax.values;
3000 3058 : bool *nulls = op->d.minmax.nulls;
3001 3058 : FunctionCallInfo fcinfo = op->d.minmax.fcinfo_data;
3002 3058 : MinMaxOp operator = op->d.minmax.op;
3003 :
3004 : /* set at initialization */
3005 : Assert(fcinfo->args[0].isnull == false);
3006 : Assert(fcinfo->args[1].isnull == false);
3007 :
3008 : /* default to null result */
3009 3058 : *op->resnull = true;
3010 :
3011 9468 : for (int off = 0; off < op->d.minmax.nelems; off++)
3012 : {
3013 : /* ignore NULL inputs */
3014 6410 : if (nulls[off])
3015 120 : continue;
3016 :
3017 6290 : if (*op->resnull)
3018 : {
3019 : /* first nonnull input, adopt value */
3020 3058 : *op->resvalue = values[off];
3021 3058 : *op->resnull = false;
3022 : }
3023 : else
3024 : {
3025 : int cmpresult;
3026 :
3027 : /* apply comparison function */
3028 3232 : fcinfo->args[0].value = *op->resvalue;
3029 3232 : fcinfo->args[1].value = values[off];
3030 :
3031 3232 : fcinfo->isnull = false;
3032 3232 : cmpresult = DatumGetInt32(FunctionCallInvoke(fcinfo));
3033 3232 : if (fcinfo->isnull) /* probably should not happen */
3034 0 : continue;
3035 :
3036 3232 : if (cmpresult > 0 && operator == IS_LEAST)
3037 248 : *op->resvalue = values[off];
3038 2984 : else if (cmpresult < 0 && operator == IS_GREATEST)
3039 180 : *op->resvalue = values[off];
3040 : }
3041 : }
3042 3058 : }
3043 :
3044 : /*
3045 : * Evaluate a FieldSelect node.
3046 : *
3047 : * Source record is in step's result variable.
3048 : */
3049 : void
3050 110188 : ExecEvalFieldSelect(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
3051 : {
3052 110188 : AttrNumber fieldnum = op->d.fieldselect.fieldnum;
3053 : Datum tupDatum;
3054 : HeapTupleHeader tuple;
3055 : Oid tupType;
3056 : int32 tupTypmod;
3057 : TupleDesc tupDesc;
3058 : Form_pg_attribute attr;
3059 : HeapTupleData tmptup;
3060 :
3061 : /* NULL record -> NULL result */
3062 110188 : if (*op->resnull)
3063 176 : return;
3064 :
3065 110012 : tupDatum = *op->resvalue;
3066 :
3067 : /* We can special-case expanded records for speed */
3068 110012 : if (VARATT_IS_EXTERNAL_EXPANDED(DatumGetPointer(tupDatum)))
3069 662 : {
3070 662 : ExpandedRecordHeader *erh = (ExpandedRecordHeader *) DatumGetEOHP(tupDatum);
3071 :
3072 : Assert(erh->er_magic == ER_MAGIC);
3073 :
3074 : /* Extract record's TupleDesc */
3075 662 : tupDesc = expanded_record_get_tupdesc(erh);
3076 :
3077 : /*
3078 : * Find field's attr record. Note we don't support system columns
3079 : * here: a datum tuple doesn't have valid values for most of the
3080 : * interesting system columns anyway.
3081 : */
3082 662 : if (fieldnum <= 0) /* should never happen */
3083 0 : elog(ERROR, "unsupported reference to system column %d in FieldSelect",
3084 : fieldnum);
3085 662 : if (fieldnum > tupDesc->natts) /* should never happen */
3086 0 : elog(ERROR, "attribute number %d exceeds number of columns %d",
3087 : fieldnum, tupDesc->natts);
3088 662 : attr = TupleDescAttr(tupDesc, fieldnum - 1);
3089 :
3090 : /* Check for dropped column, and force a NULL result if so */
3091 662 : if (attr->attisdropped)
3092 : {
3093 0 : *op->resnull = true;
3094 0 : return;
3095 : }
3096 :
3097 : /* Check for type mismatch --- possible after ALTER COLUMN TYPE? */
3098 : /* As in CheckVarSlotCompatibility, we should but can't check typmod */
3099 662 : if (op->d.fieldselect.resulttype != attr->atttypid)
3100 0 : ereport(ERROR,
3101 : (errcode(ERRCODE_DATATYPE_MISMATCH),
3102 : errmsg("attribute %d has wrong type", fieldnum),
3103 : errdetail("Table has type %s, but query expects %s.",
3104 : format_type_be(attr->atttypid),
3105 : format_type_be(op->d.fieldselect.resulttype))));
3106 :
3107 : /* extract the field */
3108 662 : *op->resvalue = expanded_record_get_field(erh, fieldnum,
3109 : op->resnull);
3110 : }
3111 : else
3112 : {
3113 : /* Get the composite datum and extract its type fields */
3114 109350 : tuple = DatumGetHeapTupleHeader(tupDatum);
3115 :
3116 109350 : tupType = HeapTupleHeaderGetTypeId(tuple);
3117 109350 : tupTypmod = HeapTupleHeaderGetTypMod(tuple);
3118 :
3119 : /* Lookup tupdesc if first time through or if type changes */
3120 109350 : tupDesc = get_cached_rowtype(tupType, tupTypmod,
3121 : &op->d.fieldselect.rowcache, NULL);
3122 :
3123 : /*
3124 : * Find field's attr record. Note we don't support system columns
3125 : * here: a datum tuple doesn't have valid values for most of the
3126 : * interesting system columns anyway.
3127 : */
3128 109350 : if (fieldnum <= 0) /* should never happen */
3129 0 : elog(ERROR, "unsupported reference to system column %d in FieldSelect",
3130 : fieldnum);
3131 109350 : if (fieldnum > tupDesc->natts) /* should never happen */
3132 0 : elog(ERROR, "attribute number %d exceeds number of columns %d",
3133 : fieldnum, tupDesc->natts);
3134 109350 : attr = TupleDescAttr(tupDesc, fieldnum - 1);
3135 :
3136 : /* Check for dropped column, and force a NULL result if so */
3137 109350 : if (attr->attisdropped)
3138 : {
3139 0 : *op->resnull = true;
3140 0 : return;
3141 : }
3142 :
3143 : /* Check for type mismatch --- possible after ALTER COLUMN TYPE? */
3144 : /* As in CheckVarSlotCompatibility, we should but can't check typmod */
3145 109350 : if (op->d.fieldselect.resulttype != attr->atttypid)
3146 0 : ereport(ERROR,
3147 : (errcode(ERRCODE_DATATYPE_MISMATCH),
3148 : errmsg("attribute %d has wrong type", fieldnum),
3149 : errdetail("Table has type %s, but query expects %s.",
3150 : format_type_be(attr->atttypid),
3151 : format_type_be(op->d.fieldselect.resulttype))));
3152 :
3153 : /* heap_getattr needs a HeapTuple not a bare HeapTupleHeader */
3154 109350 : tmptup.t_len = HeapTupleHeaderGetDatumLength(tuple);
3155 109350 : tmptup.t_data = tuple;
3156 :
3157 : /* extract the field */
3158 109350 : *op->resvalue = heap_getattr(&tmptup,
3159 : fieldnum,
3160 : tupDesc,
3161 : op->resnull);
3162 : }
3163 : }
3164 :
3165 : /*
3166 : * Deform source tuple, filling in the step's values/nulls arrays, before
3167 : * evaluating individual new values as part of a FieldStore expression.
3168 : * Subsequent steps will overwrite individual elements of the values/nulls
3169 : * arrays with the new field values, and then FIELDSTORE_FORM will build the
3170 : * new tuple value.
3171 : *
3172 : * Source record is in step's result variable.
3173 : */
3174 : void
3175 382 : ExecEvalFieldStoreDeForm(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
3176 : {
3177 : TupleDesc tupDesc;
3178 :
3179 : /* Lookup tupdesc if first time through or if type changes */
3180 382 : tupDesc = get_cached_rowtype(op->d.fieldstore.fstore->resulttype, -1,
3181 : op->d.fieldstore.rowcache, NULL);
3182 :
3183 : /* Check that current tupdesc doesn't have more fields than we allocated */
3184 382 : if (unlikely(tupDesc->natts > op->d.fieldstore.ncolumns))
3185 0 : elog(ERROR, "too many columns in composite type %u",
3186 : op->d.fieldstore.fstore->resulttype);
3187 :
3188 382 : if (*op->resnull)
3189 : {
3190 : /* Convert null input tuple into an all-nulls row */
3191 154 : memset(op->d.fieldstore.nulls, true,
3192 154 : op->d.fieldstore.ncolumns * sizeof(bool));
3193 : }
3194 : else
3195 : {
3196 : /*
3197 : * heap_deform_tuple needs a HeapTuple not a bare HeapTupleHeader. We
3198 : * set all the fields in the struct just in case.
3199 : */
3200 228 : Datum tupDatum = *op->resvalue;
3201 : HeapTupleHeader tuphdr;
3202 : HeapTupleData tmptup;
3203 :
3204 228 : tuphdr = DatumGetHeapTupleHeader(tupDatum);
3205 228 : tmptup.t_len = HeapTupleHeaderGetDatumLength(tuphdr);
3206 228 : ItemPointerSetInvalid(&(tmptup.t_self));
3207 228 : tmptup.t_tableOid = InvalidOid;
3208 228 : tmptup.t_data = tuphdr;
3209 :
3210 228 : heap_deform_tuple(&tmptup, tupDesc,
3211 : op->d.fieldstore.values,
3212 : op->d.fieldstore.nulls);
3213 : }
3214 382 : }
3215 :
3216 : /*
3217 : * Compute the new composite datum after each individual field value of a
3218 : * FieldStore expression has been evaluated.
3219 : */
3220 : void
3221 382 : ExecEvalFieldStoreForm(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
3222 : {
3223 : TupleDesc tupDesc;
3224 : HeapTuple tuple;
3225 :
3226 : /* Lookup tupdesc (should be valid already) */
3227 382 : tupDesc = get_cached_rowtype(op->d.fieldstore.fstore->resulttype, -1,
3228 : op->d.fieldstore.rowcache, NULL);
3229 :
3230 382 : tuple = heap_form_tuple(tupDesc,
3231 : op->d.fieldstore.values,
3232 : op->d.fieldstore.nulls);
3233 :
3234 382 : *op->resvalue = HeapTupleGetDatum(tuple);
3235 382 : *op->resnull = false;
3236 382 : }
3237 :
3238 : /*
3239 : * Evaluate a rowtype coercion operation.
3240 : * This may require rearranging field positions.
3241 : *
3242 : * Source record is in step's result variable.
3243 : */
3244 : void
3245 12012 : ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
3246 : {
3247 : HeapTuple result;
3248 : Datum tupDatum;
3249 : HeapTupleHeader tuple;
3250 : HeapTupleData tmptup;
3251 : TupleDesc indesc,
3252 : outdesc;
3253 12012 : bool changed = false;
3254 :
3255 : /* NULL in -> NULL out */
3256 12012 : if (*op->resnull)
3257 6 : return;
3258 :
3259 12006 : tupDatum = *op->resvalue;
3260 12006 : tuple = DatumGetHeapTupleHeader(tupDatum);
3261 :
3262 : /*
3263 : * Lookup tupdescs if first time through or if type changes. We'd better
3264 : * pin them since type conversion functions could do catalog lookups and
3265 : * hence cause cache invalidation.
3266 : */
3267 12006 : indesc = get_cached_rowtype(op->d.convert_rowtype.inputtype, -1,
3268 : op->d.convert_rowtype.incache,
3269 : &changed);
3270 12006 : IncrTupleDescRefCount(indesc);
3271 12006 : outdesc = get_cached_rowtype(op->d.convert_rowtype.outputtype, -1,
3272 : op->d.convert_rowtype.outcache,
3273 : &changed);
3274 12006 : IncrTupleDescRefCount(outdesc);
3275 :
3276 : /*
3277 : * We used to be able to assert that incoming tuples are marked with
3278 : * exactly the rowtype of indesc. However, now that ExecEvalWholeRowVar
3279 : * might change the tuples' marking to plain RECORD due to inserting
3280 : * aliases, we can only make this weak test:
3281 : */
3282 : Assert(HeapTupleHeaderGetTypeId(tuple) == indesc->tdtypeid ||
3283 : HeapTupleHeaderGetTypeId(tuple) == RECORDOID);
3284 :
3285 : /* if first time through, or after change, initialize conversion map */
3286 12006 : if (changed)
3287 : {
3288 : MemoryContext old_cxt;
3289 :
3290 : /* allocate map in long-lived memory context */
3291 358 : old_cxt = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
3292 :
3293 : /* prepare map from old to new attribute numbers */
3294 358 : op->d.convert_rowtype.map = convert_tuples_by_name(indesc, outdesc);
3295 :
3296 358 : MemoryContextSwitchTo(old_cxt);
3297 : }
3298 :
3299 : /* Following steps need a HeapTuple not a bare HeapTupleHeader */
3300 12006 : tmptup.t_len = HeapTupleHeaderGetDatumLength(tuple);
3301 12006 : tmptup.t_data = tuple;
3302 :
3303 12006 : if (op->d.convert_rowtype.map != NULL)
3304 : {
3305 : /* Full conversion with attribute rearrangement needed */
3306 572 : result = execute_attr_map_tuple(&tmptup, op->d.convert_rowtype.map);
3307 : /* Result already has appropriate composite-datum header fields */
3308 572 : *op->resvalue = HeapTupleGetDatum(result);
3309 : }
3310 : else
3311 : {
3312 : /*
3313 : * The tuple is physically compatible as-is, but we need to insert the
3314 : * destination rowtype OID in its composite-datum header field, so we
3315 : * have to copy it anyway. heap_copy_tuple_as_datum() is convenient
3316 : * for this since it will both make the physical copy and insert the
3317 : * correct composite header fields. Note that we aren't expecting to
3318 : * have to flatten any toasted fields: the input was a composite
3319 : * datum, so it shouldn't contain any. So heap_copy_tuple_as_datum()
3320 : * is overkill here, but its check for external fields is cheap.
3321 : */
3322 11434 : *op->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc);
3323 : }
3324 :
3325 12006 : DecrTupleDescRefCount(indesc);
3326 12006 : DecrTupleDescRefCount(outdesc);
3327 : }
3328 :
3329 : /*
3330 : * Evaluate "scalar op ANY/ALL (array)".
3331 : *
3332 : * Source array is in our result area, scalar arg is already evaluated into
3333 : * fcinfo->args[0].
3334 : *
3335 : * The operator always yields boolean, and we combine the results across all
3336 : * array elements using OR and AND (for ANY and ALL respectively). Of course
3337 : * we short-circuit as soon as the result is known.
3338 : */
3339 : void
3340 4618750 : ExecEvalScalarArrayOp(ExprState *state, ExprEvalStep *op)
3341 : {
3342 4618750 : FunctionCallInfo fcinfo = op->d.scalararrayop.fcinfo_data;
3343 4618750 : bool useOr = op->d.scalararrayop.useOr;
3344 4618750 : bool strictfunc = op->d.scalararrayop.finfo->fn_strict;
3345 : ArrayType *arr;
3346 : int nitems;
3347 : Datum result;
3348 : bool resultnull;
3349 : int16 typlen;
3350 : bool typbyval;
3351 : char typalign;
3352 : char *s;
3353 : bits8 *bitmap;
3354 : int bitmask;
3355 :
3356 : /*
3357 : * If the array is NULL then we return NULL --- it's not very meaningful
3358 : * to do anything else, even if the operator isn't strict.
3359 : */
3360 4618750 : if (*op->resnull)
3361 117962 : return;
3362 :
3363 : /* Else okay to fetch and detoast the array */
3364 4500788 : arr = DatumGetArrayTypeP(*op->resvalue);
3365 :
3366 : /*
3367 : * If the array is empty, we return either FALSE or TRUE per the useOr
3368 : * flag. This is correct even if the scalar is NULL; since we would
3369 : * evaluate the operator zero times, it matters not whether it would want
3370 : * to return NULL.
3371 : */
3372 4500788 : nitems = ArrayGetNItems(ARR_NDIM(arr), ARR_DIMS(arr));
3373 4500788 : if (nitems <= 0)
3374 : {
3375 12250 : *op->resvalue = BoolGetDatum(!useOr);
3376 12250 : *op->resnull = false;
3377 12250 : return;
3378 : }
3379 :
3380 : /*
3381 : * If the scalar is NULL, and the function is strict, return NULL; no
3382 : * point in iterating the loop.
3383 : */
3384 4488538 : if (fcinfo->args[0].isnull && strictfunc)
3385 : {
3386 980 : *op->resnull = true;
3387 980 : return;
3388 : }
3389 :
3390 : /*
3391 : * We arrange to look up info about the element type only once per series
3392 : * of calls, assuming the element type doesn't change underneath us.
3393 : */
3394 4487558 : if (op->d.scalararrayop.element_type != ARR_ELEMTYPE(arr))
3395 : {
3396 20052 : get_typlenbyvalalign(ARR_ELEMTYPE(arr),
3397 : &op->d.scalararrayop.typlen,
3398 : &op->d.scalararrayop.typbyval,
3399 : &op->d.scalararrayop.typalign);
3400 20052 : op->d.scalararrayop.element_type = ARR_ELEMTYPE(arr);
3401 : }
3402 :
3403 4487558 : typlen = op->d.scalararrayop.typlen;
3404 4487558 : typbyval = op->d.scalararrayop.typbyval;
3405 4487558 : typalign = op->d.scalararrayop.typalign;
3406 :
3407 : /* Initialize result appropriately depending on useOr */
3408 4487558 : result = BoolGetDatum(!useOr);
3409 4487558 : resultnull = false;
3410 :
3411 : /* Loop over the array elements */
3412 4487558 : s = (char *) ARR_DATA_PTR(arr);
3413 4487558 : bitmap = ARR_NULLBITMAP(arr);
3414 4487558 : bitmask = 1;
3415 :
3416 11816820 : for (int i = 0; i < nitems; i++)
3417 : {
3418 : Datum elt;
3419 : Datum thisresult;
3420 :
3421 : /* Get array element, checking for NULL */
3422 9526672 : if (bitmap && (*bitmap & bitmask) == 0)
3423 : {
3424 215264 : fcinfo->args[1].value = (Datum) 0;
3425 215264 : fcinfo->args[1].isnull = true;
3426 : }
3427 : else
3428 : {
3429 9311408 : elt = fetch_att(s, typbyval, typlen);
3430 9311408 : s = att_addlength_pointer(s, typlen, s);
3431 9311408 : s = (char *) att_align_nominal(s, typalign);
3432 9311408 : fcinfo->args[1].value = elt;
3433 9311408 : fcinfo->args[1].isnull = false;
3434 : }
3435 :
3436 : /* Call comparison function */
3437 9526672 : if (fcinfo->args[1].isnull && strictfunc)
3438 : {
3439 215240 : fcinfo->isnull = true;
3440 215240 : thisresult = (Datum) 0;
3441 : }
3442 : else
3443 : {
3444 9311432 : fcinfo->isnull = false;
3445 9311432 : thisresult = op->d.scalararrayop.fn_addr(fcinfo);
3446 : }
3447 :
3448 : /* Combine results per OR or AND semantics */
3449 9526672 : if (fcinfo->isnull)
3450 215336 : resultnull = true;
3451 9311336 : else if (useOr)
3452 : {
3453 8531524 : if (DatumGetBool(thisresult))
3454 : {
3455 1628698 : result = BoolGetDatum(true);
3456 1628698 : resultnull = false;
3457 1628698 : break; /* needn't look at any more elements */
3458 : }
3459 : }
3460 : else
3461 : {
3462 779812 : if (!DatumGetBool(thisresult))
3463 : {
3464 568712 : result = BoolGetDatum(false);
3465 568712 : resultnull = false;
3466 568712 : break; /* needn't look at any more elements */
3467 : }
3468 : }
3469 :
3470 : /* advance bitmap pointer if any */
3471 7329262 : if (bitmap)
3472 : {
3473 767988 : bitmask <<= 1;
3474 767988 : if (bitmask == 0x100)
3475 : {
3476 776 : bitmap++;
3477 776 : bitmask = 1;
3478 : }
3479 : }
3480 : }
3481 :
3482 4487558 : *op->resvalue = result;
3483 4487558 : *op->resnull = resultnull;
3484 : }
3485 :
3486 : /*
3487 : * Hash function for scalar array hash op elements.
3488 : *
3489 : * We use the element type's default hash opclass, and the column collation
3490 : * if the type is collation-sensitive.
3491 : */
3492 : static uint32
3493 6438 : saop_element_hash(struct saophash_hash *tb, Datum key)
3494 : {
3495 6438 : ScalarArrayOpExprHashTable *elements_tab = (ScalarArrayOpExprHashTable *) tb->private_data;
3496 6438 : FunctionCallInfo fcinfo = &elements_tab->hash_fcinfo_data;
3497 : Datum hash;
3498 :
3499 6438 : fcinfo->args[0].value = key;
3500 6438 : fcinfo->args[0].isnull = false;
3501 :
3502 6438 : hash = elements_tab->hash_finfo.fn_addr(fcinfo);
3503 :
3504 6438 : return DatumGetUInt32(hash);
3505 : }
3506 :
3507 : /*
3508 : * Matching function for scalar array hash op elements, to be used in hashtable
3509 : * lookups.
3510 : */
3511 : static bool
3512 4386 : saop_hash_element_match(struct saophash_hash *tb, Datum key1, Datum key2)
3513 : {
3514 : Datum result;
3515 :
3516 4386 : ScalarArrayOpExprHashTable *elements_tab = (ScalarArrayOpExprHashTable *) tb->private_data;
3517 4386 : FunctionCallInfo fcinfo = elements_tab->op->d.hashedscalararrayop.fcinfo_data;
3518 :
3519 4386 : fcinfo->args[0].value = key1;
3520 4386 : fcinfo->args[0].isnull = false;
3521 4386 : fcinfo->args[1].value = key2;
3522 4386 : fcinfo->args[1].isnull = false;
3523 :
3524 4386 : result = elements_tab->op->d.hashedscalararrayop.finfo->fn_addr(fcinfo);
3525 :
3526 4386 : return DatumGetBool(result);
3527 : }
3528 :
3529 : /*
3530 : * Evaluate "scalar op ANY (const array)".
3531 : *
3532 : * Similar to ExecEvalScalarArrayOp, but optimized for faster repeat lookups
3533 : * by building a hashtable on the first lookup. This hashtable will be reused
3534 : * by subsequent lookups. Unlike ExecEvalScalarArrayOp, this version only
3535 : * supports OR semantics.
3536 : *
3537 : * Source array is in our result area, scalar arg is already evaluated into
3538 : * fcinfo->args[0].
3539 : *
3540 : * The operator always yields boolean.
3541 : */
3542 : void
3543 4598 : ExecEvalHashedScalarArrayOp(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
3544 : {
3545 4598 : ScalarArrayOpExprHashTable *elements_tab = op->d.hashedscalararrayop.elements_tab;
3546 4598 : FunctionCallInfo fcinfo = op->d.hashedscalararrayop.fcinfo_data;
3547 4598 : bool inclause = op->d.hashedscalararrayop.inclause;
3548 4598 : bool strictfunc = op->d.hashedscalararrayop.finfo->fn_strict;
3549 4598 : Datum scalar = fcinfo->args[0].value;
3550 4598 : bool scalar_isnull = fcinfo->args[0].isnull;
3551 : Datum result;
3552 : bool resultnull;
3553 : bool hashfound;
3554 :
3555 : /* We don't setup a hashed scalar array op if the array const is null. */
3556 : Assert(!*op->resnull);
3557 :
3558 : /*
3559 : * If the scalar is NULL, and the function is strict, return NULL; no
3560 : * point in executing the search.
3561 : */
3562 4598 : if (fcinfo->args[0].isnull && strictfunc)
3563 : {
3564 68 : *op->resnull = true;
3565 68 : return;
3566 : }
3567 :
3568 : /* Build the hash table on first evaluation */
3569 4530 : if (elements_tab == NULL)
3570 : {
3571 : ScalarArrayOpExpr *saop;
3572 : int16 typlen;
3573 : bool typbyval;
3574 : char typalign;
3575 : int nitems;
3576 152 : bool has_nulls = false;
3577 : char *s;
3578 : bits8 *bitmap;
3579 : int bitmask;
3580 : MemoryContext oldcontext;
3581 : ArrayType *arr;
3582 :
3583 152 : saop = op->d.hashedscalararrayop.saop;
3584 :
3585 152 : arr = DatumGetArrayTypeP(*op->resvalue);
3586 152 : nitems = ArrayGetNItems(ARR_NDIM(arr), ARR_DIMS(arr));
3587 :
3588 152 : get_typlenbyvalalign(ARR_ELEMTYPE(arr),
3589 : &typlen,
3590 : &typbyval,
3591 : &typalign);
3592 :
3593 152 : oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
3594 :
3595 : elements_tab = (ScalarArrayOpExprHashTable *)
3596 152 : palloc0(offsetof(ScalarArrayOpExprHashTable, hash_fcinfo_data) +
3597 : SizeForFunctionCallInfo(1));
3598 152 : op->d.hashedscalararrayop.elements_tab = elements_tab;
3599 152 : elements_tab->op = op;
3600 :
3601 152 : fmgr_info(saop->hashfuncid, &elements_tab->hash_finfo);
3602 152 : fmgr_info_set_expr((Node *) saop, &elements_tab->hash_finfo);
3603 :
3604 152 : InitFunctionCallInfoData(elements_tab->hash_fcinfo_data,
3605 : &elements_tab->hash_finfo,
3606 : 1,
3607 : saop->inputcollid,
3608 : NULL,
3609 : NULL);
3610 :
3611 : /*
3612 : * Create the hash table sizing it according to the number of elements
3613 : * in the array. This does assume that the array has no duplicates.
3614 : * If the array happens to contain many duplicate values then it'll
3615 : * just mean that we sized the table a bit on the large side.
3616 : */
3617 152 : elements_tab->hashtab = saophash_create(CurrentMemoryContext, nitems,
3618 : elements_tab);
3619 :
3620 152 : MemoryContextSwitchTo(oldcontext);
3621 :
3622 152 : s = (char *) ARR_DATA_PTR(arr);
3623 152 : bitmap = ARR_NULLBITMAP(arr);
3624 152 : bitmask = 1;
3625 2234 : for (int i = 0; i < nitems; i++)
3626 : {
3627 : /* Get array element, checking for NULL. */
3628 2082 : if (bitmap && (*bitmap & bitmask) == 0)
3629 : {
3630 174 : has_nulls = true;
3631 : }
3632 : else
3633 : {
3634 : Datum element;
3635 :
3636 1908 : element = fetch_att(s, typbyval, typlen);
3637 1908 : s = att_addlength_pointer(s, typlen, s);
3638 1908 : s = (char *) att_align_nominal(s, typalign);
3639 :
3640 1908 : saophash_insert(elements_tab->hashtab, element, &hashfound);
3641 : }
3642 :
3643 : /* Advance bitmap pointer if any. */
3644 2082 : if (bitmap)
3645 : {
3646 570 : bitmask <<= 1;
3647 570 : if (bitmask == 0x100)
3648 : {
3649 54 : bitmap++;
3650 54 : bitmask = 1;
3651 : }
3652 : }
3653 : }
3654 :
3655 : /*
3656 : * Remember if we had any nulls so that we know if we need to execute
3657 : * non-strict functions with a null lhs value if no match is found.
3658 : */
3659 152 : op->d.hashedscalararrayop.has_nulls = has_nulls;
3660 : }
3661 :
3662 : /* Check the hash to see if we have a match. */
3663 4530 : hashfound = NULL != saophash_lookup(elements_tab->hashtab, scalar);
3664 :
3665 : /* the result depends on if the clause is an IN or NOT IN clause */
3666 4530 : if (inclause)
3667 854 : result = BoolGetDatum(hashfound); /* IN */
3668 : else
3669 3676 : result = BoolGetDatum(!hashfound); /* NOT IN */
3670 :
3671 4530 : resultnull = false;
3672 :
3673 : /*
3674 : * If we didn't find a match in the array, we still might need to handle
3675 : * the possibility of null values. We didn't put any NULLs into the
3676 : * hashtable, but instead marked if we found any when building the table
3677 : * in has_nulls.
3678 : */
3679 4530 : if (!hashfound && op->d.hashedscalararrayop.has_nulls)
3680 : {
3681 42 : if (strictfunc)
3682 : {
3683 :
3684 : /*
3685 : * We have nulls in the array so a non-null lhs and no match must
3686 : * yield NULL.
3687 : */
3688 24 : result = (Datum) 0;
3689 24 : resultnull = true;
3690 : }
3691 : else
3692 : {
3693 : /*
3694 : * Execute function will null rhs just once.
3695 : *
3696 : * The hash lookup path will have scribbled on the lhs argument so
3697 : * we need to set it up also (even though we entered this function
3698 : * with it already set).
3699 : */
3700 18 : fcinfo->args[0].value = scalar;
3701 18 : fcinfo->args[0].isnull = scalar_isnull;
3702 18 : fcinfo->args[1].value = (Datum) 0;
3703 18 : fcinfo->args[1].isnull = true;
3704 :
3705 18 : result = op->d.hashedscalararrayop.finfo->fn_addr(fcinfo);
3706 18 : resultnull = fcinfo->isnull;
3707 :
3708 : /*
3709 : * Reverse the result for NOT IN clauses since the above function
3710 : * is the equality function and we need not-equals.
3711 : */
3712 18 : if (!inclause)
3713 12 : result = !result;
3714 : }
3715 : }
3716 :
3717 4530 : *op->resvalue = result;
3718 4530 : *op->resnull = resultnull;
3719 : }
3720 :
3721 : /*
3722 : * Evaluate a NOT NULL domain constraint.
3723 : */
3724 : void
3725 360 : ExecEvalConstraintNotNull(ExprState *state, ExprEvalStep *op)
3726 : {
3727 360 : if (*op->resnull)
3728 94 : ereport(ERROR,
3729 : (errcode(ERRCODE_NOT_NULL_VIOLATION),
3730 : errmsg("domain %s does not allow null values",
3731 : format_type_be(op->d.domaincheck.resulttype)),
3732 : errdatatype(op->d.domaincheck.resulttype)));
3733 266 : }
3734 :
3735 : /*
3736 : * Evaluate a CHECK domain constraint.
3737 : */
3738 : void
3739 52534 : ExecEvalConstraintCheck(ExprState *state, ExprEvalStep *op)
3740 : {
3741 52534 : if (!*op->d.domaincheck.checknull &&
3742 45808 : !DatumGetBool(*op->d.domaincheck.checkvalue))
3743 368 : ereport(ERROR,
3744 : (errcode(ERRCODE_CHECK_VIOLATION),
3745 : errmsg("value for domain %s violates check constraint \"%s\"",
3746 : format_type_be(op->d.domaincheck.resulttype),
3747 : op->d.domaincheck.constraintname),
3748 : errdomainconstraint(op->d.domaincheck.resulttype,
3749 : op->d.domaincheck.constraintname)));
3750 52166 : }
3751 :
3752 : /*
3753 : * Evaluate the various forms of XmlExpr.
3754 : *
3755 : * Arguments have been evaluated into named_argvalue/named_argnull
3756 : * and/or argvalue/argnull arrays.
3757 : */
3758 : void
3759 43114 : ExecEvalXmlExpr(ExprState *state, ExprEvalStep *op)
3760 : {
3761 43114 : XmlExpr *xexpr = op->d.xmlexpr.xexpr;
3762 : Datum value;
3763 :
3764 43114 : *op->resnull = true; /* until we get a result */
3765 43114 : *op->resvalue = (Datum) 0;
3766 :
3767 43114 : switch (xexpr->op)
3768 : {
3769 54 : case IS_XMLCONCAT:
3770 : {
3771 54 : Datum *argvalue = op->d.xmlexpr.argvalue;
3772 54 : bool *argnull = op->d.xmlexpr.argnull;
3773 54 : List *values = NIL;
3774 :
3775 174 : for (int i = 0; i < list_length(xexpr->args); i++)
3776 : {
3777 120 : if (!argnull[i])
3778 90 : values = lappend(values, DatumGetPointer(argvalue[i]));
3779 : }
3780 :
3781 54 : if (values != NIL)
3782 : {
3783 42 : *op->resvalue = PointerGetDatum(xmlconcat(values));
3784 42 : *op->resnull = false;
3785 : }
3786 : }
3787 54 : break;
3788 :
3789 21218 : case IS_XMLFOREST:
3790 : {
3791 21218 : Datum *argvalue = op->d.xmlexpr.named_argvalue;
3792 21218 : bool *argnull = op->d.xmlexpr.named_argnull;
3793 : StringInfoData buf;
3794 : ListCell *lc;
3795 : ListCell *lc2;
3796 : int i;
3797 :
3798 21218 : initStringInfo(&buf);
3799 :
3800 21218 : i = 0;
3801 148406 : forboth(lc, xexpr->named_args, lc2, xexpr->arg_names)
3802 : {
3803 127188 : Expr *e = (Expr *) lfirst(lc);
3804 127188 : char *argname = strVal(lfirst(lc2));
3805 :
3806 127188 : if (!argnull[i])
3807 : {
3808 105966 : value = argvalue[i];
3809 105966 : appendStringInfo(&buf, "<%s>%s</%s>",
3810 : argname,
3811 : map_sql_value_to_xml_value(value,
3812 : exprType((Node *) e), true),
3813 : argname);
3814 105966 : *op->resnull = false;
3815 : }
3816 127188 : i++;
3817 : }
3818 :
3819 21218 : if (!*op->resnull)
3820 : {
3821 : text *result;
3822 :
3823 21218 : result = cstring_to_text_with_len(buf.data, buf.len);
3824 21218 : *op->resvalue = PointerGetDatum(result);
3825 : }
3826 :
3827 21218 : pfree(buf.data);
3828 : }
3829 21218 : break;
3830 :
3831 21374 : case IS_XMLELEMENT:
3832 21374 : *op->resvalue = PointerGetDatum(xmlelement(xexpr,
3833 : op->d.xmlexpr.named_argvalue,
3834 : op->d.xmlexpr.named_argnull,
3835 : op->d.xmlexpr.argvalue,
3836 : op->d.xmlexpr.argnull));
3837 21368 : *op->resnull = false;
3838 21368 : break;
3839 :
3840 132 : case IS_XMLPARSE:
3841 : {
3842 132 : Datum *argvalue = op->d.xmlexpr.argvalue;
3843 132 : bool *argnull = op->d.xmlexpr.argnull;
3844 : text *data;
3845 : bool preserve_whitespace;
3846 :
3847 : /* arguments are known to be text, bool */
3848 : Assert(list_length(xexpr->args) == 2);
3849 :
3850 132 : if (argnull[0])
3851 0 : return;
3852 132 : value = argvalue[0];
3853 132 : data = DatumGetTextPP(value);
3854 :
3855 132 : if (argnull[1]) /* probably can't happen */
3856 0 : return;
3857 132 : value = argvalue[1];
3858 132 : preserve_whitespace = DatumGetBool(value);
3859 :
3860 132 : *op->resvalue = PointerGetDatum(xmlparse(data,
3861 : xexpr->xmloption,
3862 : preserve_whitespace));
3863 84 : *op->resnull = false;
3864 : }
3865 84 : break;
3866 :
3867 72 : case IS_XMLPI:
3868 : {
3869 : text *arg;
3870 : bool isnull;
3871 :
3872 : /* optional argument is known to be text */
3873 : Assert(list_length(xexpr->args) <= 1);
3874 :
3875 72 : if (xexpr->args)
3876 : {
3877 42 : isnull = op->d.xmlexpr.argnull[0];
3878 42 : if (isnull)
3879 18 : arg = NULL;
3880 : else
3881 24 : arg = DatumGetTextPP(op->d.xmlexpr.argvalue[0]);
3882 : }
3883 : else
3884 : {
3885 30 : arg = NULL;
3886 30 : isnull = false;
3887 : }
3888 :
3889 72 : *op->resvalue = PointerGetDatum(xmlpi(xexpr->name,
3890 : arg,
3891 : isnull,
3892 : op->resnull));
3893 : }
3894 54 : break;
3895 :
3896 60 : case IS_XMLROOT:
3897 : {
3898 60 : Datum *argvalue = op->d.xmlexpr.argvalue;
3899 60 : bool *argnull = op->d.xmlexpr.argnull;
3900 : xmltype *data;
3901 : text *version;
3902 : int standalone;
3903 :
3904 : /* arguments are known to be xml, text, int */
3905 : Assert(list_length(xexpr->args) == 3);
3906 :
3907 60 : if (argnull[0])
3908 0 : return;
3909 60 : data = DatumGetXmlP(argvalue[0]);
3910 :
3911 60 : if (argnull[1])
3912 36 : version = NULL;
3913 : else
3914 24 : version = DatumGetTextPP(argvalue[1]);
3915 :
3916 : Assert(!argnull[2]); /* always present */
3917 60 : standalone = DatumGetInt32(argvalue[2]);
3918 :
3919 60 : *op->resvalue = PointerGetDatum(xmlroot(data,
3920 : version,
3921 : standalone));
3922 60 : *op->resnull = false;
3923 : }
3924 60 : break;
3925 :
3926 180 : case IS_XMLSERIALIZE:
3927 : {
3928 180 : Datum *argvalue = op->d.xmlexpr.argvalue;
3929 180 : bool *argnull = op->d.xmlexpr.argnull;
3930 :
3931 : /* argument type is known to be xml */
3932 : Assert(list_length(xexpr->args) == 1);
3933 :
3934 180 : if (argnull[0])
3935 12 : return;
3936 168 : value = argvalue[0];
3937 :
3938 276 : *op->resvalue =
3939 168 : PointerGetDatum(xmltotext_with_options(DatumGetXmlP(value),
3940 : xexpr->xmloption,
3941 168 : xexpr->indent));
3942 138 : *op->resnull = false;
3943 : }
3944 138 : break;
3945 :
3946 24 : case IS_DOCUMENT:
3947 : {
3948 24 : Datum *argvalue = op->d.xmlexpr.argvalue;
3949 24 : bool *argnull = op->d.xmlexpr.argnull;
3950 :
3951 : /* optional argument is known to be xml */
3952 : Assert(list_length(xexpr->args) == 1);
3953 :
3954 24 : if (argnull[0])
3955 0 : return;
3956 24 : value = argvalue[0];
3957 :
3958 48 : *op->resvalue =
3959 24 : BoolGetDatum(xml_is_document(DatumGetXmlP(value)));
3960 24 : *op->resnull = false;
3961 : }
3962 24 : break;
3963 :
3964 0 : default:
3965 0 : elog(ERROR, "unrecognized XML operation");
3966 : break;
3967 : }
3968 : }
3969 :
3970 : /*
3971 : * Evaluate a JSON constructor expression.
3972 : */
3973 : void
3974 496 : ExecEvalJsonConstructor(ExprState *state, ExprEvalStep *op,
3975 : ExprContext *econtext)
3976 : {
3977 : Datum res;
3978 496 : JsonConstructorExprState *jcstate = op->d.json_constructor.jcstate;
3979 496 : JsonConstructorExpr *ctor = jcstate->constructor;
3980 496 : bool is_jsonb = ctor->returning->format->format_type == JS_FORMAT_JSONB;
3981 496 : bool isnull = false;
3982 :
3983 496 : if (ctor->type == JSCTOR_JSON_ARRAY)
3984 : res = (is_jsonb ?
3985 176 : jsonb_build_array_worker :
3986 : json_build_array_worker) (jcstate->nargs,
3987 : jcstate->arg_values,
3988 : jcstate->arg_nulls,
3989 : jcstate->arg_types,
3990 176 : jcstate->constructor->absent_on_null);
3991 320 : else if (ctor->type == JSCTOR_JSON_OBJECT)
3992 : res = (is_jsonb ?
3993 320 : jsonb_build_object_worker :
3994 : json_build_object_worker) (jcstate->nargs,
3995 : jcstate->arg_values,
3996 : jcstate->arg_nulls,
3997 : jcstate->arg_types,
3998 320 : jcstate->constructor->absent_on_null,
3999 320 : jcstate->constructor->unique);
4000 : else
4001 0 : elog(ERROR, "invalid JsonConstructorExpr type %d", ctor->type);
4002 :
4003 432 : *op->resvalue = res;
4004 432 : *op->resnull = isnull;
4005 432 : }
4006 :
4007 : /*
4008 : * Evaluate a IS JSON predicate.
4009 : */
4010 : void
4011 2714 : ExecEvalJsonIsPredicate(ExprState *state, ExprEvalStep *op)
4012 : {
4013 2714 : JsonIsPredicate *pred = op->d.is_json.pred;
4014 2714 : Datum js = *op->resvalue;
4015 : Oid exprtype;
4016 : bool res;
4017 :
4018 2714 : if (*op->resnull)
4019 : {
4020 102 : *op->resvalue = BoolGetDatum(false);
4021 102 : return;
4022 : }
4023 :
4024 2612 : exprtype = exprType(pred->expr);
4025 :
4026 2612 : if (exprtype == TEXTOID || exprtype == JSONOID)
4027 2084 : {
4028 2084 : text *json = DatumGetTextP(js);
4029 :
4030 2084 : if (pred->item_type == JS_TYPE_ANY)
4031 1406 : res = true;
4032 : else
4033 : {
4034 678 : switch (json_get_first_token(json, false))
4035 : {
4036 300 : case JSON_TOKEN_OBJECT_START:
4037 300 : res = pred->item_type == JS_TYPE_OBJECT;
4038 300 : break;
4039 126 : case JSON_TOKEN_ARRAY_START:
4040 126 : res = pred->item_type == JS_TYPE_ARRAY;
4041 126 : break;
4042 216 : case JSON_TOKEN_STRING:
4043 : case JSON_TOKEN_NUMBER:
4044 : case JSON_TOKEN_TRUE:
4045 : case JSON_TOKEN_FALSE:
4046 : case JSON_TOKEN_NULL:
4047 216 : res = pred->item_type == JS_TYPE_SCALAR;
4048 216 : break;
4049 36 : default:
4050 36 : res = false;
4051 36 : break;
4052 : }
4053 : }
4054 :
4055 : /*
4056 : * Do full parsing pass only for uniqueness check or for JSON text
4057 : * validation.
4058 : */
4059 2084 : if (res && (pred->unique_keys || exprtype == TEXTOID))
4060 1290 : res = json_validate(json, pred->unique_keys, false);
4061 : }
4062 528 : else if (exprtype == JSONBOID)
4063 : {
4064 528 : if (pred->item_type == JS_TYPE_ANY)
4065 330 : res = true;
4066 : else
4067 : {
4068 198 : Jsonb *jb = DatumGetJsonbP(js);
4069 :
4070 198 : switch (pred->item_type)
4071 : {
4072 66 : case JS_TYPE_OBJECT:
4073 66 : res = JB_ROOT_IS_OBJECT(jb);
4074 66 : break;
4075 66 : case JS_TYPE_ARRAY:
4076 66 : res = JB_ROOT_IS_ARRAY(jb) && !JB_ROOT_IS_SCALAR(jb);
4077 66 : break;
4078 66 : case JS_TYPE_SCALAR:
4079 66 : res = JB_ROOT_IS_ARRAY(jb) && JB_ROOT_IS_SCALAR(jb);
4080 66 : break;
4081 0 : default:
4082 0 : res = false;
4083 0 : break;
4084 : }
4085 : }
4086 :
4087 : /* Key uniqueness check is redundant for jsonb */
4088 : }
4089 : else
4090 0 : res = false;
4091 :
4092 2612 : *op->resvalue = BoolGetDatum(res);
4093 : }
4094 :
4095 :
4096 : /*
4097 : * ExecEvalGroupingFunc
4098 : *
4099 : * Computes a bitmask with a bit for each (unevaluated) argument expression
4100 : * (rightmost arg is least significant bit).
4101 : *
4102 : * A bit is set if the corresponding expression is NOT part of the set of
4103 : * grouping expressions in the current grouping set.
4104 : */
4105 : void
4106 1688 : ExecEvalGroupingFunc(ExprState *state, ExprEvalStep *op)
4107 : {
4108 1688 : AggState *aggstate = castNode(AggState, state->parent);
4109 1688 : int result = 0;
4110 1688 : Bitmapset *grouped_cols = aggstate->grouped_cols;
4111 : ListCell *lc;
4112 :
4113 4178 : foreach(lc, op->d.grouping_func.clauses)
4114 : {
4115 2490 : int attnum = lfirst_int(lc);
4116 :
4117 2490 : result <<= 1;
4118 :
4119 2490 : if (!bms_is_member(attnum, grouped_cols))
4120 972 : result |= 1;
4121 : }
4122 :
4123 1688 : *op->resvalue = Int32GetDatum(result);
4124 1688 : *op->resnull = false;
4125 1688 : }
4126 :
4127 : /*
4128 : * Hand off evaluation of a subplan to nodeSubplan.c
4129 : */
4130 : void
4131 2274008 : ExecEvalSubPlan(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
4132 : {
4133 2274008 : SubPlanState *sstate = op->d.subplan.sstate;
4134 :
4135 : /* could potentially be nested, so make sure there's enough stack */
4136 2274008 : check_stack_depth();
4137 :
4138 2274008 : *op->resvalue = ExecSubPlan(sstate, econtext, op->resnull);
4139 2274002 : }
4140 :
4141 : /*
4142 : * Evaluate a wholerow Var expression.
4143 : *
4144 : * Returns a Datum whose value is the value of a whole-row range variable
4145 : * with respect to given expression context.
4146 : */
4147 : void
4148 37798 : ExecEvalWholeRowVar(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
4149 : {
4150 37798 : Var *variable = op->d.wholerow.var;
4151 : TupleTableSlot *slot;
4152 : TupleDesc output_tupdesc;
4153 : MemoryContext oldcontext;
4154 : HeapTupleHeader dtuple;
4155 : HeapTuple tuple;
4156 :
4157 : /* This was checked by ExecInitExpr */
4158 : Assert(variable->varattno == InvalidAttrNumber);
4159 :
4160 : /* Get the input slot we want */
4161 37798 : switch (variable->varno)
4162 : {
4163 90 : case INNER_VAR:
4164 : /* get the tuple from the inner node */
4165 90 : slot = econtext->ecxt_innertuple;
4166 90 : break;
4167 :
4168 18 : case OUTER_VAR:
4169 : /* get the tuple from the outer node */
4170 18 : slot = econtext->ecxt_outertuple;
4171 18 : break;
4172 :
4173 : /* INDEX_VAR is handled by default case */
4174 :
4175 37690 : default:
4176 : /* get the tuple from the relation being scanned */
4177 37690 : slot = econtext->ecxt_scantuple;
4178 37690 : break;
4179 : }
4180 :
4181 : /* Apply the junkfilter if any */
4182 37798 : if (op->d.wholerow.junkFilter != NULL)
4183 60 : slot = ExecFilterJunk(op->d.wholerow.junkFilter, slot);
4184 :
4185 : /*
4186 : * If first time through, obtain tuple descriptor and check compatibility.
4187 : *
4188 : * XXX: It'd be great if this could be moved to the expression
4189 : * initialization phase, but due to using slots that's currently not
4190 : * feasible.
4191 : */
4192 37798 : if (op->d.wholerow.first)
4193 : {
4194 : /* optimistically assume we don't need slow path */
4195 2308 : op->d.wholerow.slow = false;
4196 :
4197 : /*
4198 : * If the Var identifies a named composite type, we must check that
4199 : * the actual tuple type is compatible with it.
4200 : */
4201 2308 : if (variable->vartype != RECORDOID)
4202 : {
4203 : TupleDesc var_tupdesc;
4204 : TupleDesc slot_tupdesc;
4205 :
4206 : /*
4207 : * We really only care about numbers of attributes and data types.
4208 : * Also, we can ignore type mismatch on columns that are dropped
4209 : * in the destination type, so long as (1) the physical storage
4210 : * matches or (2) the actual column value is NULL. Case (1) is
4211 : * helpful in some cases involving out-of-date cached plans, while
4212 : * case (2) is expected behavior in situations such as an INSERT
4213 : * into a table with dropped columns (the planner typically
4214 : * generates an INT4 NULL regardless of the dropped column type).
4215 : * If we find a dropped column and cannot verify that case (1)
4216 : * holds, we have to use the slow path to check (2) for each row.
4217 : *
4218 : * If vartype is a domain over composite, just look through that
4219 : * to the base composite type.
4220 : */
4221 1432 : var_tupdesc = lookup_rowtype_tupdesc_domain(variable->vartype,
4222 : -1, false);
4223 :
4224 1432 : slot_tupdesc = slot->tts_tupleDescriptor;
4225 :
4226 1432 : if (var_tupdesc->natts != slot_tupdesc->natts)
4227 0 : ereport(ERROR,
4228 : (errcode(ERRCODE_DATATYPE_MISMATCH),
4229 : errmsg("table row type and query-specified row type do not match"),
4230 : errdetail_plural("Table row contains %d attribute, but query expects %d.",
4231 : "Table row contains %d attributes, but query expects %d.",
4232 : slot_tupdesc->natts,
4233 : slot_tupdesc->natts,
4234 : var_tupdesc->natts)));
4235 :
4236 5788 : for (int i = 0; i < var_tupdesc->natts; i++)
4237 : {
4238 4356 : Form_pg_attribute vattr = TupleDescAttr(var_tupdesc, i);
4239 4356 : Form_pg_attribute sattr = TupleDescAttr(slot_tupdesc, i);
4240 :
4241 4356 : if (vattr->atttypid == sattr->atttypid)
4242 4356 : continue; /* no worries */
4243 0 : if (!vattr->attisdropped)
4244 0 : ereport(ERROR,
4245 : (errcode(ERRCODE_DATATYPE_MISMATCH),
4246 : errmsg("table row type and query-specified row type do not match"),
4247 : errdetail("Table has type %s at ordinal position %d, but query expects %s.",
4248 : format_type_be(sattr->atttypid),
4249 : i + 1,
4250 : format_type_be(vattr->atttypid))));
4251 :
4252 0 : if (vattr->attlen != sattr->attlen ||
4253 0 : vattr->attalign != sattr->attalign)
4254 0 : op->d.wholerow.slow = true; /* need to check for nulls */
4255 : }
4256 :
4257 : /*
4258 : * Use the variable's declared rowtype as the descriptor for the
4259 : * output values. In particular, we *must* absorb any
4260 : * attisdropped markings.
4261 : */
4262 1432 : oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
4263 1432 : output_tupdesc = CreateTupleDescCopy(var_tupdesc);
4264 1432 : MemoryContextSwitchTo(oldcontext);
4265 :
4266 1432 : ReleaseTupleDesc(var_tupdesc);
4267 : }
4268 : else
4269 : {
4270 : /*
4271 : * In the RECORD case, we use the input slot's rowtype as the
4272 : * descriptor for the output values, modulo possibly assigning new
4273 : * column names below.
4274 : */
4275 876 : oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
4276 876 : output_tupdesc = CreateTupleDescCopy(slot->tts_tupleDescriptor);
4277 876 : MemoryContextSwitchTo(oldcontext);
4278 :
4279 : /*
4280 : * It's possible that the input slot is a relation scan slot and
4281 : * so is marked with that relation's rowtype. But we're supposed
4282 : * to be returning RECORD, so reset to that.
4283 : */
4284 876 : output_tupdesc->tdtypeid = RECORDOID;
4285 876 : output_tupdesc->tdtypmod = -1;
4286 :
4287 : /*
4288 : * We already got the correct physical datatype info above, but
4289 : * now we should try to find the source RTE and adopt its column
4290 : * aliases, since it's unlikely that the input slot has the
4291 : * desired names.
4292 : *
4293 : * If we can't locate the RTE, assume the column names we've got
4294 : * are OK. (As of this writing, the only cases where we can't
4295 : * locate the RTE are in execution of trigger WHEN clauses, and
4296 : * then the Var will have the trigger's relation's rowtype, so its
4297 : * names are fine.) Also, if the creator of the RTE didn't bother
4298 : * to fill in an eref field, assume our column names are OK. (This
4299 : * happens in COPY, and perhaps other places.)
4300 : */
4301 876 : if (econtext->ecxt_estate &&
4302 876 : variable->varno <= econtext->ecxt_estate->es_range_table_size)
4303 : {
4304 876 : RangeTblEntry *rte = exec_rt_fetch(variable->varno,
4305 876 : econtext->ecxt_estate);
4306 :
4307 876 : if (rte->eref)
4308 876 : ExecTypeSetColNames(output_tupdesc, rte->eref->colnames);
4309 : }
4310 : }
4311 :
4312 : /* Bless the tupdesc if needed, and save it in the execution state */
4313 2308 : op->d.wholerow.tupdesc = BlessTupleDesc(output_tupdesc);
4314 :
4315 2308 : op->d.wholerow.first = false;
4316 : }
4317 :
4318 : /*
4319 : * Make sure all columns of the slot are accessible in the slot's
4320 : * Datum/isnull arrays.
4321 : */
4322 37798 : slot_getallattrs(slot);
4323 :
4324 37798 : if (op->d.wholerow.slow)
4325 : {
4326 : /* Check to see if any dropped attributes are non-null */
4327 0 : TupleDesc tupleDesc = slot->tts_tupleDescriptor;
4328 0 : TupleDesc var_tupdesc = op->d.wholerow.tupdesc;
4329 :
4330 : Assert(var_tupdesc->natts == tupleDesc->natts);
4331 :
4332 0 : for (int i = 0; i < var_tupdesc->natts; i++)
4333 : {
4334 0 : Form_pg_attribute vattr = TupleDescAttr(var_tupdesc, i);
4335 0 : Form_pg_attribute sattr = TupleDescAttr(tupleDesc, i);
4336 :
4337 0 : if (!vattr->attisdropped)
4338 0 : continue; /* already checked non-dropped cols */
4339 0 : if (slot->tts_isnull[i])
4340 0 : continue; /* null is always okay */
4341 0 : if (vattr->attlen != sattr->attlen ||
4342 0 : vattr->attalign != sattr->attalign)
4343 0 : ereport(ERROR,
4344 : (errcode(ERRCODE_DATATYPE_MISMATCH),
4345 : errmsg("table row type and query-specified row type do not match"),
4346 : errdetail("Physical storage mismatch on dropped attribute at ordinal position %d.",
4347 : i + 1)));
4348 : }
4349 : }
4350 :
4351 : /*
4352 : * Build a composite datum, making sure any toasted fields get detoasted.
4353 : *
4354 : * (Note: it is critical that we not change the slot's state here.)
4355 : */
4356 37798 : tuple = toast_build_flattened_tuple(slot->tts_tupleDescriptor,
4357 : slot->tts_values,
4358 : slot->tts_isnull);
4359 37798 : dtuple = tuple->t_data;
4360 :
4361 : /*
4362 : * Label the datum with the composite type info we identified before.
4363 : *
4364 : * (Note: we could skip doing this by passing op->d.wholerow.tupdesc to
4365 : * the tuple build step; but that seems a tad risky so let's not.)
4366 : */
4367 37798 : HeapTupleHeaderSetTypeId(dtuple, op->d.wholerow.tupdesc->tdtypeid);
4368 37798 : HeapTupleHeaderSetTypMod(dtuple, op->d.wholerow.tupdesc->tdtypmod);
4369 :
4370 37798 : *op->resvalue = PointerGetDatum(dtuple);
4371 37798 : *op->resnull = false;
4372 37798 : }
4373 :
4374 : void
4375 6147226 : ExecEvalSysVar(ExprState *state, ExprEvalStep *op, ExprContext *econtext,
4376 : TupleTableSlot *slot)
4377 : {
4378 : Datum d;
4379 :
4380 : /* slot_getsysattr has sufficient defenses against bad attnums */
4381 6147226 : d = slot_getsysattr(slot,
4382 : op->d.var.attnum,
4383 : op->resnull);
4384 6147214 : *op->resvalue = d;
4385 : /* this ought to be unreachable, but it's cheap enough to check */
4386 6147214 : if (unlikely(*op->resnull))
4387 0 : elog(ERROR, "failed to fetch attribute from slot");
4388 6147214 : }
4389 :
4390 : /*
4391 : * Transition value has not been initialized. This is the first non-NULL input
4392 : * value for a group. We use it as the initial value for transValue.
4393 : */
4394 : void
4395 60046 : ExecAggInitGroup(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroup,
4396 : ExprContext *aggcontext)
4397 : {
4398 60046 : FunctionCallInfo fcinfo = pertrans->transfn_fcinfo;
4399 : MemoryContext oldContext;
4400 :
4401 : /*
4402 : * We must copy the datum into aggcontext if it is pass-by-ref. We do not
4403 : * need to pfree the old transValue, since it's NULL. (We already checked
4404 : * that the agg's input type is binary-compatible with its transtype, so
4405 : * straight copy here is OK.)
4406 : */
4407 60046 : oldContext = MemoryContextSwitchTo(aggcontext->ecxt_per_tuple_memory);
4408 120092 : pergroup->transValue = datumCopy(fcinfo->args[1].value,
4409 60046 : pertrans->transtypeByVal,
4410 60046 : pertrans->transtypeLen);
4411 60046 : pergroup->transValueIsNull = false;
4412 60046 : pergroup->noTransValue = false;
4413 60046 : MemoryContextSwitchTo(oldContext);
4414 60046 : }
4415 :
4416 : /*
4417 : * Ensure that the new transition value is stored in the aggcontext,
4418 : * rather than the per-tuple context. This should be invoked only when
4419 : * we know (a) the transition data type is pass-by-reference, and (b)
4420 : * the newValue is distinct from the oldValue.
4421 : *
4422 : * NB: This can change the current memory context.
4423 : *
4424 : * We copy the presented newValue into the aggcontext, except when the datum
4425 : * points to a R/W expanded object that is already a child of the aggcontext,
4426 : * in which case we need not copy. We then delete the oldValue, if not null.
4427 : *
4428 : * If the presented datum points to a R/W expanded object that is a child of
4429 : * some other context, ideally we would just reparent it under the aggcontext.
4430 : * Unfortunately, that doesn't work easily, and it wouldn't help anyway for
4431 : * aggregate-aware transfns. We expect that a transfn that deals in expanded
4432 : * objects and is aware of the memory management conventions for aggregate
4433 : * transition values will (1) on first call, return a R/W expanded object that
4434 : * is already in the right context, allowing us to do nothing here, and (2) on
4435 : * subsequent calls, modify and return that same object, so that control
4436 : * doesn't even reach here. However, if we have a generic transfn that
4437 : * returns a new R/W expanded object (probably in the per-tuple context),
4438 : * reparenting that result would cause problems. We'd pass that R/W object to
4439 : * the next invocation of the transfn, and then it would be at liberty to
4440 : * change or delete that object, and if it deletes it then our own attempt to
4441 : * delete the now-old transvalue afterwards would be a double free. We avoid
4442 : * this problem by forcing the stored transvalue to always be a flat
4443 : * non-expanded object unless the transfn is visibly doing aggregate-aware
4444 : * memory management. This is somewhat inefficient, but the best answer to
4445 : * that is to write a smarter transfn.
4446 : */
4447 : Datum
4448 60912 : ExecAggCopyTransValue(AggState *aggstate, AggStatePerTrans pertrans,
4449 : Datum newValue, bool newValueIsNull,
4450 : Datum oldValue, bool oldValueIsNull)
4451 : {
4452 : Assert(newValue != oldValue);
4453 :
4454 60912 : if (!newValueIsNull)
4455 : {
4456 60912 : MemoryContextSwitchTo(aggstate->curaggcontext->ecxt_per_tuple_memory);
4457 61080 : if (DatumIsReadWriteExpandedObject(newValue,
4458 : false,
4459 60906 : pertrans->transtypeLen) &&
4460 168 : MemoryContextGetParent(DatumGetEOHP(newValue)->eoh_context) == CurrentMemoryContext)
4461 : /* do nothing */ ;
4462 : else
4463 60906 : newValue = datumCopy(newValue,
4464 60906 : pertrans->transtypeByVal,
4465 60906 : pertrans->transtypeLen);
4466 : }
4467 : else
4468 : {
4469 : /*
4470 : * Ensure that AggStatePerGroup->transValue ends up being 0, so
4471 : * callers can safely compare newValue/oldValue without having to
4472 : * check their respective nullness.
4473 : */
4474 0 : newValue = (Datum) 0;
4475 : }
4476 :
4477 60912 : if (!oldValueIsNull)
4478 : {
4479 60798 : if (DatumIsReadWriteExpandedObject(oldValue,
4480 : false,
4481 : pertrans->transtypeLen))
4482 0 : DeleteExpandedObject(oldValue);
4483 : else
4484 60798 : pfree(DatumGetPointer(oldValue));
4485 : }
4486 :
4487 60912 : return newValue;
4488 : }
4489 :
4490 : /*
4491 : * ExecEvalPreOrderedDistinctSingle
4492 : * Returns true when the aggregate transition value Datum is distinct
4493 : * from the previous input Datum and returns false when the input Datum
4494 : * matches the previous input Datum.
4495 : */
4496 : bool
4497 365802 : ExecEvalPreOrderedDistinctSingle(AggState *aggstate, AggStatePerTrans pertrans)
4498 : {
4499 365802 : Datum value = pertrans->transfn_fcinfo->args[1].value;
4500 365802 : bool isnull = pertrans->transfn_fcinfo->args[1].isnull;
4501 :
4502 365802 : if (!pertrans->haslast ||
4503 347550 : pertrans->lastisnull != isnull ||
4504 347520 : (!isnull && !DatumGetBool(FunctionCall2Coll(&pertrans->equalfnOne,
4505 : pertrans->aggCollation,
4506 : pertrans->lastdatum, value))))
4507 : {
4508 101908 : if (pertrans->haslast && !pertrans->inputtypeByVal &&
4509 25946 : !pertrans->lastisnull)
4510 25946 : pfree(DatumGetPointer(pertrans->lastdatum));
4511 :
4512 101908 : pertrans->haslast = true;
4513 101908 : if (!isnull)
4514 : {
4515 : MemoryContext oldContext;
4516 :
4517 101872 : oldContext = MemoryContextSwitchTo(aggstate->curaggcontext->ecxt_per_tuple_memory);
4518 :
4519 203744 : pertrans->lastdatum = datumCopy(value, pertrans->inputtypeByVal,
4520 101872 : pertrans->inputtypeLen);
4521 :
4522 101872 : MemoryContextSwitchTo(oldContext);
4523 : }
4524 : else
4525 36 : pertrans->lastdatum = (Datum) 0;
4526 101908 : pertrans->lastisnull = isnull;
4527 101908 : return true;
4528 : }
4529 :
4530 263894 : return false;
4531 : }
4532 :
4533 : /*
4534 : * ExecEvalPreOrderedDistinctMulti
4535 : * Returns true when the aggregate input is distinct from the previous
4536 : * input and returns false when the input matches the previous input.
4537 : */
4538 : bool
4539 708 : ExecEvalPreOrderedDistinctMulti(AggState *aggstate, AggStatePerTrans pertrans)
4540 : {
4541 708 : ExprContext *tmpcontext = aggstate->tmpcontext;
4542 :
4543 2784 : for (int i = 0; i < pertrans->numTransInputs; i++)
4544 : {
4545 2076 : pertrans->sortslot->tts_values[i] = pertrans->transfn_fcinfo->args[i + 1].value;
4546 2076 : pertrans->sortslot->tts_isnull[i] = pertrans->transfn_fcinfo->args[i + 1].isnull;
4547 : }
4548 :
4549 708 : ExecClearTuple(pertrans->sortslot);
4550 708 : pertrans->sortslot->tts_nvalid = pertrans->numInputs;
4551 708 : ExecStoreVirtualTuple(pertrans->sortslot);
4552 :
4553 708 : tmpcontext->ecxt_outertuple = pertrans->sortslot;
4554 708 : tmpcontext->ecxt_innertuple = pertrans->uniqslot;
4555 :
4556 708 : if (!pertrans->haslast ||
4557 624 : !ExecQual(pertrans->equalfnMulti, tmpcontext))
4558 : {
4559 300 : if (pertrans->haslast)
4560 216 : ExecClearTuple(pertrans->uniqslot);
4561 :
4562 300 : pertrans->haslast = true;
4563 300 : ExecCopySlot(pertrans->uniqslot, pertrans->sortslot);
4564 300 : return true;
4565 : }
4566 408 : return false;
4567 : }
4568 :
4569 : /*
4570 : * Invoke ordered transition function, with a datum argument.
4571 : */
4572 : void
4573 824172 : ExecEvalAggOrderedTransDatum(ExprState *state, ExprEvalStep *op,
4574 : ExprContext *econtext)
4575 : {
4576 824172 : AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
4577 824172 : int setno = op->d.agg_trans.setno;
4578 :
4579 824172 : tuplesort_putdatum(pertrans->sortstates[setno],
4580 824172 : *op->resvalue, *op->resnull);
4581 824172 : }
4582 :
4583 : /*
4584 : * Invoke ordered transition function, with a tuple argument.
4585 : */
4586 : void
4587 180 : ExecEvalAggOrderedTransTuple(ExprState *state, ExprEvalStep *op,
4588 : ExprContext *econtext)
4589 : {
4590 180 : AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
4591 180 : int setno = op->d.agg_trans.setno;
4592 :
4593 180 : ExecClearTuple(pertrans->sortslot);
4594 180 : pertrans->sortslot->tts_nvalid = pertrans->numInputs;
4595 180 : ExecStoreVirtualTuple(pertrans->sortslot);
4596 180 : tuplesort_puttupleslot(pertrans->sortstates[setno], pertrans->sortslot);
4597 180 : }
4598 :
4599 : /* implementation of transition function invocation for byval types */
4600 : static pg_attribute_always_inline void
4601 27097854 : ExecAggPlainTransByVal(AggState *aggstate, AggStatePerTrans pertrans,
4602 : AggStatePerGroup pergroup,
4603 : ExprContext *aggcontext, int setno)
4604 : {
4605 27097854 : FunctionCallInfo fcinfo = pertrans->transfn_fcinfo;
4606 : MemoryContext oldContext;
4607 : Datum newVal;
4608 :
4609 : /* cf. select_current_set() */
4610 27097854 : aggstate->curaggcontext = aggcontext;
4611 27097854 : aggstate->current_set = setno;
4612 :
4613 : /* set up aggstate->curpertrans for AggGetAggref() */
4614 27097854 : aggstate->curpertrans = pertrans;
4615 :
4616 : /* invoke transition function in per-tuple context */
4617 27097854 : oldContext = MemoryContextSwitchTo(aggstate->tmpcontext->ecxt_per_tuple_memory);
4618 :
4619 27097854 : fcinfo->args[0].value = pergroup->transValue;
4620 27097854 : fcinfo->args[0].isnull = pergroup->transValueIsNull;
4621 27097854 : fcinfo->isnull = false; /* just in case transfn doesn't set it */
4622 :
4623 27097854 : newVal = FunctionCallInvoke(fcinfo);
4624 :
4625 27097794 : pergroup->transValue = newVal;
4626 27097794 : pergroup->transValueIsNull = fcinfo->isnull;
4627 :
4628 27097794 : MemoryContextSwitchTo(oldContext);
4629 27097794 : }
4630 :
4631 : /* implementation of transition function invocation for byref types */
4632 : static pg_attribute_always_inline void
4633 2785848 : ExecAggPlainTransByRef(AggState *aggstate, AggStatePerTrans pertrans,
4634 : AggStatePerGroup pergroup,
4635 : ExprContext *aggcontext, int setno)
4636 : {
4637 2785848 : FunctionCallInfo fcinfo = pertrans->transfn_fcinfo;
4638 : MemoryContext oldContext;
4639 : Datum newVal;
4640 :
4641 : /* cf. select_current_set() */
4642 2785848 : aggstate->curaggcontext = aggcontext;
4643 2785848 : aggstate->current_set = setno;
4644 :
4645 : /* set up aggstate->curpertrans for AggGetAggref() */
4646 2785848 : aggstate->curpertrans = pertrans;
4647 :
4648 : /* invoke transition function in per-tuple context */
4649 2785848 : oldContext = MemoryContextSwitchTo(aggstate->tmpcontext->ecxt_per_tuple_memory);
4650 :
4651 2785848 : fcinfo->args[0].value = pergroup->transValue;
4652 2785848 : fcinfo->args[0].isnull = pergroup->transValueIsNull;
4653 2785848 : fcinfo->isnull = false; /* just in case transfn doesn't set it */
4654 :
4655 2785848 : newVal = FunctionCallInvoke(fcinfo);
4656 :
4657 : /*
4658 : * For pass-by-ref datatype, must copy the new value into aggcontext and
4659 : * free the prior transValue. But if transfn returned a pointer to its
4660 : * first input, we don't need to do anything.
4661 : *
4662 : * It's safe to compare newVal with pergroup->transValue without regard
4663 : * for either being NULL, because ExecAggCopyTransValue takes care to set
4664 : * transValue to 0 when NULL. Otherwise we could end up accidentally not
4665 : * reparenting, when the transValue has the same numerical value as
4666 : * newValue, despite being NULL. This is a somewhat hot path, making it
4667 : * undesirable to instead solve this with another branch for the common
4668 : * case of the transition function returning its (modified) input
4669 : * argument.
4670 : */
4671 2785842 : if (DatumGetPointer(newVal) != DatumGetPointer(pergroup->transValue))
4672 37590 : newVal = ExecAggCopyTransValue(aggstate, pertrans,
4673 37590 : newVal, fcinfo->isnull,
4674 : pergroup->transValue,
4675 37590 : pergroup->transValueIsNull);
4676 :
4677 2785842 : pergroup->transValue = newVal;
4678 2785842 : pergroup->transValueIsNull = fcinfo->isnull;
4679 :
4680 2785842 : MemoryContextSwitchTo(oldContext);
4681 2785842 : }
|