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