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