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