Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * execExprInterp.c
4 : * Interpreted evaluation of an expression step list.
5 : *
6 : * This file provides either a "direct threaded" (for gcc, clang and
7 : * compatible) or a "switch threaded" (for all compilers) implementation of
8 : * expression evaluation. The former is amongst the fastest known methods
9 : * of interpreting programs without resorting to assembly level work, or
10 : * just-in-time compilation, but it requires support for computed gotos.
11 : * The latter is amongst the fastest approaches doable in standard C.
12 : *
13 : * In either case we use ExprEvalStep->opcode to dispatch to the code block
14 : * within ExecInterpExpr() that implements the specific opcode type.
15 : *
16 : * Switch-threading uses a plain switch() statement to perform the
17 : * dispatch. This has the advantages of being plain C and allowing the
18 : * compiler to warn if implementation of a specific opcode has been forgotten.
19 : * The disadvantage is that dispatches will, as commonly implemented by
20 : * compilers, happen from a single location, requiring more jumps and causing
21 : * bad branch prediction.
22 : *
23 : * In direct threading, we use gcc's label-as-values extension - also adopted
24 : * by some other compilers - to replace ExprEvalStep->opcode with the address
25 : * of the block implementing the instruction. Dispatch to the next instruction
26 : * is done by a "computed goto". This allows for better branch prediction
27 : * (as the jumps are happening from different locations) and fewer jumps
28 : * (as no preparatory jump to a common dispatch location is needed).
29 : *
30 : * When using direct threading, ExecReadyInterpretedExpr will replace
31 : * each step's opcode field with the address of the relevant code block and
32 : * ExprState->flags will contain EEO_FLAG_DIRECT_THREADED to remember that
33 : * that's been done.
34 : *
35 : * For very simple instructions the overhead of the full interpreter
36 : * "startup", as minimal as it is, is noticeable. Therefore
37 : * ExecReadyInterpretedExpr will choose to implement simple scalar Var
38 : * and Const expressions using special fast-path routines (ExecJust*).
39 : * Benchmarking shows anything more complex than those may as well use the
40 : * "full interpreter".
41 : *
42 : * Complex or uncommon instructions are not implemented in-line in
43 : * ExecInterpExpr(), rather we call out to a helper function appearing later
44 : * in this file. For one reason, there'd not be a noticeable performance
45 : * benefit, but more importantly those complex routines are intended to be
46 : * shared between different expression evaluation approaches. For instance
47 : * a JIT compiler would generate calls to them. (This is why they are
48 : * exported rather than being "static" in this file.)
49 : *
50 : *
51 : * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
52 : * Portions Copyright (c) 1994, Regents of the University of California
53 : *
54 : * IDENTIFICATION
55 : * src/backend/executor/execExprInterp.c
56 : *
57 : *-------------------------------------------------------------------------
58 : */
59 : #include "postgres.h"
60 :
61 : #include "access/tuptoaster.h"
62 : #include "catalog/pg_type.h"
63 : #include "commands/sequence.h"
64 : #include "executor/execExpr.h"
65 : #include "executor/nodeSubplan.h"
66 : #include "funcapi.h"
67 : #include "miscadmin.h"
68 : #include "nodes/nodeFuncs.h"
69 : #include "parser/parsetree.h"
70 : #include "pgstat.h"
71 : #include "utils/builtins.h"
72 : #include "utils/date.h"
73 : #include "utils/lsyscache.h"
74 : #include "utils/timestamp.h"
75 : #include "utils/typcache.h"
76 : #include "utils/xml.h"
77 :
78 :
79 : /*
80 : * Use computed-goto-based opcode dispatch when computed gotos are available.
81 : * But use a separate symbol so that it's easy to adjust locally in this file
82 : * for development and testing.
83 : */
84 : #ifdef HAVE_COMPUTED_GOTO
85 : #define EEO_USE_COMPUTED_GOTO
86 : #endif /* HAVE_COMPUTED_GOTO */
87 :
88 : /*
89 : * Macros for opcode dispatch.
90 : *
91 : * EEO_SWITCH - just hides the switch if not in use.
92 : * EEO_CASE - labels the implementation of named expression step type.
93 : * EEO_DISPATCH - jump to the implementation of the step type for 'op'.
94 : * EEO_OPCODE - compute opcode required by used expression evaluation method.
95 : * EEO_NEXT - increment 'op' and jump to correct next step type.
96 : * EEO_JUMP - jump to the specified step number within the current expression.
97 : */
98 : #if defined(EEO_USE_COMPUTED_GOTO)
99 :
100 : /* to make dispatch_table accessible outside ExecInterpExpr() */
101 : static const void **dispatch_table = NULL;
102 :
103 : #define EEO_SWITCH()
104 : #define EEO_CASE(name) CASE_##name:
105 : #define EEO_DISPATCH() goto *((void *) op->opcode)
106 : #define EEO_OPCODE(opcode) ((intptr_t) dispatch_table[opcode])
107 :
108 : #else /* !EEO_USE_COMPUTED_GOTO */
109 :
110 : #define EEO_SWITCH() starteval: switch ((ExprEvalOp) op->opcode)
111 : #define EEO_CASE(name) case name:
112 : #define EEO_DISPATCH() goto starteval
113 : #define EEO_OPCODE(opcode) (opcode)
114 :
115 : #endif /* EEO_USE_COMPUTED_GOTO */
116 :
117 : #define EEO_NEXT() \
118 : do { \
119 : op++; \
120 : EEO_DISPATCH(); \
121 : } while (0)
122 :
123 : #define EEO_JUMP(stepno) \
124 : do { \
125 : op = &state->steps[stepno]; \
126 : EEO_DISPATCH(); \
127 : } while (0)
128 :
129 :
130 : static Datum ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull);
131 : static void ExecInitInterpreter(void);
132 :
133 : /* support functions */
134 : static void CheckVarSlotCompatibility(TupleTableSlot *slot, int attnum, Oid vartype);
135 : static TupleDesc get_cached_rowtype(Oid type_id, int32 typmod,
136 : TupleDesc *cache_field, ExprContext *econtext);
137 : static void ShutdownTupleDescRef(Datum arg);
138 : static void ExecEvalRowNullInt(ExprState *state, ExprEvalStep *op,
139 : ExprContext *econtext, bool checkisnull);
140 :
141 : /* fast-path evaluation functions */
142 : static Datum ExecJustInnerVarFirst(ExprState *state, ExprContext *econtext, bool *isnull);
143 : static Datum ExecJustInnerVar(ExprState *state, ExprContext *econtext, bool *isnull);
144 : static Datum ExecJustOuterVarFirst(ExprState *state, ExprContext *econtext, bool *isnull);
145 : static Datum ExecJustOuterVar(ExprState *state, ExprContext *econtext, bool *isnull);
146 : static Datum ExecJustScanVarFirst(ExprState *state, ExprContext *econtext, bool *isnull);
147 : static Datum ExecJustScanVar(ExprState *state, ExprContext *econtext, bool *isnull);
148 : static Datum ExecJustConst(ExprState *state, ExprContext *econtext, bool *isnull);
149 : static Datum ExecJustAssignInnerVar(ExprState *state, ExprContext *econtext, bool *isnull);
150 : static Datum ExecJustAssignOuterVar(ExprState *state, ExprContext *econtext, bool *isnull);
151 : static Datum ExecJustAssignScanVar(ExprState *state, ExprContext *econtext, bool *isnull);
152 :
153 :
154 : /*
155 : * Prepare ExprState for interpreted execution.
156 : */
157 : void
158 108107 : ExecReadyInterpretedExpr(ExprState *state)
159 : {
160 : /* Ensure one-time interpreter setup has been done */
161 108107 : ExecInitInterpreter();
162 :
163 : /* Simple validity checks on expression */
164 108107 : Assert(state->steps_len >= 1);
165 108107 : Assert(state->steps[state->steps_len - 1].opcode == EEOP_DONE);
166 :
167 : /*
168 : * Don't perform redundant initialization. This is unreachable in current
169 : * cases, but might be hit if there's additional expression evaluation
170 : * methods that rely on interpreted execution to work.
171 : */
172 108107 : if (state->flags & EEO_FLAG_INTERPRETER_INITIALIZED)
173 0 : return;
174 :
175 : /* DIRECT_THREADED should not already be set */
176 108107 : Assert((state->flags & EEO_FLAG_DIRECT_THREADED) == 0);
177 :
178 : /*
179 : * There shouldn't be any errors before the expression is fully
180 : * initialized, and even if so, it'd lead to the expression being
181 : * abandoned. So we can set the flag now and save some code.
182 : */
183 108107 : state->flags |= EEO_FLAG_INTERPRETER_INITIALIZED;
184 :
185 : /*
186 : * Select fast-path evalfuncs for very simple expressions. "Starting up"
187 : * the full interpreter is a measurable overhead for these. Plain Vars
188 : * and Const seem to be the only ones where the intrinsic cost is small
189 : * enough that the overhead of ExecInterpExpr matters. For more complex
190 : * expressions it's cheaper to use ExecInterpExpr always.
191 : */
192 108107 : if (state->steps_len == 3)
193 : {
194 26699 : ExprEvalOp step0 = state->steps[0].opcode;
195 26699 : ExprEvalOp step1 = state->steps[1].opcode;
196 :
197 26699 : if (step0 == EEOP_INNER_FETCHSOME &&
198 : step1 == EEOP_INNER_VAR_FIRST)
199 : {
200 1770 : state->evalfunc = ExecJustInnerVarFirst;
201 1770 : return;
202 : }
203 24929 : else if (step0 == EEOP_OUTER_FETCHSOME &&
204 : step1 == EEOP_OUTER_VAR_FIRST)
205 : {
206 2088 : state->evalfunc = ExecJustOuterVarFirst;
207 2088 : return;
208 : }
209 22841 : else if (step0 == EEOP_SCAN_FETCHSOME &&
210 : step1 == EEOP_SCAN_VAR_FIRST)
211 : {
212 1837 : state->evalfunc = ExecJustScanVarFirst;
213 1837 : return;
214 : }
215 21004 : else if (step0 == EEOP_INNER_FETCHSOME &&
216 : step1 == EEOP_ASSIGN_INNER_VAR)
217 : {
218 63 : state->evalfunc = ExecJustAssignInnerVar;
219 63 : return;
220 : }
221 20941 : else if (step0 == EEOP_OUTER_FETCHSOME &&
222 : step1 == EEOP_ASSIGN_OUTER_VAR)
223 : {
224 2300 : state->evalfunc = ExecJustAssignOuterVar;
225 2300 : return;
226 : }
227 18641 : else if (step0 == EEOP_SCAN_FETCHSOME &&
228 : step1 == EEOP_ASSIGN_SCAN_VAR)
229 : {
230 2519 : state->evalfunc = ExecJustAssignScanVar;
231 2519 : return;
232 : }
233 : }
234 122925 : else if (state->steps_len == 2 &&
235 41517 : state->steps[0].opcode == EEOP_CONST)
236 : {
237 17068 : state->evalfunc = ExecJustConst;
238 17068 : return;
239 : }
240 :
241 : #if defined(EEO_USE_COMPUTED_GOTO)
242 :
243 : /*
244 : * In the direct-threaded implementation, replace each opcode with the
245 : * address to jump to. (Use ExecEvalStepOp() to get back the opcode.)
246 : */
247 : {
248 : int off;
249 :
250 465415 : for (off = 0; off < state->steps_len; off++)
251 : {
252 384953 : ExprEvalStep *op = &state->steps[off];
253 :
254 384953 : op->opcode = EEO_OPCODE(op->opcode);
255 : }
256 :
257 80462 : state->flags |= EEO_FLAG_DIRECT_THREADED;
258 : }
259 : #endif /* EEO_USE_COMPUTED_GOTO */
260 :
261 80462 : state->evalfunc = ExecInterpExpr;
262 : }
263 :
264 :
265 : /*
266 : * Evaluate expression identified by "state" in the execution context
267 : * given by "econtext". *isnull is set to the is-null flag for the result,
268 : * and the Datum value is the function result.
269 : *
270 : * As a special case, return the dispatch table's address if state is NULL.
271 : * This is used by ExecInitInterpreter to set up the dispatch_table global.
272 : * (Only applies when EEO_USE_COMPUTED_GOTO is defined.)
273 : */
274 : static Datum
275 21820228 : ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
276 : {
277 : ExprEvalStep *op;
278 : TupleTableSlot *resultslot;
279 : TupleTableSlot *innerslot;
280 : TupleTableSlot *outerslot;
281 : TupleTableSlot *scanslot;
282 :
283 : /*
284 : * This array has to be in the same order as enum ExprEvalOp.
285 : */
286 : #if defined(EEO_USE_COMPUTED_GOTO)
287 : static const void *const dispatch_table[] = {
288 : &&CASE_EEOP_DONE,
289 : &&CASE_EEOP_INNER_FETCHSOME,
290 : &&CASE_EEOP_OUTER_FETCHSOME,
291 : &&CASE_EEOP_SCAN_FETCHSOME,
292 : &&CASE_EEOP_INNER_VAR_FIRST,
293 : &&CASE_EEOP_INNER_VAR,
294 : &&CASE_EEOP_OUTER_VAR_FIRST,
295 : &&CASE_EEOP_OUTER_VAR,
296 : &&CASE_EEOP_SCAN_VAR_FIRST,
297 : &&CASE_EEOP_SCAN_VAR,
298 : &&CASE_EEOP_INNER_SYSVAR,
299 : &&CASE_EEOP_OUTER_SYSVAR,
300 : &&CASE_EEOP_SCAN_SYSVAR,
301 : &&CASE_EEOP_WHOLEROW,
302 : &&CASE_EEOP_ASSIGN_INNER_VAR,
303 : &&CASE_EEOP_ASSIGN_OUTER_VAR,
304 : &&CASE_EEOP_ASSIGN_SCAN_VAR,
305 : &&CASE_EEOP_ASSIGN_TMP,
306 : &&CASE_EEOP_ASSIGN_TMP_MAKE_RO,
307 : &&CASE_EEOP_CONST,
308 : &&CASE_EEOP_FUNCEXPR,
309 : &&CASE_EEOP_FUNCEXPR_STRICT,
310 : &&CASE_EEOP_FUNCEXPR_FUSAGE,
311 : &&CASE_EEOP_FUNCEXPR_STRICT_FUSAGE,
312 : &&CASE_EEOP_BOOL_AND_STEP_FIRST,
313 : &&CASE_EEOP_BOOL_AND_STEP,
314 : &&CASE_EEOP_BOOL_AND_STEP_LAST,
315 : &&CASE_EEOP_BOOL_OR_STEP_FIRST,
316 : &&CASE_EEOP_BOOL_OR_STEP,
317 : &&CASE_EEOP_BOOL_OR_STEP_LAST,
318 : &&CASE_EEOP_BOOL_NOT_STEP,
319 : &&CASE_EEOP_QUAL,
320 : &&CASE_EEOP_JUMP,
321 : &&CASE_EEOP_JUMP_IF_NULL,
322 : &&CASE_EEOP_JUMP_IF_NOT_NULL,
323 : &&CASE_EEOP_JUMP_IF_NOT_TRUE,
324 : &&CASE_EEOP_NULLTEST_ISNULL,
325 : &&CASE_EEOP_NULLTEST_ISNOTNULL,
326 : &&CASE_EEOP_NULLTEST_ROWISNULL,
327 : &&CASE_EEOP_NULLTEST_ROWISNOTNULL,
328 : &&CASE_EEOP_BOOLTEST_IS_TRUE,
329 : &&CASE_EEOP_BOOLTEST_IS_NOT_TRUE,
330 : &&CASE_EEOP_BOOLTEST_IS_FALSE,
331 : &&CASE_EEOP_BOOLTEST_IS_NOT_FALSE,
332 : &&CASE_EEOP_PARAM_EXEC,
333 : &&CASE_EEOP_PARAM_EXTERN,
334 : &&CASE_EEOP_CASE_TESTVAL,
335 : &&CASE_EEOP_MAKE_READONLY,
336 : &&CASE_EEOP_IOCOERCE,
337 : &&CASE_EEOP_DISTINCT,
338 : &&CASE_EEOP_NULLIF,
339 : &&CASE_EEOP_SQLVALUEFUNCTION,
340 : &&CASE_EEOP_CURRENTOFEXPR,
341 : &&CASE_EEOP_NEXTVALUEEXPR,
342 : &&CASE_EEOP_ARRAYEXPR,
343 : &&CASE_EEOP_ARRAYCOERCE,
344 : &&CASE_EEOP_ROW,
345 : &&CASE_EEOP_ROWCOMPARE_STEP,
346 : &&CASE_EEOP_ROWCOMPARE_FINAL,
347 : &&CASE_EEOP_MINMAX,
348 : &&CASE_EEOP_FIELDSELECT,
349 : &&CASE_EEOP_FIELDSTORE_DEFORM,
350 : &&CASE_EEOP_FIELDSTORE_FORM,
351 : &&CASE_EEOP_ARRAYREF_SUBSCRIPT,
352 : &&CASE_EEOP_ARRAYREF_OLD,
353 : &&CASE_EEOP_ARRAYREF_ASSIGN,
354 : &&CASE_EEOP_ARRAYREF_FETCH,
355 : &&CASE_EEOP_DOMAIN_TESTVAL,
356 : &&CASE_EEOP_DOMAIN_NOTNULL,
357 : &&CASE_EEOP_DOMAIN_CHECK,
358 : &&CASE_EEOP_CONVERT_ROWTYPE,
359 : &&CASE_EEOP_SCALARARRAYOP,
360 : &&CASE_EEOP_XMLEXPR,
361 : &&CASE_EEOP_AGGREF,
362 : &&CASE_EEOP_GROUPING_FUNC,
363 : &&CASE_EEOP_WINDOW_FUNC,
364 : &&CASE_EEOP_SUBPLAN,
365 : &&CASE_EEOP_ALTERNATIVE_SUBPLAN,
366 : &&CASE_EEOP_LAST
367 : };
368 :
369 : StaticAssertStmt(EEOP_LAST + 1 == lengthof(dispatch_table),
370 : "dispatch_table out of whack with ExprEvalOp");
371 :
372 21820228 : if (unlikely(state == NULL))
373 309 : return PointerGetDatum(dispatch_table);
374 : #else
375 : Assert(state != NULL);
376 : #endif /* EEO_USE_COMPUTED_GOTO */
377 :
378 : /* setup state */
379 21819919 : op = state->steps;
380 21819919 : resultslot = state->resultslot;
381 21819919 : innerslot = econtext->ecxt_innertuple;
382 21819919 : outerslot = econtext->ecxt_outertuple;
383 21819919 : scanslot = econtext->ecxt_scantuple;
384 :
385 : #if defined(EEO_USE_COMPUTED_GOTO)
386 21819919 : EEO_DISPATCH();
387 : #endif
388 :
389 : EEO_SWITCH()
390 : {
391 : EEO_CASE(EEOP_DONE)
392 : {
393 21816800 : goto out;
394 : }
395 :
396 : EEO_CASE(EEOP_INNER_FETCHSOME)
397 : {
398 : /* XXX: worthwhile to check tts_nvalid inline first? */
399 700465 : slot_getsomeattrs(innerslot, op->d.fetch.last_var);
400 :
401 700465 : EEO_NEXT();
402 : }
403 :
404 : EEO_CASE(EEOP_OUTER_FETCHSOME)
405 : {
406 894291 : slot_getsomeattrs(outerslot, op->d.fetch.last_var);
407 :
408 894291 : EEO_NEXT();
409 : }
410 :
411 : EEO_CASE(EEOP_SCAN_FETCHSOME)
412 : {
413 2802489 : slot_getsomeattrs(scanslot, op->d.fetch.last_var);
414 :
415 2802489 : EEO_NEXT();
416 : }
417 :
418 : EEO_CASE(EEOP_INNER_VAR_FIRST)
419 : {
420 2086 : int attnum = op->d.var.attnum;
421 :
422 : /*
423 : * First time through, check whether attribute matches Var. Might
424 : * not be ok anymore, due to schema changes.
425 : */
426 2086 : CheckVarSlotCompatibility(innerslot, attnum + 1, op->d.var.vartype);
427 :
428 : /* Skip that check on subsequent evaluations */
429 2086 : op->opcode = EEO_OPCODE(EEOP_INNER_VAR);
430 :
431 : /* FALL THROUGH to EEOP_INNER_VAR */
432 : }
433 :
434 : EEO_CASE(EEOP_INNER_VAR)
435 : {
436 678951 : int attnum = op->d.var.attnum;
437 :
438 : /*
439 : * Since we already extracted all referenced columns from the
440 : * tuple with a FETCHSOME step, we can just grab the value
441 : * directly out of the slot's decomposed-data arrays. But let's
442 : * have an Assert to check that that did happen.
443 : */
444 678951 : Assert(attnum >= 0 && attnum < innerslot->tts_nvalid);
445 678951 : *op->resvalue = innerslot->tts_values[attnum];
446 678951 : *op->resnull = innerslot->tts_isnull[attnum];
447 :
448 678951 : EEO_NEXT();
449 : }
450 :
451 : EEO_CASE(EEOP_OUTER_VAR_FIRST)
452 : {
453 3129 : int attnum = op->d.var.attnum;
454 :
455 : /* See EEOP_INNER_VAR_FIRST comments */
456 :
457 3129 : CheckVarSlotCompatibility(outerslot, attnum + 1, op->d.var.vartype);
458 3129 : op->opcode = EEO_OPCODE(EEOP_OUTER_VAR);
459 :
460 : /* FALL THROUGH to EEOP_OUTER_VAR */
461 : }
462 :
463 : EEO_CASE(EEOP_OUTER_VAR)
464 : {
465 727435 : int attnum = op->d.var.attnum;
466 :
467 : /* See EEOP_INNER_VAR comments */
468 :
469 727435 : Assert(attnum >= 0 && attnum < outerslot->tts_nvalid);
470 727435 : *op->resvalue = outerslot->tts_values[attnum];
471 727435 : *op->resnull = outerslot->tts_isnull[attnum];
472 :
473 727435 : EEO_NEXT();
474 : }
475 :
476 : EEO_CASE(EEOP_SCAN_VAR_FIRST)
477 : {
478 11600 : int attnum = op->d.var.attnum;
479 :
480 : /* See EEOP_INNER_VAR_FIRST comments */
481 :
482 11600 : CheckVarSlotCompatibility(scanslot, attnum + 1, op->d.var.vartype);
483 11596 : op->opcode = EEO_OPCODE(EEOP_SCAN_VAR);
484 :
485 : /* FALL THROUGH to EEOP_SCAN_VAR */
486 : }
487 :
488 : EEO_CASE(EEOP_SCAN_VAR)
489 : {
490 2878243 : int attnum = op->d.var.attnum;
491 :
492 : /* See EEOP_INNER_VAR comments */
493 :
494 2878243 : Assert(attnum >= 0 && attnum < scanslot->tts_nvalid);
495 2878243 : *op->resvalue = scanslot->tts_values[attnum];
496 2878243 : *op->resnull = scanslot->tts_isnull[attnum];
497 :
498 2878243 : EEO_NEXT();
499 : }
500 :
501 : EEO_CASE(EEOP_INNER_SYSVAR)
502 : {
503 0 : int attnum = op->d.var.attnum;
504 :
505 : /* these asserts must match defenses in slot_getattr */
506 0 : Assert(innerslot->tts_tuple != NULL);
507 0 : Assert(innerslot->tts_tuple != &(innerslot->tts_minhdr));
508 : /* heap_getsysattr has sufficient defenses against bad attnums */
509 :
510 0 : *op->resvalue = heap_getsysattr(innerslot->tts_tuple, attnum,
511 : innerslot->tts_tupleDescriptor,
512 : op->resnull);
513 :
514 0 : EEO_NEXT();
515 : }
516 :
517 : EEO_CASE(EEOP_OUTER_SYSVAR)
518 : {
519 0 : int attnum = op->d.var.attnum;
520 :
521 : /* these asserts must match defenses in slot_getattr */
522 0 : Assert(outerslot->tts_tuple != NULL);
523 0 : Assert(outerslot->tts_tuple != &(outerslot->tts_minhdr));
524 :
525 : /* heap_getsysattr has sufficient defenses against bad attnums */
526 0 : *op->resvalue = heap_getsysattr(outerslot->tts_tuple, attnum,
527 : outerslot->tts_tupleDescriptor,
528 : op->resnull);
529 :
530 0 : EEO_NEXT();
531 : }
532 :
533 : EEO_CASE(EEOP_SCAN_SYSVAR)
534 : {
535 575106 : int attnum = op->d.var.attnum;
536 :
537 : /* these asserts must match defenses in slot_getattr */
538 575106 : Assert(scanslot->tts_tuple != NULL);
539 575106 : Assert(scanslot->tts_tuple != &(scanslot->tts_minhdr));
540 : /* heap_getsysattr has sufficient defenses against bad attnums */
541 :
542 575106 : *op->resvalue = heap_getsysattr(scanslot->tts_tuple, attnum,
543 : scanslot->tts_tupleDescriptor,
544 : op->resnull);
545 :
546 575106 : EEO_NEXT();
547 : }
548 :
549 : EEO_CASE(EEOP_WHOLEROW)
550 : {
551 : /* too complex for an inline implementation */
552 1041 : ExecEvalWholeRowVar(state, op, econtext);
553 :
554 1041 : EEO_NEXT();
555 : }
556 :
557 : EEO_CASE(EEOP_ASSIGN_INNER_VAR)
558 : {
559 104296 : int resultnum = op->d.assign_var.resultnum;
560 104296 : int attnum = op->d.assign_var.attnum;
561 :
562 : /*
563 : * We do not need CheckVarSlotCompatibility here; that was taken
564 : * care of at compilation time. But see EEOP_INNER_VAR comments.
565 : */
566 104296 : Assert(attnum >= 0 && attnum < innerslot->tts_nvalid);
567 104296 : resultslot->tts_values[resultnum] = innerslot->tts_values[attnum];
568 104296 : resultslot->tts_isnull[resultnum] = innerslot->tts_isnull[attnum];
569 :
570 104296 : EEO_NEXT();
571 : }
572 :
573 : EEO_CASE(EEOP_ASSIGN_OUTER_VAR)
574 : {
575 697309 : int resultnum = op->d.assign_var.resultnum;
576 697309 : int attnum = op->d.assign_var.attnum;
577 :
578 : /*
579 : * We do not need CheckVarSlotCompatibility here; that was taken
580 : * care of at compilation time. But see EEOP_INNER_VAR comments.
581 : */
582 697309 : Assert(attnum >= 0 && attnum < outerslot->tts_nvalid);
583 697309 : resultslot->tts_values[resultnum] = outerslot->tts_values[attnum];
584 697309 : resultslot->tts_isnull[resultnum] = outerslot->tts_isnull[attnum];
585 :
586 697309 : EEO_NEXT();
587 : }
588 :
589 : EEO_CASE(EEOP_ASSIGN_SCAN_VAR)
590 : {
591 1983363 : int resultnum = op->d.assign_var.resultnum;
592 1983363 : int attnum = op->d.assign_var.attnum;
593 :
594 : /*
595 : * We do not need CheckVarSlotCompatibility here; that was taken
596 : * care of at compilation time. But see EEOP_INNER_VAR comments.
597 : */
598 1983363 : Assert(attnum >= 0 && attnum < scanslot->tts_nvalid);
599 1983363 : resultslot->tts_values[resultnum] = scanslot->tts_values[attnum];
600 1983363 : resultslot->tts_isnull[resultnum] = scanslot->tts_isnull[attnum];
601 :
602 1983363 : EEO_NEXT();
603 : }
604 :
605 : EEO_CASE(EEOP_ASSIGN_TMP)
606 : {
607 1622806 : int resultnum = op->d.assign_tmp.resultnum;
608 :
609 1622806 : resultslot->tts_values[resultnum] = state->resvalue;
610 1622806 : resultslot->tts_isnull[resultnum] = state->resnull;
611 :
612 1622806 : EEO_NEXT();
613 : }
614 :
615 : EEO_CASE(EEOP_ASSIGN_TMP_MAKE_RO)
616 : {
617 698796 : int resultnum = op->d.assign_tmp.resultnum;
618 :
619 698796 : resultslot->tts_isnull[resultnum] = state->resnull;
620 698796 : if (!resultslot->tts_isnull[resultnum])
621 1242878 : resultslot->tts_values[resultnum] =
622 621439 : MakeExpandedObjectReadOnlyInternal(state->resvalue);
623 : else
624 77357 : resultslot->tts_values[resultnum] = state->resvalue;
625 :
626 698796 : EEO_NEXT();
627 : }
628 :
629 : EEO_CASE(EEOP_CONST)
630 : {
631 1072268 : *op->resnull = op->d.constval.isnull;
632 1072268 : *op->resvalue = op->d.constval.value;
633 :
634 1072268 : EEO_NEXT();
635 : }
636 :
637 : /*
638 : * Function-call implementations. Arguments have previously been
639 : * evaluated directly into fcinfo->args.
640 : *
641 : * As both STRICT checks and function-usage are noticeable performance
642 : * wise, and function calls are a very hot-path (they also back
643 : * operators!), it's worth having so many separate opcodes.
644 : */
645 : EEO_CASE(EEOP_FUNCEXPR)
646 : {
647 35323 : FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
648 :
649 35323 : fcinfo->isnull = false;
650 35323 : *op->resvalue = (op->d.func.fn_addr) (fcinfo);
651 32915 : *op->resnull = fcinfo->isnull;
652 :
653 32915 : EEO_NEXT();
654 : }
655 :
656 : EEO_CASE(EEOP_FUNCEXPR_STRICT)
657 : {
658 3939815 : FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
659 3939815 : bool *argnull = fcinfo->argnull;
660 : int argno;
661 :
662 : /* strict function, so check for NULL args */
663 11145542 : for (argno = 0; argno < op->d.func.nargs; argno++)
664 : {
665 7277012 : if (argnull[argno])
666 : {
667 71285 : *op->resnull = true;
668 71285 : goto strictfail;
669 : }
670 : }
671 3868530 : fcinfo->isnull = false;
672 3868530 : *op->resvalue = (op->d.func.fn_addr) (fcinfo);
673 3867914 : *op->resnull = fcinfo->isnull;
674 :
675 : strictfail:
676 3939199 : EEO_NEXT();
677 : }
678 :
679 : EEO_CASE(EEOP_FUNCEXPR_FUSAGE)
680 : {
681 0 : FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
682 : PgStat_FunctionCallUsage fcusage;
683 :
684 0 : pgstat_init_function_usage(fcinfo, &fcusage);
685 :
686 0 : fcinfo->isnull = false;
687 0 : *op->resvalue = (op->d.func.fn_addr) (fcinfo);
688 0 : *op->resnull = fcinfo->isnull;
689 :
690 0 : pgstat_end_function_usage(&fcusage, true);
691 :
692 0 : EEO_NEXT();
693 : }
694 :
695 : EEO_CASE(EEOP_FUNCEXPR_STRICT_FUSAGE)
696 : {
697 0 : FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
698 : PgStat_FunctionCallUsage fcusage;
699 0 : bool *argnull = fcinfo->argnull;
700 : int argno;
701 :
702 : /* strict function, so check for NULL args */
703 0 : for (argno = 0; argno < op->d.func.nargs; argno++)
704 : {
705 0 : if (argnull[argno])
706 : {
707 0 : *op->resnull = true;
708 0 : goto strictfail_fusage;
709 : }
710 : }
711 :
712 0 : pgstat_init_function_usage(fcinfo, &fcusage);
713 :
714 0 : fcinfo->isnull = false;
715 0 : *op->resvalue = (op->d.func.fn_addr) (fcinfo);
716 0 : *op->resnull = fcinfo->isnull;
717 :
718 0 : pgstat_end_function_usage(&fcusage, true);
719 :
720 : strictfail_fusage:
721 0 : EEO_NEXT();
722 : }
723 :
724 : /*
725 : * If any of its clauses is FALSE, an AND's result is FALSE regardless
726 : * of the states of the rest of the clauses, so we can stop evaluating
727 : * and return FALSE immediately. If none are FALSE and one or more is
728 : * NULL, we return NULL; otherwise we return TRUE. This makes sense
729 : * when you interpret NULL as "don't know": perhaps one of the "don't
730 : * knows" would have been FALSE if we'd known its value. Only when
731 : * all the inputs are known to be TRUE can we state confidently that
732 : * the AND's result is TRUE.
733 : */
734 : EEO_CASE(EEOP_BOOL_AND_STEP_FIRST)
735 : {
736 35338 : *op->d.boolexpr.anynull = false;
737 :
738 : /*
739 : * EEOP_BOOL_AND_STEP_FIRST resets anynull, otherwise it's the
740 : * same as EEOP_BOOL_AND_STEP - so fall through to that.
741 : */
742 :
743 : /* FALL THROUGH */
744 : }
745 :
746 : EEO_CASE(EEOP_BOOL_AND_STEP)
747 : {
748 36094 : if (*op->resnull)
749 : {
750 5 : *op->d.boolexpr.anynull = true;
751 : }
752 36089 : else if (!DatumGetBool(*op->resvalue))
753 : {
754 : /* result is already set to FALSE, need not change it */
755 : /* bail out early */
756 18909 : EEO_JUMP(op->d.boolexpr.jumpdone);
757 : }
758 :
759 17185 : EEO_NEXT();
760 : }
761 :
762 : EEO_CASE(EEOP_BOOL_AND_STEP_LAST)
763 : {
764 16429 : if (*op->resnull)
765 : {
766 : /* result is already set to NULL, need not change it */
767 : }
768 16415 : else if (!DatumGetBool(*op->resvalue))
769 : {
770 : /* result is already set to FALSE, need not change it */
771 :
772 : /*
773 : * No point jumping early to jumpdone - would be same target
774 : * (as this is the last argument to the AND expression),
775 : * except more expensive.
776 : */
777 : }
778 1957 : else if (*op->d.boolexpr.anynull)
779 : {
780 0 : *op->resvalue = (Datum) 0;
781 0 : *op->resnull = true;
782 : }
783 : else
784 : {
785 : /* result is already set to TRUE, need not change it */
786 : }
787 :
788 16429 : EEO_NEXT();
789 : }
790 :
791 : /*
792 : * If any of its clauses is TRUE, an OR's result is TRUE regardless of
793 : * the states of the rest of the clauses, so we can stop evaluating
794 : * and return TRUE immediately. If none are TRUE and one or more is
795 : * NULL, we return NULL; otherwise we return FALSE. This makes sense
796 : * when you interpret NULL as "don't know": perhaps one of the "don't
797 : * knows" would have been TRUE if we'd known its value. Only when all
798 : * the inputs are known to be FALSE can we state confidently that the
799 : * OR's result is FALSE.
800 : */
801 : EEO_CASE(EEOP_BOOL_OR_STEP_FIRST)
802 : {
803 170003 : *op->d.boolexpr.anynull = false;
804 :
805 : /*
806 : * EEOP_BOOL_OR_STEP_FIRST resets anynull, otherwise it's the same
807 : * as EEOP_BOOL_OR_STEP - so fall through to that.
808 : */
809 :
810 : /* FALL THROUGH */
811 : }
812 :
813 : EEO_CASE(EEOP_BOOL_OR_STEP)
814 : {
815 289946 : if (*op->resnull)
816 : {
817 32 : *op->d.boolexpr.anynull = true;
818 : }
819 289914 : else if (DatumGetBool(*op->resvalue))
820 : {
821 : /* result is already set to TRUE, need not change it */
822 : /* bail out early */
823 53587 : EEO_JUMP(op->d.boolexpr.jumpdone);
824 : }
825 :
826 236359 : EEO_NEXT();
827 : }
828 :
829 : EEO_CASE(EEOP_BOOL_OR_STEP_LAST)
830 : {
831 116416 : if (*op->resnull)
832 : {
833 : /* result is already set to NULL, need not change it */
834 : }
835 116391 : else if (DatumGetBool(*op->resvalue))
836 : {
837 : /* result is already set to TRUE, need not change it */
838 :
839 : /*
840 : * No point jumping to jumpdone - would be same target (as
841 : * this is the last argument to the AND expression), except
842 : * more expensive.
843 : */
844 : }
845 113181 : else if (*op->d.boolexpr.anynull)
846 : {
847 11 : *op->resvalue = (Datum) 0;
848 11 : *op->resnull = true;
849 : }
850 : else
851 : {
852 : /* result is already set to FALSE, need not change it */
853 : }
854 :
855 116416 : EEO_NEXT();
856 : }
857 :
858 : EEO_CASE(EEOP_BOOL_NOT_STEP)
859 : {
860 : /*
861 : * Evaluation of 'not' is simple... if expr is false, then return
862 : * 'true' and vice versa. It's safe to do this even on a
863 : * nominally null value, so we ignore resnull; that means that
864 : * NULL in produces NULL out, which is what we want.
865 : */
866 128402 : *op->resvalue = BoolGetDatum(!DatumGetBool(*op->resvalue));
867 :
868 128402 : EEO_NEXT();
869 : }
870 :
871 : EEO_CASE(EEOP_QUAL)
872 : {
873 : /* simplified version of BOOL_AND_STEP for use by ExecQual() */
874 :
875 : /* If argument (also result) is false or null ... */
876 4608294 : if (*op->resnull ||
877 2270830 : !DatumGetBool(*op->resvalue))
878 : {
879 : /* ... bail out early, returning FALSE */
880 1334035 : *op->resnull = false;
881 1334035 : *op->resvalue = BoolGetDatum(false);
882 1334035 : EEO_JUMP(op->d.qualexpr.jumpdone);
883 : }
884 :
885 : /*
886 : * Otherwise, leave the TRUE value in place, in case this is the
887 : * last qual. Then, TRUE is the correct answer.
888 : */
889 :
890 1003429 : EEO_NEXT();
891 : }
892 :
893 : EEO_CASE(EEOP_JUMP)
894 : {
895 : /* Unconditionally jump to target step */
896 2423 : EEO_JUMP(op->d.jump.jumpdone);
897 : }
898 :
899 : EEO_CASE(EEOP_JUMP_IF_NULL)
900 : {
901 : /* Transfer control if current result is null */
902 27009 : if (*op->resnull)
903 457 : EEO_JUMP(op->d.jump.jumpdone);
904 :
905 26552 : EEO_NEXT();
906 : }
907 :
908 : EEO_CASE(EEOP_JUMP_IF_NOT_NULL)
909 : {
910 : /* Transfer control if current result is non-null */
911 22542 : if (!*op->resnull)
912 12377 : EEO_JUMP(op->d.jump.jumpdone);
913 :
914 10165 : EEO_NEXT();
915 : }
916 :
917 : EEO_CASE(EEOP_JUMP_IF_NOT_TRUE)
918 : {
919 : /* Transfer control if current result is null or false */
920 48616 : if (*op->resnull || !DatumGetBool(*op->resvalue))
921 46193 : EEO_JUMP(op->d.jump.jumpdone);
922 :
923 2423 : EEO_NEXT();
924 : }
925 :
926 : EEO_CASE(EEOP_NULLTEST_ISNULL)
927 : {
928 20576 : *op->resvalue = BoolGetDatum(*op->resnull);
929 20576 : *op->resnull = false;
930 :
931 20576 : EEO_NEXT();
932 : }
933 :
934 : EEO_CASE(EEOP_NULLTEST_ISNOTNULL)
935 : {
936 45406 : *op->resvalue = BoolGetDatum(!*op->resnull);
937 45406 : *op->resnull = false;
938 :
939 45406 : EEO_NEXT();
940 : }
941 :
942 : EEO_CASE(EEOP_NULLTEST_ROWISNULL)
943 : {
944 : /* out of line implementation: too large */
945 90 : ExecEvalRowNull(state, op, econtext);
946 :
947 90 : EEO_NEXT();
948 : }
949 :
950 : EEO_CASE(EEOP_NULLTEST_ROWISNOTNULL)
951 : {
952 : /* out of line implementation: too large */
953 49 : ExecEvalRowNotNull(state, op, econtext);
954 :
955 49 : EEO_NEXT();
956 : }
957 :
958 : /* BooleanTest implementations for all booltesttypes */
959 :
960 : EEO_CASE(EEOP_BOOLTEST_IS_TRUE)
961 : {
962 14 : if (*op->resnull)
963 : {
964 2 : *op->resvalue = BoolGetDatum(false);
965 2 : *op->resnull = false;
966 : }
967 : /* else, input value is the correct output as well */
968 :
969 14 : EEO_NEXT();
970 : }
971 :
972 : EEO_CASE(EEOP_BOOLTEST_IS_NOT_TRUE)
973 : {
974 253 : if (*op->resnull)
975 : {
976 1 : *op->resvalue = BoolGetDatum(true);
977 1 : *op->resnull = false;
978 : }
979 : else
980 252 : *op->resvalue = BoolGetDatum(!DatumGetBool(*op->resvalue));
981 :
982 253 : EEO_NEXT();
983 : }
984 :
985 : EEO_CASE(EEOP_BOOLTEST_IS_FALSE)
986 : {
987 13 : if (*op->resnull)
988 : {
989 2 : *op->resvalue = BoolGetDatum(false);
990 2 : *op->resnull = false;
991 : }
992 : else
993 11 : *op->resvalue = BoolGetDatum(!DatumGetBool(*op->resvalue));
994 :
995 13 : EEO_NEXT();
996 : }
997 :
998 : EEO_CASE(EEOP_BOOLTEST_IS_NOT_FALSE)
999 : {
1000 53 : if (*op->resnull)
1001 : {
1002 1 : *op->resvalue = BoolGetDatum(true);
1003 1 : *op->resnull = false;
1004 : }
1005 : /* else, input value is the correct output as well */
1006 :
1007 53 : EEO_NEXT();
1008 : }
1009 :
1010 : EEO_CASE(EEOP_PARAM_EXEC)
1011 : {
1012 : /* out of line implementation: too large */
1013 135806 : ExecEvalParamExec(state, op, econtext);
1014 :
1015 135804 : EEO_NEXT();
1016 : }
1017 :
1018 : EEO_CASE(EEOP_PARAM_EXTERN)
1019 : {
1020 : /* out of line implementation: too large */
1021 152588 : ExecEvalParamExtern(state, op, econtext);
1022 152588 : EEO_NEXT();
1023 : }
1024 :
1025 : EEO_CASE(EEOP_CASE_TESTVAL)
1026 : {
1027 : /*
1028 : * Normally upper parts of the expression tree have setup the
1029 : * values to be returned here, but some parts of the system
1030 : * currently misuse {caseValue,domainValue}_{datum,isNull} to set
1031 : * run-time data. So if no values have been set-up, use
1032 : * ExprContext's. This isn't pretty, but also not *that* ugly,
1033 : * and this is unlikely to be performance sensitive enough to
1034 : * worry about an extra branch.
1035 : */
1036 1075 : if (op->d.casetest.value)
1037 : {
1038 206 : *op->resvalue = *op->d.casetest.value;
1039 206 : *op->resnull = *op->d.casetest.isnull;
1040 : }
1041 : else
1042 : {
1043 869 : *op->resvalue = econtext->caseValue_datum;
1044 869 : *op->resnull = econtext->caseValue_isNull;
1045 : }
1046 :
1047 1075 : EEO_NEXT();
1048 : }
1049 :
1050 : EEO_CASE(EEOP_DOMAIN_TESTVAL)
1051 : {
1052 : /*
1053 : * See EEOP_CASE_TESTVAL comment.
1054 : */
1055 1898 : if (op->d.casetest.value)
1056 : {
1057 737 : *op->resvalue = *op->d.casetest.value;
1058 737 : *op->resnull = *op->d.casetest.isnull;
1059 : }
1060 : else
1061 : {
1062 1161 : *op->resvalue = econtext->domainValue_datum;
1063 1161 : *op->resnull = econtext->domainValue_isNull;
1064 : }
1065 :
1066 1898 : EEO_NEXT();
1067 : }
1068 :
1069 : EEO_CASE(EEOP_MAKE_READONLY)
1070 : {
1071 : /*
1072 : * Force a varlena value that might be read multiple times to R/O
1073 : */
1074 438 : if (!*op->d.make_readonly.isnull)
1075 868 : *op->resvalue =
1076 434 : MakeExpandedObjectReadOnlyInternal(*op->d.make_readonly.value);
1077 438 : *op->resnull = *op->d.make_readonly.isnull;
1078 :
1079 438 : EEO_NEXT();
1080 : }
1081 :
1082 : EEO_CASE(EEOP_IOCOERCE)
1083 : {
1084 : /*
1085 : * Evaluate a CoerceViaIO node. This can be quite a hot path, so
1086 : * inline as much work as possible. The source value is in our
1087 : * result variable.
1088 : */
1089 : char *str;
1090 :
1091 : /* call output function (similar to OutputFunctionCall) */
1092 89285 : if (*op->resnull)
1093 : {
1094 : /* output functions are not called on nulls */
1095 65 : str = NULL;
1096 : }
1097 : else
1098 : {
1099 : FunctionCallInfo fcinfo_out;
1100 :
1101 89220 : fcinfo_out = op->d.iocoerce.fcinfo_data_out;
1102 89220 : fcinfo_out->arg[0] = *op->resvalue;
1103 89220 : fcinfo_out->argnull[0] = false;
1104 :
1105 89220 : fcinfo_out->isnull = false;
1106 89220 : str = DatumGetCString(FunctionCallInvoke(fcinfo_out));
1107 :
1108 : /* OutputFunctionCall assumes result isn't null */
1109 89220 : Assert(!fcinfo_out->isnull);
1110 : }
1111 :
1112 : /* call input function (similar to InputFunctionCall) */
1113 89285 : if (!op->d.iocoerce.finfo_in->fn_strict || str != NULL)
1114 : {
1115 : FunctionCallInfo fcinfo_in;
1116 :
1117 89235 : fcinfo_in = op->d.iocoerce.fcinfo_data_in;
1118 89235 : fcinfo_in->arg[0] = PointerGetDatum(str);
1119 89235 : fcinfo_in->argnull[0] = *op->resnull;
1120 : /* second and third arguments are already set up */
1121 :
1122 89235 : fcinfo_in->isnull = false;
1123 89235 : *op->resvalue = FunctionCallInvoke(fcinfo_in);
1124 :
1125 : /* Should get null result if and only if str is NULL */
1126 89230 : if (str == NULL)
1127 : {
1128 14 : Assert(*op->resnull);
1129 14 : Assert(fcinfo_in->isnull);
1130 : }
1131 : else
1132 : {
1133 89216 : Assert(!*op->resnull);
1134 89216 : Assert(!fcinfo_in->isnull);
1135 : }
1136 : }
1137 :
1138 89280 : EEO_NEXT();
1139 : }
1140 :
1141 : EEO_CASE(EEOP_DISTINCT)
1142 : {
1143 : /*
1144 : * IS DISTINCT FROM must evaluate arguments (already done into
1145 : * fcinfo->arg/argnull) to determine whether they are NULL; if
1146 : * either is NULL then the result is determined. If neither is
1147 : * NULL, then proceed to evaluate the comparison function, which
1148 : * is just the type's standard equality operator. We need not
1149 : * care whether that function is strict. Because the handling of
1150 : * nulls is different, we can't just reuse EEOP_FUNCEXPR.
1151 : */
1152 2535 : FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
1153 :
1154 : /* check function arguments for NULLness */
1155 2535 : if (fcinfo->argnull[0] && fcinfo->argnull[1])
1156 : {
1157 : /* Both NULL? Then is not distinct... */
1158 10 : *op->resvalue = BoolGetDatum(false);
1159 10 : *op->resnull = false;
1160 : }
1161 2525 : else if (fcinfo->argnull[0] || fcinfo->argnull[1])
1162 : {
1163 : /* Only one is NULL? Then is distinct... */
1164 21 : *op->resvalue = BoolGetDatum(true);
1165 21 : *op->resnull = false;
1166 : }
1167 : else
1168 : {
1169 : /* Neither null, so apply the equality function */
1170 : Datum eqresult;
1171 :
1172 2504 : fcinfo->isnull = false;
1173 2504 : eqresult = (op->d.func.fn_addr) (fcinfo);
1174 : /* Must invert result of "="; safe to do even if null */
1175 2504 : *op->resvalue = BoolGetDatum(!DatumGetBool(eqresult));
1176 2504 : *op->resnull = fcinfo->isnull;
1177 : }
1178 :
1179 2535 : EEO_NEXT();
1180 : }
1181 :
1182 : EEO_CASE(EEOP_NULLIF)
1183 : {
1184 : /*
1185 : * The arguments are already evaluated into fcinfo->arg/argnull.
1186 : */
1187 1090 : FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
1188 :
1189 : /* if either argument is NULL they can't be equal */
1190 1090 : if (!fcinfo->argnull[0] && !fcinfo->argnull[1])
1191 : {
1192 : Datum result;
1193 :
1194 1081 : fcinfo->isnull = false;
1195 1081 : result = (op->d.func.fn_addr) (fcinfo);
1196 :
1197 : /* if the arguments are equal return null */
1198 1081 : if (!fcinfo->isnull && DatumGetBool(result))
1199 : {
1200 11 : *op->resvalue = (Datum) 0;
1201 11 : *op->resnull = true;
1202 :
1203 11 : EEO_NEXT();
1204 : }
1205 : }
1206 :
1207 : /* Arguments aren't equal, so return the first one */
1208 1079 : *op->resvalue = fcinfo->arg[0];
1209 1079 : *op->resnull = fcinfo->argnull[0];
1210 :
1211 1079 : EEO_NEXT();
1212 : }
1213 :
1214 : EEO_CASE(EEOP_SQLVALUEFUNCTION)
1215 : {
1216 : /*
1217 : * Doesn't seem worthwhile to have an inline implementation
1218 : * efficiency-wise.
1219 : */
1220 750 : ExecEvalSQLValueFunction(state, op);
1221 :
1222 750 : EEO_NEXT();
1223 : }
1224 :
1225 : EEO_CASE(EEOP_CURRENTOFEXPR)
1226 : {
1227 : /* error invocation uses space, and shouldn't ever occur */
1228 0 : ExecEvalCurrentOfExpr(state, op);
1229 :
1230 0 : EEO_NEXT();
1231 : }
1232 :
1233 : EEO_CASE(EEOP_NEXTVALUEEXPR)
1234 : {
1235 : /*
1236 : * Doesn't seem worthwhile to have an inline implementation
1237 : * efficiency-wise.
1238 : */
1239 30 : ExecEvalNextValueExpr(state, op);
1240 :
1241 30 : EEO_NEXT();
1242 : }
1243 :
1244 : EEO_CASE(EEOP_ARRAYEXPR)
1245 : {
1246 : /* too complex for an inline implementation */
1247 35641 : ExecEvalArrayExpr(state, op);
1248 :
1249 35641 : EEO_NEXT();
1250 : }
1251 :
1252 : EEO_CASE(EEOP_ARRAYCOERCE)
1253 : {
1254 : /* too complex for an inline implementation */
1255 6258 : ExecEvalArrayCoerce(state, op);
1256 :
1257 6256 : EEO_NEXT();
1258 : }
1259 :
1260 : EEO_CASE(EEOP_ROW)
1261 : {
1262 : /* too complex for an inline implementation */
1263 645 : ExecEvalRow(state, op);
1264 :
1265 645 : EEO_NEXT();
1266 : }
1267 :
1268 : EEO_CASE(EEOP_ROWCOMPARE_STEP)
1269 : {
1270 63628 : FunctionCallInfo fcinfo = op->d.rowcompare_step.fcinfo_data;
1271 :
1272 : /* force NULL result if strict fn and NULL input */
1273 127256 : if (op->d.rowcompare_step.finfo->fn_strict &&
1274 127256 : (fcinfo->argnull[0] || fcinfo->argnull[1]))
1275 : {
1276 4 : *op->resnull = true;
1277 4 : EEO_JUMP(op->d.rowcompare_step.jumpnull);
1278 : }
1279 :
1280 : /* Apply comparison function */
1281 63624 : fcinfo->isnull = false;
1282 63624 : *op->resvalue = (op->d.rowcompare_step.fn_addr) (fcinfo);
1283 :
1284 : /* force NULL result if NULL function result */
1285 63624 : if (fcinfo->isnull)
1286 : {
1287 0 : *op->resnull = true;
1288 0 : EEO_JUMP(op->d.rowcompare_step.jumpnull);
1289 : }
1290 63624 : *op->resnull = false;
1291 :
1292 : /* If unequal, no need to compare remaining columns */
1293 63624 : if (DatumGetInt32(*op->resvalue) != 0)
1294 : {
1295 25713 : EEO_JUMP(op->d.rowcompare_step.jumpdone);
1296 : }
1297 :
1298 37911 : EEO_NEXT();
1299 : }
1300 :
1301 : EEO_CASE(EEOP_ROWCOMPARE_FINAL)
1302 : {
1303 25713 : int32 cmpresult = DatumGetInt32(*op->resvalue);
1304 25713 : RowCompareType rctype = op->d.rowcompare_final.rctype;
1305 :
1306 25713 : *op->resnull = false;
1307 25713 : switch (rctype)
1308 : {
1309 : /* EQ and NE cases aren't allowed here */
1310 : case ROWCOMPARE_LT:
1311 5711 : *op->resvalue = BoolGetDatum(cmpresult < 0);
1312 5711 : break;
1313 : case ROWCOMPARE_LE:
1314 19999 : *op->resvalue = BoolGetDatum(cmpresult <= 0);
1315 19999 : break;
1316 : case ROWCOMPARE_GE:
1317 1 : *op->resvalue = BoolGetDatum(cmpresult >= 0);
1318 1 : break;
1319 : case ROWCOMPARE_GT:
1320 2 : *op->resvalue = BoolGetDatum(cmpresult > 0);
1321 2 : break;
1322 : default:
1323 0 : Assert(false);
1324 : break;
1325 : }
1326 :
1327 25713 : EEO_NEXT();
1328 : }
1329 :
1330 : EEO_CASE(EEOP_MINMAX)
1331 : {
1332 : /* too complex for an inline implementation */
1333 99 : ExecEvalMinMax(state, op);
1334 :
1335 99 : EEO_NEXT();
1336 : }
1337 :
1338 : EEO_CASE(EEOP_FIELDSELECT)
1339 : {
1340 : /* too complex for an inline implementation */
1341 13047 : ExecEvalFieldSelect(state, op, econtext);
1342 :
1343 13047 : EEO_NEXT();
1344 : }
1345 :
1346 : EEO_CASE(EEOP_FIELDSTORE_DEFORM)
1347 : {
1348 : /* too complex for an inline implementation */
1349 45 : ExecEvalFieldStoreDeForm(state, op, econtext);
1350 :
1351 45 : EEO_NEXT();
1352 : }
1353 :
1354 : EEO_CASE(EEOP_FIELDSTORE_FORM)
1355 : {
1356 : /* too complex for an inline implementation */
1357 45 : ExecEvalFieldStoreForm(state, op, econtext);
1358 :
1359 45 : EEO_NEXT();
1360 : }
1361 :
1362 : EEO_CASE(EEOP_ARRAYREF_SUBSCRIPT)
1363 : {
1364 : /* Process an array subscript */
1365 :
1366 : /* too complex for an inline implementation */
1367 26864 : if (ExecEvalArrayRefSubscript(state, op))
1368 : {
1369 26858 : EEO_NEXT();
1370 : }
1371 : else
1372 : {
1373 : /* Subscript is null, short-circuit ArrayRef to NULL */
1374 3 : EEO_JUMP(op->d.arrayref_subscript.jumpdone);
1375 : }
1376 : }
1377 :
1378 : EEO_CASE(EEOP_ARRAYREF_OLD)
1379 : {
1380 : /*
1381 : * Fetch the old value in an arrayref assignment, in case it's
1382 : * referenced (via a CaseTestExpr) inside the assignment
1383 : * expression.
1384 : */
1385 :
1386 : /* too complex for an inline implementation */
1387 33 : ExecEvalArrayRefOld(state, op);
1388 :
1389 33 : EEO_NEXT();
1390 : }
1391 :
1392 : /*
1393 : * Perform ArrayRef assignment
1394 : */
1395 : EEO_CASE(EEOP_ARRAYREF_ASSIGN)
1396 : {
1397 : /* too complex for an inline implementation */
1398 140 : ExecEvalArrayRefAssign(state, op);
1399 :
1400 137 : EEO_NEXT();
1401 : }
1402 :
1403 : /*
1404 : * Fetch subset of an array.
1405 : */
1406 : EEO_CASE(EEOP_ARRAYREF_FETCH)
1407 : {
1408 : /* too complex for an inline implementation */
1409 26549 : ExecEvalArrayRefFetch(state, op);
1410 :
1411 26545 : EEO_NEXT();
1412 : }
1413 :
1414 : EEO_CASE(EEOP_CONVERT_ROWTYPE)
1415 : {
1416 : /* too complex for an inline implementation */
1417 57 : ExecEvalConvertRowtype(state, op, econtext);
1418 :
1419 57 : EEO_NEXT();
1420 : }
1421 :
1422 : EEO_CASE(EEOP_SCALARARRAYOP)
1423 : {
1424 : /* too complex for an inline implementation */
1425 84404 : ExecEvalScalarArrayOp(state, op);
1426 :
1427 84404 : EEO_NEXT();
1428 : }
1429 :
1430 : EEO_CASE(EEOP_DOMAIN_NOTNULL)
1431 : {
1432 : /* too complex for an inline implementation */
1433 52 : ExecEvalConstraintNotNull(state, op);
1434 :
1435 40 : EEO_NEXT();
1436 : }
1437 :
1438 : EEO_CASE(EEOP_DOMAIN_CHECK)
1439 : {
1440 : /* too complex for an inline implementation */
1441 703 : ExecEvalConstraintCheck(state, op);
1442 :
1443 665 : EEO_NEXT();
1444 : }
1445 :
1446 : EEO_CASE(EEOP_XMLEXPR)
1447 : {
1448 : /* too complex for an inline implementation */
1449 24 : ExecEvalXmlExpr(state, op);
1450 :
1451 2 : EEO_NEXT();
1452 : }
1453 :
1454 : EEO_CASE(EEOP_AGGREF)
1455 : {
1456 : /*
1457 : * Returns a Datum whose value is the precomputed aggregate value
1458 : * found in the given expression context.
1459 : */
1460 4436 : AggrefExprState *aggref = op->d.aggref.astate;
1461 :
1462 4436 : Assert(econtext->ecxt_aggvalues != NULL);
1463 :
1464 4436 : *op->resvalue = econtext->ecxt_aggvalues[aggref->aggno];
1465 4436 : *op->resnull = econtext->ecxt_aggnulls[aggref->aggno];
1466 :
1467 4436 : EEO_NEXT();
1468 : }
1469 :
1470 : EEO_CASE(EEOP_GROUPING_FUNC)
1471 : {
1472 : /* too complex/uncommon for an inline implementation */
1473 264 : ExecEvalGroupingFunc(state, op);
1474 :
1475 264 : EEO_NEXT();
1476 : }
1477 :
1478 : EEO_CASE(EEOP_WINDOW_FUNC)
1479 : {
1480 : /*
1481 : * Like Aggref, just return a precomputed value from the econtext.
1482 : */
1483 91572 : WindowFuncExprState *wfunc = op->d.window_func.wfstate;
1484 :
1485 91572 : Assert(econtext->ecxt_aggvalues != NULL);
1486 :
1487 91572 : *op->resvalue = econtext->ecxt_aggvalues[wfunc->wfuncno];
1488 91572 : *op->resnull = econtext->ecxt_aggnulls[wfunc->wfuncno];
1489 :
1490 91572 : EEO_NEXT();
1491 : }
1492 :
1493 : EEO_CASE(EEOP_SUBPLAN)
1494 : {
1495 : /* too complex for an inline implementation */
1496 82700 : ExecEvalSubPlan(state, op, econtext);
1497 :
1498 82700 : EEO_NEXT();
1499 : }
1500 :
1501 : EEO_CASE(EEOP_ALTERNATIVE_SUBPLAN)
1502 : {
1503 : /* too complex for an inline implementation */
1504 143 : ExecEvalAlternativeSubPlan(state, op, econtext);
1505 :
1506 143 : EEO_NEXT();
1507 : }
1508 :
1509 : EEO_CASE(EEOP_LAST)
1510 : {
1511 : /* unreachable */
1512 0 : Assert(false);
1513 : goto out;
1514 : }
1515 : }
1516 :
1517 : out:
1518 21816800 : *isnull = state->resnull;
1519 21816800 : return state->resvalue;
1520 : }
1521 :
1522 : /*
1523 : * Check whether a user attribute in a slot can be referenced by a Var
1524 : * expression. This should succeed unless there have been schema changes
1525 : * since the expression tree has been created.
1526 : */
1527 : static void
1528 20615 : CheckVarSlotCompatibility(TupleTableSlot *slot, int attnum, Oid vartype)
1529 : {
1530 : /*
1531 : * What we have to check for here is the possibility of an attribute
1532 : * having been dropped or changed in type since the plan tree was created.
1533 : * Ideally the plan will get invalidated and not re-used, but just in
1534 : * case, we keep these defenses. Fortunately it's sufficient to check
1535 : * once on the first time through.
1536 : *
1537 : * Note: ideally we'd check typmod as well as typid, but that seems
1538 : * impractical at the moment: in many cases the tupdesc will have been
1539 : * generated by ExecTypeFromTL(), and that can't guarantee to generate an
1540 : * accurate typmod in all cases, because some expression node types don't
1541 : * carry typmod. Fortunately, for precisely that reason, there should be
1542 : * no places with a critical dependency on the typmod of a value.
1543 : *
1544 : * System attributes don't require checking since their types never
1545 : * change.
1546 : */
1547 20615 : if (attnum > 0)
1548 : {
1549 20615 : TupleDesc slot_tupdesc = slot->tts_tupleDescriptor;
1550 : Form_pg_attribute attr;
1551 :
1552 20615 : if (attnum > slot_tupdesc->natts) /* should never happen */
1553 0 : elog(ERROR, "attribute number %d exceeds number of columns %d",
1554 : attnum, slot_tupdesc->natts);
1555 :
1556 20615 : attr = TupleDescAttr(slot_tupdesc, attnum - 1);
1557 :
1558 20615 : if (attr->attisdropped)
1559 2 : ereport(ERROR,
1560 : (errcode(ERRCODE_UNDEFINED_COLUMN),
1561 : errmsg("attribute %d of type %s has been dropped",
1562 : attnum, format_type_be(slot_tupdesc->tdtypeid))));
1563 :
1564 20613 : if (vartype != attr->atttypid)
1565 2 : ereport(ERROR,
1566 : (errcode(ERRCODE_DATATYPE_MISMATCH),
1567 : errmsg("attribute %d of type %s has wrong type",
1568 : attnum, format_type_be(slot_tupdesc->tdtypeid)),
1569 : errdetail("Table has type %s, but query expects %s.",
1570 : format_type_be(attr->atttypid),
1571 : format_type_be(vartype))));
1572 : }
1573 20611 : }
1574 :
1575 : /*
1576 : * get_cached_rowtype: utility function to lookup a rowtype tupdesc
1577 : *
1578 : * type_id, typmod: identity of the rowtype
1579 : * cache_field: where to cache the TupleDesc pointer in expression state node
1580 : * (field must be initialized to NULL)
1581 : * econtext: expression context we are executing in
1582 : *
1583 : * NOTE: because the shutdown callback will be called during plan rescan,
1584 : * must be prepared to re-do this during any node execution; cannot call
1585 : * just once during expression initialization.
1586 : */
1587 : static TupleDesc
1588 13277 : get_cached_rowtype(Oid type_id, int32 typmod,
1589 : TupleDesc *cache_field, ExprContext *econtext)
1590 : {
1591 13277 : TupleDesc tupDesc = *cache_field;
1592 :
1593 : /* Do lookup if no cached value or if requested type changed */
1594 25650 : if (tupDesc == NULL ||
1595 24746 : type_id != tupDesc->tdtypeid ||
1596 12373 : typmod != tupDesc->tdtypmod)
1597 : {
1598 904 : tupDesc = lookup_rowtype_tupdesc(type_id, typmod);
1599 :
1600 904 : if (*cache_field)
1601 : {
1602 : /* Release old tupdesc; but callback is already registered */
1603 0 : ReleaseTupleDesc(*cache_field);
1604 : }
1605 : else
1606 : {
1607 : /* Need to register shutdown callback to release tupdesc */
1608 904 : RegisterExprContextCallback(econtext,
1609 : ShutdownTupleDescRef,
1610 : PointerGetDatum(cache_field));
1611 : }
1612 904 : *cache_field = tupDesc;
1613 : }
1614 13277 : return tupDesc;
1615 : }
1616 :
1617 : /*
1618 : * Callback function to release a tupdesc refcount at econtext shutdown
1619 : */
1620 : static void
1621 885 : ShutdownTupleDescRef(Datum arg)
1622 : {
1623 885 : TupleDesc *cache_field = (TupleDesc *) DatumGetPointer(arg);
1624 :
1625 885 : if (*cache_field)
1626 885 : ReleaseTupleDesc(*cache_field);
1627 885 : *cache_field = NULL;
1628 885 : }
1629 :
1630 : /*
1631 : * Fast-path functions, for very simple expressions
1632 : */
1633 :
1634 : /* Simple reference to inner Var, first time through */
1635 : static Datum
1636 1153 : ExecJustInnerVarFirst(ExprState *state, ExprContext *econtext, bool *isnull)
1637 : {
1638 1153 : ExprEvalStep *op = &state->steps[1];
1639 1153 : int attnum = op->d.var.attnum + 1;
1640 1153 : TupleTableSlot *slot = econtext->ecxt_innertuple;
1641 :
1642 : /* See ExecInterpExpr()'s comments for EEOP_INNER_VAR_FIRST */
1643 :
1644 1153 : CheckVarSlotCompatibility(slot, attnum, op->d.var.vartype);
1645 1153 : op->opcode = EEOP_INNER_VAR; /* just for cleanliness */
1646 1153 : state->evalfunc = ExecJustInnerVar;
1647 :
1648 : /*
1649 : * Since we use slot_getattr(), we don't need to implement the FETCHSOME
1650 : * step explicitly, and we also needn't Assert that the attnum is in range
1651 : * --- slot_getattr() will take care of any problems.
1652 : */
1653 1153 : return slot_getattr(slot, attnum, isnull);
1654 : }
1655 :
1656 : /* Simple reference to inner Var */
1657 : static Datum
1658 543755 : ExecJustInnerVar(ExprState *state, ExprContext *econtext, bool *isnull)
1659 : {
1660 543755 : ExprEvalStep *op = &state->steps[1];
1661 543755 : int attnum = op->d.var.attnum + 1;
1662 543755 : TupleTableSlot *slot = econtext->ecxt_innertuple;
1663 :
1664 : /* See comments in ExecJustInnerVarFirst */
1665 543755 : return slot_getattr(slot, attnum, isnull);
1666 : }
1667 :
1668 : /* Simple reference to outer Var, first time through */
1669 : static Datum
1670 1376 : ExecJustOuterVarFirst(ExprState *state, ExprContext *econtext, bool *isnull)
1671 : {
1672 1376 : ExprEvalStep *op = &state->steps[1];
1673 1376 : int attnum = op->d.var.attnum + 1;
1674 1376 : TupleTableSlot *slot = econtext->ecxt_outertuple;
1675 :
1676 1376 : CheckVarSlotCompatibility(slot, attnum, op->d.var.vartype);
1677 1376 : op->opcode = EEOP_OUTER_VAR; /* just for cleanliness */
1678 1376 : state->evalfunc = ExecJustOuterVar;
1679 :
1680 : /* See comments in ExecJustInnerVarFirst */
1681 1376 : return slot_getattr(slot, attnum, isnull);
1682 : }
1683 :
1684 : /* Simple reference to outer Var */
1685 : static Datum
1686 679974 : ExecJustOuterVar(ExprState *state, ExprContext *econtext, bool *isnull)
1687 : {
1688 679974 : ExprEvalStep *op = &state->steps[1];
1689 679974 : int attnum = op->d.var.attnum + 1;
1690 679974 : TupleTableSlot *slot = econtext->ecxt_outertuple;
1691 :
1692 : /* See comments in ExecJustInnerVarFirst */
1693 679974 : return slot_getattr(slot, attnum, isnull);
1694 : }
1695 :
1696 : /* Simple reference to scan Var, first time through */
1697 : static Datum
1698 1271 : ExecJustScanVarFirst(ExprState *state, ExprContext *econtext, bool *isnull)
1699 : {
1700 1271 : ExprEvalStep *op = &state->steps[1];
1701 1271 : int attnum = op->d.var.attnum + 1;
1702 1271 : TupleTableSlot *slot = econtext->ecxt_scantuple;
1703 :
1704 1271 : CheckVarSlotCompatibility(slot, attnum, op->d.var.vartype);
1705 1271 : op->opcode = EEOP_SCAN_VAR; /* just for cleanliness */
1706 1271 : state->evalfunc = ExecJustScanVar;
1707 :
1708 : /* See comments in ExecJustInnerVarFirst */
1709 1271 : return slot_getattr(slot, attnum, isnull);
1710 : }
1711 :
1712 : /* Simple reference to scan Var */
1713 : static Datum
1714 2583 : ExecJustScanVar(ExprState *state, ExprContext *econtext, bool *isnull)
1715 : {
1716 2583 : ExprEvalStep *op = &state->steps[1];
1717 2583 : int attnum = op->d.var.attnum + 1;
1718 2583 : TupleTableSlot *slot = econtext->ecxt_scantuple;
1719 :
1720 : /* See comments in ExecJustInnerVarFirst */
1721 2583 : return slot_getattr(slot, attnum, isnull);
1722 : }
1723 :
1724 : /* Simple Const expression */
1725 : static Datum
1726 35577 : ExecJustConst(ExprState *state, ExprContext *econtext, bool *isnull)
1727 : {
1728 35577 : ExprEvalStep *op = &state->steps[0];
1729 :
1730 35577 : *isnull = op->d.constval.isnull;
1731 35577 : return op->d.constval.value;
1732 : }
1733 :
1734 : /* Evaluate inner Var and assign to appropriate column of result tuple */
1735 : static Datum
1736 20166 : ExecJustAssignInnerVar(ExprState *state, ExprContext *econtext, bool *isnull)
1737 : {
1738 20166 : ExprEvalStep *op = &state->steps[1];
1739 20166 : int attnum = op->d.assign_var.attnum + 1;
1740 20166 : int resultnum = op->d.assign_var.resultnum;
1741 20166 : TupleTableSlot *inslot = econtext->ecxt_innertuple;
1742 20166 : TupleTableSlot *outslot = state->resultslot;
1743 :
1744 : /*
1745 : * We do not need CheckVarSlotCompatibility here; that was taken care of
1746 : * at compilation time.
1747 : *
1748 : * Since we use slot_getattr(), we don't need to implement the FETCHSOME
1749 : * step explicitly, and we also needn't Assert that the attnum is in range
1750 : * --- slot_getattr() will take care of any problems.
1751 : */
1752 40332 : outslot->tts_values[resultnum] =
1753 20166 : slot_getattr(inslot, attnum, &outslot->tts_isnull[resultnum]);
1754 20166 : return 0;
1755 : }
1756 :
1757 : /* Evaluate outer Var and assign to appropriate column of result tuple */
1758 : static Datum
1759 309728 : ExecJustAssignOuterVar(ExprState *state, ExprContext *econtext, bool *isnull)
1760 : {
1761 309728 : ExprEvalStep *op = &state->steps[1];
1762 309728 : int attnum = op->d.assign_var.attnum + 1;
1763 309728 : int resultnum = op->d.assign_var.resultnum;
1764 309728 : TupleTableSlot *inslot = econtext->ecxt_outertuple;
1765 309728 : TupleTableSlot *outslot = state->resultslot;
1766 :
1767 : /* See comments in ExecJustAssignInnerVar */
1768 619456 : outslot->tts_values[resultnum] =
1769 309728 : slot_getattr(inslot, attnum, &outslot->tts_isnull[resultnum]);
1770 309728 : return 0;
1771 : }
1772 :
1773 : /* Evaluate scan Var and assign to appropriate column of result tuple */
1774 : static Datum
1775 185063 : ExecJustAssignScanVar(ExprState *state, ExprContext *econtext, bool *isnull)
1776 : {
1777 185063 : ExprEvalStep *op = &state->steps[1];
1778 185063 : int attnum = op->d.assign_var.attnum + 1;
1779 185063 : int resultnum = op->d.assign_var.resultnum;
1780 185063 : TupleTableSlot *inslot = econtext->ecxt_scantuple;
1781 185063 : TupleTableSlot *outslot = state->resultslot;
1782 :
1783 : /* See comments in ExecJustAssignInnerVar */
1784 370126 : outslot->tts_values[resultnum] =
1785 185063 : slot_getattr(inslot, attnum, &outslot->tts_isnull[resultnum]);
1786 185063 : return 0;
1787 : }
1788 :
1789 :
1790 : /*
1791 : * Do one-time initialization of interpretation machinery.
1792 : */
1793 : static void
1794 108107 : ExecInitInterpreter(void)
1795 : {
1796 : #if defined(EEO_USE_COMPUTED_GOTO)
1797 : /* Set up externally-visible pointer to dispatch table */
1798 108107 : if (dispatch_table == NULL)
1799 309 : dispatch_table = (const void **)
1800 309 : DatumGetPointer(ExecInterpExpr(NULL, NULL, NULL));
1801 : #endif
1802 108107 : }
1803 :
1804 : /*
1805 : * Function to return the opcode of an expression step.
1806 : *
1807 : * When direct-threading is in use, ExprState->opcode isn't easily
1808 : * decipherable. This function returns the appropriate enum member.
1809 : *
1810 : * This currently is only supposed to be used in paths that aren't critical
1811 : * performance-wise. If that changes, we could add an inverse dispatch_table
1812 : * that's sorted on the address, so a binary search can be performed.
1813 : */
1814 : ExprEvalOp
1815 0 : ExecEvalStepOp(ExprState *state, ExprEvalStep *op)
1816 : {
1817 : #if defined(EEO_USE_COMPUTED_GOTO)
1818 0 : if (state->flags & EEO_FLAG_DIRECT_THREADED)
1819 : {
1820 : int i;
1821 :
1822 0 : for (i = 0; i < EEOP_LAST; i++)
1823 : {
1824 0 : if ((void *) op->opcode == dispatch_table[i])
1825 : {
1826 0 : return (ExprEvalOp) i;
1827 : }
1828 : }
1829 0 : elog(ERROR, "unknown opcode");
1830 : }
1831 : #endif
1832 0 : return (ExprEvalOp) op->opcode;
1833 : }
1834 :
1835 :
1836 : /*
1837 : * Out-of-line helper functions for complex instructions.
1838 : */
1839 :
1840 : /*
1841 : * Evaluate a PARAM_EXEC parameter.
1842 : *
1843 : * PARAM_EXEC params (internal executor parameters) are stored in the
1844 : * ecxt_param_exec_vals array, and can be accessed by array index.
1845 : */
1846 : void
1847 135806 : ExecEvalParamExec(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
1848 : {
1849 : ParamExecData *prm;
1850 :
1851 135806 : prm = &(econtext->ecxt_param_exec_vals[op->d.param.paramid]);
1852 135806 : if (unlikely(prm->execPlan != NULL))
1853 : {
1854 : /* Parameter not evaluated yet, so go do it */
1855 1727 : ExecSetParamPlan(prm->execPlan, econtext);
1856 : /* ExecSetParamPlan should have processed this param... */
1857 1725 : Assert(prm->execPlan == NULL);
1858 : }
1859 135804 : *op->resvalue = prm->value;
1860 135804 : *op->resnull = prm->isnull;
1861 135804 : }
1862 :
1863 : /*
1864 : * Evaluate a PARAM_EXTERN parameter.
1865 : *
1866 : * PARAM_EXTERN parameters must be sought in ecxt_param_list_info.
1867 : */
1868 : void
1869 152588 : ExecEvalParamExtern(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
1870 : {
1871 152588 : ParamListInfo paramInfo = econtext->ecxt_param_list_info;
1872 152588 : int paramId = op->d.param.paramid;
1873 :
1874 152588 : if (likely(paramInfo &&
1875 : paramId > 0 && paramId <= paramInfo->numParams))
1876 : {
1877 152588 : ParamExternData *prm = ¶mInfo->params[paramId - 1];
1878 :
1879 : /* give hook a chance in case parameter is dynamic */
1880 152588 : if (!OidIsValid(prm->ptype) && paramInfo->paramFetch != NULL)
1881 5588 : (*paramInfo->paramFetch) (paramInfo, paramId);
1882 :
1883 152588 : if (likely(OidIsValid(prm->ptype)))
1884 : {
1885 : /* safety check in case hook did something unexpected */
1886 152588 : if (unlikely(prm->ptype != op->d.param.paramtype))
1887 0 : ereport(ERROR,
1888 : (errcode(ERRCODE_DATATYPE_MISMATCH),
1889 : errmsg("type of parameter %d (%s) does not match that when preparing the plan (%s)",
1890 : paramId,
1891 : format_type_be(prm->ptype),
1892 : format_type_be(op->d.param.paramtype))));
1893 152588 : *op->resvalue = prm->value;
1894 152588 : *op->resnull = prm->isnull;
1895 305176 : return;
1896 : }
1897 : }
1898 :
1899 0 : ereport(ERROR,
1900 : (errcode(ERRCODE_UNDEFINED_OBJECT),
1901 : errmsg("no value found for parameter %d", paramId)));
1902 : }
1903 :
1904 : /*
1905 : * Evaluate a SQLValueFunction expression.
1906 : */
1907 : void
1908 750 : ExecEvalSQLValueFunction(ExprState *state, ExprEvalStep *op)
1909 : {
1910 750 : SQLValueFunction *svf = op->d.sqlvaluefunction.svf;
1911 : FunctionCallInfoData fcinfo;
1912 :
1913 750 : *op->resnull = false;
1914 :
1915 : /*
1916 : * Note: current_schema() can return NULL. current_user() etc currently
1917 : * cannot, but might as well code those cases the same way for safety.
1918 : */
1919 750 : switch (svf->op)
1920 : {
1921 : case SVFOP_CURRENT_DATE:
1922 4 : *op->resvalue = DateADTGetDatum(GetSQLCurrentDate());
1923 4 : break;
1924 : case SVFOP_CURRENT_TIME:
1925 : case SVFOP_CURRENT_TIME_N:
1926 1 : *op->resvalue = TimeTzADTPGetDatum(GetSQLCurrentTime(svf->typmod));
1927 1 : break;
1928 : case SVFOP_CURRENT_TIMESTAMP:
1929 : case SVFOP_CURRENT_TIMESTAMP_N:
1930 3 : *op->resvalue = TimestampTzGetDatum(GetSQLCurrentTimestamp(svf->typmod));
1931 3 : break;
1932 : case SVFOP_LOCALTIME:
1933 : case SVFOP_LOCALTIME_N:
1934 1 : *op->resvalue = TimeADTGetDatum(GetSQLLocalTime(svf->typmod));
1935 1 : break;
1936 : case SVFOP_LOCALTIMESTAMP:
1937 : case SVFOP_LOCALTIMESTAMP_N:
1938 1 : *op->resvalue = TimestampGetDatum(GetSQLLocalTimestamp(svf->typmod));
1939 1 : break;
1940 : case SVFOP_CURRENT_ROLE:
1941 : case SVFOP_CURRENT_USER:
1942 : case SVFOP_USER:
1943 711 : InitFunctionCallInfoData(fcinfo, NULL, 0, InvalidOid, NULL, NULL);
1944 711 : *op->resvalue = current_user(&fcinfo);
1945 711 : *op->resnull = fcinfo.isnull;
1946 711 : break;
1947 : case SVFOP_SESSION_USER:
1948 25 : InitFunctionCallInfoData(fcinfo, NULL, 0, InvalidOid, NULL, NULL);
1949 25 : *op->resvalue = session_user(&fcinfo);
1950 25 : *op->resnull = fcinfo.isnull;
1951 25 : break;
1952 : case SVFOP_CURRENT_CATALOG:
1953 1 : InitFunctionCallInfoData(fcinfo, NULL, 0, InvalidOid, NULL, NULL);
1954 1 : *op->resvalue = current_database(&fcinfo);
1955 1 : *op->resnull = fcinfo.isnull;
1956 1 : break;
1957 : case SVFOP_CURRENT_SCHEMA:
1958 3 : InitFunctionCallInfoData(fcinfo, NULL, 0, InvalidOid, NULL, NULL);
1959 3 : *op->resvalue = current_schema(&fcinfo);
1960 3 : *op->resnull = fcinfo.isnull;
1961 3 : break;
1962 : }
1963 750 : }
1964 :
1965 : /*
1966 : * Raise error if a CURRENT OF expression is evaluated.
1967 : *
1968 : * The planner should convert CURRENT OF into a TidScan qualification, or some
1969 : * other special handling in a ForeignScan node. So we have to be able to do
1970 : * ExecInitExpr on a CurrentOfExpr, but we shouldn't ever actually execute it.
1971 : * If we get here, we suppose we must be dealing with CURRENT OF on a foreign
1972 : * table whose FDW doesn't handle it, and complain accordingly.
1973 : */
1974 : void
1975 0 : ExecEvalCurrentOfExpr(ExprState *state, ExprEvalStep *op)
1976 : {
1977 0 : ereport(ERROR,
1978 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1979 : errmsg("WHERE CURRENT OF is not supported for this table type")));
1980 : }
1981 :
1982 : /*
1983 : * Evaluate NextValueExpr.
1984 : */
1985 : void
1986 30 : ExecEvalNextValueExpr(ExprState *state, ExprEvalStep *op)
1987 : {
1988 30 : int64 newval = nextval_internal(op->d.nextvalueexpr.seqid, false);
1989 :
1990 30 : switch (op->d.nextvalueexpr.seqtypid)
1991 : {
1992 : case INT2OID:
1993 2 : *op->resvalue = Int16GetDatum((int16) newval);
1994 2 : break;
1995 : case INT4OID:
1996 25 : *op->resvalue = Int32GetDatum((int32) newval);
1997 25 : break;
1998 : case INT8OID:
1999 3 : *op->resvalue = Int64GetDatum((int64) newval);
2000 3 : break;
2001 : default:
2002 0 : elog(ERROR, "unsupported sequence type %u",
2003 : op->d.nextvalueexpr.seqtypid);
2004 : }
2005 30 : *op->resnull = false;
2006 30 : }
2007 :
2008 : /*
2009 : * Evaluate NullTest / IS NULL for rows.
2010 : */
2011 : void
2012 90 : ExecEvalRowNull(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
2013 : {
2014 90 : ExecEvalRowNullInt(state, op, econtext, true);
2015 90 : }
2016 :
2017 : /*
2018 : * Evaluate NullTest / IS NOT NULL for rows.
2019 : */
2020 : void
2021 49 : ExecEvalRowNotNull(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
2022 : {
2023 49 : ExecEvalRowNullInt(state, op, econtext, false);
2024 49 : }
2025 :
2026 : /* Common code for IS [NOT] NULL on a row value */
2027 : static void
2028 139 : ExecEvalRowNullInt(ExprState *state, ExprEvalStep *op,
2029 : ExprContext *econtext, bool checkisnull)
2030 : {
2031 139 : Datum value = *op->resvalue;
2032 139 : bool isnull = *op->resnull;
2033 : HeapTupleHeader tuple;
2034 : Oid tupType;
2035 : int32 tupTypmod;
2036 : TupleDesc tupDesc;
2037 : HeapTupleData tmptup;
2038 : int att;
2039 :
2040 139 : *op->resnull = false;
2041 :
2042 : /* NULL row variables are treated just as NULL scalar columns */
2043 139 : if (isnull)
2044 : {
2045 9 : *op->resvalue = BoolGetDatum(checkisnull);
2046 93 : return;
2047 : }
2048 :
2049 : /*
2050 : * The SQL standard defines IS [NOT] NULL for a non-null rowtype argument
2051 : * as:
2052 : *
2053 : * "R IS NULL" is true if every field is the null value.
2054 : *
2055 : * "R IS NOT NULL" is true if no field is the null value.
2056 : *
2057 : * This definition is (apparently intentionally) not recursive; so our
2058 : * tests on the fields are primitive attisnull tests, not recursive checks
2059 : * to see if they are all-nulls or no-nulls rowtypes.
2060 : *
2061 : * The standard does not consider the possibility of zero-field rows, but
2062 : * here we consider them to vacuously satisfy both predicates.
2063 : */
2064 :
2065 130 : tuple = DatumGetHeapTupleHeader(value);
2066 :
2067 130 : tupType = HeapTupleHeaderGetTypeId(tuple);
2068 130 : tupTypmod = HeapTupleHeaderGetTypMod(tuple);
2069 :
2070 : /* Lookup tupdesc if first time through or if type changes */
2071 130 : tupDesc = get_cached_rowtype(tupType, tupTypmod,
2072 : &op->d.nulltest_row.argdesc,
2073 : econtext);
2074 :
2075 : /*
2076 : * heap_attisnull needs a HeapTuple not a bare HeapTupleHeader.
2077 : */
2078 130 : tmptup.t_len = HeapTupleHeaderGetDatumLength(tuple);
2079 130 : tmptup.t_data = tuple;
2080 :
2081 249 : for (att = 1; att <= tupDesc->natts; att++)
2082 : {
2083 : /* ignore dropped columns */
2084 194 : if (TupleDescAttr(tupDesc, att - 1)->attisdropped)
2085 0 : continue;
2086 194 : if (heap_attisnull(&tmptup, att))
2087 : {
2088 : /* null field disproves IS NOT NULL */
2089 26 : if (!checkisnull)
2090 : {
2091 4 : *op->resvalue = BoolGetDatum(false);
2092 4 : return;
2093 : }
2094 : }
2095 : else
2096 : {
2097 : /* non-null field disproves IS NULL */
2098 168 : if (checkisnull)
2099 : {
2100 71 : *op->resvalue = BoolGetDatum(false);
2101 71 : return;
2102 : }
2103 : }
2104 : }
2105 :
2106 55 : *op->resvalue = BoolGetDatum(true);
2107 : }
2108 :
2109 : /*
2110 : * Evaluate an ARRAY[] expression.
2111 : *
2112 : * The individual array elements (or subarrays) have already been evaluated
2113 : * into op->d.arrayexpr.elemvalues[]/elemnulls[].
2114 : */
2115 : void
2116 35641 : ExecEvalArrayExpr(ExprState *state, ExprEvalStep *op)
2117 : {
2118 : ArrayType *result;
2119 35641 : Oid element_type = op->d.arrayexpr.elemtype;
2120 35641 : int nelems = op->d.arrayexpr.nelems;
2121 35641 : int ndims = 0;
2122 : int dims[MAXDIM];
2123 : int lbs[MAXDIM];
2124 :
2125 : /* Set non-null as default */
2126 35641 : *op->resnull = false;
2127 :
2128 35641 : if (!op->d.arrayexpr.multidims)
2129 : {
2130 : /* Elements are presumably of scalar type */
2131 35585 : Datum *dvalues = op->d.arrayexpr.elemvalues;
2132 35585 : bool *dnulls = op->d.arrayexpr.elemnulls;
2133 :
2134 : /* Shouldn't happen here, but if length is 0, return empty array */
2135 35585 : if (nelems == 0)
2136 : {
2137 22 : *op->resvalue =
2138 11 : PointerGetDatum(construct_empty_array(element_type));
2139 22 : return;
2140 : }
2141 :
2142 : /* setup for 1-D array of the given length */
2143 35574 : ndims = 1;
2144 35574 : dims[0] = nelems;
2145 35574 : lbs[0] = 1;
2146 :
2147 106722 : result = construct_md_array(dvalues, dnulls, ndims, dims, lbs,
2148 : element_type,
2149 35574 : op->d.arrayexpr.elemlength,
2150 35574 : op->d.arrayexpr.elembyval,
2151 35574 : op->d.arrayexpr.elemalign);
2152 : }
2153 : else
2154 : {
2155 : /* Must be nested array expressions */
2156 56 : int nbytes = 0;
2157 56 : int nitems = 0;
2158 56 : int outer_nelems = 0;
2159 56 : int elem_ndims = 0;
2160 56 : int *elem_dims = NULL;
2161 56 : int *elem_lbs = NULL;
2162 56 : bool firstone = true;
2163 56 : bool havenulls = false;
2164 56 : bool haveempty = false;
2165 : char **subdata;
2166 : bits8 **subbitmaps;
2167 : int *subbytes;
2168 : int *subnitems;
2169 : int32 dataoffset;
2170 : char *dat;
2171 : int iitem;
2172 : int elemoff;
2173 : int i;
2174 :
2175 56 : subdata = (char **) palloc(nelems * sizeof(char *));
2176 56 : subbitmaps = (bits8 **) palloc(nelems * sizeof(bits8 *));
2177 56 : subbytes = (int *) palloc(nelems * sizeof(int));
2178 56 : subnitems = (int *) palloc(nelems * sizeof(int));
2179 :
2180 : /* loop through and get data area from each element */
2181 154 : for (elemoff = 0; elemoff < nelems; elemoff++)
2182 : {
2183 : Datum arraydatum;
2184 : bool eisnull;
2185 : ArrayType *array;
2186 : int this_ndims;
2187 :
2188 98 : arraydatum = op->d.arrayexpr.elemvalues[elemoff];
2189 98 : eisnull = op->d.arrayexpr.elemnulls[elemoff];
2190 :
2191 : /* temporarily ignore null subarrays */
2192 98 : if (eisnull)
2193 : {
2194 0 : haveempty = true;
2195 0 : continue;
2196 : }
2197 :
2198 98 : array = DatumGetArrayTypeP(arraydatum);
2199 :
2200 : /* run-time double-check on element type */
2201 98 : if (element_type != ARR_ELEMTYPE(array))
2202 0 : ereport(ERROR,
2203 : (errcode(ERRCODE_DATATYPE_MISMATCH),
2204 : errmsg("cannot merge incompatible arrays"),
2205 : errdetail("Array with element type %s cannot be "
2206 : "included in ARRAY construct with element type %s.",
2207 : format_type_be(ARR_ELEMTYPE(array)),
2208 : format_type_be(element_type))));
2209 :
2210 98 : this_ndims = ARR_NDIM(array);
2211 : /* temporarily ignore zero-dimensional subarrays */
2212 98 : if (this_ndims <= 0)
2213 : {
2214 0 : haveempty = true;
2215 0 : continue;
2216 : }
2217 :
2218 98 : if (firstone)
2219 : {
2220 : /* Get sub-array details from first member */
2221 56 : elem_ndims = this_ndims;
2222 56 : ndims = elem_ndims + 1;
2223 56 : if (ndims <= 0 || ndims > MAXDIM)
2224 0 : ereport(ERROR,
2225 : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
2226 : errmsg("number of array dimensions (%d) exceeds " \
2227 : "the maximum allowed (%d)", ndims, MAXDIM)));
2228 :
2229 56 : elem_dims = (int *) palloc(elem_ndims * sizeof(int));
2230 56 : memcpy(elem_dims, ARR_DIMS(array), elem_ndims * sizeof(int));
2231 56 : elem_lbs = (int *) palloc(elem_ndims * sizeof(int));
2232 56 : memcpy(elem_lbs, ARR_LBOUND(array), elem_ndims * sizeof(int));
2233 :
2234 56 : firstone = false;
2235 : }
2236 : else
2237 : {
2238 : /* Check other sub-arrays are compatible */
2239 84 : if (elem_ndims != this_ndims ||
2240 42 : memcmp(elem_dims, ARR_DIMS(array),
2241 42 : elem_ndims * sizeof(int)) != 0 ||
2242 42 : memcmp(elem_lbs, ARR_LBOUND(array),
2243 : elem_ndims * sizeof(int)) != 0)
2244 0 : ereport(ERROR,
2245 : (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
2246 : errmsg("multidimensional arrays must have array "
2247 : "expressions with matching dimensions")));
2248 : }
2249 :
2250 98 : subdata[outer_nelems] = ARR_DATA_PTR(array);
2251 98 : subbitmaps[outer_nelems] = ARR_NULLBITMAP(array);
2252 98 : subbytes[outer_nelems] = ARR_SIZE(array) - ARR_DATA_OFFSET(array);
2253 98 : nbytes += subbytes[outer_nelems];
2254 98 : subnitems[outer_nelems] = ArrayGetNItems(this_ndims,
2255 : ARR_DIMS(array));
2256 98 : nitems += subnitems[outer_nelems];
2257 98 : havenulls |= ARR_HASNULL(array);
2258 98 : outer_nelems++;
2259 : }
2260 :
2261 : /*
2262 : * If all items were null or empty arrays, return an empty array;
2263 : * otherwise, if some were and some weren't, raise error. (Note: we
2264 : * must special-case this somehow to avoid trying to generate a 1-D
2265 : * array formed from empty arrays. It's not ideal...)
2266 : */
2267 56 : if (haveempty)
2268 : {
2269 0 : if (ndims == 0) /* didn't find any nonempty array */
2270 : {
2271 0 : *op->resvalue = PointerGetDatum(construct_empty_array(element_type));
2272 0 : return;
2273 : }
2274 0 : ereport(ERROR,
2275 : (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
2276 : errmsg("multidimensional arrays must have array "
2277 : "expressions with matching dimensions")));
2278 : }
2279 :
2280 : /* setup for multi-D array */
2281 56 : dims[0] = outer_nelems;
2282 56 : lbs[0] = 1;
2283 140 : for (i = 1; i < ndims; i++)
2284 : {
2285 84 : dims[i] = elem_dims[i - 1];
2286 84 : lbs[i] = elem_lbs[i - 1];
2287 : }
2288 :
2289 56 : if (havenulls)
2290 : {
2291 1 : dataoffset = ARR_OVERHEAD_WITHNULLS(ndims, nitems);
2292 1 : nbytes += dataoffset;
2293 : }
2294 : else
2295 : {
2296 55 : dataoffset = 0; /* marker for no null bitmap */
2297 55 : nbytes += ARR_OVERHEAD_NONULLS(ndims);
2298 : }
2299 :
2300 56 : result = (ArrayType *) palloc(nbytes);
2301 56 : SET_VARSIZE(result, nbytes);
2302 56 : result->ndim = ndims;
2303 56 : result->dataoffset = dataoffset;
2304 56 : result->elemtype = element_type;
2305 56 : memcpy(ARR_DIMS(result), dims, ndims * sizeof(int));
2306 56 : memcpy(ARR_LBOUND(result), lbs, ndims * sizeof(int));
2307 :
2308 56 : dat = ARR_DATA_PTR(result);
2309 56 : iitem = 0;
2310 154 : for (i = 0; i < outer_nelems; i++)
2311 : {
2312 98 : memcpy(dat, subdata[i], subbytes[i]);
2313 98 : dat += subbytes[i];
2314 98 : if (havenulls)
2315 4 : array_bitmap_copy(ARR_NULLBITMAP(result), iitem,
2316 2 : subbitmaps[i], 0,
2317 2 : subnitems[i]);
2318 98 : iitem += subnitems[i];
2319 : }
2320 : }
2321 :
2322 35630 : *op->resvalue = PointerGetDatum(result);
2323 : }
2324 :
2325 : /*
2326 : * Evaluate an ArrayCoerceExpr expression.
2327 : *
2328 : * Source array is in step's result variable.
2329 : */
2330 : void
2331 6258 : ExecEvalArrayCoerce(ExprState *state, ExprEvalStep *op)
2332 : {
2333 6258 : ArrayCoerceExpr *acoerce = op->d.arraycoerce.coerceexpr;
2334 : Datum arraydatum;
2335 : FunctionCallInfoData locfcinfo;
2336 :
2337 : /* NULL array -> NULL result */
2338 6258 : if (*op->resnull)
2339 6237 : return;
2340 :
2341 6255 : arraydatum = *op->resvalue;
2342 :
2343 : /*
2344 : * If it's binary-compatible, modify the element type in the array header,
2345 : * but otherwise leave the array as we received it.
2346 : */
2347 6255 : if (!OidIsValid(acoerce->elemfuncid))
2348 : {
2349 : /* Detoast input array if necessary, and copy in any case */
2350 6231 : ArrayType *array = DatumGetArrayTypePCopy(arraydatum);
2351 :
2352 6231 : ARR_ELEMTYPE(array) = op->d.arraycoerce.resultelemtype;
2353 6231 : *op->resvalue = PointerGetDatum(array);
2354 6231 : return;
2355 : }
2356 :
2357 : /*
2358 : * Use array_map to apply the function to each array element.
2359 : *
2360 : * We pass on the desttypmod and isExplicit flags whether or not the
2361 : * function wants them.
2362 : *
2363 : * Note: coercion functions are assumed to not use collation.
2364 : */
2365 24 : InitFunctionCallInfoData(locfcinfo, op->d.arraycoerce.elemfunc, 3,
2366 : InvalidOid, NULL, NULL);
2367 24 : locfcinfo.arg[0] = arraydatum;
2368 24 : locfcinfo.arg[1] = Int32GetDatum(acoerce->resulttypmod);
2369 24 : locfcinfo.arg[2] = BoolGetDatum(acoerce->isExplicit);
2370 24 : locfcinfo.argnull[0] = false;
2371 24 : locfcinfo.argnull[1] = false;
2372 24 : locfcinfo.argnull[2] = false;
2373 :
2374 48 : *op->resvalue = array_map(&locfcinfo, op->d.arraycoerce.resultelemtype,
2375 24 : op->d.arraycoerce.amstate);
2376 : }
2377 :
2378 : /*
2379 : * Evaluate a ROW() expression.
2380 : *
2381 : * The individual columns have already been evaluated into
2382 : * op->d.row.elemvalues[]/elemnulls[].
2383 : */
2384 : void
2385 645 : ExecEvalRow(ExprState *state, ExprEvalStep *op)
2386 : {
2387 : HeapTuple tuple;
2388 :
2389 : /* build tuple from evaluated field values */
2390 645 : tuple = heap_form_tuple(op->d.row.tupdesc,
2391 : op->d.row.elemvalues,
2392 : op->d.row.elemnulls);
2393 :
2394 645 : *op->resvalue = HeapTupleGetDatum(tuple);
2395 645 : *op->resnull = false;
2396 645 : }
2397 :
2398 : /*
2399 : * Evaluate GREATEST() or LEAST() expression (note this is *not* MIN()/MAX()).
2400 : *
2401 : * All of the to-be-compared expressions have already been evaluated into
2402 : * op->d.minmax.values[]/nulls[].
2403 : */
2404 : void
2405 99 : ExecEvalMinMax(ExprState *state, ExprEvalStep *op)
2406 : {
2407 99 : Datum *values = op->d.minmax.values;
2408 99 : bool *nulls = op->d.minmax.nulls;
2409 99 : FunctionCallInfo fcinfo = op->d.minmax.fcinfo_data;
2410 99 : MinMaxOp operator = op->d.minmax.op;
2411 : int off;
2412 :
2413 : /* set at initialization */
2414 99 : Assert(fcinfo->argnull[0] == false);
2415 99 : Assert(fcinfo->argnull[1] == false);
2416 :
2417 : /* default to null result */
2418 99 : *op->resnull = true;
2419 :
2420 337 : for (off = 0; off < op->d.minmax.nelems; off++)
2421 : {
2422 : /* ignore NULL inputs */
2423 238 : if (nulls[off])
2424 2 : continue;
2425 :
2426 236 : if (*op->resnull)
2427 : {
2428 : /* first nonnull input, adopt value */
2429 99 : *op->resvalue = values[off];
2430 99 : *op->resnull = false;
2431 : }
2432 : else
2433 : {
2434 : int cmpresult;
2435 :
2436 : /* apply comparison function */
2437 137 : fcinfo->arg[0] = *op->resvalue;
2438 137 : fcinfo->arg[1] = values[off];
2439 :
2440 137 : fcinfo->isnull = false;
2441 137 : cmpresult = DatumGetInt32(FunctionCallInvoke(fcinfo));
2442 137 : if (fcinfo->isnull) /* probably should not happen */
2443 0 : continue;
2444 :
2445 137 : if (cmpresult > 0 && operator == IS_LEAST)
2446 18 : *op->resvalue = values[off];
2447 119 : else if (cmpresult < 0 && operator == IS_GREATEST)
2448 16 : *op->resvalue = values[off];
2449 : }
2450 : }
2451 99 : }
2452 :
2453 : /*
2454 : * Evaluate a FieldSelect node.
2455 : *
2456 : * Source record is in step's result variable.
2457 : */
2458 : void
2459 13047 : ExecEvalFieldSelect(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
2460 : {
2461 13047 : AttrNumber fieldnum = op->d.fieldselect.fieldnum;
2462 : Datum tupDatum;
2463 : HeapTupleHeader tuple;
2464 : Oid tupType;
2465 : int32 tupTypmod;
2466 : TupleDesc tupDesc;
2467 : Form_pg_attribute attr;
2468 : HeapTupleData tmptup;
2469 :
2470 : /* NULL record -> NULL result */
2471 13047 : if (*op->resnull)
2472 14 : return;
2473 :
2474 : /* Get the composite datum and extract its type fields */
2475 13040 : tupDatum = *op->resvalue;
2476 13040 : tuple = DatumGetHeapTupleHeader(tupDatum);
2477 :
2478 13040 : tupType = HeapTupleHeaderGetTypeId(tuple);
2479 13040 : tupTypmod = HeapTupleHeaderGetTypMod(tuple);
2480 :
2481 : /* Lookup tupdesc if first time through or if type changes */
2482 13040 : tupDesc = get_cached_rowtype(tupType, tupTypmod,
2483 : &op->d.fieldselect.argdesc,
2484 : econtext);
2485 :
2486 : /*
2487 : * Find field's attr record. Note we don't support system columns here: a
2488 : * datum tuple doesn't have valid values for most of the interesting
2489 : * system columns anyway.
2490 : */
2491 13040 : if (fieldnum <= 0) /* should never happen */
2492 0 : elog(ERROR, "unsupported reference to system column %d in FieldSelect",
2493 : fieldnum);
2494 13040 : if (fieldnum > tupDesc->natts) /* should never happen */
2495 0 : elog(ERROR, "attribute number %d exceeds number of columns %d",
2496 : fieldnum, tupDesc->natts);
2497 13040 : attr = TupleDescAttr(tupDesc, fieldnum - 1);
2498 :
2499 : /* Check for dropped column, and force a NULL result if so */
2500 13040 : if (attr->attisdropped)
2501 : {
2502 0 : *op->resnull = true;
2503 0 : return;
2504 : }
2505 :
2506 : /* Check for type mismatch --- possible after ALTER COLUMN TYPE? */
2507 : /* As in CheckVarSlotCompatibility, we should but can't check typmod */
2508 13040 : if (op->d.fieldselect.resulttype != attr->atttypid)
2509 0 : ereport(ERROR,
2510 : (errcode(ERRCODE_DATATYPE_MISMATCH),
2511 : errmsg("attribute %d has wrong type", fieldnum),
2512 : errdetail("Table has type %s, but query expects %s.",
2513 : format_type_be(attr->atttypid),
2514 : format_type_be(op->d.fieldselect.resulttype))));
2515 :
2516 : /* heap_getattr needs a HeapTuple not a bare HeapTupleHeader */
2517 13040 : tmptup.t_len = HeapTupleHeaderGetDatumLength(tuple);
2518 13040 : tmptup.t_data = tuple;
2519 :
2520 : /* extract the field */
2521 13040 : *op->resvalue = heap_getattr(&tmptup,
2522 : fieldnum,
2523 : tupDesc,
2524 : op->resnull);
2525 : }
2526 :
2527 : /*
2528 : * Deform source tuple, filling in the step's values/nulls arrays, before
2529 : * evaluating individual new values as part of a FieldStore expression.
2530 : * Subsequent steps will overwrite individual elements of the values/nulls
2531 : * arrays with the new field values, and then FIELDSTORE_FORM will build the
2532 : * new tuple value.
2533 : *
2534 : * Source record is in step's result variable.
2535 : */
2536 : void
2537 45 : ExecEvalFieldStoreDeForm(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
2538 : {
2539 : TupleDesc tupDesc;
2540 :
2541 : /* Lookup tupdesc if first time through or after rescan */
2542 45 : tupDesc = get_cached_rowtype(op->d.fieldstore.fstore->resulttype, -1,
2543 : op->d.fieldstore.argdesc, econtext);
2544 :
2545 : /* Check that current tupdesc doesn't have more fields than we allocated */
2546 45 : if (unlikely(tupDesc->natts > op->d.fieldstore.ncolumns))
2547 0 : elog(ERROR, "too many columns in composite type %u",
2548 : op->d.fieldstore.fstore->resulttype);
2549 :
2550 45 : if (*op->resnull)
2551 : {
2552 : /* Convert null input tuple into an all-nulls row */
2553 20 : memset(op->d.fieldstore.nulls, true,
2554 20 : op->d.fieldstore.ncolumns * sizeof(bool));
2555 : }
2556 : else
2557 : {
2558 : /*
2559 : * heap_deform_tuple needs a HeapTuple not a bare HeapTupleHeader. We
2560 : * set all the fields in the struct just in case.
2561 : */
2562 25 : Datum tupDatum = *op->resvalue;
2563 : HeapTupleHeader tuphdr;
2564 : HeapTupleData tmptup;
2565 :
2566 25 : tuphdr = DatumGetHeapTupleHeader(tupDatum);
2567 25 : tmptup.t_len = HeapTupleHeaderGetDatumLength(tuphdr);
2568 25 : ItemPointerSetInvalid(&(tmptup.t_self));
2569 25 : tmptup.t_tableOid = InvalidOid;
2570 25 : tmptup.t_data = tuphdr;
2571 :
2572 25 : heap_deform_tuple(&tmptup, tupDesc,
2573 : op->d.fieldstore.values,
2574 : op->d.fieldstore.nulls);
2575 : }
2576 45 : }
2577 :
2578 : /*
2579 : * Compute the new composite datum after each individual field value of a
2580 : * FieldStore expression has been evaluated.
2581 : */
2582 : void
2583 45 : ExecEvalFieldStoreForm(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
2584 : {
2585 : HeapTuple tuple;
2586 :
2587 : /* argdesc should already be valid from the DeForm step */
2588 45 : tuple = heap_form_tuple(*op->d.fieldstore.argdesc,
2589 : op->d.fieldstore.values,
2590 : op->d.fieldstore.nulls);
2591 :
2592 45 : *op->resvalue = HeapTupleGetDatum(tuple);
2593 45 : *op->resnull = false;
2594 45 : }
2595 :
2596 : /*
2597 : * Process a subscript in an ArrayRef expression.
2598 : *
2599 : * If subscript is NULL, throw error in assignment case, or in fetch case
2600 : * set result to NULL and return false (instructing caller to skip the rest
2601 : * of the ArrayRef sequence).
2602 : *
2603 : * Subscript expression result is in subscriptvalue/subscriptnull.
2604 : * On success, integer subscript value has been saved in upperindex[] or
2605 : * lowerindex[] for use later.
2606 : */
2607 : bool
2608 26864 : ExecEvalArrayRefSubscript(ExprState *state, ExprEvalStep *op)
2609 : {
2610 26864 : ArrayRefState *arefstate = op->d.arrayref_subscript.state;
2611 : int *indexes;
2612 : int off;
2613 :
2614 : /* If any index expr yields NULL, result is NULL or error */
2615 26864 : if (arefstate->subscriptnull)
2616 : {
2617 6 : if (arefstate->isassignment)
2618 3 : ereport(ERROR,
2619 : (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
2620 : errmsg("array subscript in assignment must not be null")));
2621 3 : *op->resnull = true;
2622 3 : return false;
2623 : }
2624 :
2625 : /* Convert datum to int, save in appropriate place */
2626 26858 : if (op->d.arrayref_subscript.isupper)
2627 26742 : indexes = arefstate->upperindex;
2628 : else
2629 116 : indexes = arefstate->lowerindex;
2630 26858 : off = op->d.arrayref_subscript.off;
2631 :
2632 26858 : indexes[off] = DatumGetInt32(arefstate->subscriptvalue);
2633 :
2634 26858 : return true;
2635 : }
2636 :
2637 : /*
2638 : * Evaluate ArrayRef fetch.
2639 : *
2640 : * Source array is in step's result variable.
2641 : */
2642 : void
2643 26549 : ExecEvalArrayRefFetch(ExprState *state, ExprEvalStep *op)
2644 : {
2645 26549 : ArrayRefState *arefstate = op->d.arrayref.state;
2646 :
2647 : /* Should not get here if source array (or any subscript) is null */
2648 26549 : Assert(!(*op->resnull));
2649 :
2650 26549 : if (arefstate->numlower == 0)
2651 : {
2652 : /* Scalar case */
2653 158976 : *op->resvalue = array_get_element(*op->resvalue,
2654 : arefstate->numupper,
2655 26496 : arefstate->upperindex,
2656 26496 : arefstate->refattrlength,
2657 26496 : arefstate->refelemlength,
2658 26496 : arefstate->refelembyval,
2659 26496 : arefstate->refelemalign,
2660 : op->resnull);
2661 : }
2662 : else
2663 : {
2664 : /* Slice case */
2665 318 : *op->resvalue = array_get_slice(*op->resvalue,
2666 : arefstate->numupper,
2667 53 : arefstate->upperindex,
2668 53 : arefstate->lowerindex,
2669 53 : arefstate->upperprovided,
2670 53 : arefstate->lowerprovided,
2671 53 : arefstate->refattrlength,
2672 53 : arefstate->refelemlength,
2673 53 : arefstate->refelembyval,
2674 53 : arefstate->refelemalign);
2675 : }
2676 26545 : }
2677 :
2678 : /*
2679 : * Compute old array element/slice value for an ArrayRef assignment
2680 : * expression. Will only be generated if the new-value subexpression
2681 : * contains ArrayRef or FieldStore. The value is stored into the
2682 : * ArrayRefState's prevvalue/prevnull fields.
2683 : */
2684 : void
2685 33 : ExecEvalArrayRefOld(ExprState *state, ExprEvalStep *op)
2686 : {
2687 33 : ArrayRefState *arefstate = op->d.arrayref.state;
2688 :
2689 33 : if (*op->resnull)
2690 : {
2691 : /* whole array is null, so any element or slice is too */
2692 9 : arefstate->prevvalue = (Datum) 0;
2693 9 : arefstate->prevnull = true;
2694 : }
2695 24 : else if (arefstate->numlower == 0)
2696 : {
2697 : /* Scalar case */
2698 144 : arefstate->prevvalue = array_get_element(*op->resvalue,
2699 : arefstate->numupper,
2700 24 : arefstate->upperindex,
2701 24 : arefstate->refattrlength,
2702 24 : arefstate->refelemlength,
2703 24 : arefstate->refelembyval,
2704 24 : arefstate->refelemalign,
2705 : &arefstate->prevnull);
2706 : }
2707 : else
2708 : {
2709 : /* Slice case */
2710 : /* this is currently unreachable */
2711 0 : arefstate->prevvalue = array_get_slice(*op->resvalue,
2712 : arefstate->numupper,
2713 0 : arefstate->upperindex,
2714 0 : arefstate->lowerindex,
2715 0 : arefstate->upperprovided,
2716 0 : arefstate->lowerprovided,
2717 0 : arefstate->refattrlength,
2718 0 : arefstate->refelemlength,
2719 0 : arefstate->refelembyval,
2720 0 : arefstate->refelemalign);
2721 0 : arefstate->prevnull = false;
2722 : }
2723 33 : }
2724 :
2725 : /*
2726 : * Evaluate ArrayRef assignment.
2727 : *
2728 : * Input array (possibly null) is in result area, replacement value is in
2729 : * ArrayRefState's replacevalue/replacenull.
2730 : */
2731 : void
2732 140 : ExecEvalArrayRefAssign(ExprState *state, ExprEvalStep *op)
2733 : {
2734 140 : ArrayRefState *arefstate = op->d.arrayref.state;
2735 :
2736 : /*
2737 : * For an assignment to a fixed-length array type, both the original array
2738 : * and the value to be assigned into it must be non-NULL, else we punt and
2739 : * return the original array.
2740 : */
2741 140 : if (arefstate->refattrlength > 0) /* fixed-length array? */
2742 : {
2743 6 : if (*op->resnull || arefstate->replacenull)
2744 140 : return;
2745 : }
2746 :
2747 : /*
2748 : * For assignment to varlena arrays, we handle a NULL original array by
2749 : * substituting an empty (zero-dimensional) array; insertion of the new
2750 : * element will result in a singleton array value. It does not matter
2751 : * whether the new element is NULL.
2752 : */
2753 137 : if (*op->resnull)
2754 : {
2755 32 : *op->resvalue = PointerGetDatum(construct_empty_array(arefstate->refelemtype));
2756 32 : *op->resnull = false;
2757 : }
2758 :
2759 137 : if (arefstate->numlower == 0)
2760 : {
2761 : /* Scalar case */
2762 679 : *op->resvalue = array_set_element(*op->resvalue,
2763 : arefstate->numupper,
2764 97 : arefstate->upperindex,
2765 : arefstate->replacevalue,
2766 97 : arefstate->replacenull,
2767 97 : arefstate->refattrlength,
2768 97 : arefstate->refelemlength,
2769 97 : arefstate->refelembyval,
2770 97 : arefstate->refelemalign);
2771 : }
2772 : else
2773 : {
2774 : /* Slice case */
2775 280 : *op->resvalue = array_set_slice(*op->resvalue,
2776 : arefstate->numupper,
2777 40 : arefstate->upperindex,
2778 40 : arefstate->lowerindex,
2779 40 : arefstate->upperprovided,
2780 40 : arefstate->lowerprovided,
2781 : arefstate->replacevalue,
2782 40 : arefstate->replacenull,
2783 40 : arefstate->refattrlength,
2784 40 : arefstate->refelemlength,
2785 40 : arefstate->refelembyval,
2786 40 : arefstate->refelemalign);
2787 : }
2788 : }
2789 :
2790 : /*
2791 : * Evaluate a rowtype coercion operation.
2792 : * This may require rearranging field positions.
2793 : *
2794 : * Source record is in step's result variable.
2795 : */
2796 : void
2797 57 : ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
2798 : {
2799 57 : ConvertRowtypeExpr *convert = op->d.convert_rowtype.convert;
2800 : HeapTuple result;
2801 : Datum tupDatum;
2802 : HeapTupleHeader tuple;
2803 : HeapTupleData tmptup;
2804 : TupleDesc indesc,
2805 : outdesc;
2806 :
2807 : /* NULL in -> NULL out */
2808 57 : if (*op->resnull)
2809 58 : return;
2810 :
2811 56 : tupDatum = *op->resvalue;
2812 56 : tuple = DatumGetHeapTupleHeader(tupDatum);
2813 :
2814 : /* Lookup tupdescs if first time through or after rescan */
2815 56 : if (op->d.convert_rowtype.indesc == NULL)
2816 : {
2817 31 : get_cached_rowtype(exprType((Node *) convert->arg), -1,
2818 : &op->d.convert_rowtype.indesc,
2819 : econtext);
2820 31 : op->d.convert_rowtype.initialized = false;
2821 : }
2822 56 : if (op->d.convert_rowtype.outdesc == NULL)
2823 : {
2824 31 : get_cached_rowtype(convert->resulttype, -1,
2825 : &op->d.convert_rowtype.outdesc,
2826 : econtext);
2827 31 : op->d.convert_rowtype.initialized = false;
2828 : }
2829 :
2830 56 : indesc = op->d.convert_rowtype.indesc;
2831 56 : outdesc = op->d.convert_rowtype.outdesc;
2832 :
2833 : /*
2834 : * We used to be able to assert that incoming tuples are marked with
2835 : * exactly the rowtype of indesc. However, now that ExecEvalWholeRowVar
2836 : * might change the tuples' marking to plain RECORD due to inserting
2837 : * aliases, we can only make this weak test:
2838 : */
2839 56 : Assert(HeapTupleHeaderGetTypeId(tuple) == indesc->tdtypeid ||
2840 : HeapTupleHeaderGetTypeId(tuple) == RECORDOID);
2841 :
2842 : /* if first time through, initialize conversion map */
2843 56 : if (!op->d.convert_rowtype.initialized)
2844 : {
2845 : MemoryContext old_cxt;
2846 :
2847 : /* allocate map in long-lived memory context */
2848 31 : old_cxt = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
2849 :
2850 : /* prepare map from old to new attribute numbers */
2851 31 : op->d.convert_rowtype.map =
2852 31 : convert_tuples_by_name(indesc, outdesc,
2853 : gettext_noop("could not convert row type"));
2854 31 : op->d.convert_rowtype.initialized = true;
2855 :
2856 31 : MemoryContextSwitchTo(old_cxt);
2857 : }
2858 :
2859 : /* Following steps need a HeapTuple not a bare HeapTupleHeader */
2860 56 : tmptup.t_len = HeapTupleHeaderGetDatumLength(tuple);
2861 56 : tmptup.t_data = tuple;
2862 :
2863 56 : if (op->d.convert_rowtype.map != NULL)
2864 : {
2865 : /* Full conversion with attribute rearrangement needed */
2866 50 : result = do_convert_tuple(&tmptup, op->d.convert_rowtype.map);
2867 : /* Result already has appropriate composite-datum header fields */
2868 50 : *op->resvalue = HeapTupleGetDatum(result);
2869 : }
2870 : else
2871 : {
2872 : /*
2873 : * The tuple is physically compatible as-is, but we need to insert the
2874 : * destination rowtype OID in its composite-datum header field, so we
2875 : * have to copy it anyway. heap_copy_tuple_as_datum() is convenient
2876 : * for this since it will both make the physical copy and insert the
2877 : * correct composite header fields. Note that we aren't expecting to
2878 : * have to flatten any toasted fields: the input was a composite
2879 : * datum, so it shouldn't contain any. So heap_copy_tuple_as_datum()
2880 : * is overkill here, but its check for external fields is cheap.
2881 : */
2882 6 : *op->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc);
2883 : }
2884 : }
2885 :
2886 : /*
2887 : * Evaluate "scalar op ANY/ALL (array)".
2888 : *
2889 : * Source array is in our result area, scalar arg is already evaluated into
2890 : * fcinfo->arg[0]/argnull[0].
2891 : *
2892 : * The operator always yields boolean, and we combine the results across all
2893 : * array elements using OR and AND (for ANY and ALL respectively). Of course
2894 : * we short-circuit as soon as the result is known.
2895 : */
2896 : void
2897 84404 : ExecEvalScalarArrayOp(ExprState *state, ExprEvalStep *op)
2898 : {
2899 84404 : FunctionCallInfo fcinfo = op->d.scalararrayop.fcinfo_data;
2900 84404 : bool useOr = op->d.scalararrayop.useOr;
2901 84404 : bool strictfunc = op->d.scalararrayop.finfo->fn_strict;
2902 : ArrayType *arr;
2903 : int nitems;
2904 : Datum result;
2905 : bool resultnull;
2906 : int i;
2907 : int16 typlen;
2908 : bool typbyval;
2909 : char typalign;
2910 : char *s;
2911 : bits8 *bitmap;
2912 : int bitmask;
2913 :
2914 : /*
2915 : * If the array is NULL then we return NULL --- it's not very meaningful
2916 : * to do anything else, even if the operator isn't strict.
2917 : */
2918 84404 : if (*op->resnull)
2919 8 : return;
2920 :
2921 : /* Else okay to fetch and detoast the array */
2922 84396 : arr = DatumGetArrayTypeP(*op->resvalue);
2923 :
2924 : /*
2925 : * If the array is empty, we return either FALSE or TRUE per the useOr
2926 : * flag. This is correct even if the scalar is NULL; since we would
2927 : * evaluate the operator zero times, it matters not whether it would want
2928 : * to return NULL.
2929 : */
2930 84396 : nitems = ArrayGetNItems(ARR_NDIM(arr), ARR_DIMS(arr));
2931 84396 : if (nitems <= 0)
2932 : {
2933 254 : *op->resvalue = BoolGetDatum(!useOr);
2934 254 : *op->resnull = false;
2935 254 : return;
2936 : }
2937 :
2938 : /*
2939 : * If the scalar is NULL, and the function is strict, return NULL; no
2940 : * point in iterating the loop.
2941 : */
2942 84142 : if (fcinfo->argnull[0] && strictfunc)
2943 : {
2944 5 : *op->resnull = true;
2945 5 : return;
2946 : }
2947 :
2948 : /*
2949 : * We arrange to look up info about the element type only once per series
2950 : * of calls, assuming the element type doesn't change underneath us.
2951 : */
2952 84137 : if (op->d.scalararrayop.element_type != ARR_ELEMTYPE(arr))
2953 : {
2954 652 : get_typlenbyvalalign(ARR_ELEMTYPE(arr),
2955 : &op->d.scalararrayop.typlen,
2956 : &op->d.scalararrayop.typbyval,
2957 : &op->d.scalararrayop.typalign);
2958 652 : op->d.scalararrayop.element_type = ARR_ELEMTYPE(arr);
2959 : }
2960 :
2961 84137 : typlen = op->d.scalararrayop.typlen;
2962 84137 : typbyval = op->d.scalararrayop.typbyval;
2963 84137 : typalign = op->d.scalararrayop.typalign;
2964 :
2965 : /* Initialize result appropriately depending on useOr */
2966 84137 : result = BoolGetDatum(!useOr);
2967 84137 : resultnull = false;
2968 :
2969 : /* Loop over the array elements */
2970 84137 : s = (char *) ARR_DATA_PTR(arr);
2971 84137 : bitmap = ARR_NULLBITMAP(arr);
2972 84137 : bitmask = 1;
2973 :
2974 218097 : for (i = 0; i < nitems; i++)
2975 : {
2976 : Datum elt;
2977 : Datum thisresult;
2978 :
2979 : /* Get array element, checking for NULL */
2980 190495 : if (bitmap && (*bitmap & bitmask) == 0)
2981 : {
2982 4 : fcinfo->arg[1] = (Datum) 0;
2983 4 : fcinfo->argnull[1] = true;
2984 : }
2985 : else
2986 : {
2987 190491 : elt = fetch_att(s, typbyval, typlen);
2988 190491 : s = att_addlength_pointer(s, typlen, s);
2989 190491 : s = (char *) att_align_nominal(s, typalign);
2990 190491 : fcinfo->arg[1] = elt;
2991 190491 : fcinfo->argnull[1] = false;
2992 : }
2993 :
2994 : /* Call comparison function */
2995 190495 : if (fcinfo->argnull[1] && strictfunc)
2996 : {
2997 4 : fcinfo->isnull = true;
2998 4 : thisresult = (Datum) 0;
2999 : }
3000 : else
3001 : {
3002 190491 : fcinfo->isnull = false;
3003 190491 : thisresult = (op->d.scalararrayop.fn_addr) (fcinfo);
3004 : }
3005 :
3006 : /* Combine results per OR or AND semantics */
3007 190495 : if (fcinfo->isnull)
3008 4 : resultnull = true;
3009 190491 : else if (useOr)
3010 : {
3011 104960 : if (DatumGetBool(thisresult))
3012 : {
3013 15827 : result = BoolGetDatum(true);
3014 15827 : resultnull = false;
3015 15827 : break; /* needn't look at any more elements */
3016 : }
3017 : }
3018 : else
3019 : {
3020 85531 : if (!DatumGetBool(thisresult))
3021 : {
3022 40708 : result = BoolGetDatum(false);
3023 40708 : resultnull = false;
3024 40708 : break; /* needn't look at any more elements */
3025 : }
3026 : }
3027 :
3028 : /* advance bitmap pointer if any */
3029 133960 : if (bitmap)
3030 : {
3031 1008 : bitmask <<= 1;
3032 1008 : if (bitmask == 0x100)
3033 : {
3034 125 : bitmap++;
3035 125 : bitmask = 1;
3036 : }
3037 : }
3038 : }
3039 :
3040 84137 : *op->resvalue = result;
3041 84137 : *op->resnull = resultnull;
3042 : }
3043 :
3044 : /*
3045 : * Evaluate a NOT NULL domain constraint.
3046 : */
3047 : void
3048 52 : ExecEvalConstraintNotNull(ExprState *state, ExprEvalStep *op)
3049 : {
3050 52 : if (*op->resnull)
3051 12 : ereport(ERROR,
3052 : (errcode(ERRCODE_NOT_NULL_VIOLATION),
3053 : errmsg("domain %s does not allow null values",
3054 : format_type_be(op->d.domaincheck.resulttype)),
3055 : errdatatype(op->d.domaincheck.resulttype)));
3056 40 : }
3057 :
3058 : /*
3059 : * Evaluate a CHECK domain constraint.
3060 : */
3061 : void
3062 703 : ExecEvalConstraintCheck(ExprState *state, ExprEvalStep *op)
3063 : {
3064 1389 : if (!*op->d.domaincheck.checknull &&
3065 686 : !DatumGetBool(*op->d.domaincheck.checkvalue))
3066 38 : ereport(ERROR,
3067 : (errcode(ERRCODE_CHECK_VIOLATION),
3068 : errmsg("value for domain %s violates check constraint \"%s\"",
3069 : format_type_be(op->d.domaincheck.resulttype),
3070 : op->d.domaincheck.constraintname),
3071 : errdomainconstraint(op->d.domaincheck.resulttype,
3072 : op->d.domaincheck.constraintname)));
3073 665 : }
3074 :
3075 : /*
3076 : * Evaluate the various forms of XmlExpr.
3077 : *
3078 : * Arguments have been evaluated into named_argvalue/named_argnull
3079 : * and/or argvalue/argnull arrays.
3080 : */
3081 : void
3082 24 : ExecEvalXmlExpr(ExprState *state, ExprEvalStep *op)
3083 : {
3084 24 : XmlExpr *xexpr = op->d.xmlexpr.xexpr;
3085 : Datum value;
3086 : int i;
3087 :
3088 24 : *op->resnull = true; /* until we get a result */
3089 24 : *op->resvalue = (Datum) 0;
3090 :
3091 24 : switch (xexpr->op)
3092 : {
3093 : case IS_XMLCONCAT:
3094 : {
3095 2 : Datum *argvalue = op->d.xmlexpr.argvalue;
3096 2 : bool *argnull = op->d.xmlexpr.argnull;
3097 2 : List *values = NIL;
3098 :
3099 5 : for (i = 0; i < list_length(xexpr->args); i++)
3100 : {
3101 3 : if (!argnull[i])
3102 0 : values = lappend(values, DatumGetPointer(argvalue[i]));
3103 : }
3104 :
3105 2 : if (values != NIL)
3106 : {
3107 0 : *op->resvalue = PointerGetDatum(xmlconcat(values));
3108 0 : *op->resnull = false;
3109 : }
3110 : }
3111 2 : break;
3112 :
3113 : case IS_XMLFOREST:
3114 : {
3115 0 : Datum *argvalue = op->d.xmlexpr.named_argvalue;
3116 0 : bool *argnull = op->d.xmlexpr.named_argnull;
3117 : StringInfoData buf;
3118 : ListCell *lc;
3119 : ListCell *lc2;
3120 :
3121 0 : initStringInfo(&buf);
3122 :
3123 0 : i = 0;
3124 0 : forboth(lc, xexpr->named_args, lc2, xexpr->arg_names)
3125 : {
3126 0 : Expr *e = (Expr *) lfirst(lc);
3127 0 : char *argname = strVal(lfirst(lc2));
3128 :
3129 0 : if (!argnull[i])
3130 : {
3131 0 : value = argvalue[i];
3132 0 : appendStringInfo(&buf, "<%s>%s</%s>",
3133 : argname,
3134 : map_sql_value_to_xml_value(value,
3135 : exprType((Node *) e), true),
3136 : argname);
3137 0 : *op->resnull = false;
3138 : }
3139 0 : i++;
3140 : }
3141 :
3142 0 : if (!*op->resnull)
3143 : {
3144 : text *result;
3145 :
3146 0 : result = cstring_to_text_with_len(buf.data, buf.len);
3147 0 : *op->resvalue = PointerGetDatum(result);
3148 : }
3149 :
3150 0 : pfree(buf.data);
3151 : }
3152 0 : break;
3153 :
3154 : case IS_XMLELEMENT:
3155 0 : *op->resvalue = PointerGetDatum(xmlelement(xexpr,
3156 : op->d.xmlexpr.named_argvalue,
3157 : op->d.xmlexpr.named_argnull,
3158 : op->d.xmlexpr.argvalue,
3159 : op->d.xmlexpr.argnull));
3160 0 : *op->resnull = false;
3161 0 : break;
3162 :
3163 : case IS_XMLPARSE:
3164 : {
3165 22 : Datum *argvalue = op->d.xmlexpr.argvalue;
3166 22 : bool *argnull = op->d.xmlexpr.argnull;
3167 : text *data;
3168 : bool preserve_whitespace;
3169 :
3170 : /* arguments are known to be text, bool */
3171 22 : Assert(list_length(xexpr->args) == 2);
3172 :
3173 22 : if (argnull[0])
3174 0 : return;
3175 22 : value = argvalue[0];
3176 22 : data = DatumGetTextPP(value);
3177 :
3178 22 : if (argnull[1]) /* probably can't happen */
3179 0 : return;
3180 22 : value = argvalue[1];
3181 22 : preserve_whitespace = DatumGetBool(value);
3182 :
3183 22 : *op->resvalue = PointerGetDatum(xmlparse(data,
3184 : xexpr->xmloption,
3185 : preserve_whitespace));
3186 0 : *op->resnull = false;
3187 : }
3188 0 : break;
3189 :
3190 : case IS_XMLPI:
3191 : {
3192 : text *arg;
3193 : bool isnull;
3194 :
3195 : /* optional argument is known to be text */
3196 0 : Assert(list_length(xexpr->args) <= 1);
3197 :
3198 0 : if (xexpr->args)
3199 : {
3200 0 : isnull = op->d.xmlexpr.argnull[0];
3201 0 : if (isnull)
3202 0 : arg = NULL;
3203 : else
3204 0 : arg = DatumGetTextPP(op->d.xmlexpr.argvalue[0]);
3205 : }
3206 : else
3207 : {
3208 0 : arg = NULL;
3209 0 : isnull = false;
3210 : }
3211 :
3212 0 : *op->resvalue = PointerGetDatum(xmlpi(xexpr->name,
3213 : arg,
3214 : isnull,
3215 : op->resnull));
3216 : }
3217 0 : break;
3218 :
3219 : case IS_XMLROOT:
3220 : {
3221 0 : Datum *argvalue = op->d.xmlexpr.argvalue;
3222 0 : bool *argnull = op->d.xmlexpr.argnull;
3223 : xmltype *data;
3224 : text *version;
3225 : int standalone;
3226 :
3227 : /* arguments are known to be xml, text, int */
3228 0 : Assert(list_length(xexpr->args) == 3);
3229 :
3230 0 : if (argnull[0])
3231 0 : return;
3232 0 : data = DatumGetXmlP(argvalue[0]);
3233 :
3234 0 : if (argnull[1])
3235 0 : version = NULL;
3236 : else
3237 0 : version = DatumGetTextPP(argvalue[1]);
3238 :
3239 0 : Assert(!argnull[2]); /* always present */
3240 0 : standalone = DatumGetInt32(argvalue[2]);
3241 :
3242 0 : *op->resvalue = PointerGetDatum(xmlroot(data,
3243 : version,
3244 : standalone));
3245 0 : *op->resnull = false;
3246 : }
3247 0 : break;
3248 :
3249 : case IS_XMLSERIALIZE:
3250 : {
3251 0 : Datum *argvalue = op->d.xmlexpr.argvalue;
3252 0 : bool *argnull = op->d.xmlexpr.argnull;
3253 :
3254 : /* argument type is known to be xml */
3255 0 : Assert(list_length(xexpr->args) == 1);
3256 :
3257 0 : if (argnull[0])
3258 0 : return;
3259 0 : value = argvalue[0];
3260 :
3261 0 : *op->resvalue = PointerGetDatum(
3262 : xmltotext_with_xmloption(DatumGetXmlP(value),
3263 : xexpr->xmloption));
3264 0 : *op->resnull = false;
3265 : }
3266 0 : break;
3267 :
3268 : case IS_DOCUMENT:
3269 : {
3270 0 : Datum *argvalue = op->d.xmlexpr.argvalue;
3271 0 : bool *argnull = op->d.xmlexpr.argnull;
3272 :
3273 : /* optional argument is known to be xml */
3274 0 : Assert(list_length(xexpr->args) == 1);
3275 :
3276 0 : if (argnull[0])
3277 0 : return;
3278 0 : value = argvalue[0];
3279 :
3280 0 : *op->resvalue =
3281 0 : BoolGetDatum(xml_is_document(DatumGetXmlP(value)));
3282 0 : *op->resnull = false;
3283 : }
3284 0 : break;
3285 :
3286 : default:
3287 0 : elog(ERROR, "unrecognized XML operation");
3288 : break;
3289 : }
3290 : }
3291 :
3292 : /*
3293 : * ExecEvalGroupingFunc
3294 : *
3295 : * Computes a bitmask with a bit for each (unevaluated) argument expression
3296 : * (rightmost arg is least significant bit).
3297 : *
3298 : * A bit is set if the corresponding expression is NOT part of the set of
3299 : * grouping expressions in the current grouping set.
3300 : */
3301 : void
3302 264 : ExecEvalGroupingFunc(ExprState *state, ExprEvalStep *op)
3303 : {
3304 264 : int result = 0;
3305 264 : Bitmapset *grouped_cols = op->d.grouping_func.parent->grouped_cols;
3306 : ListCell *lc;
3307 :
3308 667 : foreach(lc, op->d.grouping_func.clauses)
3309 : {
3310 403 : int attnum = lfirst_int(lc);
3311 :
3312 403 : result <<= 1;
3313 :
3314 403 : if (!bms_is_member(attnum, grouped_cols))
3315 156 : result |= 1;
3316 : }
3317 :
3318 264 : *op->resvalue = Int32GetDatum(result);
3319 264 : *op->resnull = false;
3320 264 : }
3321 :
3322 : /*
3323 : * Hand off evaluation of a subplan to nodeSubplan.c
3324 : */
3325 : void
3326 82700 : ExecEvalSubPlan(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
3327 : {
3328 82700 : SubPlanState *sstate = op->d.subplan.sstate;
3329 :
3330 : /* could potentially be nested, so make sure there's enough stack */
3331 82700 : check_stack_depth();
3332 :
3333 82700 : *op->resvalue = ExecSubPlan(sstate, econtext, op->resnull);
3334 82700 : }
3335 :
3336 : /*
3337 : * Hand off evaluation of an alternative subplan to nodeSubplan.c
3338 : */
3339 : void
3340 143 : ExecEvalAlternativeSubPlan(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
3341 : {
3342 143 : AlternativeSubPlanState *asstate = op->d.alternative_subplan.asstate;
3343 :
3344 : /* could potentially be nested, so make sure there's enough stack */
3345 143 : check_stack_depth();
3346 :
3347 143 : *op->resvalue = ExecAlternativeSubPlan(asstate, econtext, op->resnull);
3348 143 : }
3349 :
3350 : /*
3351 : * Evaluate a wholerow Var expression.
3352 : *
3353 : * Returns a Datum whose value is the value of a whole-row range variable
3354 : * with respect to given expression context.
3355 : */
3356 : void
3357 1041 : ExecEvalWholeRowVar(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
3358 : {
3359 1041 : Var *variable = op->d.wholerow.var;
3360 : TupleTableSlot *slot;
3361 : TupleDesc output_tupdesc;
3362 : MemoryContext oldcontext;
3363 : HeapTupleHeader dtuple;
3364 : HeapTuple tuple;
3365 :
3366 : /* This was checked by ExecInitExpr */
3367 1041 : Assert(variable->varattno == InvalidAttrNumber);
3368 :
3369 : /* Get the input slot we want */
3370 1041 : switch (variable->varno)
3371 : {
3372 : case INNER_VAR:
3373 : /* get the tuple from the inner node */
3374 9 : slot = econtext->ecxt_innertuple;
3375 9 : break;
3376 :
3377 : case OUTER_VAR:
3378 : /* get the tuple from the outer node */
3379 3 : slot = econtext->ecxt_outertuple;
3380 3 : break;
3381 :
3382 : /* INDEX_VAR is handled by default case */
3383 :
3384 : default:
3385 : /* get the tuple from the relation being scanned */
3386 1029 : slot = econtext->ecxt_scantuple;
3387 1029 : break;
3388 : }
3389 :
3390 : /* Apply the junkfilter if any */
3391 1041 : if (op->d.wholerow.junkFilter != NULL)
3392 10 : slot = ExecFilterJunk(op->d.wholerow.junkFilter, slot);
3393 :
3394 : /*
3395 : * If first time through, obtain tuple descriptor and check compatibility.
3396 : *
3397 : * XXX: It'd be great if this could be moved to the expression
3398 : * initialization phase, but due to using slots that's currently not
3399 : * feasible.
3400 : */
3401 1041 : if (op->d.wholerow.first)
3402 : {
3403 : /* optimistically assume we don't need slow path */
3404 222 : op->d.wholerow.slow = false;
3405 :
3406 : /*
3407 : * If the Var identifies a named composite type, we must check that
3408 : * the actual tuple type is compatible with it.
3409 : */
3410 222 : if (variable->vartype != RECORDOID)
3411 : {
3412 : TupleDesc var_tupdesc;
3413 : TupleDesc slot_tupdesc;
3414 : int i;
3415 :
3416 : /*
3417 : * We really only care about numbers of attributes and data types.
3418 : * Also, we can ignore type mismatch on columns that are dropped
3419 : * in the destination type, so long as (1) the physical storage
3420 : * matches or (2) the actual column value is NULL. Case (1) is
3421 : * helpful in some cases involving out-of-date cached plans, while
3422 : * case (2) is expected behavior in situations such as an INSERT
3423 : * into a table with dropped columns (the planner typically
3424 : * generates an INT4 NULL regardless of the dropped column type).
3425 : * If we find a dropped column and cannot verify that case (1)
3426 : * holds, we have to use the slow path to check (2) for each row.
3427 : */
3428 142 : var_tupdesc = lookup_rowtype_tupdesc(variable->vartype, -1);
3429 :
3430 142 : slot_tupdesc = slot->tts_tupleDescriptor;
3431 :
3432 142 : if (var_tupdesc->natts != slot_tupdesc->natts)
3433 0 : ereport(ERROR,
3434 : (errcode(ERRCODE_DATATYPE_MISMATCH),
3435 : errmsg("table row type and query-specified row type do not match"),
3436 : errdetail_plural("Table row contains %d attribute, but query expects %d.",
3437 : "Table row contains %d attributes, but query expects %d.",
3438 : slot_tupdesc->natts,
3439 : slot_tupdesc->natts,
3440 : var_tupdesc->natts)));
3441 :
3442 530 : for (i = 0; i < var_tupdesc->natts; i++)
3443 : {
3444 388 : Form_pg_attribute vattr = TupleDescAttr(var_tupdesc, i);
3445 388 : Form_pg_attribute sattr = TupleDescAttr(slot_tupdesc, i);
3446 :
3447 388 : if (vattr->atttypid == sattr->atttypid)
3448 385 : continue; /* no worries */
3449 3 : if (!vattr->attisdropped)
3450 0 : ereport(ERROR,
3451 : (errcode(ERRCODE_DATATYPE_MISMATCH),
3452 : errmsg("table row type and query-specified row type do not match"),
3453 : errdetail("Table has type %s at ordinal position %d, but query expects %s.",
3454 : format_type_be(sattr->atttypid),
3455 : i + 1,
3456 : format_type_be(vattr->atttypid))));
3457 :
3458 3 : if (vattr->attlen != sattr->attlen ||
3459 0 : vattr->attalign != sattr->attalign)
3460 3 : op->d.wholerow.slow = true; /* need to check for nulls */
3461 : }
3462 :
3463 : /*
3464 : * Use the variable's declared rowtype as the descriptor for the
3465 : * output values, modulo possibly assigning new column names
3466 : * below. In particular, we *must* absorb any attisdropped
3467 : * markings.
3468 : */
3469 142 : oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
3470 142 : output_tupdesc = CreateTupleDescCopy(var_tupdesc);
3471 142 : MemoryContextSwitchTo(oldcontext);
3472 :
3473 142 : ReleaseTupleDesc(var_tupdesc);
3474 : }
3475 : else
3476 : {
3477 : /*
3478 : * In the RECORD case, we use the input slot's rowtype as the
3479 : * descriptor for the output values, modulo possibly assigning new
3480 : * column names below.
3481 : */
3482 80 : oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
3483 80 : output_tupdesc = CreateTupleDescCopy(slot->tts_tupleDescriptor);
3484 80 : MemoryContextSwitchTo(oldcontext);
3485 : }
3486 :
3487 : /*
3488 : * Construct a tuple descriptor for the composite values we'll
3489 : * produce, and make sure its record type is "blessed". The main
3490 : * reason to do this is to be sure that operations such as
3491 : * row_to_json() will see the desired column names when they look up
3492 : * the descriptor from the type information embedded in the composite
3493 : * values.
3494 : *
3495 : * We already got the correct physical datatype info above, but now we
3496 : * should try to find the source RTE and adopt its column aliases, in
3497 : * case they are different from the original rowtype's names. For
3498 : * example, in "SELECT foo(t) FROM tab t(x,y)", the first two columns
3499 : * in the composite output should be named "x" and "y" regardless of
3500 : * tab's column names.
3501 : *
3502 : * If we can't locate the RTE, assume the column names we've got are
3503 : * OK. (As of this writing, the only cases where we can't locate the
3504 : * RTE are in execution of trigger WHEN clauses, and then the Var will
3505 : * have the trigger's relation's rowtype, so its names are fine.)
3506 : * Also, if the creator of the RTE didn't bother to fill in an eref
3507 : * field, assume our column names are OK. (This happens in COPY, and
3508 : * perhaps other places.)
3509 : */
3510 444 : if (econtext->ecxt_estate &&
3511 222 : variable->varno <= list_length(econtext->ecxt_estate->es_range_table))
3512 : {
3513 214 : RangeTblEntry *rte = rt_fetch(variable->varno,
3514 : econtext->ecxt_estate->es_range_table);
3515 :
3516 214 : if (rte->eref)
3517 214 : ExecTypeSetColNames(output_tupdesc, rte->eref->colnames);
3518 : }
3519 :
3520 : /* Bless the tupdesc if needed, and save it in the execution state */
3521 222 : op->d.wholerow.tupdesc = BlessTupleDesc(output_tupdesc);
3522 :
3523 222 : op->d.wholerow.first = false;
3524 : }
3525 :
3526 : /*
3527 : * Make sure all columns of the slot are accessible in the slot's
3528 : * Datum/isnull arrays.
3529 : */
3530 1041 : slot_getallattrs(slot);
3531 :
3532 1041 : if (op->d.wholerow.slow)
3533 : {
3534 : /* Check to see if any dropped attributes are non-null */
3535 5 : TupleDesc tupleDesc = slot->tts_tupleDescriptor;
3536 5 : TupleDesc var_tupdesc = op->d.wholerow.tupdesc;
3537 : int i;
3538 :
3539 5 : Assert(var_tupdesc->natts == tupleDesc->natts);
3540 :
3541 20 : for (i = 0; i < var_tupdesc->natts; i++)
3542 : {
3543 15 : Form_pg_attribute vattr = TupleDescAttr(var_tupdesc, i);
3544 15 : Form_pg_attribute sattr = TupleDescAttr(tupleDesc, i);
3545 :
3546 15 : if (!vattr->attisdropped)
3547 10 : continue; /* already checked non-dropped cols */
3548 5 : if (slot->tts_isnull[i])
3549 5 : continue; /* null is always okay */
3550 0 : if (vattr->attlen != sattr->attlen ||
3551 0 : vattr->attalign != sattr->attalign)
3552 0 : ereport(ERROR,
3553 : (errcode(ERRCODE_DATATYPE_MISMATCH),
3554 : errmsg("table row type and query-specified row type do not match"),
3555 : errdetail("Physical storage mismatch on dropped attribute at ordinal position %d.",
3556 : i + 1)));
3557 : }
3558 : }
3559 :
3560 : /*
3561 : * Build a composite datum, making sure any toasted fields get detoasted.
3562 : *
3563 : * (Note: it is critical that we not change the slot's state here.)
3564 : */
3565 1041 : tuple = toast_build_flattened_tuple(slot->tts_tupleDescriptor,
3566 : slot->tts_values,
3567 : slot->tts_isnull);
3568 1041 : dtuple = tuple->t_data;
3569 :
3570 : /*
3571 : * Label the datum with the composite type info we identified before.
3572 : *
3573 : * (Note: we could skip doing this by passing op->d.wholerow.tupdesc to
3574 : * the tuple build step; but that seems a tad risky so let's not.)
3575 : */
3576 1041 : HeapTupleHeaderSetTypeId(dtuple, op->d.wholerow.tupdesc->tdtypeid);
3577 1041 : HeapTupleHeaderSetTypMod(dtuple, op->d.wholerow.tupdesc->tdtypmod);
3578 :
3579 1041 : *op->resvalue = PointerGetDatum(dtuple);
3580 1041 : *op->resnull = false;
3581 1041 : }
|