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