Coverage Report

Created: 2025-08-12 06:43

/src/postgres/src/backend/executor/execExprInterp.c
Line
Count
Source (jump to first uncovered line)
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-2025, 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/miscnodes.h"
67
#include "nodes/nodeFuncs.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/jsonfuncs.h"
76
#include "utils/jsonpath.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
0
#define EEO_CASE(name)    CASE_##name:
119
0
#define EEO_DISPATCH()    goto *((void *) op->opcode)
120
0
#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
0
  do { \
133
0
    op++; \
134
0
    EEO_DISPATCH(); \
135
0
  } while (0)
136
137
#define EEO_JUMP(stepno) \
138
0
  do { \
139
0
    op = &state->steps[stepno]; \
140
0
    EEO_DISPATCH(); \
141
0
  } while (0)
142
143
144
static Datum ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull);
145
static void ExecInitInterpreter(void);
146
147
/* support functions */
148
static void CheckVarSlotCompatibility(TupleTableSlot *slot, int attnum, Oid vartype);
149
static void CheckOpSlotCompatibility(ExprEvalStep *op, TupleTableSlot *slot);
150
static TupleDesc get_cached_rowtype(Oid type_id, int32 typmod,
151
                  ExprEvalRowtypeCache *rowcache,
152
                  bool *changed);
153
static void ExecEvalRowNullInt(ExprState *state, ExprEvalStep *op,
154
                 ExprContext *econtext, bool checkisnull);
155
156
/* fast-path evaluation functions */
157
static Datum ExecJustInnerVar(ExprState *state, ExprContext *econtext, bool *isnull);
158
static Datum ExecJustOuterVar(ExprState *state, ExprContext *econtext, bool *isnull);
159
static Datum ExecJustScanVar(ExprState *state, ExprContext *econtext, bool *isnull);
160
static Datum ExecJustAssignInnerVar(ExprState *state, ExprContext *econtext, bool *isnull);
161
static Datum ExecJustAssignOuterVar(ExprState *state, ExprContext *econtext, bool *isnull);
162
static Datum ExecJustAssignScanVar(ExprState *state, ExprContext *econtext, bool *isnull);
163
static Datum ExecJustApplyFuncToCase(ExprState *state, ExprContext *econtext, bool *isnull);
164
static Datum ExecJustConst(ExprState *state, ExprContext *econtext, bool *isnull);
165
static Datum ExecJustInnerVarVirt(ExprState *state, ExprContext *econtext, bool *isnull);
166
static Datum ExecJustOuterVarVirt(ExprState *state, ExprContext *econtext, bool *isnull);
167
static Datum ExecJustScanVarVirt(ExprState *state, ExprContext *econtext, bool *isnull);
168
static Datum ExecJustAssignInnerVarVirt(ExprState *state, ExprContext *econtext, bool *isnull);
169
static Datum ExecJustAssignOuterVarVirt(ExprState *state, ExprContext *econtext, bool *isnull);
170
static Datum ExecJustAssignScanVarVirt(ExprState *state, ExprContext *econtext, bool *isnull);
171
static Datum ExecJustHashInnerVarWithIV(ExprState *state, ExprContext *econtext, bool *isnull);
172
static Datum ExecJustHashOuterVar(ExprState *state, ExprContext *econtext, bool *isnull);
173
static Datum ExecJustHashInnerVar(ExprState *state, ExprContext *econtext, bool *isnull);
174
static Datum ExecJustHashOuterVarVirt(ExprState *state, ExprContext *econtext, bool *isnull);
175
static Datum ExecJustHashInnerVarVirt(ExprState *state, ExprContext *econtext, bool *isnull);
176
static Datum ExecJustHashOuterVarStrict(ExprState *state, ExprContext *econtext, bool *isnull);
177
178
/* execution helper functions */
179
static pg_attribute_always_inline void ExecAggPlainTransByVal(AggState *aggstate,
180
                                AggStatePerTrans pertrans,
181
                                AggStatePerGroup pergroup,
182
                                ExprContext *aggcontext,
183
                                int setno);
184
static pg_attribute_always_inline void ExecAggPlainTransByRef(AggState *aggstate,
185
                                AggStatePerTrans pertrans,
186
                                AggStatePerGroup pergroup,
187
                                ExprContext *aggcontext,
188
                                int setno);
189
static char *ExecGetJsonValueItemString(JsonbValue *item, bool *resnull);
190
191
/*
192
 * ScalarArrayOpExprHashEntry
193
 *    Hash table entry type used during EEOP_HASHED_SCALARARRAYOP
194
 */
195
typedef struct ScalarArrayOpExprHashEntry
196
{
197
  Datum   key;
198
  uint32    status;     /* hash status */
199
  uint32    hash;     /* hash value (cached) */
200
} ScalarArrayOpExprHashEntry;
201
202
#define SH_PREFIX saophash
203
#define SH_ELEMENT_TYPE ScalarArrayOpExprHashEntry
204
#define SH_KEY_TYPE Datum
205
#define SH_SCOPE static inline
206
#define SH_DECLARE
207
#include "lib/simplehash.h"
208
209
static bool saop_hash_element_match(struct saophash_hash *tb, Datum key1,
210
                  Datum key2);
211
static uint32 saop_element_hash(struct saophash_hash *tb, Datum key);
212
213
/*
214
 * ScalarArrayOpExprHashTable
215
 *    Hash table for EEOP_HASHED_SCALARARRAYOP
216
 */
217
typedef struct ScalarArrayOpExprHashTable
218
{
219
  saophash_hash *hashtab;   /* underlying hash table */
220
  struct ExprEvalStep *op;
221
  FmgrInfo  hash_finfo;   /* function's lookup data */
222
  FunctionCallInfoBaseData hash_fcinfo_data;  /* arguments etc */
223
} ScalarArrayOpExprHashTable;
224
225
/* Define parameters for ScalarArrayOpExpr hash table code generation. */
226
#define SH_PREFIX saophash
227
0
#define SH_ELEMENT_TYPE ScalarArrayOpExprHashEntry
228
#define SH_KEY_TYPE Datum
229
0
#define SH_KEY key
230
0
#define SH_HASH_KEY(tb, key) saop_element_hash(tb, key)
231
0
#define SH_EQUAL(tb, a, b) saop_hash_element_match(tb, a, b)
232
#define SH_SCOPE static inline
233
#define SH_STORE_HASH
234
0
#define SH_GET_HASH(tb, a) a->hash
235
#define SH_DEFINE
236
#include "lib/simplehash.h"
237
238
/*
239
 * Prepare ExprState for interpreted execution.
240
 */
241
void
242
ExecReadyInterpretedExpr(ExprState *state)
243
0
{
244
  /* Ensure one-time interpreter setup has been done */
245
0
  ExecInitInterpreter();
246
247
  /* Simple validity checks on expression */
248
0
  Assert(state->steps_len >= 1);
249
0
  Assert(state->steps[state->steps_len - 1].opcode == EEOP_DONE_RETURN ||
250
0
       state->steps[state->steps_len - 1].opcode == EEOP_DONE_NO_RETURN);
251
252
  /*
253
   * Don't perform redundant initialization. This is unreachable in current
254
   * cases, but might be hit if there's additional expression evaluation
255
   * methods that rely on interpreted execution to work.
256
   */
257
0
  if (state->flags & EEO_FLAG_INTERPRETER_INITIALIZED)
258
0
    return;
259
260
  /*
261
   * First time through, check whether attribute matches Var.  Might not be
262
   * ok anymore, due to schema changes. We do that by setting up a callback
263
   * that does checking on the first call, which then sets the evalfunc
264
   * callback to the actual method of execution.
265
   */
266
0
  state->evalfunc = ExecInterpExprStillValid;
267
268
  /* DIRECT_THREADED should not already be set */
269
0
  Assert((state->flags & EEO_FLAG_DIRECT_THREADED) == 0);
270
271
  /*
272
   * There shouldn't be any errors before the expression is fully
273
   * initialized, and even if so, it'd lead to the expression being
274
   * abandoned.  So we can set the flag now and save some code.
275
   */
276
0
  state->flags |= EEO_FLAG_INTERPRETER_INITIALIZED;
277
278
  /*
279
   * Select fast-path evalfuncs for very simple expressions.  "Starting up"
280
   * the full interpreter is a measurable overhead for these, and these
281
   * patterns occur often enough to be worth optimizing.
282
   */
283
0
  if (state->steps_len == 5)
284
0
  {
285
0
    ExprEvalOp  step0 = state->steps[0].opcode;
286
0
    ExprEvalOp  step1 = state->steps[1].opcode;
287
0
    ExprEvalOp  step2 = state->steps[2].opcode;
288
0
    ExprEvalOp  step3 = state->steps[3].opcode;
289
290
0
    if (step0 == EEOP_INNER_FETCHSOME &&
291
0
      step1 == EEOP_HASHDATUM_SET_INITVAL &&
292
0
      step2 == EEOP_INNER_VAR &&
293
0
      step3 == EEOP_HASHDATUM_NEXT32)
294
0
    {
295
0
      state->evalfunc_private = (void *) ExecJustHashInnerVarWithIV;
296
0
      return;
297
0
    }
298
0
  }
299
0
  else if (state->steps_len == 4)
300
0
  {
301
0
    ExprEvalOp  step0 = state->steps[0].opcode;
302
0
    ExprEvalOp  step1 = state->steps[1].opcode;
303
0
    ExprEvalOp  step2 = state->steps[2].opcode;
304
305
0
    if (step0 == EEOP_OUTER_FETCHSOME &&
306
0
      step1 == EEOP_OUTER_VAR &&
307
0
      step2 == EEOP_HASHDATUM_FIRST)
308
0
    {
309
0
      state->evalfunc_private = (void *) ExecJustHashOuterVar;
310
0
      return;
311
0
    }
312
0
    else if (step0 == EEOP_INNER_FETCHSOME &&
313
0
         step1 == EEOP_INNER_VAR &&
314
0
         step2 == EEOP_HASHDATUM_FIRST)
315
0
    {
316
0
      state->evalfunc_private = (void *) ExecJustHashInnerVar;
317
0
      return;
318
0
    }
319
0
    else if (step0 == EEOP_OUTER_FETCHSOME &&
320
0
         step1 == EEOP_OUTER_VAR &&
321
0
         step2 == EEOP_HASHDATUM_FIRST_STRICT)
322
0
    {
323
0
      state->evalfunc_private = (void *) ExecJustHashOuterVarStrict;
324
0
      return;
325
0
    }
326
0
  }
327
0
  else if (state->steps_len == 3)
328
0
  {
329
0
    ExprEvalOp  step0 = state->steps[0].opcode;
330
0
    ExprEvalOp  step1 = state->steps[1].opcode;
331
332
0
    if (step0 == EEOP_INNER_FETCHSOME &&
333
0
      step1 == EEOP_INNER_VAR)
334
0
    {
335
0
      state->evalfunc_private = ExecJustInnerVar;
336
0
      return;
337
0
    }
338
0
    else if (step0 == EEOP_OUTER_FETCHSOME &&
339
0
         step1 == EEOP_OUTER_VAR)
340
0
    {
341
0
      state->evalfunc_private = ExecJustOuterVar;
342
0
      return;
343
0
    }
344
0
    else if (step0 == EEOP_SCAN_FETCHSOME &&
345
0
         step1 == EEOP_SCAN_VAR)
346
0
    {
347
0
      state->evalfunc_private = ExecJustScanVar;
348
0
      return;
349
0
    }
350
0
    else if (step0 == EEOP_INNER_FETCHSOME &&
351
0
         step1 == EEOP_ASSIGN_INNER_VAR)
352
0
    {
353
0
      state->evalfunc_private = ExecJustAssignInnerVar;
354
0
      return;
355
0
    }
356
0
    else if (step0 == EEOP_OUTER_FETCHSOME &&
357
0
         step1 == EEOP_ASSIGN_OUTER_VAR)
358
0
    {
359
0
      state->evalfunc_private = ExecJustAssignOuterVar;
360
0
      return;
361
0
    }
362
0
    else if (step0 == EEOP_SCAN_FETCHSOME &&
363
0
         step1 == EEOP_ASSIGN_SCAN_VAR)
364
0
    {
365
0
      state->evalfunc_private = ExecJustAssignScanVar;
366
0
      return;
367
0
    }
368
0
    else if (step0 == EEOP_CASE_TESTVAL &&
369
0
         (step1 == EEOP_FUNCEXPR_STRICT ||
370
0
          step1 == EEOP_FUNCEXPR_STRICT_1 ||
371
0
          step1 == EEOP_FUNCEXPR_STRICT_2))
372
0
    {
373
0
      state->evalfunc_private = ExecJustApplyFuncToCase;
374
0
      return;
375
0
    }
376
0
    else if (step0 == EEOP_INNER_VAR &&
377
0
         step1 == EEOP_HASHDATUM_FIRST)
378
0
    {
379
0
      state->evalfunc_private = (void *) ExecJustHashInnerVarVirt;
380
0
      return;
381
0
    }
382
0
    else if (step0 == EEOP_OUTER_VAR &&
383
0
         step1 == EEOP_HASHDATUM_FIRST)
384
0
    {
385
0
      state->evalfunc_private = (void *) ExecJustHashOuterVarVirt;
386
0
      return;
387
0
    }
388
0
  }
389
0
  else if (state->steps_len == 2)
390
0
  {
391
0
    ExprEvalOp  step0 = state->steps[0].opcode;
392
393
0
    if (step0 == EEOP_CONST)
394
0
    {
395
0
      state->evalfunc_private = ExecJustConst;
396
0
      return;
397
0
    }
398
0
    else if (step0 == EEOP_INNER_VAR)
399
0
    {
400
0
      state->evalfunc_private = ExecJustInnerVarVirt;
401
0
      return;
402
0
    }
403
0
    else if (step0 == EEOP_OUTER_VAR)
404
0
    {
405
0
      state->evalfunc_private = ExecJustOuterVarVirt;
406
0
      return;
407
0
    }
408
0
    else if (step0 == EEOP_SCAN_VAR)
409
0
    {
410
0
      state->evalfunc_private = ExecJustScanVarVirt;
411
0
      return;
412
0
    }
413
0
    else if (step0 == EEOP_ASSIGN_INNER_VAR)
414
0
    {
415
0
      state->evalfunc_private = ExecJustAssignInnerVarVirt;
416
0
      return;
417
0
    }
418
0
    else if (step0 == EEOP_ASSIGN_OUTER_VAR)
419
0
    {
420
0
      state->evalfunc_private = ExecJustAssignOuterVarVirt;
421
0
      return;
422
0
    }
423
0
    else if (step0 == EEOP_ASSIGN_SCAN_VAR)
424
0
    {
425
0
      state->evalfunc_private = ExecJustAssignScanVarVirt;
426
0
      return;
427
0
    }
428
0
  }
429
430
0
#if defined(EEO_USE_COMPUTED_GOTO)
431
432
  /*
433
   * In the direct-threaded implementation, replace each opcode with the
434
   * address to jump to.  (Use ExecEvalStepOp() to get back the opcode.)
435
   */
436
0
  for (int off = 0; off < state->steps_len; off++)
437
0
  {
438
0
    ExprEvalStep *op = &state->steps[off];
439
440
0
    op->opcode = EEO_OPCODE(op->opcode);
441
0
  }
442
443
0
  state->flags |= EEO_FLAG_DIRECT_THREADED;
444
0
#endif              /* EEO_USE_COMPUTED_GOTO */
445
446
0
  state->evalfunc_private = ExecInterpExpr;
447
0
}
448
449
450
/*
451
 * Evaluate expression identified by "state" in the execution context
452
 * given by "econtext".  *isnull is set to the is-null flag for the result,
453
 * and the Datum value is the function result.
454
 *
455
 * As a special case, return the dispatch table's address if state is NULL.
456
 * This is used by ExecInitInterpreter to set up the dispatch_table global.
457
 * (Only applies when EEO_USE_COMPUTED_GOTO is defined.)
458
 */
459
static Datum
460
ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
461
0
{
462
0
  ExprEvalStep *op;
463
0
  TupleTableSlot *resultslot;
464
0
  TupleTableSlot *innerslot;
465
0
  TupleTableSlot *outerslot;
466
0
  TupleTableSlot *scanslot;
467
0
  TupleTableSlot *oldslot;
468
0
  TupleTableSlot *newslot;
469
470
  /*
471
   * This array has to be in the same order as enum ExprEvalOp.
472
   */
473
0
#if defined(EEO_USE_COMPUTED_GOTO)
474
0
  static const void *const dispatch_table[] = {
475
0
    &&CASE_EEOP_DONE_RETURN,
476
0
    &&CASE_EEOP_DONE_NO_RETURN,
477
0
    &&CASE_EEOP_INNER_FETCHSOME,
478
0
    &&CASE_EEOP_OUTER_FETCHSOME,
479
0
    &&CASE_EEOP_SCAN_FETCHSOME,
480
0
    &&CASE_EEOP_OLD_FETCHSOME,
481
0
    &&CASE_EEOP_NEW_FETCHSOME,
482
0
    &&CASE_EEOP_INNER_VAR,
483
0
    &&CASE_EEOP_OUTER_VAR,
484
0
    &&CASE_EEOP_SCAN_VAR,
485
0
    &&CASE_EEOP_OLD_VAR,
486
0
    &&CASE_EEOP_NEW_VAR,
487
0
    &&CASE_EEOP_INNER_SYSVAR,
488
0
    &&CASE_EEOP_OUTER_SYSVAR,
489
0
    &&CASE_EEOP_SCAN_SYSVAR,
490
0
    &&CASE_EEOP_OLD_SYSVAR,
491
0
    &&CASE_EEOP_NEW_SYSVAR,
492
0
    &&CASE_EEOP_WHOLEROW,
493
0
    &&CASE_EEOP_ASSIGN_INNER_VAR,
494
0
    &&CASE_EEOP_ASSIGN_OUTER_VAR,
495
0
    &&CASE_EEOP_ASSIGN_SCAN_VAR,
496
0
    &&CASE_EEOP_ASSIGN_OLD_VAR,
497
0
    &&CASE_EEOP_ASSIGN_NEW_VAR,
498
0
    &&CASE_EEOP_ASSIGN_TMP,
499
0
    &&CASE_EEOP_ASSIGN_TMP_MAKE_RO,
500
0
    &&CASE_EEOP_CONST,
501
0
    &&CASE_EEOP_FUNCEXPR,
502
0
    &&CASE_EEOP_FUNCEXPR_STRICT,
503
0
    &&CASE_EEOP_FUNCEXPR_STRICT_1,
504
0
    &&CASE_EEOP_FUNCEXPR_STRICT_2,
505
0
    &&CASE_EEOP_FUNCEXPR_FUSAGE,
506
0
    &&CASE_EEOP_FUNCEXPR_STRICT_FUSAGE,
507
0
    &&CASE_EEOP_BOOL_AND_STEP_FIRST,
508
0
    &&CASE_EEOP_BOOL_AND_STEP,
509
0
    &&CASE_EEOP_BOOL_AND_STEP_LAST,
510
0
    &&CASE_EEOP_BOOL_OR_STEP_FIRST,
511
0
    &&CASE_EEOP_BOOL_OR_STEP,
512
0
    &&CASE_EEOP_BOOL_OR_STEP_LAST,
513
0
    &&CASE_EEOP_BOOL_NOT_STEP,
514
0
    &&CASE_EEOP_QUAL,
515
0
    &&CASE_EEOP_JUMP,
516
0
    &&CASE_EEOP_JUMP_IF_NULL,
517
0
    &&CASE_EEOP_JUMP_IF_NOT_NULL,
518
0
    &&CASE_EEOP_JUMP_IF_NOT_TRUE,
519
0
    &&CASE_EEOP_NULLTEST_ISNULL,
520
0
    &&CASE_EEOP_NULLTEST_ISNOTNULL,
521
0
    &&CASE_EEOP_NULLTEST_ROWISNULL,
522
0
    &&CASE_EEOP_NULLTEST_ROWISNOTNULL,
523
0
    &&CASE_EEOP_BOOLTEST_IS_TRUE,
524
0
    &&CASE_EEOP_BOOLTEST_IS_NOT_TRUE,
525
0
    &&CASE_EEOP_BOOLTEST_IS_FALSE,
526
0
    &&CASE_EEOP_BOOLTEST_IS_NOT_FALSE,
527
0
    &&CASE_EEOP_PARAM_EXEC,
528
0
    &&CASE_EEOP_PARAM_EXTERN,
529
0
    &&CASE_EEOP_PARAM_CALLBACK,
530
0
    &&CASE_EEOP_PARAM_SET,
531
0
    &&CASE_EEOP_CASE_TESTVAL,
532
0
    &&CASE_EEOP_CASE_TESTVAL_EXT,
533
0
    &&CASE_EEOP_MAKE_READONLY,
534
0
    &&CASE_EEOP_IOCOERCE,
535
0
    &&CASE_EEOP_IOCOERCE_SAFE,
536
0
    &&CASE_EEOP_DISTINCT,
537
0
    &&CASE_EEOP_NOT_DISTINCT,
538
0
    &&CASE_EEOP_NULLIF,
539
0
    &&CASE_EEOP_SQLVALUEFUNCTION,
540
0
    &&CASE_EEOP_CURRENTOFEXPR,
541
0
    &&CASE_EEOP_NEXTVALUEEXPR,
542
0
    &&CASE_EEOP_RETURNINGEXPR,
543
0
    &&CASE_EEOP_ARRAYEXPR,
544
0
    &&CASE_EEOP_ARRAYCOERCE,
545
0
    &&CASE_EEOP_ROW,
546
0
    &&CASE_EEOP_ROWCOMPARE_STEP,
547
0
    &&CASE_EEOP_ROWCOMPARE_FINAL,
548
0
    &&CASE_EEOP_MINMAX,
549
0
    &&CASE_EEOP_FIELDSELECT,
550
0
    &&CASE_EEOP_FIELDSTORE_DEFORM,
551
0
    &&CASE_EEOP_FIELDSTORE_FORM,
552
0
    &&CASE_EEOP_SBSREF_SUBSCRIPTS,
553
0
    &&CASE_EEOP_SBSREF_OLD,
554
0
    &&CASE_EEOP_SBSREF_ASSIGN,
555
0
    &&CASE_EEOP_SBSREF_FETCH,
556
0
    &&CASE_EEOP_DOMAIN_TESTVAL,
557
0
    &&CASE_EEOP_DOMAIN_TESTVAL_EXT,
558
0
    &&CASE_EEOP_DOMAIN_NOTNULL,
559
0
    &&CASE_EEOP_DOMAIN_CHECK,
560
0
    &&CASE_EEOP_HASHDATUM_SET_INITVAL,
561
0
    &&CASE_EEOP_HASHDATUM_FIRST,
562
0
    &&CASE_EEOP_HASHDATUM_FIRST_STRICT,
563
0
    &&CASE_EEOP_HASHDATUM_NEXT32,
564
0
    &&CASE_EEOP_HASHDATUM_NEXT32_STRICT,
565
0
    &&CASE_EEOP_CONVERT_ROWTYPE,
566
0
    &&CASE_EEOP_SCALARARRAYOP,
567
0
    &&CASE_EEOP_HASHED_SCALARARRAYOP,
568
0
    &&CASE_EEOP_XMLEXPR,
569
0
    &&CASE_EEOP_JSON_CONSTRUCTOR,
570
0
    &&CASE_EEOP_IS_JSON,
571
0
    &&CASE_EEOP_JSONEXPR_PATH,
572
0
    &&CASE_EEOP_JSONEXPR_COERCION,
573
0
    &&CASE_EEOP_JSONEXPR_COERCION_FINISH,
574
0
    &&CASE_EEOP_AGGREF,
575
0
    &&CASE_EEOP_GROUPING_FUNC,
576
0
    &&CASE_EEOP_WINDOW_FUNC,
577
0
    &&CASE_EEOP_MERGE_SUPPORT_FUNC,
578
0
    &&CASE_EEOP_SUBPLAN,
579
0
    &&CASE_EEOP_AGG_STRICT_DESERIALIZE,
580
0
    &&CASE_EEOP_AGG_DESERIALIZE,
581
0
    &&CASE_EEOP_AGG_STRICT_INPUT_CHECK_ARGS,
582
0
    &&CASE_EEOP_AGG_STRICT_INPUT_CHECK_ARGS_1,
583
0
    &&CASE_EEOP_AGG_STRICT_INPUT_CHECK_NULLS,
584
0
    &&CASE_EEOP_AGG_PLAIN_PERGROUP_NULLCHECK,
585
0
    &&CASE_EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL,
586
0
    &&CASE_EEOP_AGG_PLAIN_TRANS_STRICT_BYVAL,
587
0
    &&CASE_EEOP_AGG_PLAIN_TRANS_BYVAL,
588
0
    &&CASE_EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYREF,
589
0
    &&CASE_EEOP_AGG_PLAIN_TRANS_STRICT_BYREF,
590
0
    &&CASE_EEOP_AGG_PLAIN_TRANS_BYREF,
591
0
    &&CASE_EEOP_AGG_PRESORTED_DISTINCT_SINGLE,
592
0
    &&CASE_EEOP_AGG_PRESORTED_DISTINCT_MULTI,
593
0
    &&CASE_EEOP_AGG_ORDERED_TRANS_DATUM,
594
0
    &&CASE_EEOP_AGG_ORDERED_TRANS_TUPLE,
595
0
    &&CASE_EEOP_LAST
596
0
  };
597
598
0
  StaticAssertDecl(lengthof(dispatch_table) == EEOP_LAST + 1,
599
0
           "dispatch_table out of whack with ExprEvalOp");
600
601
0
  if (unlikely(state == NULL))
602
0
    return PointerGetDatum(dispatch_table);
603
#else
604
  Assert(state != NULL);
605
#endif              /* EEO_USE_COMPUTED_GOTO */
606
607
  /* setup state */
608
0
  op = state->steps;
609
0
  resultslot = state->resultslot;
610
0
  innerslot = econtext->ecxt_innertuple;
611
0
  outerslot = econtext->ecxt_outertuple;
612
0
  scanslot = econtext->ecxt_scantuple;
613
0
  oldslot = econtext->ecxt_oldtuple;
614
0
  newslot = econtext->ecxt_newtuple;
615
616
0
#if defined(EEO_USE_COMPUTED_GOTO)
617
0
  EEO_DISPATCH();
618
0
#endif
619
620
0
  EEO_SWITCH()
621
0
  {
622
0
    EEO_CASE(EEOP_DONE_RETURN)
623
0
    {
624
0
      *isnull = state->resnull;
625
0
      return state->resvalue;
626
0
    }
627
628
0
    EEO_CASE(EEOP_DONE_NO_RETURN)
629
0
    {
630
0
      Assert(isnull == NULL);
631
0
      return (Datum) 0;
632
0
    }
633
634
0
    EEO_CASE(EEOP_INNER_FETCHSOME)
635
0
    {
636
0
      CheckOpSlotCompatibility(op, innerslot);
637
638
0
      slot_getsomeattrs(innerslot, op->d.fetch.last_var);
639
640
0
      EEO_NEXT();
641
0
    }
642
643
0
    EEO_CASE(EEOP_OUTER_FETCHSOME)
644
0
    {
645
0
      CheckOpSlotCompatibility(op, outerslot);
646
647
0
      slot_getsomeattrs(outerslot, op->d.fetch.last_var);
648
649
0
      EEO_NEXT();
650
0
    }
651
652
0
    EEO_CASE(EEOP_SCAN_FETCHSOME)
653
0
    {
654
0
      CheckOpSlotCompatibility(op, scanslot);
655
656
0
      slot_getsomeattrs(scanslot, op->d.fetch.last_var);
657
658
0
      EEO_NEXT();
659
0
    }
660
661
0
    EEO_CASE(EEOP_OLD_FETCHSOME)
662
0
    {
663
0
      CheckOpSlotCompatibility(op, oldslot);
664
665
0
      slot_getsomeattrs(oldslot, op->d.fetch.last_var);
666
667
0
      EEO_NEXT();
668
0
    }
669
670
0
    EEO_CASE(EEOP_NEW_FETCHSOME)
671
0
    {
672
0
      CheckOpSlotCompatibility(op, newslot);
673
674
0
      slot_getsomeattrs(newslot, op->d.fetch.last_var);
675
676
0
      EEO_NEXT();
677
0
    }
678
679
0
    EEO_CASE(EEOP_INNER_VAR)
680
0
    {
681
0
      int     attnum = op->d.var.attnum;
682
683
      /*
684
       * Since we already extracted all referenced columns from the
685
       * tuple with a FETCHSOME step, we can just grab the value
686
       * directly out of the slot's decomposed-data arrays.  But let's
687
       * have an Assert to check that that did happen.
688
       */
689
0
      Assert(attnum >= 0 && attnum < innerslot->tts_nvalid);
690
0
      *op->resvalue = innerslot->tts_values[attnum];
691
0
      *op->resnull = innerslot->tts_isnull[attnum];
692
693
0
      EEO_NEXT();
694
0
    }
695
696
0
    EEO_CASE(EEOP_OUTER_VAR)
697
0
    {
698
0
      int     attnum = op->d.var.attnum;
699
700
      /* See EEOP_INNER_VAR comments */
701
702
0
      Assert(attnum >= 0 && attnum < outerslot->tts_nvalid);
703
0
      *op->resvalue = outerslot->tts_values[attnum];
704
0
      *op->resnull = outerslot->tts_isnull[attnum];
705
706
0
      EEO_NEXT();
707
0
    }
708
709
0
    EEO_CASE(EEOP_SCAN_VAR)
710
0
    {
711
0
      int     attnum = op->d.var.attnum;
712
713
      /* See EEOP_INNER_VAR comments */
714
715
0
      Assert(attnum >= 0 && attnum < scanslot->tts_nvalid);
716
0
      *op->resvalue = scanslot->tts_values[attnum];
717
0
      *op->resnull = scanslot->tts_isnull[attnum];
718
719
0
      EEO_NEXT();
720
0
    }
721
722
0
    EEO_CASE(EEOP_OLD_VAR)
723
0
    {
724
0
      int     attnum = op->d.var.attnum;
725
726
      /* See EEOP_INNER_VAR comments */
727
728
0
      Assert(attnum >= 0 && attnum < oldslot->tts_nvalid);
729
0
      *op->resvalue = oldslot->tts_values[attnum];
730
0
      *op->resnull = oldslot->tts_isnull[attnum];
731
732
0
      EEO_NEXT();
733
0
    }
734
735
0
    EEO_CASE(EEOP_NEW_VAR)
736
0
    {
737
0
      int     attnum = op->d.var.attnum;
738
739
      /* See EEOP_INNER_VAR comments */
740
741
0
      Assert(attnum >= 0 && attnum < newslot->tts_nvalid);
742
0
      *op->resvalue = newslot->tts_values[attnum];
743
0
      *op->resnull = newslot->tts_isnull[attnum];
744
745
0
      EEO_NEXT();
746
0
    }
747
748
0
    EEO_CASE(EEOP_INNER_SYSVAR)
749
0
    {
750
0
      ExecEvalSysVar(state, op, econtext, innerslot);
751
0
      EEO_NEXT();
752
0
    }
753
754
0
    EEO_CASE(EEOP_OUTER_SYSVAR)
755
0
    {
756
0
      ExecEvalSysVar(state, op, econtext, outerslot);
757
0
      EEO_NEXT();
758
0
    }
759
760
0
    EEO_CASE(EEOP_SCAN_SYSVAR)
761
0
    {
762
0
      ExecEvalSysVar(state, op, econtext, scanslot);
763
0
      EEO_NEXT();
764
0
    }
765
766
0
    EEO_CASE(EEOP_OLD_SYSVAR)
767
0
    {
768
0
      ExecEvalSysVar(state, op, econtext, oldslot);
769
0
      EEO_NEXT();
770
0
    }
771
772
0
    EEO_CASE(EEOP_NEW_SYSVAR)
773
0
    {
774
0
      ExecEvalSysVar(state, op, econtext, newslot);
775
0
      EEO_NEXT();
776
0
    }
777
778
0
    EEO_CASE(EEOP_WHOLEROW)
779
0
    {
780
      /* too complex for an inline implementation */
781
0
      ExecEvalWholeRowVar(state, op, econtext);
782
783
0
      EEO_NEXT();
784
0
    }
785
786
0
    EEO_CASE(EEOP_ASSIGN_INNER_VAR)
787
0
    {
788
0
      int     resultnum = op->d.assign_var.resultnum;
789
0
      int     attnum = op->d.assign_var.attnum;
790
791
      /*
792
       * We do not need CheckVarSlotCompatibility here; that was taken
793
       * care of at compilation time.  But see EEOP_INNER_VAR comments.
794
       */
795
0
      Assert(attnum >= 0 && attnum < innerslot->tts_nvalid);
796
0
      Assert(resultnum >= 0 && resultnum < resultslot->tts_tupleDescriptor->natts);
797
0
      resultslot->tts_values[resultnum] = innerslot->tts_values[attnum];
798
0
      resultslot->tts_isnull[resultnum] = innerslot->tts_isnull[attnum];
799
800
0
      EEO_NEXT();
801
0
    }
802
803
0
    EEO_CASE(EEOP_ASSIGN_OUTER_VAR)
804
0
    {
805
0
      int     resultnum = op->d.assign_var.resultnum;
806
0
      int     attnum = op->d.assign_var.attnum;
807
808
      /*
809
       * We do not need CheckVarSlotCompatibility here; that was taken
810
       * care of at compilation time.  But see EEOP_INNER_VAR comments.
811
       */
812
0
      Assert(attnum >= 0 && attnum < outerslot->tts_nvalid);
813
0
      Assert(resultnum >= 0 && resultnum < resultslot->tts_tupleDescriptor->natts);
814
0
      resultslot->tts_values[resultnum] = outerslot->tts_values[attnum];
815
0
      resultslot->tts_isnull[resultnum] = outerslot->tts_isnull[attnum];
816
817
0
      EEO_NEXT();
818
0
    }
819
820
0
    EEO_CASE(EEOP_ASSIGN_SCAN_VAR)
821
0
    {
822
0
      int     resultnum = op->d.assign_var.resultnum;
823
0
      int     attnum = op->d.assign_var.attnum;
824
825
      /*
826
       * We do not need CheckVarSlotCompatibility here; that was taken
827
       * care of at compilation time.  But see EEOP_INNER_VAR comments.
828
       */
829
0
      Assert(attnum >= 0 && attnum < scanslot->tts_nvalid);
830
0
      Assert(resultnum >= 0 && resultnum < resultslot->tts_tupleDescriptor->natts);
831
0
      resultslot->tts_values[resultnum] = scanslot->tts_values[attnum];
832
0
      resultslot->tts_isnull[resultnum] = scanslot->tts_isnull[attnum];
833
834
0
      EEO_NEXT();
835
0
    }
836
837
0
    EEO_CASE(EEOP_ASSIGN_OLD_VAR)
838
0
    {
839
0
      int     resultnum = op->d.assign_var.resultnum;
840
0
      int     attnum = op->d.assign_var.attnum;
841
842
      /*
843
       * We do not need CheckVarSlotCompatibility here; that was taken
844
       * care of at compilation time.  But see EEOP_INNER_VAR comments.
845
       */
846
0
      Assert(attnum >= 0 && attnum < oldslot->tts_nvalid);
847
0
      Assert(resultnum >= 0 && resultnum < resultslot->tts_tupleDescriptor->natts);
848
0
      resultslot->tts_values[resultnum] = oldslot->tts_values[attnum];
849
0
      resultslot->tts_isnull[resultnum] = oldslot->tts_isnull[attnum];
850
851
0
      EEO_NEXT();
852
0
    }
853
854
0
    EEO_CASE(EEOP_ASSIGN_NEW_VAR)
855
0
    {
856
0
      int     resultnum = op->d.assign_var.resultnum;
857
0
      int     attnum = op->d.assign_var.attnum;
858
859
      /*
860
       * We do not need CheckVarSlotCompatibility here; that was taken
861
       * care of at compilation time.  But see EEOP_INNER_VAR comments.
862
       */
863
0
      Assert(attnum >= 0 && attnum < newslot->tts_nvalid);
864
0
      Assert(resultnum >= 0 && resultnum < resultslot->tts_tupleDescriptor->natts);
865
0
      resultslot->tts_values[resultnum] = newslot->tts_values[attnum];
866
0
      resultslot->tts_isnull[resultnum] = newslot->tts_isnull[attnum];
867
868
0
      EEO_NEXT();
869
0
    }
870
871
0
    EEO_CASE(EEOP_ASSIGN_TMP)
872
0
    {
873
0
      int     resultnum = op->d.assign_tmp.resultnum;
874
875
0
      Assert(resultnum >= 0 && resultnum < resultslot->tts_tupleDescriptor->natts);
876
0
      resultslot->tts_values[resultnum] = state->resvalue;
877
0
      resultslot->tts_isnull[resultnum] = state->resnull;
878
879
0
      EEO_NEXT();
880
0
    }
881
882
0
    EEO_CASE(EEOP_ASSIGN_TMP_MAKE_RO)
883
0
    {
884
0
      int     resultnum = op->d.assign_tmp.resultnum;
885
886
0
      Assert(resultnum >= 0 && resultnum < resultslot->tts_tupleDescriptor->natts);
887
0
      resultslot->tts_isnull[resultnum] = state->resnull;
888
0
      if (!resultslot->tts_isnull[resultnum])
889
0
        resultslot->tts_values[resultnum] =
890
0
          MakeExpandedObjectReadOnlyInternal(state->resvalue);
891
0
      else
892
0
        resultslot->tts_values[resultnum] = state->resvalue;
893
894
0
      EEO_NEXT();
895
0
    }
896
897
0
    EEO_CASE(EEOP_CONST)
898
0
    {
899
0
      *op->resnull = op->d.constval.isnull;
900
0
      *op->resvalue = op->d.constval.value;
901
902
0
      EEO_NEXT();
903
0
    }
904
905
    /*
906
     * Function-call implementations. Arguments have previously been
907
     * evaluated directly into fcinfo->args.
908
     *
909
     * As both STRICT checks and function-usage are noticeable performance
910
     * wise, and function calls are a very hot-path (they also back
911
     * operators!), it's worth having so many separate opcodes.
912
     *
913
     * Note: the reason for using a temporary variable "d", here and in
914
     * other places, is that some compilers think "*op->resvalue = f();"
915
     * requires them to evaluate op->resvalue into a register before
916
     * calling f(), just in case f() is able to modify op->resvalue
917
     * somehow.  The extra line of code can save a useless register spill
918
     * and reload across the function call.
919
     */
920
0
    EEO_CASE(EEOP_FUNCEXPR)
921
0
    {
922
0
      FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
923
0
      Datum   d;
924
925
0
      fcinfo->isnull = false;
926
0
      d = op->d.func.fn_addr(fcinfo);
927
0
      *op->resvalue = d;
928
0
      *op->resnull = fcinfo->isnull;
929
930
0
      EEO_NEXT();
931
0
    }
932
933
    /* strict function call with more than two arguments */
934
0
    EEO_CASE(EEOP_FUNCEXPR_STRICT)
935
0
    {
936
0
      FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
937
0
      NullableDatum *args = fcinfo->args;
938
0
      int     nargs = op->d.func.nargs;
939
0
      Datum   d;
940
941
0
      Assert(nargs > 2);
942
943
      /* strict function, so check for NULL args */
944
0
      for (int argno = 0; argno < nargs; argno++)
945
0
      {
946
0
        if (args[argno].isnull)
947
0
        {
948
0
          *op->resnull = true;
949
0
          goto strictfail;
950
0
        }
951
0
      }
952
0
      fcinfo->isnull = false;
953
0
      d = op->d.func.fn_addr(fcinfo);
954
0
      *op->resvalue = d;
955
0
      *op->resnull = fcinfo->isnull;
956
957
0
  strictfail:
958
0
      EEO_NEXT();
959
0
    }
960
961
    /* strict function call with one argument */
962
0
    EEO_CASE(EEOP_FUNCEXPR_STRICT_1)
963
0
    {
964
0
      FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
965
0
      NullableDatum *args = fcinfo->args;
966
967
0
      Assert(op->d.func.nargs == 1);
968
969
      /* strict function, so check for NULL args */
970
0
      if (args[0].isnull)
971
0
        *op->resnull = true;
972
0
      else
973
0
      {
974
0
        Datum   d;
975
976
0
        fcinfo->isnull = false;
977
0
        d = op->d.func.fn_addr(fcinfo);
978
0
        *op->resvalue = d;
979
0
        *op->resnull = fcinfo->isnull;
980
0
      }
981
982
0
      EEO_NEXT();
983
0
    }
984
985
    /* strict function call with two arguments */
986
0
    EEO_CASE(EEOP_FUNCEXPR_STRICT_2)
987
0
    {
988
0
      FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
989
0
      NullableDatum *args = fcinfo->args;
990
991
0
      Assert(op->d.func.nargs == 2);
992
993
      /* strict function, so check for NULL args */
994
0
      if (args[0].isnull || args[1].isnull)
995
0
        *op->resnull = true;
996
0
      else
997
0
      {
998
0
        Datum   d;
999
1000
0
        fcinfo->isnull = false;
1001
0
        d = op->d.func.fn_addr(fcinfo);
1002
0
        *op->resvalue = d;
1003
0
        *op->resnull = fcinfo->isnull;
1004
0
      }
1005
1006
0
      EEO_NEXT();
1007
0
    }
1008
1009
0
    EEO_CASE(EEOP_FUNCEXPR_FUSAGE)
1010
0
    {
1011
      /* not common enough to inline */
1012
0
      ExecEvalFuncExprFusage(state, op, econtext);
1013
1014
0
      EEO_NEXT();
1015
0
    }
1016
1017
0
    EEO_CASE(EEOP_FUNCEXPR_STRICT_FUSAGE)
1018
0
    {
1019
      /* not common enough to inline */
1020
0
      ExecEvalFuncExprStrictFusage(state, op, econtext);
1021
1022
0
      EEO_NEXT();
1023
0
    }
1024
1025
    /*
1026
     * If any of its clauses is FALSE, an AND's result is FALSE regardless
1027
     * of the states of the rest of the clauses, so we can stop evaluating
1028
     * and return FALSE immediately.  If none are FALSE and one or more is
1029
     * NULL, we return NULL; otherwise we return TRUE.  This makes sense
1030
     * when you interpret NULL as "don't know": perhaps one of the "don't
1031
     * knows" would have been FALSE if we'd known its value.  Only when
1032
     * all the inputs are known to be TRUE can we state confidently that
1033
     * the AND's result is TRUE.
1034
     */
1035
0
    EEO_CASE(EEOP_BOOL_AND_STEP_FIRST)
1036
0
    {
1037
0
      *op->d.boolexpr.anynull = false;
1038
1039
      /*
1040
       * EEOP_BOOL_AND_STEP_FIRST resets anynull, otherwise it's the
1041
       * same as EEOP_BOOL_AND_STEP - so fall through to that.
1042
       */
1043
1044
      /* FALL THROUGH */
1045
0
    }
1046
1047
0
    EEO_CASE(EEOP_BOOL_AND_STEP)
1048
0
    {
1049
0
      if (*op->resnull)
1050
0
      {
1051
0
        *op->d.boolexpr.anynull = true;
1052
0
      }
1053
0
      else if (!DatumGetBool(*op->resvalue))
1054
0
      {
1055
        /* result is already set to FALSE, need not change it */
1056
        /* bail out early */
1057
0
        EEO_JUMP(op->d.boolexpr.jumpdone);
1058
0
      }
1059
1060
0
      EEO_NEXT();
1061
0
    }
1062
1063
0
    EEO_CASE(EEOP_BOOL_AND_STEP_LAST)
1064
0
    {
1065
0
      if (*op->resnull)
1066
0
      {
1067
        /* result is already set to NULL, need not change it */
1068
0
      }
1069
0
      else if (!DatumGetBool(*op->resvalue))
1070
0
      {
1071
        /* result is already set to FALSE, need not change it */
1072
1073
        /*
1074
         * No point jumping early to jumpdone - would be same target
1075
         * (as this is the last argument to the AND expression),
1076
         * except more expensive.
1077
         */
1078
0
      }
1079
0
      else if (*op->d.boolexpr.anynull)
1080
0
      {
1081
0
        *op->resvalue = (Datum) 0;
1082
0
        *op->resnull = true;
1083
0
      }
1084
0
      else
1085
0
      {
1086
        /* result is already set to TRUE, need not change it */
1087
0
      }
1088
1089
0
      EEO_NEXT();
1090
0
    }
1091
1092
    /*
1093
     * If any of its clauses is TRUE, an OR's result is TRUE regardless of
1094
     * the states of the rest of the clauses, so we can stop evaluating
1095
     * and return TRUE immediately.  If none are TRUE and one or more is
1096
     * NULL, we return NULL; otherwise we return FALSE.  This makes sense
1097
     * when you interpret NULL as "don't know": perhaps one of the "don't
1098
     * knows" would have been TRUE if we'd known its value.  Only when all
1099
     * the inputs are known to be FALSE can we state confidently that the
1100
     * OR's result is FALSE.
1101
     */
1102
0
    EEO_CASE(EEOP_BOOL_OR_STEP_FIRST)
1103
0
    {
1104
0
      *op->d.boolexpr.anynull = false;
1105
1106
      /*
1107
       * EEOP_BOOL_OR_STEP_FIRST resets anynull, otherwise it's the same
1108
       * as EEOP_BOOL_OR_STEP - so fall through to that.
1109
       */
1110
1111
      /* FALL THROUGH */
1112
0
    }
1113
1114
0
    EEO_CASE(EEOP_BOOL_OR_STEP)
1115
0
    {
1116
0
      if (*op->resnull)
1117
0
      {
1118
0
        *op->d.boolexpr.anynull = true;
1119
0
      }
1120
0
      else if (DatumGetBool(*op->resvalue))
1121
0
      {
1122
        /* result is already set to TRUE, need not change it */
1123
        /* bail out early */
1124
0
        EEO_JUMP(op->d.boolexpr.jumpdone);
1125
0
      }
1126
1127
0
      EEO_NEXT();
1128
0
    }
1129
1130
0
    EEO_CASE(EEOP_BOOL_OR_STEP_LAST)
1131
0
    {
1132
0
      if (*op->resnull)
1133
0
      {
1134
        /* result is already set to NULL, need not change it */
1135
0
      }
1136
0
      else if (DatumGetBool(*op->resvalue))
1137
0
      {
1138
        /* result is already set to TRUE, need not change it */
1139
1140
        /*
1141
         * No point jumping to jumpdone - would be same target (as
1142
         * this is the last argument to the AND expression), except
1143
         * more expensive.
1144
         */
1145
0
      }
1146
0
      else if (*op->d.boolexpr.anynull)
1147
0
      {
1148
0
        *op->resvalue = (Datum) 0;
1149
0
        *op->resnull = true;
1150
0
      }
1151
0
      else
1152
0
      {
1153
        /* result is already set to FALSE, need not change it */
1154
0
      }
1155
1156
0
      EEO_NEXT();
1157
0
    }
1158
1159
0
    EEO_CASE(EEOP_BOOL_NOT_STEP)
1160
0
    {
1161
      /*
1162
       * Evaluation of 'not' is simple... if expr is false, then return
1163
       * 'true' and vice versa.  It's safe to do this even on a
1164
       * nominally null value, so we ignore resnull; that means that
1165
       * NULL in produces NULL out, which is what we want.
1166
       */
1167
0
      *op->resvalue = BoolGetDatum(!DatumGetBool(*op->resvalue));
1168
1169
0
      EEO_NEXT();
1170
0
    }
1171
1172
0
    EEO_CASE(EEOP_QUAL)
1173
0
    {
1174
      /* simplified version of BOOL_AND_STEP for use by ExecQual() */
1175
1176
      /* If argument (also result) is false or null ... */
1177
0
      if (*op->resnull ||
1178
0
        !DatumGetBool(*op->resvalue))
1179
0
      {
1180
        /* ... bail out early, returning FALSE */
1181
0
        *op->resnull = false;
1182
0
        *op->resvalue = BoolGetDatum(false);
1183
0
        EEO_JUMP(op->d.qualexpr.jumpdone);
1184
0
      }
1185
1186
      /*
1187
       * Otherwise, leave the TRUE value in place, in case this is the
1188
       * last qual.  Then, TRUE is the correct answer.
1189
       */
1190
1191
0
      EEO_NEXT();
1192
0
    }
1193
1194
0
    EEO_CASE(EEOP_JUMP)
1195
0
    {
1196
      /* Unconditionally jump to target step */
1197
0
      EEO_JUMP(op->d.jump.jumpdone);
1198
0
    }
1199
1200
0
    EEO_CASE(EEOP_JUMP_IF_NULL)
1201
0
    {
1202
      /* Transfer control if current result is null */
1203
0
      if (*op->resnull)
1204
0
        EEO_JUMP(op->d.jump.jumpdone);
1205
1206
0
      EEO_NEXT();
1207
0
    }
1208
1209
0
    EEO_CASE(EEOP_JUMP_IF_NOT_NULL)
1210
0
    {
1211
      /* Transfer control if current result is non-null */
1212
0
      if (!*op->resnull)
1213
0
        EEO_JUMP(op->d.jump.jumpdone);
1214
1215
0
      EEO_NEXT();
1216
0
    }
1217
1218
0
    EEO_CASE(EEOP_JUMP_IF_NOT_TRUE)
1219
0
    {
1220
      /* Transfer control if current result is null or false */
1221
0
      if (*op->resnull || !DatumGetBool(*op->resvalue))
1222
0
        EEO_JUMP(op->d.jump.jumpdone);
1223
1224
0
      EEO_NEXT();
1225
0
    }
1226
1227
0
    EEO_CASE(EEOP_NULLTEST_ISNULL)
1228
0
    {
1229
0
      *op->resvalue = BoolGetDatum(*op->resnull);
1230
0
      *op->resnull = false;
1231
1232
0
      EEO_NEXT();
1233
0
    }
1234
1235
0
    EEO_CASE(EEOP_NULLTEST_ISNOTNULL)
1236
0
    {
1237
0
      *op->resvalue = BoolGetDatum(!*op->resnull);
1238
0
      *op->resnull = false;
1239
1240
0
      EEO_NEXT();
1241
0
    }
1242
1243
0
    EEO_CASE(EEOP_NULLTEST_ROWISNULL)
1244
0
    {
1245
      /* out of line implementation: too large */
1246
0
      ExecEvalRowNull(state, op, econtext);
1247
1248
0
      EEO_NEXT();
1249
0
    }
1250
1251
0
    EEO_CASE(EEOP_NULLTEST_ROWISNOTNULL)
1252
0
    {
1253
      /* out of line implementation: too large */
1254
0
      ExecEvalRowNotNull(state, op, econtext);
1255
1256
0
      EEO_NEXT();
1257
0
    }
1258
1259
    /* BooleanTest implementations for all booltesttypes */
1260
1261
0
    EEO_CASE(EEOP_BOOLTEST_IS_TRUE)
1262
0
    {
1263
0
      if (*op->resnull)
1264
0
      {
1265
0
        *op->resvalue = BoolGetDatum(false);
1266
0
        *op->resnull = false;
1267
0
      }
1268
      /* else, input value is the correct output as well */
1269
1270
0
      EEO_NEXT();
1271
0
    }
1272
1273
0
    EEO_CASE(EEOP_BOOLTEST_IS_NOT_TRUE)
1274
0
    {
1275
0
      if (*op->resnull)
1276
0
      {
1277
0
        *op->resvalue = BoolGetDatum(true);
1278
0
        *op->resnull = false;
1279
0
      }
1280
0
      else
1281
0
        *op->resvalue = BoolGetDatum(!DatumGetBool(*op->resvalue));
1282
1283
0
      EEO_NEXT();
1284
0
    }
1285
1286
0
    EEO_CASE(EEOP_BOOLTEST_IS_FALSE)
1287
0
    {
1288
0
      if (*op->resnull)
1289
0
      {
1290
0
        *op->resvalue = BoolGetDatum(false);
1291
0
        *op->resnull = false;
1292
0
      }
1293
0
      else
1294
0
        *op->resvalue = BoolGetDatum(!DatumGetBool(*op->resvalue));
1295
1296
0
      EEO_NEXT();
1297
0
    }
1298
1299
0
    EEO_CASE(EEOP_BOOLTEST_IS_NOT_FALSE)
1300
0
    {
1301
0
      if (*op->resnull)
1302
0
      {
1303
0
        *op->resvalue = BoolGetDatum(true);
1304
0
        *op->resnull = false;
1305
0
      }
1306
      /* else, input value is the correct output as well */
1307
1308
0
      EEO_NEXT();
1309
0
    }
1310
1311
0
    EEO_CASE(EEOP_PARAM_EXEC)
1312
0
    {
1313
      /* out of line implementation: too large */
1314
0
      ExecEvalParamExec(state, op, econtext);
1315
1316
0
      EEO_NEXT();
1317
0
    }
1318
1319
0
    EEO_CASE(EEOP_PARAM_EXTERN)
1320
0
    {
1321
      /* out of line implementation: too large */
1322
0
      ExecEvalParamExtern(state, op, econtext);
1323
0
      EEO_NEXT();
1324
0
    }
1325
1326
0
    EEO_CASE(EEOP_PARAM_CALLBACK)
1327
0
    {
1328
      /* allow an extension module to supply a PARAM_EXTERN value */
1329
0
      op->d.cparam.paramfunc(state, op, econtext);
1330
0
      EEO_NEXT();
1331
0
    }
1332
1333
0
    EEO_CASE(EEOP_PARAM_SET)
1334
0
    {
1335
      /* out of line, unlikely to matter performance-wise */
1336
0
      ExecEvalParamSet(state, op, econtext);
1337
0
      EEO_NEXT();
1338
0
    }
1339
1340
0
    EEO_CASE(EEOP_CASE_TESTVAL)
1341
0
    {
1342
0
      *op->resvalue = *op->d.casetest.value;
1343
0
      *op->resnull = *op->d.casetest.isnull;
1344
1345
0
      EEO_NEXT();
1346
0
    }
1347
1348
0
    EEO_CASE(EEOP_CASE_TESTVAL_EXT)
1349
0
    {
1350
0
      *op->resvalue = econtext->caseValue_datum;
1351
0
      *op->resnull = econtext->caseValue_isNull;
1352
1353
0
      EEO_NEXT();
1354
0
    }
1355
1356
0
    EEO_CASE(EEOP_MAKE_READONLY)
1357
0
    {
1358
      /*
1359
       * Force a varlena value that might be read multiple times to R/O
1360
       */
1361
0
      if (!*op->d.make_readonly.isnull)
1362
0
        *op->resvalue =
1363
0
          MakeExpandedObjectReadOnlyInternal(*op->d.make_readonly.value);
1364
0
      *op->resnull = *op->d.make_readonly.isnull;
1365
1366
0
      EEO_NEXT();
1367
0
    }
1368
1369
0
    EEO_CASE(EEOP_IOCOERCE)
1370
0
    {
1371
      /*
1372
       * Evaluate a CoerceViaIO node.  This can be quite a hot path, so
1373
       * inline as much work as possible.  The source value is in our
1374
       * result variable.
1375
       *
1376
       * Also look at ExecEvalCoerceViaIOSafe() if you change anything
1377
       * here.
1378
       */
1379
0
      char     *str;
1380
1381
      /* call output function (similar to OutputFunctionCall) */
1382
0
      if (*op->resnull)
1383
0
      {
1384
        /* output functions are not called on nulls */
1385
0
        str = NULL;
1386
0
      }
1387
0
      else
1388
0
      {
1389
0
        FunctionCallInfo fcinfo_out;
1390
1391
0
        fcinfo_out = op->d.iocoerce.fcinfo_data_out;
1392
0
        fcinfo_out->args[0].value = *op->resvalue;
1393
0
        fcinfo_out->args[0].isnull = false;
1394
1395
0
        fcinfo_out->isnull = false;
1396
0
        str = DatumGetCString(FunctionCallInvoke(fcinfo_out));
1397
1398
        /* OutputFunctionCall assumes result isn't null */
1399
0
        Assert(!fcinfo_out->isnull);
1400
0
      }
1401
1402
      /* call input function (similar to InputFunctionCall) */
1403
0
      if (!op->d.iocoerce.finfo_in->fn_strict || str != NULL)
1404
0
      {
1405
0
        FunctionCallInfo fcinfo_in;
1406
0
        Datum   d;
1407
1408
0
        fcinfo_in = op->d.iocoerce.fcinfo_data_in;
1409
0
        fcinfo_in->args[0].value = PointerGetDatum(str);
1410
0
        fcinfo_in->args[0].isnull = *op->resnull;
1411
        /* second and third arguments are already set up */
1412
1413
0
        fcinfo_in->isnull = false;
1414
0
        d = FunctionCallInvoke(fcinfo_in);
1415
0
        *op->resvalue = d;
1416
1417
        /* Should get null result if and only if str is NULL */
1418
0
        if (str == NULL)
1419
0
        {
1420
0
          Assert(*op->resnull);
1421
0
          Assert(fcinfo_in->isnull);
1422
0
        }
1423
0
        else
1424
0
        {
1425
0
          Assert(!*op->resnull);
1426
0
          Assert(!fcinfo_in->isnull);
1427
0
        }
1428
0
      }
1429
1430
0
      EEO_NEXT();
1431
0
    }
1432
1433
0
    EEO_CASE(EEOP_IOCOERCE_SAFE)
1434
0
    {
1435
0
      ExecEvalCoerceViaIOSafe(state, op);
1436
0
      EEO_NEXT();
1437
0
    }
1438
1439
0
    EEO_CASE(EEOP_DISTINCT)
1440
0
    {
1441
      /*
1442
       * IS DISTINCT FROM must evaluate arguments (already done into
1443
       * fcinfo->args) to determine whether they are NULL; if either is
1444
       * NULL then the result is determined.  If neither is NULL, then
1445
       * proceed to evaluate the comparison function, which is just the
1446
       * type's standard equality operator.  We need not care whether
1447
       * that function is strict.  Because the handling of nulls is
1448
       * different, we can't just reuse EEOP_FUNCEXPR.
1449
       */
1450
0
      FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
1451
1452
      /* check function arguments for NULLness */
1453
0
      if (fcinfo->args[0].isnull && fcinfo->args[1].isnull)
1454
0
      {
1455
        /* Both NULL? Then is not distinct... */
1456
0
        *op->resvalue = BoolGetDatum(false);
1457
0
        *op->resnull = false;
1458
0
      }
1459
0
      else if (fcinfo->args[0].isnull || fcinfo->args[1].isnull)
1460
0
      {
1461
        /* Only one is NULL? Then is distinct... */
1462
0
        *op->resvalue = BoolGetDatum(true);
1463
0
        *op->resnull = false;
1464
0
      }
1465
0
      else
1466
0
      {
1467
        /* Neither null, so apply the equality function */
1468
0
        Datum   eqresult;
1469
1470
0
        fcinfo->isnull = false;
1471
0
        eqresult = op->d.func.fn_addr(fcinfo);
1472
        /* Must invert result of "="; safe to do even if null */
1473
0
        *op->resvalue = BoolGetDatum(!DatumGetBool(eqresult));
1474
0
        *op->resnull = fcinfo->isnull;
1475
0
      }
1476
1477
0
      EEO_NEXT();
1478
0
    }
1479
1480
    /* see EEOP_DISTINCT for comments, this is just inverted */
1481
0
    EEO_CASE(EEOP_NOT_DISTINCT)
1482
0
    {
1483
0
      FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
1484
1485
0
      if (fcinfo->args[0].isnull && fcinfo->args[1].isnull)
1486
0
      {
1487
0
        *op->resvalue = BoolGetDatum(true);
1488
0
        *op->resnull = false;
1489
0
      }
1490
0
      else if (fcinfo->args[0].isnull || fcinfo->args[1].isnull)
1491
0
      {
1492
0
        *op->resvalue = BoolGetDatum(false);
1493
0
        *op->resnull = false;
1494
0
      }
1495
0
      else
1496
0
      {
1497
0
        Datum   eqresult;
1498
1499
0
        fcinfo->isnull = false;
1500
0
        eqresult = op->d.func.fn_addr(fcinfo);
1501
0
        *op->resvalue = eqresult;
1502
0
        *op->resnull = fcinfo->isnull;
1503
0
      }
1504
1505
0
      EEO_NEXT();
1506
0
    }
1507
1508
0
    EEO_CASE(EEOP_NULLIF)
1509
0
    {
1510
      /*
1511
       * The arguments are already evaluated into fcinfo->args.
1512
       */
1513
0
      FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
1514
0
      Datum   save_arg0 = fcinfo->args[0].value;
1515
1516
      /* if either argument is NULL they can't be equal */
1517
0
      if (!fcinfo->args[0].isnull && !fcinfo->args[1].isnull)
1518
0
      {
1519
0
        Datum   result;
1520
1521
        /*
1522
         * If first argument is of varlena type, it might be an
1523
         * expanded datum.  We need to ensure that the value passed to
1524
         * the comparison function is a read-only pointer.  However,
1525
         * if we end by returning the first argument, that will be the
1526
         * original read-write pointer if it was read-write.
1527
         */
1528
0
        if (op->d.func.make_ro)
1529
0
          fcinfo->args[0].value =
1530
0
            MakeExpandedObjectReadOnlyInternal(save_arg0);
1531
1532
0
        fcinfo->isnull = false;
1533
0
        result = op->d.func.fn_addr(fcinfo);
1534
1535
        /* if the arguments are equal return null */
1536
0
        if (!fcinfo->isnull && DatumGetBool(result))
1537
0
        {
1538
0
          *op->resvalue = (Datum) 0;
1539
0
          *op->resnull = true;
1540
1541
0
          EEO_NEXT();
1542
0
        }
1543
0
      }
1544
1545
      /* Arguments aren't equal, so return the first one */
1546
0
      *op->resvalue = save_arg0;
1547
0
      *op->resnull = fcinfo->args[0].isnull;
1548
1549
0
      EEO_NEXT();
1550
0
    }
1551
1552
0
    EEO_CASE(EEOP_SQLVALUEFUNCTION)
1553
0
    {
1554
      /*
1555
       * Doesn't seem worthwhile to have an inline implementation
1556
       * efficiency-wise.
1557
       */
1558
0
      ExecEvalSQLValueFunction(state, op);
1559
1560
0
      EEO_NEXT();
1561
0
    }
1562
1563
0
    EEO_CASE(EEOP_CURRENTOFEXPR)
1564
0
    {
1565
      /* error invocation uses space, and shouldn't ever occur */
1566
0
      ExecEvalCurrentOfExpr(state, op);
1567
1568
0
      EEO_NEXT();
1569
0
    }
1570
1571
0
    EEO_CASE(EEOP_NEXTVALUEEXPR)
1572
0
    {
1573
      /*
1574
       * Doesn't seem worthwhile to have an inline implementation
1575
       * efficiency-wise.
1576
       */
1577
0
      ExecEvalNextValueExpr(state, op);
1578
1579
0
      EEO_NEXT();
1580
0
    }
1581
1582
0
    EEO_CASE(EEOP_RETURNINGEXPR)
1583
0
    {
1584
      /*
1585
       * The next op actually evaluates the expression.  If the OLD/NEW
1586
       * row doesn't exist, skip that and return NULL.
1587
       */
1588
0
      if (state->flags & op->d.returningexpr.nullflag)
1589
0
      {
1590
0
        *op->resvalue = (Datum) 0;
1591
0
        *op->resnull = true;
1592
1593
0
        EEO_JUMP(op->d.returningexpr.jumpdone);
1594
0
      }
1595
1596
0
      EEO_NEXT();
1597
0
    }
1598
1599
0
    EEO_CASE(EEOP_ARRAYEXPR)
1600
0
    {
1601
      /* too complex for an inline implementation */
1602
0
      ExecEvalArrayExpr(state, op);
1603
1604
0
      EEO_NEXT();
1605
0
    }
1606
1607
0
    EEO_CASE(EEOP_ARRAYCOERCE)
1608
0
    {
1609
      /* too complex for an inline implementation */
1610
0
      ExecEvalArrayCoerce(state, op, econtext);
1611
1612
0
      EEO_NEXT();
1613
0
    }
1614
1615
0
    EEO_CASE(EEOP_ROW)
1616
0
    {
1617
      /* too complex for an inline implementation */
1618
0
      ExecEvalRow(state, op);
1619
1620
0
      EEO_NEXT();
1621
0
    }
1622
1623
0
    EEO_CASE(EEOP_ROWCOMPARE_STEP)
1624
0
    {
1625
0
      FunctionCallInfo fcinfo = op->d.rowcompare_step.fcinfo_data;
1626
0
      Datum   d;
1627
1628
      /* force NULL result if strict fn and NULL input */
1629
0
      if (op->d.rowcompare_step.finfo->fn_strict &&
1630
0
        (fcinfo->args[0].isnull || fcinfo->args[1].isnull))
1631
0
      {
1632
0
        *op->resnull = true;
1633
0
        EEO_JUMP(op->d.rowcompare_step.jumpnull);
1634
0
      }
1635
1636
      /* Apply comparison function */
1637
0
      fcinfo->isnull = false;
1638
0
      d = op->d.rowcompare_step.fn_addr(fcinfo);
1639
0
      *op->resvalue = d;
1640
1641
      /* force NULL result if NULL function result */
1642
0
      if (fcinfo->isnull)
1643
0
      {
1644
0
        *op->resnull = true;
1645
0
        EEO_JUMP(op->d.rowcompare_step.jumpnull);
1646
0
      }
1647
0
      *op->resnull = false;
1648
1649
      /* If unequal, no need to compare remaining columns */
1650
0
      if (DatumGetInt32(*op->resvalue) != 0)
1651
0
      {
1652
0
        EEO_JUMP(op->d.rowcompare_step.jumpdone);
1653
0
      }
1654
1655
0
      EEO_NEXT();
1656
0
    }
1657
1658
0
    EEO_CASE(EEOP_ROWCOMPARE_FINAL)
1659
0
    {
1660
0
      int32   cmpresult = DatumGetInt32(*op->resvalue);
1661
0
      CompareType cmptype = op->d.rowcompare_final.cmptype;
1662
1663
0
      *op->resnull = false;
1664
0
      switch (cmptype)
1665
0
      {
1666
          /* EQ and NE cases aren't allowed here */
1667
0
        case COMPARE_LT:
1668
0
          *op->resvalue = BoolGetDatum(cmpresult < 0);
1669
0
          break;
1670
0
        case COMPARE_LE:
1671
0
          *op->resvalue = BoolGetDatum(cmpresult <= 0);
1672
0
          break;
1673
0
        case COMPARE_GE:
1674
0
          *op->resvalue = BoolGetDatum(cmpresult >= 0);
1675
0
          break;
1676
0
        case COMPARE_GT:
1677
0
          *op->resvalue = BoolGetDatum(cmpresult > 0);
1678
0
          break;
1679
0
        default:
1680
0
          Assert(false);
1681
0
          break;
1682
0
      }
1683
1684
0
      EEO_NEXT();
1685
0
    }
1686
1687
0
    EEO_CASE(EEOP_MINMAX)
1688
0
    {
1689
      /* too complex for an inline implementation */
1690
0
      ExecEvalMinMax(state, op);
1691
1692
0
      EEO_NEXT();
1693
0
    }
1694
1695
0
    EEO_CASE(EEOP_FIELDSELECT)
1696
0
    {
1697
      /* too complex for an inline implementation */
1698
0
      ExecEvalFieldSelect(state, op, econtext);
1699
1700
0
      EEO_NEXT();
1701
0
    }
1702
1703
0
    EEO_CASE(EEOP_FIELDSTORE_DEFORM)
1704
0
    {
1705
      /* too complex for an inline implementation */
1706
0
      ExecEvalFieldStoreDeForm(state, op, econtext);
1707
1708
0
      EEO_NEXT();
1709
0
    }
1710
1711
0
    EEO_CASE(EEOP_FIELDSTORE_FORM)
1712
0
    {
1713
      /* too complex for an inline implementation */
1714
0
      ExecEvalFieldStoreForm(state, op, econtext);
1715
1716
0
      EEO_NEXT();
1717
0
    }
1718
1719
0
    EEO_CASE(EEOP_SBSREF_SUBSCRIPTS)
1720
0
    {
1721
      /* Precheck SubscriptingRef subscript(s) */
1722
0
      if (op->d.sbsref_subscript.subscriptfunc(state, op, econtext))
1723
0
      {
1724
0
        EEO_NEXT();
1725
0
      }
1726
0
      else
1727
0
      {
1728
        /* Subscript is null, short-circuit SubscriptingRef to NULL */
1729
0
        EEO_JUMP(op->d.sbsref_subscript.jumpdone);
1730
0
      }
1731
0
    }
1732
1733
0
    EEO_CASE(EEOP_SBSREF_OLD)
1734
0
      EEO_CASE(EEOP_SBSREF_ASSIGN)
1735
0
      EEO_CASE(EEOP_SBSREF_FETCH)
1736
0
    {
1737
      /* Perform a SubscriptingRef fetch or assignment */
1738
0
      op->d.sbsref.subscriptfunc(state, op, econtext);
1739
1740
0
      EEO_NEXT();
1741
0
    }
1742
1743
0
    EEO_CASE(EEOP_CONVERT_ROWTYPE)
1744
0
    {
1745
      /* too complex for an inline implementation */
1746
0
      ExecEvalConvertRowtype(state, op, econtext);
1747
1748
0
      EEO_NEXT();
1749
0
    }
1750
1751
0
    EEO_CASE(EEOP_SCALARARRAYOP)
1752
0
    {
1753
      /* too complex for an inline implementation */
1754
0
      ExecEvalScalarArrayOp(state, op);
1755
1756
0
      EEO_NEXT();
1757
0
    }
1758
1759
0
    EEO_CASE(EEOP_HASHED_SCALARARRAYOP)
1760
0
    {
1761
      /* too complex for an inline implementation */
1762
0
      ExecEvalHashedScalarArrayOp(state, op, econtext);
1763
1764
0
      EEO_NEXT();
1765
0
    }
1766
1767
0
    EEO_CASE(EEOP_DOMAIN_TESTVAL)
1768
0
    {
1769
0
      *op->resvalue = *op->d.casetest.value;
1770
0
      *op->resnull = *op->d.casetest.isnull;
1771
1772
0
      EEO_NEXT();
1773
0
    }
1774
1775
0
    EEO_CASE(EEOP_DOMAIN_TESTVAL_EXT)
1776
0
    {
1777
0
      *op->resvalue = econtext->domainValue_datum;
1778
0
      *op->resnull = econtext->domainValue_isNull;
1779
1780
0
      EEO_NEXT();
1781
0
    }
1782
1783
0
    EEO_CASE(EEOP_DOMAIN_NOTNULL)
1784
0
    {
1785
      /* too complex for an inline implementation */
1786
0
      ExecEvalConstraintNotNull(state, op);
1787
1788
0
      EEO_NEXT();
1789
0
    }
1790
1791
0
    EEO_CASE(EEOP_DOMAIN_CHECK)
1792
0
    {
1793
      /* too complex for an inline implementation */
1794
0
      ExecEvalConstraintCheck(state, op);
1795
1796
0
      EEO_NEXT();
1797
0
    }
1798
1799
0
    EEO_CASE(EEOP_HASHDATUM_SET_INITVAL)
1800
0
    {
1801
0
      *op->resvalue = op->d.hashdatum_initvalue.init_value;
1802
0
      *op->resnull = false;
1803
1804
0
      EEO_NEXT();
1805
0
    }
1806
1807
0
    EEO_CASE(EEOP_HASHDATUM_FIRST)
1808
0
    {
1809
0
      FunctionCallInfo fcinfo = op->d.hashdatum.fcinfo_data;
1810
1811
      /*
1812
       * Save the Datum on non-null inputs, otherwise store 0 so that
1813
       * subsequent NEXT32 operations combine with an initialized value.
1814
       */
1815
0
      if (!fcinfo->args[0].isnull)
1816
0
        *op->resvalue = op->d.hashdatum.fn_addr(fcinfo);
1817
0
      else
1818
0
        *op->resvalue = (Datum) 0;
1819
1820
0
      *op->resnull = false;
1821
1822
0
      EEO_NEXT();
1823
0
    }
1824
1825
0
    EEO_CASE(EEOP_HASHDATUM_FIRST_STRICT)
1826
0
    {
1827
0
      FunctionCallInfo fcinfo = op->d.hashdatum.fcinfo_data;
1828
1829
0
      if (fcinfo->args[0].isnull)
1830
0
      {
1831
        /*
1832
         * With strict we have the expression return NULL instead of
1833
         * ignoring NULL input values.  We've nothing more to do after
1834
         * finding a NULL.
1835
         */
1836
0
        *op->resnull = true;
1837
0
        *op->resvalue = (Datum) 0;
1838
0
        EEO_JUMP(op->d.hashdatum.jumpdone);
1839
0
      }
1840
1841
      /* execute the hash function and save the resulting value */
1842
0
      *op->resvalue = op->d.hashdatum.fn_addr(fcinfo);
1843
0
      *op->resnull = false;
1844
1845
0
      EEO_NEXT();
1846
0
    }
1847
1848
0
    EEO_CASE(EEOP_HASHDATUM_NEXT32)
1849
0
    {
1850
0
      FunctionCallInfo fcinfo = op->d.hashdatum.fcinfo_data;
1851
0
      uint32    existinghash;
1852
1853
0
      existinghash = DatumGetUInt32(op->d.hashdatum.iresult->value);
1854
      /* combine successive hash values by rotating */
1855
0
      existinghash = pg_rotate_left32(existinghash, 1);
1856
1857
      /* leave the hash value alone on NULL inputs */
1858
0
      if (!fcinfo->args[0].isnull)
1859
0
      {
1860
0
        uint32    hashvalue;
1861
1862
        /* execute hash func and combine with previous hash value */
1863
0
        hashvalue = DatumGetUInt32(op->d.hashdatum.fn_addr(fcinfo));
1864
0
        existinghash = existinghash ^ hashvalue;
1865
0
      }
1866
1867
0
      *op->resvalue = UInt32GetDatum(existinghash);
1868
0
      *op->resnull = false;
1869
1870
0
      EEO_NEXT();
1871
0
    }
1872
1873
0
    EEO_CASE(EEOP_HASHDATUM_NEXT32_STRICT)
1874
0
    {
1875
0
      FunctionCallInfo fcinfo = op->d.hashdatum.fcinfo_data;
1876
1877
0
      if (fcinfo->args[0].isnull)
1878
0
      {
1879
        /*
1880
         * With strict we have the expression return NULL instead of
1881
         * ignoring NULL input values.  We've nothing more to do after
1882
         * finding a NULL.
1883
         */
1884
0
        *op->resnull = true;
1885
0
        *op->resvalue = (Datum) 0;
1886
0
        EEO_JUMP(op->d.hashdatum.jumpdone);
1887
0
      }
1888
0
      else
1889
0
      {
1890
0
        uint32    existinghash;
1891
0
        uint32    hashvalue;
1892
1893
0
        existinghash = DatumGetUInt32(op->d.hashdatum.iresult->value);
1894
        /* combine successive hash values by rotating */
1895
0
        existinghash = pg_rotate_left32(existinghash, 1);
1896
1897
        /* execute hash func and combine with previous hash value */
1898
0
        hashvalue = DatumGetUInt32(op->d.hashdatum.fn_addr(fcinfo));
1899
0
        *op->resvalue = UInt32GetDatum(existinghash ^ hashvalue);
1900
0
        *op->resnull = false;
1901
0
      }
1902
1903
0
      EEO_NEXT();
1904
0
    }
1905
1906
0
    EEO_CASE(EEOP_XMLEXPR)
1907
0
    {
1908
      /* too complex for an inline implementation */
1909
0
      ExecEvalXmlExpr(state, op);
1910
1911
0
      EEO_NEXT();
1912
0
    }
1913
1914
0
    EEO_CASE(EEOP_JSON_CONSTRUCTOR)
1915
0
    {
1916
      /* too complex for an inline implementation */
1917
0
      ExecEvalJsonConstructor(state, op, econtext);
1918
0
      EEO_NEXT();
1919
0
    }
1920
1921
0
    EEO_CASE(EEOP_IS_JSON)
1922
0
    {
1923
      /* too complex for an inline implementation */
1924
0
      ExecEvalJsonIsPredicate(state, op);
1925
1926
0
      EEO_NEXT();
1927
0
    }
1928
1929
0
    EEO_CASE(EEOP_JSONEXPR_PATH)
1930
0
    {
1931
      /* too complex for an inline implementation */
1932
0
      EEO_JUMP(ExecEvalJsonExprPath(state, op, econtext));
1933
0
    }
1934
1935
0
    EEO_CASE(EEOP_JSONEXPR_COERCION)
1936
0
    {
1937
      /* too complex for an inline implementation */
1938
0
      ExecEvalJsonCoercion(state, op, econtext);
1939
1940
0
      EEO_NEXT();
1941
0
    }
1942
1943
0
    EEO_CASE(EEOP_JSONEXPR_COERCION_FINISH)
1944
0
    {
1945
      /* too complex for an inline implementation */
1946
0
      ExecEvalJsonCoercionFinish(state, op);
1947
1948
0
      EEO_NEXT();
1949
0
    }
1950
1951
0
    EEO_CASE(EEOP_AGGREF)
1952
0
    {
1953
      /*
1954
       * Returns a Datum whose value is the precomputed aggregate value
1955
       * found in the given expression context.
1956
       */
1957
0
      int     aggno = op->d.aggref.aggno;
1958
1959
0
      Assert(econtext->ecxt_aggvalues != NULL);
1960
1961
0
      *op->resvalue = econtext->ecxt_aggvalues[aggno];
1962
0
      *op->resnull = econtext->ecxt_aggnulls[aggno];
1963
1964
0
      EEO_NEXT();
1965
0
    }
1966
1967
0
    EEO_CASE(EEOP_GROUPING_FUNC)
1968
0
    {
1969
      /* too complex/uncommon for an inline implementation */
1970
0
      ExecEvalGroupingFunc(state, op);
1971
1972
0
      EEO_NEXT();
1973
0
    }
1974
1975
0
    EEO_CASE(EEOP_WINDOW_FUNC)
1976
0
    {
1977
      /*
1978
       * Like Aggref, just return a precomputed value from the econtext.
1979
       */
1980
0
      WindowFuncExprState *wfunc = op->d.window_func.wfstate;
1981
1982
0
      Assert(econtext->ecxt_aggvalues != NULL);
1983
1984
0
      *op->resvalue = econtext->ecxt_aggvalues[wfunc->wfuncno];
1985
0
      *op->resnull = econtext->ecxt_aggnulls[wfunc->wfuncno];
1986
1987
0
      EEO_NEXT();
1988
0
    }
1989
1990
0
    EEO_CASE(EEOP_MERGE_SUPPORT_FUNC)
1991
0
    {
1992
      /* too complex/uncommon for an inline implementation */
1993
0
      ExecEvalMergeSupportFunc(state, op, econtext);
1994
1995
0
      EEO_NEXT();
1996
0
    }
1997
1998
0
    EEO_CASE(EEOP_SUBPLAN)
1999
0
    {
2000
      /* too complex for an inline implementation */
2001
0
      ExecEvalSubPlan(state, op, econtext);
2002
2003
0
      EEO_NEXT();
2004
0
    }
2005
2006
    /* evaluate a strict aggregate deserialization function */
2007
0
    EEO_CASE(EEOP_AGG_STRICT_DESERIALIZE)
2008
0
    {
2009
      /* Don't call a strict deserialization function with NULL input */
2010
0
      if (op->d.agg_deserialize.fcinfo_data->args[0].isnull)
2011
0
        EEO_JUMP(op->d.agg_deserialize.jumpnull);
2012
2013
      /* fallthrough */
2014
0
    }
2015
2016
    /* evaluate aggregate deserialization function (non-strict portion) */
2017
0
    EEO_CASE(EEOP_AGG_DESERIALIZE)
2018
0
    {
2019
0
      FunctionCallInfo fcinfo = op->d.agg_deserialize.fcinfo_data;
2020
0
      AggState   *aggstate = castNode(AggState, state->parent);
2021
0
      MemoryContext oldContext;
2022
2023
      /*
2024
       * We run the deserialization functions in per-input-tuple memory
2025
       * context.
2026
       */
2027
0
      oldContext = MemoryContextSwitchTo(aggstate->tmpcontext->ecxt_per_tuple_memory);
2028
0
      fcinfo->isnull = false;
2029
0
      *op->resvalue = FunctionCallInvoke(fcinfo);
2030
0
      *op->resnull = fcinfo->isnull;
2031
0
      MemoryContextSwitchTo(oldContext);
2032
2033
0
      EEO_NEXT();
2034
0
    }
2035
2036
    /*
2037
     * Check that a strict aggregate transition / combination function's
2038
     * input is not NULL.
2039
     */
2040
2041
    /* when checking more than one argument */
2042
0
    EEO_CASE(EEOP_AGG_STRICT_INPUT_CHECK_ARGS)
2043
0
    {
2044
0
      NullableDatum *args = op->d.agg_strict_input_check.args;
2045
0
      int     nargs = op->d.agg_strict_input_check.nargs;
2046
2047
0
      Assert(nargs > 1);
2048
2049
0
      for (int argno = 0; argno < nargs; argno++)
2050
0
      {
2051
0
        if (args[argno].isnull)
2052
0
          EEO_JUMP(op->d.agg_strict_input_check.jumpnull);
2053
0
      }
2054
0
      EEO_NEXT();
2055
0
    }
2056
2057
    /* special case for just one argument */
2058
0
    EEO_CASE(EEOP_AGG_STRICT_INPUT_CHECK_ARGS_1)
2059
0
    {
2060
0
      NullableDatum *args = op->d.agg_strict_input_check.args;
2061
0
      PG_USED_FOR_ASSERTS_ONLY int nargs = op->d.agg_strict_input_check.nargs;
2062
2063
0
      Assert(nargs == 1);
2064
2065
0
      if (args[0].isnull)
2066
0
        EEO_JUMP(op->d.agg_strict_input_check.jumpnull);
2067
0
      EEO_NEXT();
2068
0
    }
2069
2070
0
    EEO_CASE(EEOP_AGG_STRICT_INPUT_CHECK_NULLS)
2071
0
    {
2072
0
      bool     *nulls = op->d.agg_strict_input_check.nulls;
2073
0
      int     nargs = op->d.agg_strict_input_check.nargs;
2074
2075
0
      for (int argno = 0; argno < nargs; argno++)
2076
0
      {
2077
0
        if (nulls[argno])
2078
0
          EEO_JUMP(op->d.agg_strict_input_check.jumpnull);
2079
0
      }
2080
0
      EEO_NEXT();
2081
0
    }
2082
2083
    /*
2084
     * Check for a NULL pointer to the per-group states.
2085
     */
2086
2087
0
    EEO_CASE(EEOP_AGG_PLAIN_PERGROUP_NULLCHECK)
2088
0
    {
2089
0
      AggState   *aggstate = castNode(AggState, state->parent);
2090
0
      AggStatePerGroup pergroup_allaggs =
2091
0
        aggstate->all_pergroups[op->d.agg_plain_pergroup_nullcheck.setoff];
2092
2093
0
      if (pergroup_allaggs == NULL)
2094
0
        EEO_JUMP(op->d.agg_plain_pergroup_nullcheck.jumpnull);
2095
2096
0
      EEO_NEXT();
2097
0
    }
2098
2099
    /*
2100
     * Different types of aggregate transition functions are implemented
2101
     * as different types of steps, to avoid incurring unnecessary
2102
     * overhead.  There's a step type for each valid combination of having
2103
     * a by value / by reference transition type, [not] needing to the
2104
     * initialize the transition value for the first row in a group from
2105
     * input, and [not] strict transition function.
2106
     *
2107
     * Could optimize further by splitting off by-reference for
2108
     * fixed-length types, but currently that doesn't seem worth it.
2109
     */
2110
2111
0
    EEO_CASE(EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL)
2112
0
    {
2113
0
      AggState   *aggstate = castNode(AggState, state->parent);
2114
0
      AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
2115
0
      AggStatePerGroup pergroup =
2116
0
        &aggstate->all_pergroups[op->d.agg_trans.setoff][op->d.agg_trans.transno];
2117
2118
0
      Assert(pertrans->transtypeByVal);
2119
2120
0
      if (pergroup->noTransValue)
2121
0
      {
2122
        /* If transValue has not yet been initialized, do so now. */
2123
0
        ExecAggInitGroup(aggstate, pertrans, pergroup,
2124
0
                 op->d.agg_trans.aggcontext);
2125
        /* copied trans value from input, done this round */
2126
0
      }
2127
0
      else if (likely(!pergroup->transValueIsNull))
2128
0
      {
2129
        /* invoke transition function, unless prevented by strictness */
2130
0
        ExecAggPlainTransByVal(aggstate, pertrans, pergroup,
2131
0
                     op->d.agg_trans.aggcontext,
2132
0
                     op->d.agg_trans.setno);
2133
0
      }
2134
2135
0
      EEO_NEXT();
2136
0
    }
2137
2138
    /* see comments above EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL */
2139
0
    EEO_CASE(EEOP_AGG_PLAIN_TRANS_STRICT_BYVAL)
2140
0
    {
2141
0
      AggState   *aggstate = castNode(AggState, state->parent);
2142
0
      AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
2143
0
      AggStatePerGroup pergroup =
2144
0
        &aggstate->all_pergroups[op->d.agg_trans.setoff][op->d.agg_trans.transno];
2145
2146
0
      Assert(pertrans->transtypeByVal);
2147
2148
0
      if (likely(!pergroup->transValueIsNull))
2149
0
        ExecAggPlainTransByVal(aggstate, pertrans, pergroup,
2150
0
                     op->d.agg_trans.aggcontext,
2151
0
                     op->d.agg_trans.setno);
2152
2153
0
      EEO_NEXT();
2154
0
    }
2155
2156
    /* see comments above EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL */
2157
0
    EEO_CASE(EEOP_AGG_PLAIN_TRANS_BYVAL)
2158
0
    {
2159
0
      AggState   *aggstate = castNode(AggState, state->parent);
2160
0
      AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
2161
0
      AggStatePerGroup pergroup =
2162
0
        &aggstate->all_pergroups[op->d.agg_trans.setoff][op->d.agg_trans.transno];
2163
2164
0
      Assert(pertrans->transtypeByVal);
2165
2166
0
      ExecAggPlainTransByVal(aggstate, pertrans, pergroup,
2167
0
                   op->d.agg_trans.aggcontext,
2168
0
                   op->d.agg_trans.setno);
2169
2170
0
      EEO_NEXT();
2171
0
    }
2172
2173
    /* see comments above EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL */
2174
0
    EEO_CASE(EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYREF)
2175
0
    {
2176
0
      AggState   *aggstate = castNode(AggState, state->parent);
2177
0
      AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
2178
0
      AggStatePerGroup pergroup =
2179
0
        &aggstate->all_pergroups[op->d.agg_trans.setoff][op->d.agg_trans.transno];
2180
2181
0
      Assert(!pertrans->transtypeByVal);
2182
2183
0
      if (pergroup->noTransValue)
2184
0
        ExecAggInitGroup(aggstate, pertrans, pergroup,
2185
0
                 op->d.agg_trans.aggcontext);
2186
0
      else if (likely(!pergroup->transValueIsNull))
2187
0
        ExecAggPlainTransByRef(aggstate, pertrans, pergroup,
2188
0
                     op->d.agg_trans.aggcontext,
2189
0
                     op->d.agg_trans.setno);
2190
2191
0
      EEO_NEXT();
2192
0
    }
2193
2194
    /* see comments above EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL */
2195
0
    EEO_CASE(EEOP_AGG_PLAIN_TRANS_STRICT_BYREF)
2196
0
    {
2197
0
      AggState   *aggstate = castNode(AggState, state->parent);
2198
0
      AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
2199
0
      AggStatePerGroup pergroup =
2200
0
        &aggstate->all_pergroups[op->d.agg_trans.setoff][op->d.agg_trans.transno];
2201
2202
0
      Assert(!pertrans->transtypeByVal);
2203
2204
0
      if (likely(!pergroup->transValueIsNull))
2205
0
        ExecAggPlainTransByRef(aggstate, pertrans, pergroup,
2206
0
                     op->d.agg_trans.aggcontext,
2207
0
                     op->d.agg_trans.setno);
2208
0
      EEO_NEXT();
2209
0
    }
2210
2211
    /* see comments above EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL */
2212
0
    EEO_CASE(EEOP_AGG_PLAIN_TRANS_BYREF)
2213
0
    {
2214
0
      AggState   *aggstate = castNode(AggState, state->parent);
2215
0
      AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
2216
0
      AggStatePerGroup pergroup =
2217
0
        &aggstate->all_pergroups[op->d.agg_trans.setoff][op->d.agg_trans.transno];
2218
2219
0
      Assert(!pertrans->transtypeByVal);
2220
2221
0
      ExecAggPlainTransByRef(aggstate, pertrans, pergroup,
2222
0
                   op->d.agg_trans.aggcontext,
2223
0
                   op->d.agg_trans.setno);
2224
2225
0
      EEO_NEXT();
2226
0
    }
2227
2228
0
    EEO_CASE(EEOP_AGG_PRESORTED_DISTINCT_SINGLE)
2229
0
    {
2230
0
      AggStatePerTrans pertrans = op->d.agg_presorted_distinctcheck.pertrans;
2231
0
      AggState   *aggstate = castNode(AggState, state->parent);
2232
2233
0
      if (ExecEvalPreOrderedDistinctSingle(aggstate, pertrans))
2234
0
        EEO_NEXT();
2235
0
      else
2236
0
        EEO_JUMP(op->d.agg_presorted_distinctcheck.jumpdistinct);
2237
0
    }
2238
2239
0
    EEO_CASE(EEOP_AGG_PRESORTED_DISTINCT_MULTI)
2240
0
    {
2241
0
      AggState   *aggstate = castNode(AggState, state->parent);
2242
0
      AggStatePerTrans pertrans = op->d.agg_presorted_distinctcheck.pertrans;
2243
2244
0
      if (ExecEvalPreOrderedDistinctMulti(aggstate, pertrans))
2245
0
        EEO_NEXT();
2246
0
      else
2247
0
        EEO_JUMP(op->d.agg_presorted_distinctcheck.jumpdistinct);
2248
0
    }
2249
2250
    /* process single-column ordered aggregate datum */
2251
0
    EEO_CASE(EEOP_AGG_ORDERED_TRANS_DATUM)
2252
0
    {
2253
      /* too complex for an inline implementation */
2254
0
      ExecEvalAggOrderedTransDatum(state, op, econtext);
2255
2256
0
      EEO_NEXT();
2257
0
    }
2258
2259
    /* process multi-column ordered aggregate tuple */
2260
0
    EEO_CASE(EEOP_AGG_ORDERED_TRANS_TUPLE)
2261
0
    {
2262
      /* too complex for an inline implementation */
2263
0
      ExecEvalAggOrderedTransTuple(state, op, econtext);
2264
2265
0
      EEO_NEXT();
2266
0
    }
2267
2268
0
    EEO_CASE(EEOP_LAST)
2269
0
    {
2270
      /* unreachable */
2271
0
      Assert(false);
2272
0
      goto out_error;
2273
0
    }
2274
0
  }
2275
2276
0
out_error:
2277
0
  pg_unreachable();
2278
0
  return (Datum) 0;
2279
0
}
2280
2281
/*
2282
 * Expression evaluation callback that performs extra checks before executing
2283
 * the expression. Declared extern so other methods of execution can use it
2284
 * too.
2285
 */
2286
Datum
2287
ExecInterpExprStillValid(ExprState *state, ExprContext *econtext, bool *isNull)
2288
0
{
2289
  /*
2290
   * First time through, check whether attribute matches Var.  Might not be
2291
   * ok anymore, due to schema changes.
2292
   */
2293
0
  CheckExprStillValid(state, econtext);
2294
2295
  /* skip the check during further executions */
2296
0
  state->evalfunc = (ExprStateEvalFunc) state->evalfunc_private;
2297
2298
  /* and actually execute */
2299
0
  return state->evalfunc(state, econtext, isNull);
2300
0
}
2301
2302
/*
2303
 * Check that an expression is still valid in the face of potential schema
2304
 * changes since the plan has been created.
2305
 */
2306
void
2307
CheckExprStillValid(ExprState *state, ExprContext *econtext)
2308
0
{
2309
0
  TupleTableSlot *innerslot;
2310
0
  TupleTableSlot *outerslot;
2311
0
  TupleTableSlot *scanslot;
2312
0
  TupleTableSlot *oldslot;
2313
0
  TupleTableSlot *newslot;
2314
2315
0
  innerslot = econtext->ecxt_innertuple;
2316
0
  outerslot = econtext->ecxt_outertuple;
2317
0
  scanslot = econtext->ecxt_scantuple;
2318
0
  oldslot = econtext->ecxt_oldtuple;
2319
0
  newslot = econtext->ecxt_newtuple;
2320
2321
0
  for (int i = 0; i < state->steps_len; i++)
2322
0
  {
2323
0
    ExprEvalStep *op = &state->steps[i];
2324
2325
0
    switch (ExecEvalStepOp(state, op))
2326
0
    {
2327
0
      case EEOP_INNER_VAR:
2328
0
        {
2329
0
          int     attnum = op->d.var.attnum;
2330
2331
0
          CheckVarSlotCompatibility(innerslot, attnum + 1, op->d.var.vartype);
2332
0
          break;
2333
0
        }
2334
2335
0
      case EEOP_OUTER_VAR:
2336
0
        {
2337
0
          int     attnum = op->d.var.attnum;
2338
2339
0
          CheckVarSlotCompatibility(outerslot, attnum + 1, op->d.var.vartype);
2340
0
          break;
2341
0
        }
2342
2343
0
      case EEOP_SCAN_VAR:
2344
0
        {
2345
0
          int     attnum = op->d.var.attnum;
2346
2347
0
          CheckVarSlotCompatibility(scanslot, attnum + 1, op->d.var.vartype);
2348
0
          break;
2349
0
        }
2350
2351
0
      case EEOP_OLD_VAR:
2352
0
        {
2353
0
          int     attnum = op->d.var.attnum;
2354
2355
0
          CheckVarSlotCompatibility(oldslot, attnum + 1, op->d.var.vartype);
2356
0
          break;
2357
0
        }
2358
2359
0
      case EEOP_NEW_VAR:
2360
0
        {
2361
0
          int     attnum = op->d.var.attnum;
2362
2363
0
          CheckVarSlotCompatibility(newslot, attnum + 1, op->d.var.vartype);
2364
0
          break;
2365
0
        }
2366
0
      default:
2367
0
        break;
2368
0
    }
2369
0
  }
2370
0
}
2371
2372
/*
2373
 * Check whether a user attribute in a slot can be referenced by a Var
2374
 * expression.  This should succeed unless there have been schema changes
2375
 * since the expression tree has been created.
2376
 */
2377
static void
2378
CheckVarSlotCompatibility(TupleTableSlot *slot, int attnum, Oid vartype)
2379
0
{
2380
  /*
2381
   * What we have to check for here is the possibility of an attribute
2382
   * having been dropped or changed in type since the plan tree was created.
2383
   * Ideally the plan will get invalidated and not re-used, but just in
2384
   * case, we keep these defenses.  Fortunately it's sufficient to check
2385
   * once on the first time through.
2386
   *
2387
   * Note: ideally we'd check typmod as well as typid, but that seems
2388
   * impractical at the moment: in many cases the tupdesc will have been
2389
   * generated by ExecTypeFromTL(), and that can't guarantee to generate an
2390
   * accurate typmod in all cases, because some expression node types don't
2391
   * carry typmod.  Fortunately, for precisely that reason, there should be
2392
   * no places with a critical dependency on the typmod of a value.
2393
   *
2394
   * System attributes don't require checking since their types never
2395
   * change.
2396
   */
2397
0
  if (attnum > 0)
2398
0
  {
2399
0
    TupleDesc slot_tupdesc = slot->tts_tupleDescriptor;
2400
0
    Form_pg_attribute attr;
2401
2402
0
    if (attnum > slot_tupdesc->natts) /* should never happen */
2403
0
      elog(ERROR, "attribute number %d exceeds number of columns %d",
2404
0
         attnum, slot_tupdesc->natts);
2405
2406
0
    attr = TupleDescAttr(slot_tupdesc, attnum - 1);
2407
2408
    /* Internal error: somebody forgot to expand it. */
2409
0
    if (attr->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL)
2410
0
      elog(ERROR, "unexpected virtual generated column reference");
2411
2412
0
    if (attr->attisdropped)
2413
0
      ereport(ERROR,
2414
0
          (errcode(ERRCODE_UNDEFINED_COLUMN),
2415
0
           errmsg("attribute %d of type %s has been dropped",
2416
0
              attnum, format_type_be(slot_tupdesc->tdtypeid))));
2417
2418
0
    if (vartype != attr->atttypid)
2419
0
      ereport(ERROR,
2420
0
          (errcode(ERRCODE_DATATYPE_MISMATCH),
2421
0
           errmsg("attribute %d of type %s has wrong type",
2422
0
              attnum, format_type_be(slot_tupdesc->tdtypeid)),
2423
0
           errdetail("Table has type %s, but query expects %s.",
2424
0
                 format_type_be(attr->atttypid),
2425
0
                 format_type_be(vartype))));
2426
0
  }
2427
0
}
2428
2429
/*
2430
 * Verify that the slot is compatible with a EEOP_*_FETCHSOME operation.
2431
 */
2432
static void
2433
CheckOpSlotCompatibility(ExprEvalStep *op, TupleTableSlot *slot)
2434
0
{
2435
#ifdef USE_ASSERT_CHECKING
2436
  /* there's nothing to check */
2437
  if (!op->d.fetch.fixed)
2438
    return;
2439
2440
  /*
2441
   * Should probably fixed at some point, but for now it's easier to allow
2442
   * buffer and heap tuples to be used interchangeably.
2443
   */
2444
  if (slot->tts_ops == &TTSOpsBufferHeapTuple &&
2445
    op->d.fetch.kind == &TTSOpsHeapTuple)
2446
    return;
2447
  if (slot->tts_ops == &TTSOpsHeapTuple &&
2448
    op->d.fetch.kind == &TTSOpsBufferHeapTuple)
2449
    return;
2450
2451
  /*
2452
   * At the moment we consider it OK if a virtual slot is used instead of a
2453
   * specific type of slot, as a virtual slot never needs to be deformed.
2454
   */
2455
  if (slot->tts_ops == &TTSOpsVirtual)
2456
    return;
2457
2458
  Assert(op->d.fetch.kind == slot->tts_ops);
2459
#endif
2460
0
}
2461
2462
/*
2463
 * get_cached_rowtype: utility function to lookup a rowtype tupdesc
2464
 *
2465
 * type_id, typmod: identity of the rowtype
2466
 * rowcache: space for caching identity info
2467
 *    (rowcache->cacheptr must be initialized to NULL)
2468
 * changed: if not NULL, *changed is set to true on any update
2469
 *
2470
 * The returned TupleDesc is not guaranteed pinned; caller must pin it
2471
 * to use it across any operation that might incur cache invalidation,
2472
 * including for example detoasting of input tuples.
2473
 * (The TupleDesc is always refcounted, so just use IncrTupleDescRefCount.)
2474
 *
2475
 * NOTE: because composite types can change contents, we must be prepared
2476
 * to re-do this during any node execution; cannot call just once during
2477
 * expression initialization.
2478
 */
2479
static TupleDesc
2480
get_cached_rowtype(Oid type_id, int32 typmod,
2481
           ExprEvalRowtypeCache *rowcache,
2482
           bool *changed)
2483
0
{
2484
0
  if (type_id != RECORDOID)
2485
0
  {
2486
    /*
2487
     * It's a named composite type, so use the regular typcache.  Do a
2488
     * lookup first time through, or if the composite type changed.  Note:
2489
     * "tupdesc_id == 0" may look redundant, but it protects against the
2490
     * admittedly-theoretical possibility that type_id was RECORDOID the
2491
     * last time through, so that the cacheptr isn't TypeCacheEntry *.
2492
     */
2493
0
    TypeCacheEntry *typentry = (TypeCacheEntry *) rowcache->cacheptr;
2494
2495
0
    if (unlikely(typentry == NULL ||
2496
0
           rowcache->tupdesc_id == 0 ||
2497
0
           typentry->tupDesc_identifier != rowcache->tupdesc_id))
2498
0
    {
2499
0
      typentry = lookup_type_cache(type_id, TYPECACHE_TUPDESC);
2500
0
      if (typentry->tupDesc == NULL)
2501
0
        ereport(ERROR,
2502
0
            (errcode(ERRCODE_WRONG_OBJECT_TYPE),
2503
0
             errmsg("type %s is not composite",
2504
0
                format_type_be(type_id))));
2505
0
      rowcache->cacheptr = typentry;
2506
0
      rowcache->tupdesc_id = typentry->tupDesc_identifier;
2507
0
      if (changed)
2508
0
        *changed = true;
2509
0
    }
2510
0
    return typentry->tupDesc;
2511
0
  }
2512
0
  else
2513
0
  {
2514
    /*
2515
     * A RECORD type, once registered, doesn't change for the life of the
2516
     * backend.  So we don't need a typcache entry as such, which is good
2517
     * because there isn't one.  It's possible that the caller is asking
2518
     * about a different type than before, though.
2519
     */
2520
0
    TupleDesc tupDesc = (TupleDesc) rowcache->cacheptr;
2521
2522
0
    if (unlikely(tupDesc == NULL ||
2523
0
           rowcache->tupdesc_id != 0 ||
2524
0
           type_id != tupDesc->tdtypeid ||
2525
0
           typmod != tupDesc->tdtypmod))
2526
0
    {
2527
0
      tupDesc = lookup_rowtype_tupdesc(type_id, typmod);
2528
      /* Drop pin acquired by lookup_rowtype_tupdesc */
2529
0
      ReleaseTupleDesc(tupDesc);
2530
0
      rowcache->cacheptr = tupDesc;
2531
0
      rowcache->tupdesc_id = 0; /* not a valid value for non-RECORD */
2532
0
      if (changed)
2533
0
        *changed = true;
2534
0
    }
2535
0
    return tupDesc;
2536
0
  }
2537
0
}
2538
2539
2540
/*
2541
 * Fast-path functions, for very simple expressions
2542
 */
2543
2544
/* implementation of ExecJust(Inner|Outer|Scan)Var */
2545
static pg_attribute_always_inline Datum
2546
ExecJustVarImpl(ExprState *state, TupleTableSlot *slot, bool *isnull)
2547
0
{
2548
0
  ExprEvalStep *op = &state->steps[1];
2549
0
  int     attnum = op->d.var.attnum + 1;
2550
2551
0
  CheckOpSlotCompatibility(&state->steps[0], slot);
2552
2553
  /*
2554
   * Since we use slot_getattr(), we don't need to implement the FETCHSOME
2555
   * step explicitly, and we also needn't Assert that the attnum is in range
2556
   * --- slot_getattr() will take care of any problems.
2557
   */
2558
0
  return slot_getattr(slot, attnum, isnull);
2559
0
}
2560
2561
/* Simple reference to inner Var */
2562
static Datum
2563
ExecJustInnerVar(ExprState *state, ExprContext *econtext, bool *isnull)
2564
0
{
2565
0
  return ExecJustVarImpl(state, econtext->ecxt_innertuple, isnull);
2566
0
}
2567
2568
/* Simple reference to outer Var */
2569
static Datum
2570
ExecJustOuterVar(ExprState *state, ExprContext *econtext, bool *isnull)
2571
0
{
2572
0
  return ExecJustVarImpl(state, econtext->ecxt_outertuple, isnull);
2573
0
}
2574
2575
/* Simple reference to scan Var */
2576
static Datum
2577
ExecJustScanVar(ExprState *state, ExprContext *econtext, bool *isnull)
2578
0
{
2579
0
  return ExecJustVarImpl(state, econtext->ecxt_scantuple, isnull);
2580
0
}
2581
2582
/* implementation of ExecJustAssign(Inner|Outer|Scan)Var */
2583
static pg_attribute_always_inline Datum
2584
ExecJustAssignVarImpl(ExprState *state, TupleTableSlot *inslot, bool *isnull)
2585
0
{
2586
0
  ExprEvalStep *op = &state->steps[1];
2587
0
  int     attnum = op->d.assign_var.attnum + 1;
2588
0
  int     resultnum = op->d.assign_var.resultnum;
2589
0
  TupleTableSlot *outslot = state->resultslot;
2590
2591
0
  CheckOpSlotCompatibility(&state->steps[0], inslot);
2592
2593
  /*
2594
   * We do not need CheckVarSlotCompatibility here; that was taken care of
2595
   * at compilation time.
2596
   *
2597
   * Since we use slot_getattr(), we don't need to implement the FETCHSOME
2598
   * step explicitly, and we also needn't Assert that the attnum is in range
2599
   * --- slot_getattr() will take care of any problems.  Nonetheless, check
2600
   * that resultnum is in range.
2601
   */
2602
0
  Assert(resultnum >= 0 && resultnum < outslot->tts_tupleDescriptor->natts);
2603
0
  outslot->tts_values[resultnum] =
2604
0
    slot_getattr(inslot, attnum, &outslot->tts_isnull[resultnum]);
2605
0
  return 0;
2606
0
}
2607
2608
/* Evaluate inner Var and assign to appropriate column of result tuple */
2609
static Datum
2610
ExecJustAssignInnerVar(ExprState *state, ExprContext *econtext, bool *isnull)
2611
0
{
2612
0
  return ExecJustAssignVarImpl(state, econtext->ecxt_innertuple, isnull);
2613
0
}
2614
2615
/* Evaluate outer Var and assign to appropriate column of result tuple */
2616
static Datum
2617
ExecJustAssignOuterVar(ExprState *state, ExprContext *econtext, bool *isnull)
2618
0
{
2619
0
  return ExecJustAssignVarImpl(state, econtext->ecxt_outertuple, isnull);
2620
0
}
2621
2622
/* Evaluate scan Var and assign to appropriate column of result tuple */
2623
static Datum
2624
ExecJustAssignScanVar(ExprState *state, ExprContext *econtext, bool *isnull)
2625
0
{
2626
0
  return ExecJustAssignVarImpl(state, econtext->ecxt_scantuple, isnull);
2627
0
}
2628
2629
/* Evaluate CASE_TESTVAL and apply a strict function to it */
2630
static Datum
2631
ExecJustApplyFuncToCase(ExprState *state, ExprContext *econtext, bool *isnull)
2632
0
{
2633
0
  ExprEvalStep *op = &state->steps[0];
2634
0
  FunctionCallInfo fcinfo;
2635
0
  NullableDatum *args;
2636
0
  int     nargs;
2637
0
  Datum   d;
2638
2639
  /*
2640
   * XXX with some redesign of the CaseTestExpr mechanism, maybe we could
2641
   * get rid of this data shuffling?
2642
   */
2643
0
  *op->resvalue = *op->d.casetest.value;
2644
0
  *op->resnull = *op->d.casetest.isnull;
2645
2646
0
  op++;
2647
2648
0
  nargs = op->d.func.nargs;
2649
0
  fcinfo = op->d.func.fcinfo_data;
2650
0
  args = fcinfo->args;
2651
2652
  /* strict function, so check for NULL args */
2653
0
  for (int argno = 0; argno < nargs; argno++)
2654
0
  {
2655
0
    if (args[argno].isnull)
2656
0
    {
2657
0
      *isnull = true;
2658
0
      return (Datum) 0;
2659
0
    }
2660
0
  }
2661
0
  fcinfo->isnull = false;
2662
0
  d = op->d.func.fn_addr(fcinfo);
2663
0
  *isnull = fcinfo->isnull;
2664
0
  return d;
2665
0
}
2666
2667
/* Simple Const expression */
2668
static Datum
2669
ExecJustConst(ExprState *state, ExprContext *econtext, bool *isnull)
2670
0
{
2671
0
  ExprEvalStep *op = &state->steps[0];
2672
2673
0
  *isnull = op->d.constval.isnull;
2674
0
  return op->d.constval.value;
2675
0
}
2676
2677
/* implementation of ExecJust(Inner|Outer|Scan)VarVirt */
2678
static pg_attribute_always_inline Datum
2679
ExecJustVarVirtImpl(ExprState *state, TupleTableSlot *slot, bool *isnull)
2680
0
{
2681
0
  ExprEvalStep *op = &state->steps[0];
2682
0
  int     attnum = op->d.var.attnum;
2683
2684
  /*
2685
   * As it is guaranteed that a virtual slot is used, there never is a need
2686
   * to perform tuple deforming (nor would it be possible). Therefore
2687
   * execExpr.c has not emitted an EEOP_*_FETCHSOME step. Verify, as much as
2688
   * possible, that that determination was accurate.
2689
   */
2690
0
  Assert(TTS_IS_VIRTUAL(slot));
2691
0
  Assert(TTS_FIXED(slot));
2692
0
  Assert(attnum >= 0 && attnum < slot->tts_nvalid);
2693
2694
0
  *isnull = slot->tts_isnull[attnum];
2695
2696
0
  return slot->tts_values[attnum];
2697
0
}
2698
2699
/* Like ExecJustInnerVar, optimized for virtual slots */
2700
static Datum
2701
ExecJustInnerVarVirt(ExprState *state, ExprContext *econtext, bool *isnull)
2702
0
{
2703
0
  return ExecJustVarVirtImpl(state, econtext->ecxt_innertuple, isnull);
2704
0
}
2705
2706
/* Like ExecJustOuterVar, optimized for virtual slots */
2707
static Datum
2708
ExecJustOuterVarVirt(ExprState *state, ExprContext *econtext, bool *isnull)
2709
0
{
2710
0
  return ExecJustVarVirtImpl(state, econtext->ecxt_outertuple, isnull);
2711
0
}
2712
2713
/* Like ExecJustScanVar, optimized for virtual slots */
2714
static Datum
2715
ExecJustScanVarVirt(ExprState *state, ExprContext *econtext, bool *isnull)
2716
0
{
2717
0
  return ExecJustVarVirtImpl(state, econtext->ecxt_scantuple, isnull);
2718
0
}
2719
2720
/* implementation of ExecJustAssign(Inner|Outer|Scan)VarVirt */
2721
static pg_attribute_always_inline Datum
2722
ExecJustAssignVarVirtImpl(ExprState *state, TupleTableSlot *inslot, bool *isnull)
2723
0
{
2724
0
  ExprEvalStep *op = &state->steps[0];
2725
0
  int     attnum = op->d.assign_var.attnum;
2726
0
  int     resultnum = op->d.assign_var.resultnum;
2727
0
  TupleTableSlot *outslot = state->resultslot;
2728
2729
  /* see ExecJustVarVirtImpl for comments */
2730
2731
0
  Assert(TTS_IS_VIRTUAL(inslot));
2732
0
  Assert(TTS_FIXED(inslot));
2733
0
  Assert(attnum >= 0 && attnum < inslot->tts_nvalid);
2734
0
  Assert(resultnum >= 0 && resultnum < outslot->tts_tupleDescriptor->natts);
2735
2736
0
  outslot->tts_values[resultnum] = inslot->tts_values[attnum];
2737
0
  outslot->tts_isnull[resultnum] = inslot->tts_isnull[attnum];
2738
2739
0
  return 0;
2740
0
}
2741
2742
/* Like ExecJustAssignInnerVar, optimized for virtual slots */
2743
static Datum
2744
ExecJustAssignInnerVarVirt(ExprState *state, ExprContext *econtext, bool *isnull)
2745
0
{
2746
0
  return ExecJustAssignVarVirtImpl(state, econtext->ecxt_innertuple, isnull);
2747
0
}
2748
2749
/* Like ExecJustAssignOuterVar, optimized for virtual slots */
2750
static Datum
2751
ExecJustAssignOuterVarVirt(ExprState *state, ExprContext *econtext, bool *isnull)
2752
0
{
2753
0
  return ExecJustAssignVarVirtImpl(state, econtext->ecxt_outertuple, isnull);
2754
0
}
2755
2756
/* Like ExecJustAssignScanVar, optimized for virtual slots */
2757
static Datum
2758
ExecJustAssignScanVarVirt(ExprState *state, ExprContext *econtext, bool *isnull)
2759
0
{
2760
0
  return ExecJustAssignVarVirtImpl(state, econtext->ecxt_scantuple, isnull);
2761
0
}
2762
2763
/*
2764
 * implementation for hashing an inner Var, seeding with an initial value.
2765
 */
2766
static Datum
2767
ExecJustHashInnerVarWithIV(ExprState *state, ExprContext *econtext,
2768
               bool *isnull)
2769
0
{
2770
0
  ExprEvalStep *fetchop = &state->steps[0];
2771
0
  ExprEvalStep *setivop = &state->steps[1];
2772
0
  ExprEvalStep *innervar = &state->steps[2];
2773
0
  ExprEvalStep *hashop = &state->steps[3];
2774
0
  FunctionCallInfo fcinfo = hashop->d.hashdatum.fcinfo_data;
2775
0
  int     attnum = innervar->d.var.attnum;
2776
0
  uint32    hashkey;
2777
2778
0
  CheckOpSlotCompatibility(fetchop, econtext->ecxt_innertuple);
2779
0
  slot_getsomeattrs(econtext->ecxt_innertuple, fetchop->d.fetch.last_var);
2780
2781
0
  fcinfo->args[0].value = econtext->ecxt_innertuple->tts_values[attnum];
2782
0
  fcinfo->args[0].isnull = econtext->ecxt_innertuple->tts_isnull[attnum];
2783
2784
0
  hashkey = DatumGetUInt32(setivop->d.hashdatum_initvalue.init_value);
2785
0
  hashkey = pg_rotate_left32(hashkey, 1);
2786
2787
0
  if (!fcinfo->args[0].isnull)
2788
0
  {
2789
0
    uint32    hashvalue;
2790
2791
0
    hashvalue = DatumGetUInt32(hashop->d.hashdatum.fn_addr(fcinfo));
2792
0
    hashkey = hashkey ^ hashvalue;
2793
0
  }
2794
2795
0
  *isnull = false;
2796
0
  return UInt32GetDatum(hashkey);
2797
0
}
2798
2799
/* implementation of ExecJustHash(Inner|Outer)Var */
2800
static pg_attribute_always_inline Datum
2801
ExecJustHashVarImpl(ExprState *state, TupleTableSlot *slot, bool *isnull)
2802
0
{
2803
0
  ExprEvalStep *fetchop = &state->steps[0];
2804
0
  ExprEvalStep *var = &state->steps[1];
2805
0
  ExprEvalStep *hashop = &state->steps[2];
2806
0
  FunctionCallInfo fcinfo = hashop->d.hashdatum.fcinfo_data;
2807
0
  int     attnum = var->d.var.attnum;
2808
2809
0
  CheckOpSlotCompatibility(fetchop, slot);
2810
0
  slot_getsomeattrs(slot, fetchop->d.fetch.last_var);
2811
2812
0
  fcinfo->args[0].value = slot->tts_values[attnum];
2813
0
  fcinfo->args[0].isnull = slot->tts_isnull[attnum];
2814
2815
0
  *isnull = false;
2816
2817
0
  if (!fcinfo->args[0].isnull)
2818
0
    return hashop->d.hashdatum.fn_addr(fcinfo);
2819
0
  else
2820
0
    return (Datum) 0;
2821
0
}
2822
2823
/* implementation for hashing an outer Var */
2824
static Datum
2825
ExecJustHashOuterVar(ExprState *state, ExprContext *econtext, bool *isnull)
2826
0
{
2827
0
  return ExecJustHashVarImpl(state, econtext->ecxt_outertuple, isnull);
2828
0
}
2829
2830
/* implementation for hashing an inner Var */
2831
static Datum
2832
ExecJustHashInnerVar(ExprState *state, ExprContext *econtext, bool *isnull)
2833
0
{
2834
0
  return ExecJustHashVarImpl(state, econtext->ecxt_innertuple, isnull);
2835
0
}
2836
2837
/* implementation of ExecJustHash(Inner|Outer)VarVirt */
2838
static pg_attribute_always_inline Datum
2839
ExecJustHashVarVirtImpl(ExprState *state, TupleTableSlot *slot, bool *isnull)
2840
0
{
2841
0
  ExprEvalStep *var = &state->steps[0];
2842
0
  ExprEvalStep *hashop = &state->steps[1];
2843
0
  FunctionCallInfo fcinfo = hashop->d.hashdatum.fcinfo_data;
2844
0
  int     attnum = var->d.var.attnum;
2845
2846
0
  fcinfo->args[0].value = slot->tts_values[attnum];
2847
0
  fcinfo->args[0].isnull = slot->tts_isnull[attnum];
2848
2849
0
  *isnull = false;
2850
2851
0
  if (!fcinfo->args[0].isnull)
2852
0
    return hashop->d.hashdatum.fn_addr(fcinfo);
2853
0
  else
2854
0
    return (Datum) 0;
2855
0
}
2856
2857
/* Like ExecJustHashInnerVar, optimized for virtual slots */
2858
static Datum
2859
ExecJustHashInnerVarVirt(ExprState *state, ExprContext *econtext,
2860
             bool *isnull)
2861
0
{
2862
0
  return ExecJustHashVarVirtImpl(state, econtext->ecxt_innertuple, isnull);
2863
0
}
2864
2865
/* Like ExecJustHashOuterVar, optimized for virtual slots */
2866
static Datum
2867
ExecJustHashOuterVarVirt(ExprState *state, ExprContext *econtext,
2868
             bool *isnull)
2869
0
{
2870
0
  return ExecJustHashVarVirtImpl(state, econtext->ecxt_outertuple, isnull);
2871
0
}
2872
2873
/*
2874
 * implementation for hashing an outer Var.  Returns NULL on NULL input.
2875
 */
2876
static Datum
2877
ExecJustHashOuterVarStrict(ExprState *state, ExprContext *econtext,
2878
               bool *isnull)
2879
0
{
2880
0
  ExprEvalStep *fetchop = &state->steps[0];
2881
0
  ExprEvalStep *var = &state->steps[1];
2882
0
  ExprEvalStep *hashop = &state->steps[2];
2883
0
  FunctionCallInfo fcinfo = hashop->d.hashdatum.fcinfo_data;
2884
0
  int     attnum = var->d.var.attnum;
2885
2886
0
  CheckOpSlotCompatibility(fetchop, econtext->ecxt_outertuple);
2887
0
  slot_getsomeattrs(econtext->ecxt_outertuple, fetchop->d.fetch.last_var);
2888
2889
0
  fcinfo->args[0].value = econtext->ecxt_outertuple->tts_values[attnum];
2890
0
  fcinfo->args[0].isnull = econtext->ecxt_outertuple->tts_isnull[attnum];
2891
2892
0
  if (!fcinfo->args[0].isnull)
2893
0
  {
2894
0
    *isnull = false;
2895
0
    return hashop->d.hashdatum.fn_addr(fcinfo);
2896
0
  }
2897
0
  else
2898
0
  {
2899
    /* return NULL on NULL input */
2900
0
    *isnull = true;
2901
0
    return (Datum) 0;
2902
0
  }
2903
0
}
2904
2905
#if defined(EEO_USE_COMPUTED_GOTO)
2906
/*
2907
 * Comparator used when building address->opcode lookup table for
2908
 * ExecEvalStepOp() in the threaded dispatch case.
2909
 */
2910
static int
2911
dispatch_compare_ptr(const void *a, const void *b)
2912
0
{
2913
0
  const ExprEvalOpLookup *la = (const ExprEvalOpLookup *) a;
2914
0
  const ExprEvalOpLookup *lb = (const ExprEvalOpLookup *) b;
2915
2916
0
  if (la->opcode < lb->opcode)
2917
0
    return -1;
2918
0
  else if (la->opcode > lb->opcode)
2919
0
    return 1;
2920
0
  return 0;
2921
0
}
2922
#endif
2923
2924
/*
2925
 * Do one-time initialization of interpretation machinery.
2926
 */
2927
static void
2928
ExecInitInterpreter(void)
2929
0
{
2930
0
#if defined(EEO_USE_COMPUTED_GOTO)
2931
  /* Set up externally-visible pointer to dispatch table */
2932
0
  if (dispatch_table == NULL)
2933
0
  {
2934
0
    dispatch_table = (const void **)
2935
0
      DatumGetPointer(ExecInterpExpr(NULL, NULL, NULL));
2936
2937
    /* build reverse lookup table */
2938
0
    for (int i = 0; i < EEOP_LAST; i++)
2939
0
    {
2940
0
      reverse_dispatch_table[i].opcode = dispatch_table[i];
2941
0
      reverse_dispatch_table[i].op = (ExprEvalOp) i;
2942
0
    }
2943
2944
    /* make it bsearch()able */
2945
0
    qsort(reverse_dispatch_table,
2946
0
        EEOP_LAST /* nmembers */ ,
2947
0
        sizeof(ExprEvalOpLookup),
2948
0
        dispatch_compare_ptr);
2949
0
  }
2950
0
#endif
2951
0
}
2952
2953
/*
2954
 * Function to return the opcode of an expression step.
2955
 *
2956
 * When direct-threading is in use, ExprState->opcode isn't easily
2957
 * decipherable. This function returns the appropriate enum member.
2958
 */
2959
ExprEvalOp
2960
ExecEvalStepOp(ExprState *state, ExprEvalStep *op)
2961
0
{
2962
0
#if defined(EEO_USE_COMPUTED_GOTO)
2963
0
  if (state->flags & EEO_FLAG_DIRECT_THREADED)
2964
0
  {
2965
0
    ExprEvalOpLookup key;
2966
0
    ExprEvalOpLookup *res;
2967
2968
0
    key.opcode = (void *) op->opcode;
2969
0
    res = bsearch(&key,
2970
0
            reverse_dispatch_table,
2971
0
            EEOP_LAST /* nmembers */ ,
2972
0
            sizeof(ExprEvalOpLookup),
2973
0
            dispatch_compare_ptr);
2974
0
    Assert(res);      /* unknown ops shouldn't get looked up */
2975
0
    return res->op;
2976
0
  }
2977
0
#endif
2978
0
  return (ExprEvalOp) op->opcode;
2979
0
}
2980
2981
2982
/*
2983
 * Out-of-line helper functions for complex instructions.
2984
 */
2985
2986
/*
2987
 * Evaluate EEOP_FUNCEXPR_FUSAGE
2988
 */
2989
void
2990
ExecEvalFuncExprFusage(ExprState *state, ExprEvalStep *op,
2991
             ExprContext *econtext)
2992
0
{
2993
0
  FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
2994
0
  PgStat_FunctionCallUsage fcusage;
2995
0
  Datum   d;
2996
2997
0
  pgstat_init_function_usage(fcinfo, &fcusage);
2998
2999
0
  fcinfo->isnull = false;
3000
0
  d = op->d.func.fn_addr(fcinfo);
3001
0
  *op->resvalue = d;
3002
0
  *op->resnull = fcinfo->isnull;
3003
3004
0
  pgstat_end_function_usage(&fcusage, true);
3005
0
}
3006
3007
/*
3008
 * Evaluate EEOP_FUNCEXPR_STRICT_FUSAGE
3009
 */
3010
void
3011
ExecEvalFuncExprStrictFusage(ExprState *state, ExprEvalStep *op,
3012
               ExprContext *econtext)
3013
0
{
3014
3015
0
  FunctionCallInfo fcinfo = op->d.func.fcinfo_data;
3016
0
  PgStat_FunctionCallUsage fcusage;
3017
0
  NullableDatum *args = fcinfo->args;
3018
0
  int     nargs = op->d.func.nargs;
3019
0
  Datum   d;
3020
3021
  /* strict function, so check for NULL args */
3022
0
  for (int argno = 0; argno < nargs; argno++)
3023
0
  {
3024
0
    if (args[argno].isnull)
3025
0
    {
3026
0
      *op->resnull = true;
3027
0
      return;
3028
0
    }
3029
0
  }
3030
3031
0
  pgstat_init_function_usage(fcinfo, &fcusage);
3032
3033
0
  fcinfo->isnull = false;
3034
0
  d = op->d.func.fn_addr(fcinfo);
3035
0
  *op->resvalue = d;
3036
0
  *op->resnull = fcinfo->isnull;
3037
3038
0
  pgstat_end_function_usage(&fcusage, true);
3039
0
}
3040
3041
/*
3042
 * Evaluate a PARAM_EXEC parameter.
3043
 *
3044
 * PARAM_EXEC params (internal executor parameters) are stored in the
3045
 * ecxt_param_exec_vals array, and can be accessed by array index.
3046
 */
3047
void
3048
ExecEvalParamExec(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
3049
0
{
3050
0
  ParamExecData *prm;
3051
3052
0
  prm = &(econtext->ecxt_param_exec_vals[op->d.param.paramid]);
3053
0
  if (unlikely(prm->execPlan != NULL))
3054
0
  {
3055
    /* Parameter not evaluated yet, so go do it */
3056
0
    ExecSetParamPlan(prm->execPlan, econtext);
3057
    /* ExecSetParamPlan should have processed this param... */
3058
0
    Assert(prm->execPlan == NULL);
3059
0
  }
3060
0
  *op->resvalue = prm->value;
3061
0
  *op->resnull = prm->isnull;
3062
0
}
3063
3064
/*
3065
 * Evaluate a PARAM_EXTERN parameter.
3066
 *
3067
 * PARAM_EXTERN parameters must be sought in ecxt_param_list_info.
3068
 */
3069
void
3070
ExecEvalParamExtern(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
3071
0
{
3072
0
  ParamListInfo paramInfo = econtext->ecxt_param_list_info;
3073
0
  int     paramId = op->d.param.paramid;
3074
3075
0
  if (likely(paramInfo &&
3076
0
         paramId > 0 && paramId <= paramInfo->numParams))
3077
0
  {
3078
0
    ParamExternData *prm;
3079
0
    ParamExternData prmdata;
3080
3081
    /* give hook a chance in case parameter is dynamic */
3082
0
    if (paramInfo->paramFetch != NULL)
3083
0
      prm = paramInfo->paramFetch(paramInfo, paramId, false, &prmdata);
3084
0
    else
3085
0
      prm = &paramInfo->params[paramId - 1];
3086
3087
0
    if (likely(OidIsValid(prm->ptype)))
3088
0
    {
3089
      /* safety check in case hook did something unexpected */
3090
0
      if (unlikely(prm->ptype != op->d.param.paramtype))
3091
0
        ereport(ERROR,
3092
0
            (errcode(ERRCODE_DATATYPE_MISMATCH),
3093
0
             errmsg("type of parameter %d (%s) does not match that when preparing the plan (%s)",
3094
0
                paramId,
3095
0
                format_type_be(prm->ptype),
3096
0
                format_type_be(op->d.param.paramtype))));
3097
0
      *op->resvalue = prm->value;
3098
0
      *op->resnull = prm->isnull;
3099
0
      return;
3100
0
    }
3101
0
  }
3102
3103
0
  ereport(ERROR,
3104
0
      (errcode(ERRCODE_UNDEFINED_OBJECT),
3105
0
       errmsg("no value found for parameter %d", paramId)));
3106
0
}
3107
3108
/*
3109
 * Set value of a param (currently always PARAM_EXEC) from
3110
 * state->res{value,null}.
3111
 */
3112
void
3113
ExecEvalParamSet(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
3114
0
{
3115
0
  ParamExecData *prm;
3116
3117
0
  prm = &(econtext->ecxt_param_exec_vals[op->d.param.paramid]);
3118
3119
  /* Shouldn't have a pending evaluation anymore */
3120
0
  Assert(prm->execPlan == NULL);
3121
3122
0
  prm->value = state->resvalue;
3123
0
  prm->isnull = state->resnull;
3124
0
}
3125
3126
/*
3127
 * Evaluate a CoerceViaIO node in soft-error mode.
3128
 *
3129
 * The source value is in op's result variable.
3130
 *
3131
 * Note: This implements EEOP_IOCOERCE_SAFE. If you change anything here,
3132
 * also look at the inline code for EEOP_IOCOERCE.
3133
 */
3134
void
3135
ExecEvalCoerceViaIOSafe(ExprState *state, ExprEvalStep *op)
3136
0
{
3137
0
  char     *str;
3138
3139
  /* call output function (similar to OutputFunctionCall) */
3140
0
  if (*op->resnull)
3141
0
  {
3142
    /* output functions are not called on nulls */
3143
0
    str = NULL;
3144
0
  }
3145
0
  else
3146
0
  {
3147
0
    FunctionCallInfo fcinfo_out;
3148
3149
0
    fcinfo_out = op->d.iocoerce.fcinfo_data_out;
3150
0
    fcinfo_out->args[0].value = *op->resvalue;
3151
0
    fcinfo_out->args[0].isnull = false;
3152
3153
0
    fcinfo_out->isnull = false;
3154
0
    str = DatumGetCString(FunctionCallInvoke(fcinfo_out));
3155
3156
    /* OutputFunctionCall assumes result isn't null */
3157
0
    Assert(!fcinfo_out->isnull);
3158
0
  }
3159
3160
  /* call input function (similar to InputFunctionCallSafe) */
3161
0
  if (!op->d.iocoerce.finfo_in->fn_strict || str != NULL)
3162
0
  {
3163
0
    FunctionCallInfo fcinfo_in;
3164
3165
0
    fcinfo_in = op->d.iocoerce.fcinfo_data_in;
3166
0
    fcinfo_in->args[0].value = PointerGetDatum(str);
3167
0
    fcinfo_in->args[0].isnull = *op->resnull;
3168
    /* second and third arguments are already set up */
3169
3170
    /* ErrorSaveContext must be present. */
3171
0
    Assert(IsA(fcinfo_in->context, ErrorSaveContext));
3172
3173
0
    fcinfo_in->isnull = false;
3174
0
    *op->resvalue = FunctionCallInvoke(fcinfo_in);
3175
3176
0
    if (SOFT_ERROR_OCCURRED(fcinfo_in->context))
3177
0
    {
3178
0
      *op->resnull = true;
3179
0
      *op->resvalue = (Datum) 0;
3180
0
      return;
3181
0
    }
3182
3183
    /* Should get null result if and only if str is NULL */
3184
0
    if (str == NULL)
3185
0
      Assert(*op->resnull);
3186
0
    else
3187
0
      Assert(!*op->resnull);
3188
0
  }
3189
0
}
3190
3191
/*
3192
 * Evaluate a SQLValueFunction expression.
3193
 */
3194
void
3195
ExecEvalSQLValueFunction(ExprState *state, ExprEvalStep *op)
3196
0
{
3197
0
  LOCAL_FCINFO(fcinfo, 0);
3198
0
  SQLValueFunction *svf = op->d.sqlvaluefunction.svf;
3199
3200
0
  *op->resnull = false;
3201
3202
  /*
3203
   * Note: current_schema() can return NULL.  current_user() etc currently
3204
   * cannot, but might as well code those cases the same way for safety.
3205
   */
3206
0
  switch (svf->op)
3207
0
  {
3208
0
    case SVFOP_CURRENT_DATE:
3209
0
      *op->resvalue = DateADTGetDatum(GetSQLCurrentDate());
3210
0
      break;
3211
0
    case SVFOP_CURRENT_TIME:
3212
0
    case SVFOP_CURRENT_TIME_N:
3213
0
      *op->resvalue = TimeTzADTPGetDatum(GetSQLCurrentTime(svf->typmod));
3214
0
      break;
3215
0
    case SVFOP_CURRENT_TIMESTAMP:
3216
0
    case SVFOP_CURRENT_TIMESTAMP_N:
3217
0
      *op->resvalue = TimestampTzGetDatum(GetSQLCurrentTimestamp(svf->typmod));
3218
0
      break;
3219
0
    case SVFOP_LOCALTIME:
3220
0
    case SVFOP_LOCALTIME_N:
3221
0
      *op->resvalue = TimeADTGetDatum(GetSQLLocalTime(svf->typmod));
3222
0
      break;
3223
0
    case SVFOP_LOCALTIMESTAMP:
3224
0
    case SVFOP_LOCALTIMESTAMP_N:
3225
0
      *op->resvalue = TimestampGetDatum(GetSQLLocalTimestamp(svf->typmod));
3226
0
      break;
3227
0
    case SVFOP_CURRENT_ROLE:
3228
0
    case SVFOP_CURRENT_USER:
3229
0
    case SVFOP_USER:
3230
0
      InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL);
3231
0
      *op->resvalue = current_user(fcinfo);
3232
0
      *op->resnull = fcinfo->isnull;
3233
0
      break;
3234
0
    case SVFOP_SESSION_USER:
3235
0
      InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL);
3236
0
      *op->resvalue = session_user(fcinfo);
3237
0
      *op->resnull = fcinfo->isnull;
3238
0
      break;
3239
0
    case SVFOP_CURRENT_CATALOG:
3240
0
      InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL);
3241
0
      *op->resvalue = current_database(fcinfo);
3242
0
      *op->resnull = fcinfo->isnull;
3243
0
      break;
3244
0
    case SVFOP_CURRENT_SCHEMA:
3245
0
      InitFunctionCallInfoData(*fcinfo, NULL, 0, InvalidOid, NULL, NULL);
3246
0
      *op->resvalue = current_schema(fcinfo);
3247
0
      *op->resnull = fcinfo->isnull;
3248
0
      break;
3249
0
  }
3250
0
}
3251
3252
/*
3253
 * Raise error if a CURRENT OF expression is evaluated.
3254
 *
3255
 * The planner should convert CURRENT OF into a TidScan qualification, or some
3256
 * other special handling in a ForeignScan node.  So we have to be able to do
3257
 * ExecInitExpr on a CurrentOfExpr, but we shouldn't ever actually execute it.
3258
 * If we get here, we suppose we must be dealing with CURRENT OF on a foreign
3259
 * table whose FDW doesn't handle it, and complain accordingly.
3260
 */
3261
void
3262
ExecEvalCurrentOfExpr(ExprState *state, ExprEvalStep *op)
3263
0
{
3264
0
  ereport(ERROR,
3265
0
      (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3266
0
       errmsg("WHERE CURRENT OF is not supported for this table type")));
3267
0
}
3268
3269
/*
3270
 * Evaluate NextValueExpr.
3271
 */
3272
void
3273
ExecEvalNextValueExpr(ExprState *state, ExprEvalStep *op)
3274
0
{
3275
0
  int64   newval = nextval_internal(op->d.nextvalueexpr.seqid, false);
3276
3277
0
  switch (op->d.nextvalueexpr.seqtypid)
3278
0
  {
3279
0
    case INT2OID:
3280
0
      *op->resvalue = Int16GetDatum((int16) newval);
3281
0
      break;
3282
0
    case INT4OID:
3283
0
      *op->resvalue = Int32GetDatum((int32) newval);
3284
0
      break;
3285
0
    case INT8OID:
3286
0
      *op->resvalue = Int64GetDatum((int64) newval);
3287
0
      break;
3288
0
    default:
3289
0
      elog(ERROR, "unsupported sequence type %u",
3290
0
         op->d.nextvalueexpr.seqtypid);
3291
0
  }
3292
0
  *op->resnull = false;
3293
0
}
3294
3295
/*
3296
 * Evaluate NullTest / IS NULL for rows.
3297
 */
3298
void
3299
ExecEvalRowNull(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
3300
0
{
3301
0
  ExecEvalRowNullInt(state, op, econtext, true);
3302
0
}
3303
3304
/*
3305
 * Evaluate NullTest / IS NOT NULL for rows.
3306
 */
3307
void
3308
ExecEvalRowNotNull(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
3309
0
{
3310
0
  ExecEvalRowNullInt(state, op, econtext, false);
3311
0
}
3312
3313
/* Common code for IS [NOT] NULL on a row value */
3314
static void
3315
ExecEvalRowNullInt(ExprState *state, ExprEvalStep *op,
3316
           ExprContext *econtext, bool checkisnull)
3317
0
{
3318
0
  Datum   value = *op->resvalue;
3319
0
  bool    isnull = *op->resnull;
3320
0
  HeapTupleHeader tuple;
3321
0
  Oid     tupType;
3322
0
  int32   tupTypmod;
3323
0
  TupleDesc tupDesc;
3324
0
  HeapTupleData tmptup;
3325
3326
0
  *op->resnull = false;
3327
3328
  /* NULL row variables are treated just as NULL scalar columns */
3329
0
  if (isnull)
3330
0
  {
3331
0
    *op->resvalue = BoolGetDatum(checkisnull);
3332
0
    return;
3333
0
  }
3334
3335
  /*
3336
   * The SQL standard defines IS [NOT] NULL for a non-null rowtype argument
3337
   * as:
3338
   *
3339
   * "R IS NULL" is true if every field is the null value.
3340
   *
3341
   * "R IS NOT NULL" is true if no field is the null value.
3342
   *
3343
   * This definition is (apparently intentionally) not recursive; so our
3344
   * tests on the fields are primitive attisnull tests, not recursive checks
3345
   * to see if they are all-nulls or no-nulls rowtypes.
3346
   *
3347
   * The standard does not consider the possibility of zero-field rows, but
3348
   * here we consider them to vacuously satisfy both predicates.
3349
   */
3350
3351
0
  tuple = DatumGetHeapTupleHeader(value);
3352
3353
0
  tupType = HeapTupleHeaderGetTypeId(tuple);
3354
0
  tupTypmod = HeapTupleHeaderGetTypMod(tuple);
3355
3356
  /* Lookup tupdesc if first time through or if type changes */
3357
0
  tupDesc = get_cached_rowtype(tupType, tupTypmod,
3358
0
                 &op->d.nulltest_row.rowcache, NULL);
3359
3360
  /*
3361
   * heap_attisnull needs a HeapTuple not a bare HeapTupleHeader.
3362
   */
3363
0
  tmptup.t_len = HeapTupleHeaderGetDatumLength(tuple);
3364
0
  tmptup.t_data = tuple;
3365
3366
0
  for (int att = 1; att <= tupDesc->natts; att++)
3367
0
  {
3368
    /* ignore dropped columns */
3369
0
    if (TupleDescCompactAttr(tupDesc, att - 1)->attisdropped)
3370
0
      continue;
3371
0
    if (heap_attisnull(&tmptup, att, tupDesc))
3372
0
    {
3373
      /* null field disproves IS NOT NULL */
3374
0
      if (!checkisnull)
3375
0
      {
3376
0
        *op->resvalue = BoolGetDatum(false);
3377
0
        return;
3378
0
      }
3379
0
    }
3380
0
    else
3381
0
    {
3382
      /* non-null field disproves IS NULL */
3383
0
      if (checkisnull)
3384
0
      {
3385
0
        *op->resvalue = BoolGetDatum(false);
3386
0
        return;
3387
0
      }
3388
0
    }
3389
0
  }
3390
3391
0
  *op->resvalue = BoolGetDatum(true);
3392
0
}
3393
3394
/*
3395
 * Evaluate an ARRAY[] expression.
3396
 *
3397
 * The individual array elements (or subarrays) have already been evaluated
3398
 * into op->d.arrayexpr.elemvalues[]/elemnulls[].
3399
 */
3400
void
3401
ExecEvalArrayExpr(ExprState *state, ExprEvalStep *op)
3402
0
{
3403
0
  ArrayType  *result;
3404
0
  Oid     element_type = op->d.arrayexpr.elemtype;
3405
0
  int     nelems = op->d.arrayexpr.nelems;
3406
0
  int     ndims = 0;
3407
0
  int     dims[MAXDIM];
3408
0
  int     lbs[MAXDIM];
3409
3410
  /* Set non-null as default */
3411
0
  *op->resnull = false;
3412
3413
0
  if (!op->d.arrayexpr.multidims)
3414
0
  {
3415
    /* Elements are presumably of scalar type */
3416
0
    Datum    *dvalues = op->d.arrayexpr.elemvalues;
3417
0
    bool     *dnulls = op->d.arrayexpr.elemnulls;
3418
3419
    /* setup for 1-D array of the given length */
3420
0
    ndims = 1;
3421
0
    dims[0] = nelems;
3422
0
    lbs[0] = 1;
3423
3424
0
    result = construct_md_array(dvalues, dnulls, ndims, dims, lbs,
3425
0
                  element_type,
3426
0
                  op->d.arrayexpr.elemlength,
3427
0
                  op->d.arrayexpr.elembyval,
3428
0
                  op->d.arrayexpr.elemalign);
3429
0
  }
3430
0
  else
3431
0
  {
3432
    /* Must be nested array expressions */
3433
0
    int     nbytes = 0;
3434
0
    int     nitems;
3435
0
    int     outer_nelems = 0;
3436
0
    int     elem_ndims = 0;
3437
0
    int      *elem_dims = NULL;
3438
0
    int      *elem_lbs = NULL;
3439
0
    bool    firstone = true;
3440
0
    bool    havenulls = false;
3441
0
    bool    haveempty = false;
3442
0
    char    **subdata;
3443
0
    bits8   **subbitmaps;
3444
0
    int      *subbytes;
3445
0
    int      *subnitems;
3446
0
    int32   dataoffset;
3447
0
    char     *dat;
3448
0
    int     iitem;
3449
3450
0
    subdata = (char **) palloc(nelems * sizeof(char *));
3451
0
    subbitmaps = (bits8 **) palloc(nelems * sizeof(bits8 *));
3452
0
    subbytes = (int *) palloc(nelems * sizeof(int));
3453
0
    subnitems = (int *) palloc(nelems * sizeof(int));
3454
3455
    /* loop through and get data area from each element */
3456
0
    for (int elemoff = 0; elemoff < nelems; elemoff++)
3457
0
    {
3458
0
      Datum   arraydatum;
3459
0
      bool    eisnull;
3460
0
      ArrayType  *array;
3461
0
      int     this_ndims;
3462
3463
0
      arraydatum = op->d.arrayexpr.elemvalues[elemoff];
3464
0
      eisnull = op->d.arrayexpr.elemnulls[elemoff];
3465
3466
      /* temporarily ignore null subarrays */
3467
0
      if (eisnull)
3468
0
      {
3469
0
        haveempty = true;
3470
0
        continue;
3471
0
      }
3472
3473
0
      array = DatumGetArrayTypeP(arraydatum);
3474
3475
      /* run-time double-check on element type */
3476
0
      if (element_type != ARR_ELEMTYPE(array))
3477
0
        ereport(ERROR,
3478
0
            (errcode(ERRCODE_DATATYPE_MISMATCH),
3479
0
             errmsg("cannot merge incompatible arrays"),
3480
0
             errdetail("Array with element type %s cannot be "
3481
0
                   "included in ARRAY construct with element type %s.",
3482
0
                   format_type_be(ARR_ELEMTYPE(array)),
3483
0
                   format_type_be(element_type))));
3484
3485
0
      this_ndims = ARR_NDIM(array);
3486
      /* temporarily ignore zero-dimensional subarrays */
3487
0
      if (this_ndims <= 0)
3488
0
      {
3489
0
        haveempty = true;
3490
0
        continue;
3491
0
      }
3492
3493
0
      if (firstone)
3494
0
      {
3495
        /* Get sub-array details from first member */
3496
0
        elem_ndims = this_ndims;
3497
0
        ndims = elem_ndims + 1;
3498
0
        if (ndims <= 0 || ndims > MAXDIM)
3499
0
          ereport(ERROR,
3500
0
              (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
3501
0
               errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
3502
0
                  ndims, MAXDIM)));
3503
3504
0
        elem_dims = (int *) palloc(elem_ndims * sizeof(int));
3505
0
        memcpy(elem_dims, ARR_DIMS(array), elem_ndims * sizeof(int));
3506
0
        elem_lbs = (int *) palloc(elem_ndims * sizeof(int));
3507
0
        memcpy(elem_lbs, ARR_LBOUND(array), elem_ndims * sizeof(int));
3508
3509
0
        firstone = false;
3510
0
      }
3511
0
      else
3512
0
      {
3513
        /* Check other sub-arrays are compatible */
3514
0
        if (elem_ndims != this_ndims ||
3515
0
          memcmp(elem_dims, ARR_DIMS(array),
3516
0
               elem_ndims * sizeof(int)) != 0 ||
3517
0
          memcmp(elem_lbs, ARR_LBOUND(array),
3518
0
               elem_ndims * sizeof(int)) != 0)
3519
0
          ereport(ERROR,
3520
0
              (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
3521
0
               errmsg("multidimensional arrays must have array "
3522
0
                  "expressions with matching dimensions")));
3523
0
      }
3524
3525
0
      subdata[outer_nelems] = ARR_DATA_PTR(array);
3526
0
      subbitmaps[outer_nelems] = ARR_NULLBITMAP(array);
3527
0
      subbytes[outer_nelems] = ARR_SIZE(array) - ARR_DATA_OFFSET(array);
3528
0
      nbytes += subbytes[outer_nelems];
3529
      /* check for overflow of total request */
3530
0
      if (!AllocSizeIsValid(nbytes))
3531
0
        ereport(ERROR,
3532
0
            (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
3533
0
             errmsg("array size exceeds the maximum allowed (%d)",
3534
0
                (int) MaxAllocSize)));
3535
0
      subnitems[outer_nelems] = ArrayGetNItems(this_ndims,
3536
0
                           ARR_DIMS(array));
3537
0
      havenulls |= ARR_HASNULL(array);
3538
0
      outer_nelems++;
3539
0
    }
3540
3541
    /*
3542
     * If all items were null or empty arrays, return an empty array;
3543
     * otherwise, if some were and some weren't, raise error.  (Note: we
3544
     * must special-case this somehow to avoid trying to generate a 1-D
3545
     * array formed from empty arrays.  It's not ideal...)
3546
     */
3547
0
    if (haveempty)
3548
0
    {
3549
0
      if (ndims == 0)   /* didn't find any nonempty array */
3550
0
      {
3551
0
        *op->resvalue = PointerGetDatum(construct_empty_array(element_type));
3552
0
        return;
3553
0
      }
3554
0
      ereport(ERROR,
3555
0
          (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
3556
0
           errmsg("multidimensional arrays must have array "
3557
0
              "expressions with matching dimensions")));
3558
0
    }
3559
3560
    /* setup for multi-D array */
3561
0
    dims[0] = outer_nelems;
3562
0
    lbs[0] = 1;
3563
0
    for (int i = 1; i < ndims; i++)
3564
0
    {
3565
0
      dims[i] = elem_dims[i - 1];
3566
0
      lbs[i] = elem_lbs[i - 1];
3567
0
    }
3568
3569
    /* check for subscript overflow */
3570
0
    nitems = ArrayGetNItems(ndims, dims);
3571
0
    ArrayCheckBounds(ndims, dims, lbs);
3572
3573
0
    if (havenulls)
3574
0
    {
3575
0
      dataoffset = ARR_OVERHEAD_WITHNULLS(ndims, nitems);
3576
0
      nbytes += dataoffset;
3577
0
    }
3578
0
    else
3579
0
    {
3580
0
      dataoffset = 0;   /* marker for no null bitmap */
3581
0
      nbytes += ARR_OVERHEAD_NONULLS(ndims);
3582
0
    }
3583
3584
0
    result = (ArrayType *) palloc0(nbytes);
3585
0
    SET_VARSIZE(result, nbytes);
3586
0
    result->ndim = ndims;
3587
0
    result->dataoffset = dataoffset;
3588
0
    result->elemtype = element_type;
3589
0
    memcpy(ARR_DIMS(result), dims, ndims * sizeof(int));
3590
0
    memcpy(ARR_LBOUND(result), lbs, ndims * sizeof(int));
3591
3592
0
    dat = ARR_DATA_PTR(result);
3593
0
    iitem = 0;
3594
0
    for (int i = 0; i < outer_nelems; i++)
3595
0
    {
3596
0
      memcpy(dat, subdata[i], subbytes[i]);
3597
0
      dat += subbytes[i];
3598
0
      if (havenulls)
3599
0
        array_bitmap_copy(ARR_NULLBITMAP(result), iitem,
3600
0
                  subbitmaps[i], 0,
3601
0
                  subnitems[i]);
3602
0
      iitem += subnitems[i];
3603
0
    }
3604
0
  }
3605
3606
0
  *op->resvalue = PointerGetDatum(result);
3607
0
}
3608
3609
/*
3610
 * Evaluate an ArrayCoerceExpr expression.
3611
 *
3612
 * Source array is in step's result variable.
3613
 */
3614
void
3615
ExecEvalArrayCoerce(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
3616
0
{
3617
0
  Datum   arraydatum;
3618
3619
  /* NULL array -> NULL result */
3620
0
  if (*op->resnull)
3621
0
    return;
3622
3623
0
  arraydatum = *op->resvalue;
3624
3625
  /*
3626
   * If it's binary-compatible, modify the element type in the array header,
3627
   * but otherwise leave the array as we received it.
3628
   */
3629
0
  if (op->d.arraycoerce.elemexprstate == NULL)
3630
0
  {
3631
    /* Detoast input array if necessary, and copy in any case */
3632
0
    ArrayType  *array = DatumGetArrayTypePCopy(arraydatum);
3633
3634
0
    ARR_ELEMTYPE(array) = op->d.arraycoerce.resultelemtype;
3635
0
    *op->resvalue = PointerGetDatum(array);
3636
0
    return;
3637
0
  }
3638
3639
  /*
3640
   * Use array_map to apply the sub-expression to each array element.
3641
   */
3642
0
  *op->resvalue = array_map(arraydatum,
3643
0
                op->d.arraycoerce.elemexprstate,
3644
0
                econtext,
3645
0
                op->d.arraycoerce.resultelemtype,
3646
0
                op->d.arraycoerce.amstate);
3647
0
}
3648
3649
/*
3650
 * Evaluate a ROW() expression.
3651
 *
3652
 * The individual columns have already been evaluated into
3653
 * op->d.row.elemvalues[]/elemnulls[].
3654
 */
3655
void
3656
ExecEvalRow(ExprState *state, ExprEvalStep *op)
3657
0
{
3658
0
  HeapTuple tuple;
3659
3660
  /* build tuple from evaluated field values */
3661
0
  tuple = heap_form_tuple(op->d.row.tupdesc,
3662
0
              op->d.row.elemvalues,
3663
0
              op->d.row.elemnulls);
3664
3665
0
  *op->resvalue = HeapTupleGetDatum(tuple);
3666
0
  *op->resnull = false;
3667
0
}
3668
3669
/*
3670
 * Evaluate GREATEST() or LEAST() expression (note this is *not* MIN()/MAX()).
3671
 *
3672
 * All of the to-be-compared expressions have already been evaluated into
3673
 * op->d.minmax.values[]/nulls[].
3674
 */
3675
void
3676
ExecEvalMinMax(ExprState *state, ExprEvalStep *op)
3677
0
{
3678
0
  Datum    *values = op->d.minmax.values;
3679
0
  bool     *nulls = op->d.minmax.nulls;
3680
0
  FunctionCallInfo fcinfo = op->d.minmax.fcinfo_data;
3681
0
  MinMaxOp  operator = op->d.minmax.op;
3682
3683
  /* set at initialization */
3684
0
  Assert(fcinfo->args[0].isnull == false);
3685
0
  Assert(fcinfo->args[1].isnull == false);
3686
3687
  /* default to null result */
3688
0
  *op->resnull = true;
3689
3690
0
  for (int off = 0; off < op->d.minmax.nelems; off++)
3691
0
  {
3692
    /* ignore NULL inputs */
3693
0
    if (nulls[off])
3694
0
      continue;
3695
3696
0
    if (*op->resnull)
3697
0
    {
3698
      /* first nonnull input, adopt value */
3699
0
      *op->resvalue = values[off];
3700
0
      *op->resnull = false;
3701
0
    }
3702
0
    else
3703
0
    {
3704
0
      int     cmpresult;
3705
3706
      /* apply comparison function */
3707
0
      fcinfo->args[0].value = *op->resvalue;
3708
0
      fcinfo->args[1].value = values[off];
3709
3710
0
      fcinfo->isnull = false;
3711
0
      cmpresult = DatumGetInt32(FunctionCallInvoke(fcinfo));
3712
0
      if (fcinfo->isnull) /* probably should not happen */
3713
0
        continue;
3714
3715
0
      if (cmpresult > 0 && operator == IS_LEAST)
3716
0
        *op->resvalue = values[off];
3717
0
      else if (cmpresult < 0 && operator == IS_GREATEST)
3718
0
        *op->resvalue = values[off];
3719
0
    }
3720
0
  }
3721
0
}
3722
3723
/*
3724
 * Evaluate a FieldSelect node.
3725
 *
3726
 * Source record is in step's result variable.
3727
 */
3728
void
3729
ExecEvalFieldSelect(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
3730
0
{
3731
0
  AttrNumber  fieldnum = op->d.fieldselect.fieldnum;
3732
0
  Datum   tupDatum;
3733
0
  HeapTupleHeader tuple;
3734
0
  Oid     tupType;
3735
0
  int32   tupTypmod;
3736
0
  TupleDesc tupDesc;
3737
0
  Form_pg_attribute attr;
3738
0
  HeapTupleData tmptup;
3739
3740
  /* NULL record -> NULL result */
3741
0
  if (*op->resnull)
3742
0
    return;
3743
3744
0
  tupDatum = *op->resvalue;
3745
3746
  /* We can special-case expanded records for speed */
3747
0
  if (VARATT_IS_EXTERNAL_EXPANDED(DatumGetPointer(tupDatum)))
3748
0
  {
3749
0
    ExpandedRecordHeader *erh = (ExpandedRecordHeader *) DatumGetEOHP(tupDatum);
3750
3751
0
    Assert(erh->er_magic == ER_MAGIC);
3752
3753
    /* Extract record's TupleDesc */
3754
0
    tupDesc = expanded_record_get_tupdesc(erh);
3755
3756
    /*
3757
     * Find field's attr record.  Note we don't support system columns
3758
     * here: a datum tuple doesn't have valid values for most of the
3759
     * interesting system columns anyway.
3760
     */
3761
0
    if (fieldnum <= 0)   /* should never happen */
3762
0
      elog(ERROR, "unsupported reference to system column %d in FieldSelect",
3763
0
         fieldnum);
3764
0
    if (fieldnum > tupDesc->natts) /* should never happen */
3765
0
      elog(ERROR, "attribute number %d exceeds number of columns %d",
3766
0
         fieldnum, tupDesc->natts);
3767
0
    attr = TupleDescAttr(tupDesc, fieldnum - 1);
3768
3769
    /* Check for dropped column, and force a NULL result if so */
3770
0
    if (attr->attisdropped)
3771
0
    {
3772
0
      *op->resnull = true;
3773
0
      return;
3774
0
    }
3775
3776
    /* Check for type mismatch --- possible after ALTER COLUMN TYPE? */
3777
    /* As in CheckVarSlotCompatibility, we should but can't check typmod */
3778
0
    if (op->d.fieldselect.resulttype != attr->atttypid)
3779
0
      ereport(ERROR,
3780
0
          (errcode(ERRCODE_DATATYPE_MISMATCH),
3781
0
           errmsg("attribute %d has wrong type", fieldnum),
3782
0
           errdetail("Table has type %s, but query expects %s.",
3783
0
                 format_type_be(attr->atttypid),
3784
0
                 format_type_be(op->d.fieldselect.resulttype))));
3785
3786
    /* extract the field */
3787
0
    *op->resvalue = expanded_record_get_field(erh, fieldnum,
3788
0
                          op->resnull);
3789
0
  }
3790
0
  else
3791
0
  {
3792
    /* Get the composite datum and extract its type fields */
3793
0
    tuple = DatumGetHeapTupleHeader(tupDatum);
3794
3795
0
    tupType = HeapTupleHeaderGetTypeId(tuple);
3796
0
    tupTypmod = HeapTupleHeaderGetTypMod(tuple);
3797
3798
    /* Lookup tupdesc if first time through or if type changes */
3799
0
    tupDesc = get_cached_rowtype(tupType, tupTypmod,
3800
0
                   &op->d.fieldselect.rowcache, NULL);
3801
3802
    /*
3803
     * Find field's attr record.  Note we don't support system columns
3804
     * here: a datum tuple doesn't have valid values for most of the
3805
     * interesting system columns anyway.
3806
     */
3807
0
    if (fieldnum <= 0)   /* should never happen */
3808
0
      elog(ERROR, "unsupported reference to system column %d in FieldSelect",
3809
0
         fieldnum);
3810
0
    if (fieldnum > tupDesc->natts) /* should never happen */
3811
0
      elog(ERROR, "attribute number %d exceeds number of columns %d",
3812
0
         fieldnum, tupDesc->natts);
3813
0
    attr = TupleDescAttr(tupDesc, fieldnum - 1);
3814
3815
    /* Check for dropped column, and force a NULL result if so */
3816
0
    if (attr->attisdropped)
3817
0
    {
3818
0
      *op->resnull = true;
3819
0
      return;
3820
0
    }
3821
3822
    /* Check for type mismatch --- possible after ALTER COLUMN TYPE? */
3823
    /* As in CheckVarSlotCompatibility, we should but can't check typmod */
3824
0
    if (op->d.fieldselect.resulttype != attr->atttypid)
3825
0
      ereport(ERROR,
3826
0
          (errcode(ERRCODE_DATATYPE_MISMATCH),
3827
0
           errmsg("attribute %d has wrong type", fieldnum),
3828
0
           errdetail("Table has type %s, but query expects %s.",
3829
0
                 format_type_be(attr->atttypid),
3830
0
                 format_type_be(op->d.fieldselect.resulttype))));
3831
3832
    /* heap_getattr needs a HeapTuple not a bare HeapTupleHeader */
3833
0
    tmptup.t_len = HeapTupleHeaderGetDatumLength(tuple);
3834
0
    tmptup.t_data = tuple;
3835
3836
    /* extract the field */
3837
0
    *op->resvalue = heap_getattr(&tmptup,
3838
0
                   fieldnum,
3839
0
                   tupDesc,
3840
0
                   op->resnull);
3841
0
  }
3842
0
}
3843
3844
/*
3845
 * Deform source tuple, filling in the step's values/nulls arrays, before
3846
 * evaluating individual new values as part of a FieldStore expression.
3847
 * Subsequent steps will overwrite individual elements of the values/nulls
3848
 * arrays with the new field values, and then FIELDSTORE_FORM will build the
3849
 * new tuple value.
3850
 *
3851
 * Source record is in step's result variable.
3852
 */
3853
void
3854
ExecEvalFieldStoreDeForm(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
3855
0
{
3856
0
  if (*op->resnull)
3857
0
  {
3858
    /* Convert null input tuple into an all-nulls row */
3859
0
    memset(op->d.fieldstore.nulls, true,
3860
0
         op->d.fieldstore.ncolumns * sizeof(bool));
3861
0
  }
3862
0
  else
3863
0
  {
3864
    /*
3865
     * heap_deform_tuple needs a HeapTuple not a bare HeapTupleHeader. We
3866
     * set all the fields in the struct just in case.
3867
     */
3868
0
    Datum   tupDatum = *op->resvalue;
3869
0
    HeapTupleHeader tuphdr;
3870
0
    HeapTupleData tmptup;
3871
0
    TupleDesc tupDesc;
3872
3873
0
    tuphdr = DatumGetHeapTupleHeader(tupDatum);
3874
0
    tmptup.t_len = HeapTupleHeaderGetDatumLength(tuphdr);
3875
0
    ItemPointerSetInvalid(&(tmptup.t_self));
3876
0
    tmptup.t_tableOid = InvalidOid;
3877
0
    tmptup.t_data = tuphdr;
3878
3879
    /*
3880
     * Lookup tupdesc if first time through or if type changes.  Because
3881
     * we don't pin the tupdesc, we must not do this lookup until after
3882
     * doing DatumGetHeapTupleHeader: that could do database access while
3883
     * detoasting the datum.
3884
     */
3885
0
    tupDesc = get_cached_rowtype(op->d.fieldstore.fstore->resulttype, -1,
3886
0
                   op->d.fieldstore.rowcache, NULL);
3887
3888
    /* Check that current tupdesc doesn't have more fields than allocated */
3889
0
    if (unlikely(tupDesc->natts > op->d.fieldstore.ncolumns))
3890
0
      elog(ERROR, "too many columns in composite type %u",
3891
0
         op->d.fieldstore.fstore->resulttype);
3892
3893
0
    heap_deform_tuple(&tmptup, tupDesc,
3894
0
              op->d.fieldstore.values,
3895
0
              op->d.fieldstore.nulls);
3896
0
  }
3897
0
}
3898
3899
/*
3900
 * Compute the new composite datum after each individual field value of a
3901
 * FieldStore expression has been evaluated.
3902
 */
3903
void
3904
ExecEvalFieldStoreForm(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
3905
0
{
3906
0
  TupleDesc tupDesc;
3907
0
  HeapTuple tuple;
3908
3909
  /* Lookup tupdesc (should be valid already) */
3910
0
  tupDesc = get_cached_rowtype(op->d.fieldstore.fstore->resulttype, -1,
3911
0
                 op->d.fieldstore.rowcache, NULL);
3912
3913
0
  tuple = heap_form_tuple(tupDesc,
3914
0
              op->d.fieldstore.values,
3915
0
              op->d.fieldstore.nulls);
3916
3917
0
  *op->resvalue = HeapTupleGetDatum(tuple);
3918
0
  *op->resnull = false;
3919
0
}
3920
3921
/*
3922
 * Evaluate a rowtype coercion operation.
3923
 * This may require rearranging field positions.
3924
 *
3925
 * Source record is in step's result variable.
3926
 */
3927
void
3928
ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
3929
0
{
3930
0
  HeapTuple result;
3931
0
  Datum   tupDatum;
3932
0
  HeapTupleHeader tuple;
3933
0
  HeapTupleData tmptup;
3934
0
  TupleDesc indesc,
3935
0
        outdesc;
3936
0
  bool    changed = false;
3937
3938
  /* NULL in -> NULL out */
3939
0
  if (*op->resnull)
3940
0
    return;
3941
3942
0
  tupDatum = *op->resvalue;
3943
0
  tuple = DatumGetHeapTupleHeader(tupDatum);
3944
3945
  /*
3946
   * Lookup tupdescs if first time through or if type changes.  We'd better
3947
   * pin them since type conversion functions could do catalog lookups and
3948
   * hence cause cache invalidation.
3949
   */
3950
0
  indesc = get_cached_rowtype(op->d.convert_rowtype.inputtype, -1,
3951
0
                op->d.convert_rowtype.incache,
3952
0
                &changed);
3953
0
  IncrTupleDescRefCount(indesc);
3954
0
  outdesc = get_cached_rowtype(op->d.convert_rowtype.outputtype, -1,
3955
0
                 op->d.convert_rowtype.outcache,
3956
0
                 &changed);
3957
0
  IncrTupleDescRefCount(outdesc);
3958
3959
  /*
3960
   * We used to be able to assert that incoming tuples are marked with
3961
   * exactly the rowtype of indesc.  However, now that ExecEvalWholeRowVar
3962
   * might change the tuples' marking to plain RECORD due to inserting
3963
   * aliases, we can only make this weak test:
3964
   */
3965
0
  Assert(HeapTupleHeaderGetTypeId(tuple) == indesc->tdtypeid ||
3966
0
       HeapTupleHeaderGetTypeId(tuple) == RECORDOID);
3967
3968
  /* if first time through, or after change, initialize conversion map */
3969
0
  if (changed)
3970
0
  {
3971
0
    MemoryContext old_cxt;
3972
3973
    /* allocate map in long-lived memory context */
3974
0
    old_cxt = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
3975
3976
    /* prepare map from old to new attribute numbers */
3977
0
    op->d.convert_rowtype.map = convert_tuples_by_name(indesc, outdesc);
3978
3979
0
    MemoryContextSwitchTo(old_cxt);
3980
0
  }
3981
3982
  /* Following steps need a HeapTuple not a bare HeapTupleHeader */
3983
0
  tmptup.t_len = HeapTupleHeaderGetDatumLength(tuple);
3984
0
  tmptup.t_data = tuple;
3985
3986
0
  if (op->d.convert_rowtype.map != NULL)
3987
0
  {
3988
    /* Full conversion with attribute rearrangement needed */
3989
0
    result = execute_attr_map_tuple(&tmptup, op->d.convert_rowtype.map);
3990
    /* Result already has appropriate composite-datum header fields */
3991
0
    *op->resvalue = HeapTupleGetDatum(result);
3992
0
  }
3993
0
  else
3994
0
  {
3995
    /*
3996
     * The tuple is physically compatible as-is, but we need to insert the
3997
     * destination rowtype OID in its composite-datum header field, so we
3998
     * have to copy it anyway.  heap_copy_tuple_as_datum() is convenient
3999
     * for this since it will both make the physical copy and insert the
4000
     * correct composite header fields.  Note that we aren't expecting to
4001
     * have to flatten any toasted fields: the input was a composite
4002
     * datum, so it shouldn't contain any.  So heap_copy_tuple_as_datum()
4003
     * is overkill here, but its check for external fields is cheap.
4004
     */
4005
0
    *op->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc);
4006
0
  }
4007
4008
0
  DecrTupleDescRefCount(indesc);
4009
0
  DecrTupleDescRefCount(outdesc);
4010
0
}
4011
4012
/*
4013
 * Evaluate "scalar op ANY/ALL (array)".
4014
 *
4015
 * Source array is in our result area, scalar arg is already evaluated into
4016
 * fcinfo->args[0].
4017
 *
4018
 * The operator always yields boolean, and we combine the results across all
4019
 * array elements using OR and AND (for ANY and ALL respectively).  Of course
4020
 * we short-circuit as soon as the result is known.
4021
 */
4022
void
4023
ExecEvalScalarArrayOp(ExprState *state, ExprEvalStep *op)
4024
0
{
4025
0
  FunctionCallInfo fcinfo = op->d.scalararrayop.fcinfo_data;
4026
0
  bool    useOr = op->d.scalararrayop.useOr;
4027
0
  bool    strictfunc = op->d.scalararrayop.finfo->fn_strict;
4028
0
  ArrayType  *arr;
4029
0
  int     nitems;
4030
0
  Datum   result;
4031
0
  bool    resultnull;
4032
0
  int16   typlen;
4033
0
  bool    typbyval;
4034
0
  char    typalign;
4035
0
  char     *s;
4036
0
  bits8    *bitmap;
4037
0
  int     bitmask;
4038
4039
  /*
4040
   * If the array is NULL then we return NULL --- it's not very meaningful
4041
   * to do anything else, even if the operator isn't strict.
4042
   */
4043
0
  if (*op->resnull)
4044
0
    return;
4045
4046
  /* Else okay to fetch and detoast the array */
4047
0
  arr = DatumGetArrayTypeP(*op->resvalue);
4048
4049
  /*
4050
   * If the array is empty, we return either FALSE or TRUE per the useOr
4051
   * flag.  This is correct even if the scalar is NULL; since we would
4052
   * evaluate the operator zero times, it matters not whether it would want
4053
   * to return NULL.
4054
   */
4055
0
  nitems = ArrayGetNItems(ARR_NDIM(arr), ARR_DIMS(arr));
4056
0
  if (nitems <= 0)
4057
0
  {
4058
0
    *op->resvalue = BoolGetDatum(!useOr);
4059
0
    *op->resnull = false;
4060
0
    return;
4061
0
  }
4062
4063
  /*
4064
   * If the scalar is NULL, and the function is strict, return NULL; no
4065
   * point in iterating the loop.
4066
   */
4067
0
  if (fcinfo->args[0].isnull && strictfunc)
4068
0
  {
4069
0
    *op->resnull = true;
4070
0
    return;
4071
0
  }
4072
4073
  /*
4074
   * We arrange to look up info about the element type only once per series
4075
   * of calls, assuming the element type doesn't change underneath us.
4076
   */
4077
0
  if (op->d.scalararrayop.element_type != ARR_ELEMTYPE(arr))
4078
0
  {
4079
0
    get_typlenbyvalalign(ARR_ELEMTYPE(arr),
4080
0
               &op->d.scalararrayop.typlen,
4081
0
               &op->d.scalararrayop.typbyval,
4082
0
               &op->d.scalararrayop.typalign);
4083
0
    op->d.scalararrayop.element_type = ARR_ELEMTYPE(arr);
4084
0
  }
4085
4086
0
  typlen = op->d.scalararrayop.typlen;
4087
0
  typbyval = op->d.scalararrayop.typbyval;
4088
0
  typalign = op->d.scalararrayop.typalign;
4089
4090
  /* Initialize result appropriately depending on useOr */
4091
0
  result = BoolGetDatum(!useOr);
4092
0
  resultnull = false;
4093
4094
  /* Loop over the array elements */
4095
0
  s = (char *) ARR_DATA_PTR(arr);
4096
0
  bitmap = ARR_NULLBITMAP(arr);
4097
0
  bitmask = 1;
4098
4099
0
  for (int i = 0; i < nitems; i++)
4100
0
  {
4101
0
    Datum   elt;
4102
0
    Datum   thisresult;
4103
4104
    /* Get array element, checking for NULL */
4105
0
    if (bitmap && (*bitmap & bitmask) == 0)
4106
0
    {
4107
0
      fcinfo->args[1].value = (Datum) 0;
4108
0
      fcinfo->args[1].isnull = true;
4109
0
    }
4110
0
    else
4111
0
    {
4112
0
      elt = fetch_att(s, typbyval, typlen);
4113
0
      s = att_addlength_pointer(s, typlen, s);
4114
0
      s = (char *) att_align_nominal(s, typalign);
4115
0
      fcinfo->args[1].value = elt;
4116
0
      fcinfo->args[1].isnull = false;
4117
0
    }
4118
4119
    /* Call comparison function */
4120
0
    if (fcinfo->args[1].isnull && strictfunc)
4121
0
    {
4122
0
      fcinfo->isnull = true;
4123
0
      thisresult = (Datum) 0;
4124
0
    }
4125
0
    else
4126
0
    {
4127
0
      fcinfo->isnull = false;
4128
0
      thisresult = op->d.scalararrayop.fn_addr(fcinfo);
4129
0
    }
4130
4131
    /* Combine results per OR or AND semantics */
4132
0
    if (fcinfo->isnull)
4133
0
      resultnull = true;
4134
0
    else if (useOr)
4135
0
    {
4136
0
      if (DatumGetBool(thisresult))
4137
0
      {
4138
0
        result = BoolGetDatum(true);
4139
0
        resultnull = false;
4140
0
        break;      /* needn't look at any more elements */
4141
0
      }
4142
0
    }
4143
0
    else
4144
0
    {
4145
0
      if (!DatumGetBool(thisresult))
4146
0
      {
4147
0
        result = BoolGetDatum(false);
4148
0
        resultnull = false;
4149
0
        break;      /* needn't look at any more elements */
4150
0
      }
4151
0
    }
4152
4153
    /* advance bitmap pointer if any */
4154
0
    if (bitmap)
4155
0
    {
4156
0
      bitmask <<= 1;
4157
0
      if (bitmask == 0x100)
4158
0
      {
4159
0
        bitmap++;
4160
0
        bitmask = 1;
4161
0
      }
4162
0
    }
4163
0
  }
4164
4165
0
  *op->resvalue = result;
4166
0
  *op->resnull = resultnull;
4167
0
}
4168
4169
/*
4170
 * Hash function for scalar array hash op elements.
4171
 *
4172
 * We use the element type's default hash opclass, and the column collation
4173
 * if the type is collation-sensitive.
4174
 */
4175
static uint32
4176
saop_element_hash(struct saophash_hash *tb, Datum key)
4177
0
{
4178
0
  ScalarArrayOpExprHashTable *elements_tab = (ScalarArrayOpExprHashTable *) tb->private_data;
4179
0
  FunctionCallInfo fcinfo = &elements_tab->hash_fcinfo_data;
4180
0
  Datum   hash;
4181
4182
0
  fcinfo->args[0].value = key;
4183
0
  fcinfo->args[0].isnull = false;
4184
4185
0
  hash = elements_tab->hash_finfo.fn_addr(fcinfo);
4186
4187
0
  return DatumGetUInt32(hash);
4188
0
}
4189
4190
/*
4191
 * Matching function for scalar array hash op elements, to be used in hashtable
4192
 * lookups.
4193
 */
4194
static bool
4195
saop_hash_element_match(struct saophash_hash *tb, Datum key1, Datum key2)
4196
0
{
4197
0
  Datum   result;
4198
4199
0
  ScalarArrayOpExprHashTable *elements_tab = (ScalarArrayOpExprHashTable *) tb->private_data;
4200
0
  FunctionCallInfo fcinfo = elements_tab->op->d.hashedscalararrayop.fcinfo_data;
4201
4202
0
  fcinfo->args[0].value = key1;
4203
0
  fcinfo->args[0].isnull = false;
4204
0
  fcinfo->args[1].value = key2;
4205
0
  fcinfo->args[1].isnull = false;
4206
4207
0
  result = elements_tab->op->d.hashedscalararrayop.finfo->fn_addr(fcinfo);
4208
4209
0
  return DatumGetBool(result);
4210
0
}
4211
4212
/*
4213
 * Evaluate "scalar op ANY (const array)".
4214
 *
4215
 * Similar to ExecEvalScalarArrayOp, but optimized for faster repeat lookups
4216
 * by building a hashtable on the first lookup.  This hashtable will be reused
4217
 * by subsequent lookups.  Unlike ExecEvalScalarArrayOp, this version only
4218
 * supports OR semantics.
4219
 *
4220
 * Source array is in our result area, scalar arg is already evaluated into
4221
 * fcinfo->args[0].
4222
 *
4223
 * The operator always yields boolean.
4224
 */
4225
void
4226
ExecEvalHashedScalarArrayOp(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
4227
0
{
4228
0
  ScalarArrayOpExprHashTable *elements_tab = op->d.hashedscalararrayop.elements_tab;
4229
0
  FunctionCallInfo fcinfo = op->d.hashedscalararrayop.fcinfo_data;
4230
0
  bool    inclause = op->d.hashedscalararrayop.inclause;
4231
0
  bool    strictfunc = op->d.hashedscalararrayop.finfo->fn_strict;
4232
0
  Datum   scalar = fcinfo->args[0].value;
4233
0
  bool    scalar_isnull = fcinfo->args[0].isnull;
4234
0
  Datum   result;
4235
0
  bool    resultnull;
4236
0
  bool    hashfound;
4237
4238
  /* We don't setup a hashed scalar array op if the array const is null. */
4239
0
  Assert(!*op->resnull);
4240
4241
  /*
4242
   * If the scalar is NULL, and the function is strict, return NULL; no
4243
   * point in executing the search.
4244
   */
4245
0
  if (fcinfo->args[0].isnull && strictfunc)
4246
0
  {
4247
0
    *op->resnull = true;
4248
0
    return;
4249
0
  }
4250
4251
  /* Build the hash table on first evaluation */
4252
0
  if (elements_tab == NULL)
4253
0
  {
4254
0
    ScalarArrayOpExpr *saop;
4255
0
    int16   typlen;
4256
0
    bool    typbyval;
4257
0
    char    typalign;
4258
0
    int     nitems;
4259
0
    bool    has_nulls = false;
4260
0
    char     *s;
4261
0
    bits8    *bitmap;
4262
0
    int     bitmask;
4263
0
    MemoryContext oldcontext;
4264
0
    ArrayType  *arr;
4265
4266
0
    saop = op->d.hashedscalararrayop.saop;
4267
4268
0
    arr = DatumGetArrayTypeP(*op->resvalue);
4269
0
    nitems = ArrayGetNItems(ARR_NDIM(arr), ARR_DIMS(arr));
4270
4271
0
    get_typlenbyvalalign(ARR_ELEMTYPE(arr),
4272
0
               &typlen,
4273
0
               &typbyval,
4274
0
               &typalign);
4275
4276
0
    oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
4277
4278
0
    elements_tab = (ScalarArrayOpExprHashTable *)
4279
0
      palloc0(offsetof(ScalarArrayOpExprHashTable, hash_fcinfo_data) +
4280
0
          SizeForFunctionCallInfo(1));
4281
0
    op->d.hashedscalararrayop.elements_tab = elements_tab;
4282
0
    elements_tab->op = op;
4283
4284
0
    fmgr_info(saop->hashfuncid, &elements_tab->hash_finfo);
4285
0
    fmgr_info_set_expr((Node *) saop, &elements_tab->hash_finfo);
4286
4287
0
    InitFunctionCallInfoData(elements_tab->hash_fcinfo_data,
4288
0
                 &elements_tab->hash_finfo,
4289
0
                 1,
4290
0
                 saop->inputcollid,
4291
0
                 NULL,
4292
0
                 NULL);
4293
4294
    /*
4295
     * Create the hash table sizing it according to the number of elements
4296
     * in the array.  This does assume that the array has no duplicates.
4297
     * If the array happens to contain many duplicate values then it'll
4298
     * just mean that we sized the table a bit on the large side.
4299
     */
4300
0
    elements_tab->hashtab = saophash_create(CurrentMemoryContext, nitems,
4301
0
                        elements_tab);
4302
4303
0
    MemoryContextSwitchTo(oldcontext);
4304
4305
0
    s = (char *) ARR_DATA_PTR(arr);
4306
0
    bitmap = ARR_NULLBITMAP(arr);
4307
0
    bitmask = 1;
4308
0
    for (int i = 0; i < nitems; i++)
4309
0
    {
4310
      /* Get array element, checking for NULL. */
4311
0
      if (bitmap && (*bitmap & bitmask) == 0)
4312
0
      {
4313
0
        has_nulls = true;
4314
0
      }
4315
0
      else
4316
0
      {
4317
0
        Datum   element;
4318
4319
0
        element = fetch_att(s, typbyval, typlen);
4320
0
        s = att_addlength_pointer(s, typlen, s);
4321
0
        s = (char *) att_align_nominal(s, typalign);
4322
4323
0
        saophash_insert(elements_tab->hashtab, element, &hashfound);
4324
0
      }
4325
4326
      /* Advance bitmap pointer if any. */
4327
0
      if (bitmap)
4328
0
      {
4329
0
        bitmask <<= 1;
4330
0
        if (bitmask == 0x100)
4331
0
        {
4332
0
          bitmap++;
4333
0
          bitmask = 1;
4334
0
        }
4335
0
      }
4336
0
    }
4337
4338
    /*
4339
     * Remember if we had any nulls so that we know if we need to execute
4340
     * non-strict functions with a null lhs value if no match is found.
4341
     */
4342
0
    op->d.hashedscalararrayop.has_nulls = has_nulls;
4343
0
  }
4344
4345
  /* Check the hash to see if we have a match. */
4346
0
  hashfound = NULL != saophash_lookup(elements_tab->hashtab, scalar);
4347
4348
  /* the result depends on if the clause is an IN or NOT IN clause */
4349
0
  if (inclause)
4350
0
    result = BoolGetDatum(hashfound); /* IN */
4351
0
  else
4352
0
    result = BoolGetDatum(!hashfound); /* NOT IN */
4353
4354
0
  resultnull = false;
4355
4356
  /*
4357
   * If we didn't find a match in the array, we still might need to handle
4358
   * the possibility of null values.  We didn't put any NULLs into the
4359
   * hashtable, but instead marked if we found any when building the table
4360
   * in has_nulls.
4361
   */
4362
0
  if (!hashfound && op->d.hashedscalararrayop.has_nulls)
4363
0
  {
4364
0
    if (strictfunc)
4365
0
    {
4366
4367
      /*
4368
       * We have nulls in the array so a non-null lhs and no match must
4369
       * yield NULL.
4370
       */
4371
0
      result = (Datum) 0;
4372
0
      resultnull = true;
4373
0
    }
4374
0
    else
4375
0
    {
4376
      /*
4377
       * Execute function will null rhs just once.
4378
       *
4379
       * The hash lookup path will have scribbled on the lhs argument so
4380
       * we need to set it up also (even though we entered this function
4381
       * with it already set).
4382
       */
4383
0
      fcinfo->args[0].value = scalar;
4384
0
      fcinfo->args[0].isnull = scalar_isnull;
4385
0
      fcinfo->args[1].value = (Datum) 0;
4386
0
      fcinfo->args[1].isnull = true;
4387
4388
0
      result = op->d.hashedscalararrayop.finfo->fn_addr(fcinfo);
4389
0
      resultnull = fcinfo->isnull;
4390
4391
      /*
4392
       * Reverse the result for NOT IN clauses since the above function
4393
       * is the equality function and we need not-equals.
4394
       */
4395
0
      if (!inclause)
4396
0
        result = BoolGetDatum(!DatumGetBool(result));
4397
0
    }
4398
0
  }
4399
4400
0
  *op->resvalue = result;
4401
0
  *op->resnull = resultnull;
4402
0
}
4403
4404
/*
4405
 * Evaluate a NOT NULL domain constraint.
4406
 */
4407
void
4408
ExecEvalConstraintNotNull(ExprState *state, ExprEvalStep *op)
4409
0
{
4410
0
  if (*op->resnull)
4411
0
    errsave((Node *) op->d.domaincheck.escontext,
4412
0
        (errcode(ERRCODE_NOT_NULL_VIOLATION),
4413
0
         errmsg("domain %s does not allow null values",
4414
0
            format_type_be(op->d.domaincheck.resulttype)),
4415
0
         errdatatype(op->d.domaincheck.resulttype)));
4416
0
}
4417
4418
/*
4419
 * Evaluate a CHECK domain constraint.
4420
 */
4421
void
4422
ExecEvalConstraintCheck(ExprState *state, ExprEvalStep *op)
4423
0
{
4424
0
  if (!*op->d.domaincheck.checknull &&
4425
0
    !DatumGetBool(*op->d.domaincheck.checkvalue))
4426
0
    errsave((Node *) op->d.domaincheck.escontext,
4427
0
        (errcode(ERRCODE_CHECK_VIOLATION),
4428
0
         errmsg("value for domain %s violates check constraint \"%s\"",
4429
0
            format_type_be(op->d.domaincheck.resulttype),
4430
0
            op->d.domaincheck.constraintname),
4431
0
         errdomainconstraint(op->d.domaincheck.resulttype,
4432
0
                   op->d.domaincheck.constraintname)));
4433
0
}
4434
4435
/*
4436
 * Evaluate the various forms of XmlExpr.
4437
 *
4438
 * Arguments have been evaluated into named_argvalue/named_argnull
4439
 * and/or argvalue/argnull arrays.
4440
 */
4441
void
4442
ExecEvalXmlExpr(ExprState *state, ExprEvalStep *op)
4443
0
{
4444
0
  XmlExpr    *xexpr = op->d.xmlexpr.xexpr;
4445
0
  Datum   value;
4446
4447
0
  *op->resnull = true;    /* until we get a result */
4448
0
  *op->resvalue = (Datum) 0;
4449
4450
0
  switch (xexpr->op)
4451
0
  {
4452
0
    case IS_XMLCONCAT:
4453
0
      {
4454
0
        Datum    *argvalue = op->d.xmlexpr.argvalue;
4455
0
        bool     *argnull = op->d.xmlexpr.argnull;
4456
0
        List     *values = NIL;
4457
4458
0
        for (int i = 0; i < list_length(xexpr->args); i++)
4459
0
        {
4460
0
          if (!argnull[i])
4461
0
            values = lappend(values, DatumGetPointer(argvalue[i]));
4462
0
        }
4463
4464
0
        if (values != NIL)
4465
0
        {
4466
0
          *op->resvalue = PointerGetDatum(xmlconcat(values));
4467
0
          *op->resnull = false;
4468
0
        }
4469
0
      }
4470
0
      break;
4471
4472
0
    case IS_XMLFOREST:
4473
0
      {
4474
0
        Datum    *argvalue = op->d.xmlexpr.named_argvalue;
4475
0
        bool     *argnull = op->d.xmlexpr.named_argnull;
4476
0
        StringInfoData buf;
4477
0
        ListCell   *lc;
4478
0
        ListCell   *lc2;
4479
0
        int     i;
4480
4481
0
        initStringInfo(&buf);
4482
4483
0
        i = 0;
4484
0
        forboth(lc, xexpr->named_args, lc2, xexpr->arg_names)
4485
0
        {
4486
0
          Expr     *e = (Expr *) lfirst(lc);
4487
0
          char     *argname = strVal(lfirst(lc2));
4488
4489
0
          if (!argnull[i])
4490
0
          {
4491
0
            value = argvalue[i];
4492
0
            appendStringInfo(&buf, "<%s>%s</%s>",
4493
0
                     argname,
4494
0
                     map_sql_value_to_xml_value(value,
4495
0
                                  exprType((Node *) e), true),
4496
0
                     argname);
4497
0
            *op->resnull = false;
4498
0
          }
4499
0
          i++;
4500
0
        }
4501
4502
0
        if (!*op->resnull)
4503
0
        {
4504
0
          text     *result;
4505
4506
0
          result = cstring_to_text_with_len(buf.data, buf.len);
4507
0
          *op->resvalue = PointerGetDatum(result);
4508
0
        }
4509
4510
0
        pfree(buf.data);
4511
0
      }
4512
0
      break;
4513
4514
0
    case IS_XMLELEMENT:
4515
0
      *op->resvalue = PointerGetDatum(xmlelement(xexpr,
4516
0
                             op->d.xmlexpr.named_argvalue,
4517
0
                             op->d.xmlexpr.named_argnull,
4518
0
                             op->d.xmlexpr.argvalue,
4519
0
                             op->d.xmlexpr.argnull));
4520
0
      *op->resnull = false;
4521
0
      break;
4522
4523
0
    case IS_XMLPARSE:
4524
0
      {
4525
0
        Datum    *argvalue = op->d.xmlexpr.argvalue;
4526
0
        bool     *argnull = op->d.xmlexpr.argnull;
4527
0
        text     *data;
4528
0
        bool    preserve_whitespace;
4529
4530
        /* arguments are known to be text, bool */
4531
0
        Assert(list_length(xexpr->args) == 2);
4532
4533
0
        if (argnull[0])
4534
0
          return;
4535
0
        value = argvalue[0];
4536
0
        data = DatumGetTextPP(value);
4537
4538
0
        if (argnull[1]) /* probably can't happen */
4539
0
          return;
4540
0
        value = argvalue[1];
4541
0
        preserve_whitespace = DatumGetBool(value);
4542
4543
0
        *op->resvalue = PointerGetDatum(xmlparse(data,
4544
0
                             xexpr->xmloption,
4545
0
                             preserve_whitespace));
4546
0
        *op->resnull = false;
4547
0
      }
4548
0
      break;
4549
4550
0
    case IS_XMLPI:
4551
0
      {
4552
0
        text     *arg;
4553
0
        bool    isnull;
4554
4555
        /* optional argument is known to be text */
4556
0
        Assert(list_length(xexpr->args) <= 1);
4557
4558
0
        if (xexpr->args)
4559
0
        {
4560
0
          isnull = op->d.xmlexpr.argnull[0];
4561
0
          if (isnull)
4562
0
            arg = NULL;
4563
0
          else
4564
0
            arg = DatumGetTextPP(op->d.xmlexpr.argvalue[0]);
4565
0
        }
4566
0
        else
4567
0
        {
4568
0
          arg = NULL;
4569
0
          isnull = false;
4570
0
        }
4571
4572
0
        *op->resvalue = PointerGetDatum(xmlpi(xexpr->name,
4573
0
                            arg,
4574
0
                            isnull,
4575
0
                            op->resnull));
4576
0
      }
4577
0
      break;
4578
4579
0
    case IS_XMLROOT:
4580
0
      {
4581
0
        Datum    *argvalue = op->d.xmlexpr.argvalue;
4582
0
        bool     *argnull = op->d.xmlexpr.argnull;
4583
0
        xmltype    *data;
4584
0
        text     *version;
4585
0
        int     standalone;
4586
4587
        /* arguments are known to be xml, text, int */
4588
0
        Assert(list_length(xexpr->args) == 3);
4589
4590
0
        if (argnull[0])
4591
0
          return;
4592
0
        data = DatumGetXmlP(argvalue[0]);
4593
4594
0
        if (argnull[1])
4595
0
          version = NULL;
4596
0
        else
4597
0
          version = DatumGetTextPP(argvalue[1]);
4598
4599
0
        Assert(!argnull[2]);  /* always present */
4600
0
        standalone = DatumGetInt32(argvalue[2]);
4601
4602
0
        *op->resvalue = PointerGetDatum(xmlroot(data,
4603
0
                            version,
4604
0
                            standalone));
4605
0
        *op->resnull = false;
4606
0
      }
4607
0
      break;
4608
4609
0
    case IS_XMLSERIALIZE:
4610
0
      {
4611
0
        Datum    *argvalue = op->d.xmlexpr.argvalue;
4612
0
        bool     *argnull = op->d.xmlexpr.argnull;
4613
4614
        /* argument type is known to be xml */
4615
0
        Assert(list_length(xexpr->args) == 1);
4616
4617
0
        if (argnull[0])
4618
0
          return;
4619
0
        value = argvalue[0];
4620
4621
0
        *op->resvalue =
4622
0
          PointerGetDatum(xmltotext_with_options(DatumGetXmlP(value),
4623
0
                               xexpr->xmloption,
4624
0
                               xexpr->indent));
4625
0
        *op->resnull = false;
4626
0
      }
4627
0
      break;
4628
4629
0
    case IS_DOCUMENT:
4630
0
      {
4631
0
        Datum    *argvalue = op->d.xmlexpr.argvalue;
4632
0
        bool     *argnull = op->d.xmlexpr.argnull;
4633
4634
        /* optional argument is known to be xml */
4635
0
        Assert(list_length(xexpr->args) == 1);
4636
4637
0
        if (argnull[0])
4638
0
          return;
4639
0
        value = argvalue[0];
4640
4641
0
        *op->resvalue =
4642
0
          BoolGetDatum(xml_is_document(DatumGetXmlP(value)));
4643
0
        *op->resnull = false;
4644
0
      }
4645
0
      break;
4646
4647
0
    default:
4648
0
      elog(ERROR, "unrecognized XML operation");
4649
0
      break;
4650
0
  }
4651
0
}
4652
4653
/*
4654
 * Evaluate a JSON constructor expression.
4655
 */
4656
void
4657
ExecEvalJsonConstructor(ExprState *state, ExprEvalStep *op,
4658
            ExprContext *econtext)
4659
0
{
4660
0
  Datum   res;
4661
0
  JsonConstructorExprState *jcstate = op->d.json_constructor.jcstate;
4662
0
  JsonConstructorExpr *ctor = jcstate->constructor;
4663
0
  bool    is_jsonb = ctor->returning->format->format_type == JS_FORMAT_JSONB;
4664
0
  bool    isnull = false;
4665
4666
0
  if (ctor->type == JSCTOR_JSON_ARRAY)
4667
0
    res = (is_jsonb ?
4668
0
         jsonb_build_array_worker :
4669
0
         json_build_array_worker) (jcstate->nargs,
4670
0
                     jcstate->arg_values,
4671
0
                     jcstate->arg_nulls,
4672
0
                     jcstate->arg_types,
4673
0
                     jcstate->constructor->absent_on_null);
4674
0
  else if (ctor->type == JSCTOR_JSON_OBJECT)
4675
0
    res = (is_jsonb ?
4676
0
         jsonb_build_object_worker :
4677
0
         json_build_object_worker) (jcstate->nargs,
4678
0
                      jcstate->arg_values,
4679
0
                      jcstate->arg_nulls,
4680
0
                      jcstate->arg_types,
4681
0
                      jcstate->constructor->absent_on_null,
4682
0
                      jcstate->constructor->unique);
4683
0
  else if (ctor->type == JSCTOR_JSON_SCALAR)
4684
0
  {
4685
0
    if (jcstate->arg_nulls[0])
4686
0
    {
4687
0
      res = (Datum) 0;
4688
0
      isnull = true;
4689
0
    }
4690
0
    else
4691
0
    {
4692
0
      Datum   value = jcstate->arg_values[0];
4693
0
      Oid     outfuncid = jcstate->arg_type_cache[0].outfuncid;
4694
0
      JsonTypeCategory category = (JsonTypeCategory)
4695
0
        jcstate->arg_type_cache[0].category;
4696
4697
0
      if (is_jsonb)
4698
0
        res = datum_to_jsonb(value, category, outfuncid);
4699
0
      else
4700
0
        res = datum_to_json(value, category, outfuncid);
4701
0
    }
4702
0
  }
4703
0
  else if (ctor->type == JSCTOR_JSON_PARSE)
4704
0
  {
4705
0
    if (jcstate->arg_nulls[0])
4706
0
    {
4707
0
      res = (Datum) 0;
4708
0
      isnull = true;
4709
0
    }
4710
0
    else
4711
0
    {
4712
0
      Datum   value = jcstate->arg_values[0];
4713
0
      text     *js = DatumGetTextP(value);
4714
4715
0
      if (is_jsonb)
4716
0
        res = jsonb_from_text(js, true);
4717
0
      else
4718
0
      {
4719
0
        (void) json_validate(js, true, true);
4720
0
        res = value;
4721
0
      }
4722
0
    }
4723
0
  }
4724
0
  else
4725
0
    elog(ERROR, "invalid JsonConstructorExpr type %d", ctor->type);
4726
4727
0
  *op->resvalue = res;
4728
0
  *op->resnull = isnull;
4729
0
}
4730
4731
/*
4732
 * Evaluate a IS JSON predicate.
4733
 */
4734
void
4735
ExecEvalJsonIsPredicate(ExprState *state, ExprEvalStep *op)
4736
0
{
4737
0
  JsonIsPredicate *pred = op->d.is_json.pred;
4738
0
  Datum   js = *op->resvalue;
4739
0
  Oid     exprtype;
4740
0
  bool    res;
4741
4742
0
  if (*op->resnull)
4743
0
  {
4744
0
    *op->resvalue = BoolGetDatum(false);
4745
0
    return;
4746
0
  }
4747
4748
0
  exprtype = exprType(pred->expr);
4749
4750
0
  if (exprtype == TEXTOID || exprtype == JSONOID)
4751
0
  {
4752
0
    text     *json = DatumGetTextP(js);
4753
4754
0
    if (pred->item_type == JS_TYPE_ANY)
4755
0
      res = true;
4756
0
    else
4757
0
    {
4758
0
      switch (json_get_first_token(json, false))
4759
0
      {
4760
0
        case JSON_TOKEN_OBJECT_START:
4761
0
          res = pred->item_type == JS_TYPE_OBJECT;
4762
0
          break;
4763
0
        case JSON_TOKEN_ARRAY_START:
4764
0
          res = pred->item_type == JS_TYPE_ARRAY;
4765
0
          break;
4766
0
        case JSON_TOKEN_STRING:
4767
0
        case JSON_TOKEN_NUMBER:
4768
0
        case JSON_TOKEN_TRUE:
4769
0
        case JSON_TOKEN_FALSE:
4770
0
        case JSON_TOKEN_NULL:
4771
0
          res = pred->item_type == JS_TYPE_SCALAR;
4772
0
          break;
4773
0
        default:
4774
0
          res = false;
4775
0
          break;
4776
0
      }
4777
0
    }
4778
4779
    /*
4780
     * Do full parsing pass only for uniqueness check or for JSON text
4781
     * validation.
4782
     */
4783
0
    if (res && (pred->unique_keys || exprtype == TEXTOID))
4784
0
      res = json_validate(json, pred->unique_keys, false);
4785
0
  }
4786
0
  else if (exprtype == JSONBOID)
4787
0
  {
4788
0
    if (pred->item_type == JS_TYPE_ANY)
4789
0
      res = true;
4790
0
    else
4791
0
    {
4792
0
      Jsonb    *jb = DatumGetJsonbP(js);
4793
4794
0
      switch (pred->item_type)
4795
0
      {
4796
0
        case JS_TYPE_OBJECT:
4797
0
          res = JB_ROOT_IS_OBJECT(jb);
4798
0
          break;
4799
0
        case JS_TYPE_ARRAY:
4800
0
          res = JB_ROOT_IS_ARRAY(jb) && !JB_ROOT_IS_SCALAR(jb);
4801
0
          break;
4802
0
        case JS_TYPE_SCALAR:
4803
0
          res = JB_ROOT_IS_ARRAY(jb) && JB_ROOT_IS_SCALAR(jb);
4804
0
          break;
4805
0
        default:
4806
0
          res = false;
4807
0
          break;
4808
0
      }
4809
0
    }
4810
4811
    /* Key uniqueness check is redundant for jsonb */
4812
0
  }
4813
0
  else
4814
0
    res = false;
4815
4816
0
  *op->resvalue = BoolGetDatum(res);
4817
0
}
4818
4819
/*
4820
 * Evaluate a jsonpath against a document, both of which must have been
4821
 * evaluated and their values saved in op->d.jsonexpr.jsestate.
4822
 *
4823
 * If an error occurs during JsonPath* evaluation or when coercing its result
4824
 * to the RETURNING type, JsonExprState.error is set to true, provided the
4825
 * ON ERROR behavior is not ERROR.  Similarly, if JsonPath{Query|Value}() found
4826
 * no matching items, JsonExprState.empty is set to true, provided the ON EMPTY
4827
 * behavior is not ERROR.  That is to signal to the subsequent steps that check
4828
 * those flags to return the ON ERROR / ON EMPTY expression.
4829
 *
4830
 * Return value is the step address to be performed next.  It will be one of
4831
 * jump_error, jump_empty, jump_eval_coercion, or jump_end, all given in
4832
 * op->d.jsonexpr.jsestate.
4833
 */
4834
int
4835
ExecEvalJsonExprPath(ExprState *state, ExprEvalStep *op,
4836
           ExprContext *econtext)
4837
0
{
4838
0
  JsonExprState *jsestate = op->d.jsonexpr.jsestate;
4839
0
  JsonExpr   *jsexpr = jsestate->jsexpr;
4840
0
  Datum   item;
4841
0
  JsonPath   *path;
4842
0
  bool    throw_error = jsexpr->on_error->btype == JSON_BEHAVIOR_ERROR;
4843
0
  bool    error = false,
4844
0
        empty = false;
4845
0
  int     jump_eval_coercion = jsestate->jump_eval_coercion;
4846
0
  char     *val_string = NULL;
4847
4848
0
  item = jsestate->formatted_expr.value;
4849
0
  path = DatumGetJsonPathP(jsestate->pathspec.value);
4850
4851
  /* Set error/empty to false. */
4852
0
  memset(&jsestate->error, 0, sizeof(NullableDatum));
4853
0
  memset(&jsestate->empty, 0, sizeof(NullableDatum));
4854
4855
  /* Also reset ErrorSaveContext contents for the next row. */
4856
0
  if (jsestate->escontext.details_wanted)
4857
0
  {
4858
0
    jsestate->escontext.error_data = NULL;
4859
0
    jsestate->escontext.details_wanted = false;
4860
0
  }
4861
0
  jsestate->escontext.error_occurred = false;
4862
4863
0
  switch (jsexpr->op)
4864
0
  {
4865
0
    case JSON_EXISTS_OP:
4866
0
      {
4867
0
        bool    exists = JsonPathExists(item, path,
4868
0
                          !throw_error ? &error : NULL,
4869
0
                          jsestate->args);
4870
4871
0
        if (!error)
4872
0
        {
4873
0
          *op->resnull = false;
4874
0
          *op->resvalue = BoolGetDatum(exists);
4875
0
        }
4876
0
      }
4877
0
      break;
4878
4879
0
    case JSON_QUERY_OP:
4880
0
      *op->resvalue = JsonPathQuery(item, path, jsexpr->wrapper, &empty,
4881
0
                      !throw_error ? &error : NULL,
4882
0
                      jsestate->args,
4883
0
                      jsexpr->column_name);
4884
4885
0
      *op->resnull = (DatumGetPointer(*op->resvalue) == NULL);
4886
0
      break;
4887
4888
0
    case JSON_VALUE_OP:
4889
0
      {
4890
0
        JsonbValue *jbv = JsonPathValue(item, path, &empty,
4891
0
                        !throw_error ? &error : NULL,
4892
0
                        jsestate->args,
4893
0
                        jsexpr->column_name);
4894
4895
0
        if (jbv == NULL)
4896
0
        {
4897
          /* Will be coerced with json_populate_type(), if needed. */
4898
0
          *op->resvalue = (Datum) 0;
4899
0
          *op->resnull = true;
4900
0
        }
4901
0
        else if (!error && !empty)
4902
0
        {
4903
0
          if (jsexpr->returning->typid == JSONOID ||
4904
0
            jsexpr->returning->typid == JSONBOID)
4905
0
          {
4906
0
            val_string = DatumGetCString(DirectFunctionCall1(jsonb_out,
4907
0
                                     JsonbPGetDatum(JsonbValueToJsonb(jbv))));
4908
0
          }
4909
0
          else if (jsexpr->use_json_coercion)
4910
0
          {
4911
0
            *op->resvalue = JsonbPGetDatum(JsonbValueToJsonb(jbv));
4912
0
            *op->resnull = false;
4913
0
          }
4914
0
          else
4915
0
          {
4916
0
            val_string = ExecGetJsonValueItemString(jbv, op->resnull);
4917
4918
            /*
4919
             * Simply convert to the default RETURNING type (text)
4920
             * if no coercion needed.
4921
             */
4922
0
            if (!jsexpr->use_io_coercion)
4923
0
              *op->resvalue = DirectFunctionCall1(textin,
4924
0
                                CStringGetDatum(val_string));
4925
0
          }
4926
0
        }
4927
0
        break;
4928
0
      }
4929
4930
      /* JSON_TABLE_OP can't happen here */
4931
4932
0
    default:
4933
0
      elog(ERROR, "unrecognized SQL/JSON expression op %d",
4934
0
         (int) jsexpr->op);
4935
0
      return false;
4936
0
  }
4937
4938
  /*
4939
   * Coerce the result value to the RETURNING type by calling its input
4940
   * function.
4941
   */
4942
0
  if (!*op->resnull && jsexpr->use_io_coercion)
4943
0
  {
4944
0
    FunctionCallInfo fcinfo;
4945
4946
0
    Assert(jump_eval_coercion == -1);
4947
0
    fcinfo = jsestate->input_fcinfo;
4948
0
    Assert(fcinfo != NULL);
4949
0
    Assert(val_string != NULL);
4950
0
    fcinfo->args[0].value = PointerGetDatum(val_string);
4951
0
    fcinfo->args[0].isnull = *op->resnull;
4952
4953
    /*
4954
     * Second and third arguments are already set up in
4955
     * ExecInitJsonExpr().
4956
     */
4957
4958
0
    fcinfo->isnull = false;
4959
0
    *op->resvalue = FunctionCallInvoke(fcinfo);
4960
0
    if (SOFT_ERROR_OCCURRED(&jsestate->escontext))
4961
0
      error = true;
4962
0
  }
4963
4964
  /*
4965
   * When setting up the ErrorSaveContext (if needed) for capturing the
4966
   * errors that occur when coercing the JsonBehavior expression, set
4967
   * details_wanted to be able to show the actual error message as the
4968
   * DETAIL of the error message that tells that it is the JsonBehavior
4969
   * expression that caused the error; see ExecEvalJsonCoercionFinish().
4970
   */
4971
4972
  /* Handle ON EMPTY. */
4973
0
  if (empty)
4974
0
  {
4975
0
    *op->resvalue = (Datum) 0;
4976
0
    *op->resnull = true;
4977
0
    if (jsexpr->on_empty)
4978
0
    {
4979
0
      if (jsexpr->on_empty->btype != JSON_BEHAVIOR_ERROR)
4980
0
      {
4981
0
        jsestate->empty.value = BoolGetDatum(true);
4982
        /* Set up to catch coercion errors of the ON EMPTY value. */
4983
0
        jsestate->escontext.error_occurred = false;
4984
0
        jsestate->escontext.details_wanted = true;
4985
        /* Jump to end if the ON EMPTY behavior is to return NULL */
4986
0
        return jsestate->jump_empty >= 0 ? jsestate->jump_empty : jsestate->jump_end;
4987
0
      }
4988
0
    }
4989
0
    else if (jsexpr->on_error->btype != JSON_BEHAVIOR_ERROR)
4990
0
    {
4991
0
      jsestate->error.value = BoolGetDatum(true);
4992
      /* Set up to catch coercion errors of the ON ERROR value. */
4993
0
      jsestate->escontext.error_occurred = false;
4994
0
      jsestate->escontext.details_wanted = true;
4995
0
      Assert(!throw_error);
4996
      /* Jump to end if the ON ERROR behavior is to return NULL */
4997
0
      return jsestate->jump_error >= 0 ? jsestate->jump_error : jsestate->jump_end;
4998
0
    }
4999
5000
0
    if (jsexpr->column_name)
5001
0
      ereport(ERROR,
5002
0
          errcode(ERRCODE_NO_SQL_JSON_ITEM),
5003
0
          errmsg("no SQL/JSON item found for specified path of column \"%s\"",
5004
0
               jsexpr->column_name));
5005
0
    else
5006
0
      ereport(ERROR,
5007
0
          errcode(ERRCODE_NO_SQL_JSON_ITEM),
5008
0
          errmsg("no SQL/JSON item found for specified path"));
5009
0
  }
5010
5011
  /*
5012
   * ON ERROR. Wouldn't get here if the behavior is ERROR, because they
5013
   * would have already been thrown.
5014
   */
5015
0
  if (error)
5016
0
  {
5017
0
    Assert(!throw_error);
5018
0
    *op->resvalue = (Datum) 0;
5019
0
    *op->resnull = true;
5020
0
    jsestate->error.value = BoolGetDatum(true);
5021
    /* Set up to catch coercion errors of the ON ERROR value. */
5022
0
    jsestate->escontext.error_occurred = false;
5023
0
    jsestate->escontext.details_wanted = true;
5024
    /* Jump to end if the ON ERROR behavior is to return NULL */
5025
0
    return jsestate->jump_error >= 0 ? jsestate->jump_error : jsestate->jump_end;
5026
0
  }
5027
5028
0
  return jump_eval_coercion >= 0 ? jump_eval_coercion : jsestate->jump_end;
5029
0
}
5030
5031
/*
5032
 * Convert the given JsonbValue to its C string representation
5033
 *
5034
 * *resnull is set if the JsonbValue is a jbvNull.
5035
 */
5036
static char *
5037
ExecGetJsonValueItemString(JsonbValue *item, bool *resnull)
5038
0
{
5039
0
  *resnull = false;
5040
5041
  /* get coercion state reference and datum of the corresponding SQL type */
5042
0
  switch (item->type)
5043
0
  {
5044
0
    case jbvNull:
5045
0
      *resnull = true;
5046
0
      return NULL;
5047
5048
0
    case jbvString:
5049
0
      {
5050
0
        char     *str = palloc(item->val.string.len + 1);
5051
5052
0
        memcpy(str, item->val.string.val, item->val.string.len);
5053
0
        str[item->val.string.len] = '\0';
5054
0
        return str;
5055
0
      }
5056
5057
0
    case jbvNumeric:
5058
0
      return DatumGetCString(DirectFunctionCall1(numeric_out,
5059
0
                             NumericGetDatum(item->val.numeric)));
5060
5061
0
    case jbvBool:
5062
0
      return DatumGetCString(DirectFunctionCall1(boolout,
5063
0
                             BoolGetDatum(item->val.boolean)));
5064
5065
0
    case jbvDatetime:
5066
0
      switch (item->val.datetime.typid)
5067
0
      {
5068
0
        case DATEOID:
5069
0
          return DatumGetCString(DirectFunctionCall1(date_out,
5070
0
                                 item->val.datetime.value));
5071
0
        case TIMEOID:
5072
0
          return DatumGetCString(DirectFunctionCall1(time_out,
5073
0
                                 item->val.datetime.value));
5074
0
        case TIMETZOID:
5075
0
          return DatumGetCString(DirectFunctionCall1(timetz_out,
5076
0
                                 item->val.datetime.value));
5077
0
        case TIMESTAMPOID:
5078
0
          return DatumGetCString(DirectFunctionCall1(timestamp_out,
5079
0
                                 item->val.datetime.value));
5080
0
        case TIMESTAMPTZOID:
5081
0
          return DatumGetCString(DirectFunctionCall1(timestamptz_out,
5082
0
                                 item->val.datetime.value));
5083
0
        default:
5084
0
          elog(ERROR, "unexpected jsonb datetime type oid %u",
5085
0
             item->val.datetime.typid);
5086
0
      }
5087
0
      break;
5088
5089
0
    case jbvArray:
5090
0
    case jbvObject:
5091
0
    case jbvBinary:
5092
0
      return DatumGetCString(DirectFunctionCall1(jsonb_out,
5093
0
                             JsonbPGetDatum(JsonbValueToJsonb(item))));
5094
5095
0
    default:
5096
0
      elog(ERROR, "unexpected jsonb value type %d", item->type);
5097
0
  }
5098
5099
0
  Assert(false);
5100
0
  *resnull = true;
5101
0
  return NULL;
5102
0
}
5103
5104
/*
5105
 * Coerce a jsonb value produced by ExecEvalJsonExprPath() or an ON ERROR /
5106
 * ON EMPTY behavior expression to the target type.
5107
 *
5108
 * Any soft errors that occur here will be checked by
5109
 * EEOP_JSONEXPR_COERCION_FINISH that will run after this.
5110
 */
5111
void
5112
ExecEvalJsonCoercion(ExprState *state, ExprEvalStep *op,
5113
           ExprContext *econtext)
5114
0
{
5115
0
  ErrorSaveContext *escontext = op->d.jsonexpr_coercion.escontext;
5116
5117
  /*
5118
   * Prepare to call json_populate_type() to coerce the boolean result of
5119
   * JSON_EXISTS_OP to the target type.  If the target type is integer or a
5120
   * domain over integer, call the boolean-to-integer cast function instead,
5121
   * because the integer's input function (which is what
5122
   * json_populate_type() calls to coerce to scalar target types) doesn't
5123
   * accept boolean literals as valid input.  We only have a special case
5124
   * for integer and domains thereof as it seems common to use those types
5125
   * for EXISTS columns in JSON_TABLE().
5126
   */
5127
0
  if (op->d.jsonexpr_coercion.exists_coerce)
5128
0
  {
5129
0
    if (op->d.jsonexpr_coercion.exists_cast_to_int)
5130
0
    {
5131
      /* Check domain constraints if any. */
5132
0
      if (op->d.jsonexpr_coercion.exists_check_domain &&
5133
0
        !domain_check_safe(*op->resvalue, *op->resnull,
5134
0
                   op->d.jsonexpr_coercion.targettype,
5135
0
                   &op->d.jsonexpr_coercion.json_coercion_cache,
5136
0
                   econtext->ecxt_per_query_memory,
5137
0
                   (Node *) escontext))
5138
0
      {
5139
0
        *op->resnull = true;
5140
0
        *op->resvalue = (Datum) 0;
5141
0
      }
5142
0
      else
5143
0
        *op->resvalue = DirectFunctionCall1(bool_int4, *op->resvalue);
5144
0
      return;
5145
0
    }
5146
5147
0
    *op->resvalue = DirectFunctionCall1(jsonb_in,
5148
0
                      DatumGetBool(*op->resvalue) ?
5149
0
                      CStringGetDatum("true") :
5150
0
                      CStringGetDatum("false"));
5151
0
  }
5152
5153
0
  *op->resvalue = json_populate_type(*op->resvalue, JSONBOID,
5154
0
                     op->d.jsonexpr_coercion.targettype,
5155
0
                     op->d.jsonexpr_coercion.targettypmod,
5156
0
                     &op->d.jsonexpr_coercion.json_coercion_cache,
5157
0
                     econtext->ecxt_per_query_memory,
5158
0
                     op->resnull,
5159
0
                     op->d.jsonexpr_coercion.omit_quotes,
5160
0
                     (Node *) escontext);
5161
0
}
5162
5163
static char *
5164
GetJsonBehaviorValueString(JsonBehavior *behavior)
5165
0
{
5166
  /*
5167
   * The order of array elements must correspond to the order of
5168
   * JsonBehaviorType members.
5169
   */
5170
0
  const char *behavior_names[] =
5171
0
  {
5172
0
    "NULL",
5173
0
    "ERROR",
5174
0
    "EMPTY",
5175
0
    "TRUE",
5176
0
    "FALSE",
5177
0
    "UNKNOWN",
5178
0
    "EMPTY ARRAY",
5179
0
    "EMPTY OBJECT",
5180
0
    "DEFAULT"
5181
0
  };
5182
5183
0
  return pstrdup(behavior_names[behavior->btype]);
5184
0
}
5185
5186
/*
5187
 * Checks if an error occurred in ExecEvalJsonCoercion().  If so, this sets
5188
 * JsonExprState.error to trigger the ON ERROR handling steps, unless the
5189
 * error is thrown when coercing a JsonBehavior value.
5190
 */
5191
void
5192
ExecEvalJsonCoercionFinish(ExprState *state, ExprEvalStep *op)
5193
0
{
5194
0
  JsonExprState *jsestate = op->d.jsonexpr.jsestate;
5195
5196
0
  if (SOFT_ERROR_OCCURRED(&jsestate->escontext))
5197
0
  {
5198
    /*
5199
     * jsestate->error or jsestate->empty being set means that the error
5200
     * occurred when coercing the JsonBehavior value.  Throw the error in
5201
     * that case with the actual coercion error message shown in the
5202
     * DETAIL part.
5203
     */
5204
0
    if (DatumGetBool(jsestate->error.value))
5205
0
      ereport(ERROR,
5206
0
          (errcode(ERRCODE_DATATYPE_MISMATCH),
5207
      /*- translator: first %s is a SQL/JSON clause (e.g. ON ERROR) */
5208
0
           errmsg("could not coerce %s expression (%s) to the RETURNING type",
5209
0
              "ON ERROR",
5210
0
              GetJsonBehaviorValueString(jsestate->jsexpr->on_error)),
5211
0
           errdetail("%s", jsestate->escontext.error_data->message)));
5212
0
    else if (DatumGetBool(jsestate->empty.value))
5213
0
      ereport(ERROR,
5214
0
          (errcode(ERRCODE_DATATYPE_MISMATCH),
5215
      /*- translator: first %s is a SQL/JSON clause (e.g. ON ERROR) */
5216
0
           errmsg("could not coerce %s expression (%s) to the RETURNING type",
5217
0
              "ON EMPTY",
5218
0
              GetJsonBehaviorValueString(jsestate->jsexpr->on_empty)),
5219
0
           errdetail("%s", jsestate->escontext.error_data->message)));
5220
5221
0
    *op->resvalue = (Datum) 0;
5222
0
    *op->resnull = true;
5223
5224
0
    jsestate->error.value = BoolGetDatum(true);
5225
5226
    /*
5227
     * Reset for next use such as for catching errors when coercing a
5228
     * JsonBehavior expression.
5229
     */
5230
0
    jsestate->escontext.error_occurred = false;
5231
0
    jsestate->escontext.details_wanted = true;
5232
0
  }
5233
0
}
5234
5235
/*
5236
 * ExecEvalGroupingFunc
5237
 *
5238
 * Computes a bitmask with a bit for each (unevaluated) argument expression
5239
 * (rightmost arg is least significant bit).
5240
 *
5241
 * A bit is set if the corresponding expression is NOT part of the set of
5242
 * grouping expressions in the current grouping set.
5243
 */
5244
void
5245
ExecEvalGroupingFunc(ExprState *state, ExprEvalStep *op)
5246
0
{
5247
0
  AggState   *aggstate = castNode(AggState, state->parent);
5248
0
  int     result = 0;
5249
0
  Bitmapset  *grouped_cols = aggstate->grouped_cols;
5250
0
  ListCell   *lc;
5251
5252
0
  foreach(lc, op->d.grouping_func.clauses)
5253
0
  {
5254
0
    int     attnum = lfirst_int(lc);
5255
5256
0
    result <<= 1;
5257
5258
0
    if (!bms_is_member(attnum, grouped_cols))
5259
0
      result |= 1;
5260
0
  }
5261
5262
0
  *op->resvalue = Int32GetDatum(result);
5263
0
  *op->resnull = false;
5264
0
}
5265
5266
/*
5267
 * ExecEvalMergeSupportFunc
5268
 *
5269
 * Returns information about the current MERGE action for its RETURNING list.
5270
 */
5271
void
5272
ExecEvalMergeSupportFunc(ExprState *state, ExprEvalStep *op,
5273
             ExprContext *econtext)
5274
0
{
5275
0
  ModifyTableState *mtstate = castNode(ModifyTableState, state->parent);
5276
0
  MergeActionState *relaction = mtstate->mt_merge_action;
5277
5278
0
  if (!relaction)
5279
0
    elog(ERROR, "no merge action in progress");
5280
5281
  /* Return the MERGE action ("INSERT", "UPDATE", or "DELETE") */
5282
0
  switch (relaction->mas_action->commandType)
5283
0
  {
5284
0
    case CMD_INSERT:
5285
0
      *op->resvalue = PointerGetDatum(cstring_to_text_with_len("INSERT", 6));
5286
0
      *op->resnull = false;
5287
0
      break;
5288
0
    case CMD_UPDATE:
5289
0
      *op->resvalue = PointerGetDatum(cstring_to_text_with_len("UPDATE", 6));
5290
0
      *op->resnull = false;
5291
0
      break;
5292
0
    case CMD_DELETE:
5293
0
      *op->resvalue = PointerGetDatum(cstring_to_text_with_len("DELETE", 6));
5294
0
      *op->resnull = false;
5295
0
      break;
5296
0
    case CMD_NOTHING:
5297
0
      elog(ERROR, "unexpected merge action: DO NOTHING");
5298
0
      break;
5299
0
    default:
5300
0
      elog(ERROR, "unrecognized commandType: %d",
5301
0
         (int) relaction->mas_action->commandType);
5302
0
  }
5303
0
}
5304
5305
/*
5306
 * Hand off evaluation of a subplan to nodeSubplan.c
5307
 */
5308
void
5309
ExecEvalSubPlan(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
5310
0
{
5311
0
  SubPlanState *sstate = op->d.subplan.sstate;
5312
5313
  /* could potentially be nested, so make sure there's enough stack */
5314
0
  check_stack_depth();
5315
5316
0
  *op->resvalue = ExecSubPlan(sstate, econtext, op->resnull);
5317
0
}
5318
5319
/*
5320
 * Evaluate a wholerow Var expression.
5321
 *
5322
 * Returns a Datum whose value is the value of a whole-row range variable
5323
 * with respect to given expression context.
5324
 */
5325
void
5326
ExecEvalWholeRowVar(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
5327
0
{
5328
0
  Var      *variable = op->d.wholerow.var;
5329
0
  TupleTableSlot *slot = NULL;
5330
0
  TupleDesc output_tupdesc;
5331
0
  MemoryContext oldcontext;
5332
0
  HeapTupleHeader dtuple;
5333
0
  HeapTuple tuple;
5334
5335
  /* This was checked by ExecInitExpr */
5336
0
  Assert(variable->varattno == InvalidAttrNumber);
5337
5338
  /* Get the input slot we want */
5339
0
  switch (variable->varno)
5340
0
  {
5341
0
    case INNER_VAR:
5342
      /* get the tuple from the inner node */
5343
0
      slot = econtext->ecxt_innertuple;
5344
0
      break;
5345
5346
0
    case OUTER_VAR:
5347
      /* get the tuple from the outer node */
5348
0
      slot = econtext->ecxt_outertuple;
5349
0
      break;
5350
5351
      /* INDEX_VAR is handled by default case */
5352
5353
0
    default:
5354
5355
      /*
5356
       * Get the tuple from the relation being scanned.
5357
       *
5358
       * By default, this uses the "scan" tuple slot, but a wholerow Var
5359
       * in the RETURNING list may explicitly refer to OLD/NEW.  If the
5360
       * OLD/NEW row doesn't exist, we just return NULL.
5361
       */
5362
0
      switch (variable->varreturningtype)
5363
0
      {
5364
0
        case VAR_RETURNING_DEFAULT:
5365
0
          slot = econtext->ecxt_scantuple;
5366
0
          break;
5367
5368
0
        case VAR_RETURNING_OLD:
5369
0
          if (state->flags & EEO_FLAG_OLD_IS_NULL)
5370
0
          {
5371
0
            *op->resvalue = (Datum) 0;
5372
0
            *op->resnull = true;
5373
0
            return;
5374
0
          }
5375
0
          slot = econtext->ecxt_oldtuple;
5376
0
          break;
5377
5378
0
        case VAR_RETURNING_NEW:
5379
0
          if (state->flags & EEO_FLAG_NEW_IS_NULL)
5380
0
          {
5381
0
            *op->resvalue = (Datum) 0;
5382
0
            *op->resnull = true;
5383
0
            return;
5384
0
          }
5385
0
          slot = econtext->ecxt_newtuple;
5386
0
          break;
5387
0
      }
5388
0
      break;
5389
0
  }
5390
5391
  /* Apply the junkfilter if any */
5392
0
  if (op->d.wholerow.junkFilter != NULL)
5393
0
    slot = ExecFilterJunk(op->d.wholerow.junkFilter, slot);
5394
5395
  /*
5396
   * If first time through, obtain tuple descriptor and check compatibility.
5397
   *
5398
   * XXX: It'd be great if this could be moved to the expression
5399
   * initialization phase, but due to using slots that's currently not
5400
   * feasible.
5401
   */
5402
0
  if (op->d.wholerow.first)
5403
0
  {
5404
    /* optimistically assume we don't need slow path */
5405
0
    op->d.wholerow.slow = false;
5406
5407
    /*
5408
     * If the Var identifies a named composite type, we must check that
5409
     * the actual tuple type is compatible with it.
5410
     */
5411
0
    if (variable->vartype != RECORDOID)
5412
0
    {
5413
0
      TupleDesc var_tupdesc;
5414
0
      TupleDesc slot_tupdesc;
5415
5416
      /*
5417
       * We really only care about numbers of attributes and data types.
5418
       * Also, we can ignore type mismatch on columns that are dropped
5419
       * in the destination type, so long as (1) the physical storage
5420
       * matches or (2) the actual column value is NULL.  Case (1) is
5421
       * helpful in some cases involving out-of-date cached plans, while
5422
       * case (2) is expected behavior in situations such as an INSERT
5423
       * into a table with dropped columns (the planner typically
5424
       * generates an INT4 NULL regardless of the dropped column type).
5425
       * If we find a dropped column and cannot verify that case (1)
5426
       * holds, we have to use the slow path to check (2) for each row.
5427
       *
5428
       * If vartype is a domain over composite, just look through that
5429
       * to the base composite type.
5430
       */
5431
0
      var_tupdesc = lookup_rowtype_tupdesc_domain(variable->vartype,
5432
0
                            -1, false);
5433
5434
0
      slot_tupdesc = slot->tts_tupleDescriptor;
5435
5436
0
      if (var_tupdesc->natts != slot_tupdesc->natts)
5437
0
        ereport(ERROR,
5438
0
            (errcode(ERRCODE_DATATYPE_MISMATCH),
5439
0
             errmsg("table row type and query-specified row type do not match"),
5440
0
             errdetail_plural("Table row contains %d attribute, but query expects %d.",
5441
0
                      "Table row contains %d attributes, but query expects %d.",
5442
0
                      slot_tupdesc->natts,
5443
0
                      slot_tupdesc->natts,
5444
0
                      var_tupdesc->natts)));
5445
5446
0
      for (int i = 0; i < var_tupdesc->natts; i++)
5447
0
      {
5448
0
        Form_pg_attribute vattr = TupleDescAttr(var_tupdesc, i);
5449
0
        Form_pg_attribute sattr = TupleDescAttr(slot_tupdesc, i);
5450
5451
0
        if (vattr->atttypid == sattr->atttypid)
5452
0
          continue; /* no worries */
5453
0
        if (!vattr->attisdropped)
5454
0
          ereport(ERROR,
5455
0
              (errcode(ERRCODE_DATATYPE_MISMATCH),
5456
0
               errmsg("table row type and query-specified row type do not match"),
5457
0
               errdetail("Table has type %s at ordinal position %d, but query expects %s.",
5458
0
                     format_type_be(sattr->atttypid),
5459
0
                     i + 1,
5460
0
                     format_type_be(vattr->atttypid))));
5461
5462
0
        if (vattr->attlen != sattr->attlen ||
5463
0
          vattr->attalign != sattr->attalign)
5464
0
          op->d.wholerow.slow = true; /* need to check for nulls */
5465
0
      }
5466
5467
      /*
5468
       * Use the variable's declared rowtype as the descriptor for the
5469
       * output values.  In particular, we *must* absorb any
5470
       * attisdropped markings.
5471
       */
5472
0
      oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
5473
0
      output_tupdesc = CreateTupleDescCopy(var_tupdesc);
5474
0
      MemoryContextSwitchTo(oldcontext);
5475
5476
0
      ReleaseTupleDesc(var_tupdesc);
5477
0
    }
5478
0
    else
5479
0
    {
5480
      /*
5481
       * In the RECORD case, we use the input slot's rowtype as the
5482
       * descriptor for the output values, modulo possibly assigning new
5483
       * column names below.
5484
       */
5485
0
      oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
5486
0
      output_tupdesc = CreateTupleDescCopy(slot->tts_tupleDescriptor);
5487
0
      MemoryContextSwitchTo(oldcontext);
5488
5489
      /*
5490
       * It's possible that the input slot is a relation scan slot and
5491
       * so is marked with that relation's rowtype.  But we're supposed
5492
       * to be returning RECORD, so reset to that.
5493
       */
5494
0
      output_tupdesc->tdtypeid = RECORDOID;
5495
0
      output_tupdesc->tdtypmod = -1;
5496
5497
      /*
5498
       * We already got the correct physical datatype info above, but
5499
       * now we should try to find the source RTE and adopt its column
5500
       * aliases, since it's unlikely that the input slot has the
5501
       * desired names.
5502
       *
5503
       * If we can't locate the RTE, assume the column names we've got
5504
       * are OK.  (As of this writing, the only cases where we can't
5505
       * locate the RTE are in execution of trigger WHEN clauses, and
5506
       * then the Var will have the trigger's relation's rowtype, so its
5507
       * names are fine.)  Also, if the creator of the RTE didn't bother
5508
       * to fill in an eref field, assume our column names are OK. (This
5509
       * happens in COPY, and perhaps other places.)
5510
       */
5511
0
      if (econtext->ecxt_estate &&
5512
0
        variable->varno <= econtext->ecxt_estate->es_range_table_size)
5513
0
      {
5514
0
        RangeTblEntry *rte = exec_rt_fetch(variable->varno,
5515
0
                           econtext->ecxt_estate);
5516
5517
0
        if (rte->eref)
5518
0
          ExecTypeSetColNames(output_tupdesc, rte->eref->colnames);
5519
0
      }
5520
0
    }
5521
5522
    /* Bless the tupdesc if needed, and save it in the execution state */
5523
0
    op->d.wholerow.tupdesc = BlessTupleDesc(output_tupdesc);
5524
5525
0
    op->d.wholerow.first = false;
5526
0
  }
5527
5528
  /*
5529
   * Make sure all columns of the slot are accessible in the slot's
5530
   * Datum/isnull arrays.
5531
   */
5532
0
  slot_getallattrs(slot);
5533
5534
0
  if (op->d.wholerow.slow)
5535
0
  {
5536
    /* Check to see if any dropped attributes are non-null */
5537
0
    TupleDesc tupleDesc = slot->tts_tupleDescriptor;
5538
0
    TupleDesc var_tupdesc = op->d.wholerow.tupdesc;
5539
5540
0
    Assert(var_tupdesc->natts == tupleDesc->natts);
5541
5542
0
    for (int i = 0; i < var_tupdesc->natts; i++)
5543
0
    {
5544
0
      CompactAttribute *vattr = TupleDescCompactAttr(var_tupdesc, i);
5545
0
      CompactAttribute *sattr = TupleDescCompactAttr(tupleDesc, i);
5546
5547
0
      if (!vattr->attisdropped)
5548
0
        continue;   /* already checked non-dropped cols */
5549
0
      if (slot->tts_isnull[i])
5550
0
        continue;   /* null is always okay */
5551
0
      if (vattr->attlen != sattr->attlen ||
5552
0
        vattr->attalignby != sattr->attalignby)
5553
0
        ereport(ERROR,
5554
0
            (errcode(ERRCODE_DATATYPE_MISMATCH),
5555
0
             errmsg("table row type and query-specified row type do not match"),
5556
0
             errdetail("Physical storage mismatch on dropped attribute at ordinal position %d.",
5557
0
                   i + 1)));
5558
0
    }
5559
0
  }
5560
5561
  /*
5562
   * Build a composite datum, making sure any toasted fields get detoasted.
5563
   *
5564
   * (Note: it is critical that we not change the slot's state here.)
5565
   */
5566
0
  tuple = toast_build_flattened_tuple(slot->tts_tupleDescriptor,
5567
0
                    slot->tts_values,
5568
0
                    slot->tts_isnull);
5569
0
  dtuple = tuple->t_data;
5570
5571
  /*
5572
   * Label the datum with the composite type info we identified before.
5573
   *
5574
   * (Note: we could skip doing this by passing op->d.wholerow.tupdesc to
5575
   * the tuple build step; but that seems a tad risky so let's not.)
5576
   */
5577
0
  HeapTupleHeaderSetTypeId(dtuple, op->d.wholerow.tupdesc->tdtypeid);
5578
0
  HeapTupleHeaderSetTypMod(dtuple, op->d.wholerow.tupdesc->tdtypmod);
5579
5580
0
  *op->resvalue = PointerGetDatum(dtuple);
5581
0
  *op->resnull = false;
5582
0
}
5583
5584
void
5585
ExecEvalSysVar(ExprState *state, ExprEvalStep *op, ExprContext *econtext,
5586
         TupleTableSlot *slot)
5587
0
{
5588
0
  Datum   d;
5589
5590
  /* OLD/NEW system attribute is NULL if OLD/NEW row is NULL */
5591
0
  if ((op->d.var.varreturningtype == VAR_RETURNING_OLD &&
5592
0
     state->flags & EEO_FLAG_OLD_IS_NULL) ||
5593
0
    (op->d.var.varreturningtype == VAR_RETURNING_NEW &&
5594
0
     state->flags & EEO_FLAG_NEW_IS_NULL))
5595
0
  {
5596
0
    *op->resvalue = (Datum) 0;
5597
0
    *op->resnull = true;
5598
0
    return;
5599
0
  }
5600
5601
  /* slot_getsysattr has sufficient defenses against bad attnums */
5602
0
  d = slot_getsysattr(slot,
5603
0
            op->d.var.attnum,
5604
0
            op->resnull);
5605
0
  *op->resvalue = d;
5606
  /* this ought to be unreachable, but it's cheap enough to check */
5607
0
  if (unlikely(*op->resnull))
5608
0
    elog(ERROR, "failed to fetch attribute from slot");
5609
0
}
5610
5611
/*
5612
 * Transition value has not been initialized. This is the first non-NULL input
5613
 * value for a group. We use it as the initial value for transValue.
5614
 */
5615
void
5616
ExecAggInitGroup(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroup,
5617
         ExprContext *aggcontext)
5618
0
{
5619
0
  FunctionCallInfo fcinfo = pertrans->transfn_fcinfo;
5620
0
  MemoryContext oldContext;
5621
5622
  /*
5623
   * We must copy the datum into aggcontext if it is pass-by-ref. We do not
5624
   * need to pfree the old transValue, since it's NULL.  (We already checked
5625
   * that the agg's input type is binary-compatible with its transtype, so
5626
   * straight copy here is OK.)
5627
   */
5628
0
  oldContext = MemoryContextSwitchTo(aggcontext->ecxt_per_tuple_memory);
5629
0
  pergroup->transValue = datumCopy(fcinfo->args[1].value,
5630
0
                   pertrans->transtypeByVal,
5631
0
                   pertrans->transtypeLen);
5632
0
  pergroup->transValueIsNull = false;
5633
0
  pergroup->noTransValue = false;
5634
0
  MemoryContextSwitchTo(oldContext);
5635
0
}
5636
5637
/*
5638
 * Ensure that the new transition value is stored in the aggcontext,
5639
 * rather than the per-tuple context.  This should be invoked only when
5640
 * we know (a) the transition data type is pass-by-reference, and (b)
5641
 * the newValue is distinct from the oldValue.
5642
 *
5643
 * NB: This can change the current memory context.
5644
 *
5645
 * We copy the presented newValue into the aggcontext, except when the datum
5646
 * points to a R/W expanded object that is already a child of the aggcontext,
5647
 * in which case we need not copy.  We then delete the oldValue, if not null.
5648
 *
5649
 * If the presented datum points to a R/W expanded object that is a child of
5650
 * some other context, ideally we would just reparent it under the aggcontext.
5651
 * Unfortunately, that doesn't work easily, and it wouldn't help anyway for
5652
 * aggregate-aware transfns.  We expect that a transfn that deals in expanded
5653
 * objects and is aware of the memory management conventions for aggregate
5654
 * transition values will (1) on first call, return a R/W expanded object that
5655
 * is already in the right context, allowing us to do nothing here, and (2) on
5656
 * subsequent calls, modify and return that same object, so that control
5657
 * doesn't even reach here.  However, if we have a generic transfn that
5658
 * returns a new R/W expanded object (probably in the per-tuple context),
5659
 * reparenting that result would cause problems.  We'd pass that R/W object to
5660
 * the next invocation of the transfn, and then it would be at liberty to
5661
 * change or delete that object, and if it deletes it then our own attempt to
5662
 * delete the now-old transvalue afterwards would be a double free.  We avoid
5663
 * this problem by forcing the stored transvalue to always be a flat
5664
 * non-expanded object unless the transfn is visibly doing aggregate-aware
5665
 * memory management.  This is somewhat inefficient, but the best answer to
5666
 * that is to write a smarter transfn.
5667
 */
5668
Datum
5669
ExecAggCopyTransValue(AggState *aggstate, AggStatePerTrans pertrans,
5670
            Datum newValue, bool newValueIsNull,
5671
            Datum oldValue, bool oldValueIsNull)
5672
0
{
5673
0
  Assert(newValue != oldValue);
5674
5675
0
  if (!newValueIsNull)
5676
0
  {
5677
0
    MemoryContextSwitchTo(aggstate->curaggcontext->ecxt_per_tuple_memory);
5678
0
    if (DatumIsReadWriteExpandedObject(newValue,
5679
0
                       false,
5680
0
                       pertrans->transtypeLen) &&
5681
0
      MemoryContextGetParent(DatumGetEOHP(newValue)->eoh_context) == CurrentMemoryContext)
5682
0
       /* do nothing */ ;
5683
0
    else
5684
0
      newValue = datumCopy(newValue,
5685
0
                 pertrans->transtypeByVal,
5686
0
                 pertrans->transtypeLen);
5687
0
  }
5688
0
  else
5689
0
  {
5690
    /*
5691
     * Ensure that AggStatePerGroup->transValue ends up being 0, so
5692
     * callers can safely compare newValue/oldValue without having to
5693
     * check their respective nullness.
5694
     */
5695
0
    newValue = (Datum) 0;
5696
0
  }
5697
5698
0
  if (!oldValueIsNull)
5699
0
  {
5700
0
    if (DatumIsReadWriteExpandedObject(oldValue,
5701
0
                       false,
5702
0
                       pertrans->transtypeLen))
5703
0
      DeleteExpandedObject(oldValue);
5704
0
    else
5705
0
      pfree(DatumGetPointer(oldValue));
5706
0
  }
5707
5708
0
  return newValue;
5709
0
}
5710
5711
/*
5712
 * ExecEvalPreOrderedDistinctSingle
5713
 *    Returns true when the aggregate transition value Datum is distinct
5714
 *    from the previous input Datum and returns false when the input Datum
5715
 *    matches the previous input Datum.
5716
 */
5717
bool
5718
ExecEvalPreOrderedDistinctSingle(AggState *aggstate, AggStatePerTrans pertrans)
5719
0
{
5720
0
  Datum   value = pertrans->transfn_fcinfo->args[1].value;
5721
0
  bool    isnull = pertrans->transfn_fcinfo->args[1].isnull;
5722
5723
0
  if (!pertrans->haslast ||
5724
0
    pertrans->lastisnull != isnull ||
5725
0
    (!isnull && !DatumGetBool(FunctionCall2Coll(&pertrans->equalfnOne,
5726
0
                          pertrans->aggCollation,
5727
0
                          pertrans->lastdatum, value))))
5728
0
  {
5729
0
    if (pertrans->haslast && !pertrans->inputtypeByVal &&
5730
0
      !pertrans->lastisnull)
5731
0
      pfree(DatumGetPointer(pertrans->lastdatum));
5732
5733
0
    pertrans->haslast = true;
5734
0
    if (!isnull)
5735
0
    {
5736
0
      MemoryContext oldContext;
5737
5738
0
      oldContext = MemoryContextSwitchTo(aggstate->curaggcontext->ecxt_per_tuple_memory);
5739
5740
0
      pertrans->lastdatum = datumCopy(value, pertrans->inputtypeByVal,
5741
0
                      pertrans->inputtypeLen);
5742
5743
0
      MemoryContextSwitchTo(oldContext);
5744
0
    }
5745
0
    else
5746
0
      pertrans->lastdatum = (Datum) 0;
5747
0
    pertrans->lastisnull = isnull;
5748
0
    return true;
5749
0
  }
5750
5751
0
  return false;
5752
0
}
5753
5754
/*
5755
 * ExecEvalPreOrderedDistinctMulti
5756
 *    Returns true when the aggregate input is distinct from the previous
5757
 *    input and returns false when the input matches the previous input, or
5758
 *    when there was no previous input.
5759
 */
5760
bool
5761
ExecEvalPreOrderedDistinctMulti(AggState *aggstate, AggStatePerTrans pertrans)
5762
0
{
5763
0
  ExprContext *tmpcontext = aggstate->tmpcontext;
5764
0
  bool    isdistinct = false; /* for now */
5765
0
  TupleTableSlot *save_outer;
5766
0
  TupleTableSlot *save_inner;
5767
5768
0
  for (int i = 0; i < pertrans->numTransInputs; i++)
5769
0
  {
5770
0
    pertrans->sortslot->tts_values[i] = pertrans->transfn_fcinfo->args[i + 1].value;
5771
0
    pertrans->sortslot->tts_isnull[i] = pertrans->transfn_fcinfo->args[i + 1].isnull;
5772
0
  }
5773
5774
0
  ExecClearTuple(pertrans->sortslot);
5775
0
  pertrans->sortslot->tts_nvalid = pertrans->numInputs;
5776
0
  ExecStoreVirtualTuple(pertrans->sortslot);
5777
5778
  /* save the previous slots before we overwrite them */
5779
0
  save_outer = tmpcontext->ecxt_outertuple;
5780
0
  save_inner = tmpcontext->ecxt_innertuple;
5781
5782
0
  tmpcontext->ecxt_outertuple = pertrans->sortslot;
5783
0
  tmpcontext->ecxt_innertuple = pertrans->uniqslot;
5784
5785
0
  if (!pertrans->haslast ||
5786
0
    !ExecQual(pertrans->equalfnMulti, tmpcontext))
5787
0
  {
5788
0
    if (pertrans->haslast)
5789
0
      ExecClearTuple(pertrans->uniqslot);
5790
5791
0
    pertrans->haslast = true;
5792
0
    ExecCopySlot(pertrans->uniqslot, pertrans->sortslot);
5793
5794
0
    isdistinct = true;
5795
0
  }
5796
5797
  /* restore the original slots */
5798
0
  tmpcontext->ecxt_outertuple = save_outer;
5799
0
  tmpcontext->ecxt_innertuple = save_inner;
5800
5801
0
  return isdistinct;
5802
0
}
5803
5804
/*
5805
 * Invoke ordered transition function, with a datum argument.
5806
 */
5807
void
5808
ExecEvalAggOrderedTransDatum(ExprState *state, ExprEvalStep *op,
5809
               ExprContext *econtext)
5810
0
{
5811
0
  AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
5812
0
  int     setno = op->d.agg_trans.setno;
5813
5814
0
  tuplesort_putdatum(pertrans->sortstates[setno],
5815
0
             *op->resvalue, *op->resnull);
5816
0
}
5817
5818
/*
5819
 * Invoke ordered transition function, with a tuple argument.
5820
 */
5821
void
5822
ExecEvalAggOrderedTransTuple(ExprState *state, ExprEvalStep *op,
5823
               ExprContext *econtext)
5824
0
{
5825
0
  AggStatePerTrans pertrans = op->d.agg_trans.pertrans;
5826
0
  int     setno = op->d.agg_trans.setno;
5827
5828
0
  ExecClearTuple(pertrans->sortslot);
5829
0
  pertrans->sortslot->tts_nvalid = pertrans->numInputs;
5830
0
  ExecStoreVirtualTuple(pertrans->sortslot);
5831
0
  tuplesort_puttupleslot(pertrans->sortstates[setno], pertrans->sortslot);
5832
0
}
5833
5834
/* implementation of transition function invocation for byval types */
5835
static pg_attribute_always_inline void
5836
ExecAggPlainTransByVal(AggState *aggstate, AggStatePerTrans pertrans,
5837
             AggStatePerGroup pergroup,
5838
             ExprContext *aggcontext, int setno)
5839
0
{
5840
0
  FunctionCallInfo fcinfo = pertrans->transfn_fcinfo;
5841
0
  MemoryContext oldContext;
5842
0
  Datum   newVal;
5843
5844
  /* cf. select_current_set() */
5845
0
  aggstate->curaggcontext = aggcontext;
5846
0
  aggstate->current_set = setno;
5847
5848
  /* set up aggstate->curpertrans for AggGetAggref() */
5849
0
  aggstate->curpertrans = pertrans;
5850
5851
  /* invoke transition function in per-tuple context */
5852
0
  oldContext = MemoryContextSwitchTo(aggstate->tmpcontext->ecxt_per_tuple_memory);
5853
5854
0
  fcinfo->args[0].value = pergroup->transValue;
5855
0
  fcinfo->args[0].isnull = pergroup->transValueIsNull;
5856
0
  fcinfo->isnull = false;   /* just in case transfn doesn't set it */
5857
5858
0
  newVal = FunctionCallInvoke(fcinfo);
5859
5860
0
  pergroup->transValue = newVal;
5861
0
  pergroup->transValueIsNull = fcinfo->isnull;
5862
5863
0
  MemoryContextSwitchTo(oldContext);
5864
0
}
5865
5866
/* implementation of transition function invocation for byref types */
5867
static pg_attribute_always_inline void
5868
ExecAggPlainTransByRef(AggState *aggstate, AggStatePerTrans pertrans,
5869
             AggStatePerGroup pergroup,
5870
             ExprContext *aggcontext, int setno)
5871
0
{
5872
0
  FunctionCallInfo fcinfo = pertrans->transfn_fcinfo;
5873
0
  MemoryContext oldContext;
5874
0
  Datum   newVal;
5875
5876
  /* cf. select_current_set() */
5877
0
  aggstate->curaggcontext = aggcontext;
5878
0
  aggstate->current_set = setno;
5879
5880
  /* set up aggstate->curpertrans for AggGetAggref() */
5881
0
  aggstate->curpertrans = pertrans;
5882
5883
  /* invoke transition function in per-tuple context */
5884
0
  oldContext = MemoryContextSwitchTo(aggstate->tmpcontext->ecxt_per_tuple_memory);
5885
5886
0
  fcinfo->args[0].value = pergroup->transValue;
5887
0
  fcinfo->args[0].isnull = pergroup->transValueIsNull;
5888
0
  fcinfo->isnull = false;   /* just in case transfn doesn't set it */
5889
5890
0
  newVal = FunctionCallInvoke(fcinfo);
5891
5892
  /*
5893
   * For pass-by-ref datatype, must copy the new value into aggcontext and
5894
   * free the prior transValue.  But if transfn returned a pointer to its
5895
   * first input, we don't need to do anything.
5896
   *
5897
   * It's safe to compare newVal with pergroup->transValue without regard
5898
   * for either being NULL, because ExecAggCopyTransValue takes care to set
5899
   * transValue to 0 when NULL. Otherwise we could end up accidentally not
5900
   * reparenting, when the transValue has the same numerical value as
5901
   * newValue, despite being NULL.  This is a somewhat hot path, making it
5902
   * undesirable to instead solve this with another branch for the common
5903
   * case of the transition function returning its (modified) input
5904
   * argument.
5905
   */
5906
0
  if (DatumGetPointer(newVal) != DatumGetPointer(pergroup->transValue))
5907
0
    newVal = ExecAggCopyTransValue(aggstate, pertrans,
5908
0
                     newVal, fcinfo->isnull,
5909
0
                     pergroup->transValue,
5910
0
                     pergroup->transValueIsNull);
5911
5912
0
  pergroup->transValue = newVal;
5913
0
  pergroup->transValueIsNull = fcinfo->isnull;
5914
5915
0
  MemoryContextSwitchTo(oldContext);
5916
0
}