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