PostgreSQL Source Code  git master
execExpr.c File Reference
#include "postgres.h"
#include "access/nbtree.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "executor/execExpr.h"
#include "executor/nodeSubplan.h"
#include "funcapi.h"
#include "jit/jit.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "nodes/subscripting.h"
#include "optimizer/optimizer.h"
#include "pgstat.h"
#include "utils/acl.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/datum.h"
#include "utils/lsyscache.h"
#include "utils/typcache.h"
Include dependency graph for execExpr.c:

Go to the source code of this file.

Data Structures

struct  ExprSetupInfo
 

Typedefs

typedef struct ExprSetupInfo ExprSetupInfo
 

Functions

static void ExecReadyExpr (ExprState *state)
 
static void ExecInitExprRec (Expr *node, ExprState *state, Datum *resv, bool *resnull)
 
static void ExecInitFunc (ExprEvalStep *scratch, Expr *node, List *args, Oid funcid, Oid inputcollid, ExprState *state)
 
static void ExecCreateExprSetupSteps (ExprState *state, Node *node)
 
static void ExecPushExprSetupSteps (ExprState *state, ExprSetupInfo *info)
 
static bool expr_setup_walker (Node *node, ExprSetupInfo *info)
 
static bool ExecComputeSlotInfo (ExprState *state, ExprEvalStep *op)
 
static void ExecInitWholeRowVar (ExprEvalStep *scratch, Var *variable, ExprState *state)
 
static void ExecInitSubscriptingRef (ExprEvalStep *scratch, SubscriptingRef *sbsref, ExprState *state, Datum *resv, bool *resnull)
 
static bool isAssignmentIndirectionExpr (Expr *expr)
 
static void ExecInitCoerceToDomain (ExprEvalStep *scratch, CoerceToDomain *ctest, ExprState *state, Datum *resv, bool *resnull)
 
static void ExecBuildAggTransCall (ExprState *state, AggState *aggstate, ExprEvalStep *scratch, FunctionCallInfo fcinfo, AggStatePerTrans pertrans, int transno, int setno, int setoff, bool ishash, bool nullcheck)
 
ExprStateExecInitExpr (Expr *node, PlanState *parent)
 
ExprStateExecInitExprWithParams (Expr *node, ParamListInfo ext_params)
 
ExprStateExecInitQual (List *qual, PlanState *parent)
 
ExprStateExecInitCheck (List *qual, PlanState *parent)
 
ListExecInitExprList (List *nodes, PlanState *parent)
 
ProjectionInfoExecBuildProjectionInfo (List *targetList, ExprContext *econtext, TupleTableSlot *slot, PlanState *parent, TupleDesc inputDesc)
 
ProjectionInfoExecBuildUpdateProjection (List *targetList, bool evalTargetList, List *targetColnos, TupleDesc relDesc, ExprContext *econtext, TupleTableSlot *slot, PlanState *parent)
 
ExprStateExecPrepareExpr (Expr *node, EState *estate)
 
ExprStateExecPrepareQual (List *qual, EState *estate)
 
ExprStateExecPrepareCheck (List *qual, EState *estate)
 
ListExecPrepareExprList (List *nodes, EState *estate)
 
bool ExecCheck (ExprState *state, ExprContext *econtext)
 
void ExprEvalPushStep (ExprState *es, const ExprEvalStep *s)
 
ExprStateExecBuildAggTrans (AggState *aggstate, AggStatePerPhase phase, bool doSort, bool doHash, bool nullcheck)
 
ExprStateExecBuildGroupingEqual (TupleDesc ldesc, TupleDesc rdesc, const TupleTableSlotOps *lops, const TupleTableSlotOps *rops, int numCols, const AttrNumber *keyColIdx, const Oid *eqfunctions, const Oid *collations, PlanState *parent)
 
ExprStateExecBuildParamSetEqual (TupleDesc desc, const TupleTableSlotOps *lops, const TupleTableSlotOps *rops, const Oid *eqfunctions, const Oid *collations, const List *param_exprs, PlanState *parent)
 

Typedef Documentation

◆ ExprSetupInfo

typedef struct ExprSetupInfo ExprSetupInfo

Function Documentation

◆ ExecBuildAggTrans()

ExprState* ExecBuildAggTrans ( AggState aggstate,
AggStatePerPhase  phase,
bool  doSort,
bool  doHash,
bool  nullcheck 
)

Definition at line 3404 of file execExpr.c.

3406 {
3408  PlanState *parent = &aggstate->ss.ps;
3409  ExprEvalStep scratch = {0};
3410  bool isCombine = DO_AGGSPLIT_COMBINE(aggstate->aggsplit);
3411  ExprSetupInfo deform = {0, 0, 0, NIL};
3412 
3413  state->expr = (Expr *) aggstate;
3414  state->parent = parent;
3415 
3416  scratch.resvalue = &state->resvalue;
3417  scratch.resnull = &state->resnull;
3418 
3419  /*
3420  * First figure out which slots, and how many columns from each, we're
3421  * going to need.
3422  */
3423  for (int transno = 0; transno < aggstate->numtrans; transno++)
3424  {
3425  AggStatePerTrans pertrans = &aggstate->pertrans[transno];
3426 
3427  expr_setup_walker((Node *) pertrans->aggref->aggdirectargs,
3428  &deform);
3429  expr_setup_walker((Node *) pertrans->aggref->args,
3430  &deform);
3431  expr_setup_walker((Node *) pertrans->aggref->aggorder,
3432  &deform);
3433  expr_setup_walker((Node *) pertrans->aggref->aggdistinct,
3434  &deform);
3435  expr_setup_walker((Node *) pertrans->aggref->aggfilter,
3436  &deform);
3437  }
3438  ExecPushExprSetupSteps(state, &deform);
3439 
3440  /*
3441  * Emit instructions for each transition value / grouping set combination.
3442  */
3443  for (int transno = 0; transno < aggstate->numtrans; transno++)
3444  {
3445  AggStatePerTrans pertrans = &aggstate->pertrans[transno];
3446  FunctionCallInfo trans_fcinfo = pertrans->transfn_fcinfo;
3447  List *adjust_bailout = NIL;
3448  NullableDatum *strictargs = NULL;
3449  bool *strictnulls = NULL;
3450  int argno;
3451  ListCell *bail;
3452 
3453  /*
3454  * If filter present, emit. Do so before evaluating the input, to
3455  * avoid potentially unneeded computations, or even worse, unintended
3456  * side-effects. When combining, all the necessary filtering has
3457  * already been done.
3458  */
3459  if (pertrans->aggref->aggfilter && !isCombine)
3460  {
3461  /* evaluate filter expression */
3462  ExecInitExprRec(pertrans->aggref->aggfilter, state,
3463  &state->resvalue, &state->resnull);
3464  /* and jump out if false */
3465  scratch.opcode = EEOP_JUMP_IF_NOT_TRUE;
3466  scratch.d.jump.jumpdone = -1; /* adjust later */
3467  ExprEvalPushStep(state, &scratch);
3468  adjust_bailout = lappend_int(adjust_bailout,
3469  state->steps_len - 1);
3470  }
3471 
3472  /*
3473  * Evaluate arguments to aggregate/combine function.
3474  */
3475  argno = 0;
3476  if (isCombine)
3477  {
3478  /*
3479  * Combining two aggregate transition values. Instead of directly
3480  * coming from a tuple the input is a, potentially deserialized,
3481  * transition value.
3482  */
3483  TargetEntry *source_tle;
3484 
3485  Assert(pertrans->numSortCols == 0);
3486  Assert(list_length(pertrans->aggref->args) == 1);
3487 
3488  strictargs = trans_fcinfo->args + 1;
3489  source_tle = (TargetEntry *) linitial(pertrans->aggref->args);
3490 
3491  /*
3492  * deserialfn_oid will be set if we must deserialize the input
3493  * state before calling the combine function.
3494  */
3495  if (!OidIsValid(pertrans->deserialfn_oid))
3496  {
3497  /*
3498  * Start from 1, since the 0th arg will be the transition
3499  * value
3500  */
3501  ExecInitExprRec(source_tle->expr, state,
3502  &trans_fcinfo->args[argno + 1].value,
3503  &trans_fcinfo->args[argno + 1].isnull);
3504  }
3505  else
3506  {
3507  FunctionCallInfo ds_fcinfo = pertrans->deserialfn_fcinfo;
3508 
3509  /* evaluate argument */
3510  ExecInitExprRec(source_tle->expr, state,
3511  &ds_fcinfo->args[0].value,
3512  &ds_fcinfo->args[0].isnull);
3513 
3514  /* Dummy second argument for type-safety reasons */
3515  ds_fcinfo->args[1].value = PointerGetDatum(NULL);
3516  ds_fcinfo->args[1].isnull = false;
3517 
3518  /*
3519  * Don't call a strict deserialization function with NULL
3520  * input
3521  */
3522  if (pertrans->deserialfn.fn_strict)
3524  else
3525  scratch.opcode = EEOP_AGG_DESERIALIZE;
3526 
3527  scratch.d.agg_deserialize.fcinfo_data = ds_fcinfo;
3528  scratch.d.agg_deserialize.jumpnull = -1; /* adjust later */
3529  scratch.resvalue = &trans_fcinfo->args[argno + 1].value;
3530  scratch.resnull = &trans_fcinfo->args[argno + 1].isnull;
3531 
3532  ExprEvalPushStep(state, &scratch);
3533  /* don't add an adjustment unless the function is strict */
3534  if (pertrans->deserialfn.fn_strict)
3535  adjust_bailout = lappend_int(adjust_bailout,
3536  state->steps_len - 1);
3537 
3538  /* restore normal settings of scratch fields */
3539  scratch.resvalue = &state->resvalue;
3540  scratch.resnull = &state->resnull;
3541  }
3542  argno++;
3543 
3544  Assert(pertrans->numInputs == argno);
3545  }
3546  else if (!pertrans->aggsortrequired)
3547  {
3548  ListCell *arg;
3549 
3550  /*
3551  * Normal transition function without ORDER BY / DISTINCT or with
3552  * ORDER BY / DISTINCT but the planner has given us pre-sorted
3553  * input.
3554  */
3555  strictargs = trans_fcinfo->args + 1;
3556 
3557  foreach(arg, pertrans->aggref->args)
3558  {
3559  TargetEntry *source_tle = (TargetEntry *) lfirst(arg);
3560 
3561  /*
3562  * Don't initialize args for any ORDER BY clause that might
3563  * exist in a presorted aggregate.
3564  */
3565  if (argno == pertrans->numTransInputs)
3566  break;
3567 
3568  /*
3569  * Start from 1, since the 0th arg will be the transition
3570  * value
3571  */
3572  ExecInitExprRec(source_tle->expr, state,
3573  &trans_fcinfo->args[argno + 1].value,
3574  &trans_fcinfo->args[argno + 1].isnull);
3575  argno++;
3576  }
3577  Assert(pertrans->numTransInputs == argno);
3578  }
3579  else if (pertrans->numInputs == 1)
3580  {
3581  /*
3582  * Non-presorted DISTINCT and/or ORDER BY case, with a single
3583  * column sorted on.
3584  */
3585  TargetEntry *source_tle =
3586  (TargetEntry *) linitial(pertrans->aggref->args);
3587 
3588  Assert(list_length(pertrans->aggref->args) == 1);
3589 
3590  ExecInitExprRec(source_tle->expr, state,
3591  &state->resvalue,
3592  &state->resnull);
3593  strictnulls = &state->resnull;
3594  argno++;
3595 
3596  Assert(pertrans->numInputs == argno);
3597  }
3598  else
3599  {
3600  /*
3601  * Non-presorted DISTINCT and/or ORDER BY case, with multiple
3602  * columns sorted on.
3603  */
3604  Datum *values = pertrans->sortslot->tts_values;
3605  bool *nulls = pertrans->sortslot->tts_isnull;
3606  ListCell *arg;
3607 
3608  strictnulls = nulls;
3609 
3610  foreach(arg, pertrans->aggref->args)
3611  {
3612  TargetEntry *source_tle = (TargetEntry *) lfirst(arg);
3613 
3614  ExecInitExprRec(source_tle->expr, state,
3615  &values[argno], &nulls[argno]);
3616  argno++;
3617  }
3618  Assert(pertrans->numInputs == argno);
3619  }
3620 
3621  /*
3622  * For a strict transfn, nothing happens when there's a NULL input; we
3623  * just keep the prior transValue. This is true for both plain and
3624  * sorted/distinct aggregates.
3625  */
3626  if (trans_fcinfo->flinfo->fn_strict && pertrans->numTransInputs > 0)
3627  {
3628  if (strictnulls)
3630  else
3632  scratch.d.agg_strict_input_check.nulls = strictnulls;
3633  scratch.d.agg_strict_input_check.args = strictargs;
3634  scratch.d.agg_strict_input_check.jumpnull = -1; /* adjust later */
3635  scratch.d.agg_strict_input_check.nargs = pertrans->numTransInputs;
3636  ExprEvalPushStep(state, &scratch);
3637  adjust_bailout = lappend_int(adjust_bailout,
3638  state->steps_len - 1);
3639  }
3640 
3641  /* Handle DISTINCT aggregates which have pre-sorted input */
3642  if (pertrans->numDistinctCols > 0 && !pertrans->aggsortrequired)
3643  {
3644  if (pertrans->numDistinctCols > 1)
3646  else
3648 
3649  scratch.d.agg_presorted_distinctcheck.pertrans = pertrans;
3650  scratch.d.agg_presorted_distinctcheck.jumpdistinct = -1; /* adjust later */
3651  ExprEvalPushStep(state, &scratch);
3652  adjust_bailout = lappend_int(adjust_bailout,
3653  state->steps_len - 1);
3654  }
3655 
3656  /*
3657  * Call transition function (once for each concurrently evaluated
3658  * grouping set). Do so for both sort and hash based computations, as
3659  * applicable.
3660  */
3661  if (doSort)
3662  {
3663  int processGroupingSets = Max(phase->numsets, 1);
3664  int setoff = 0;
3665 
3666  for (int setno = 0; setno < processGroupingSets; setno++)
3667  {
3668  ExecBuildAggTransCall(state, aggstate, &scratch, trans_fcinfo,
3669  pertrans, transno, setno, setoff, false,
3670  nullcheck);
3671  setoff++;
3672  }
3673  }
3674 
3675  if (doHash)
3676  {
3677  int numHashes = aggstate->num_hashes;
3678  int setoff;
3679 
3680  /* in MIXED mode, there'll be preceding transition values */
3681  if (aggstate->aggstrategy != AGG_HASHED)
3682  setoff = aggstate->maxsets;
3683  else
3684  setoff = 0;
3685 
3686  for (int setno = 0; setno < numHashes; setno++)
3687  {
3688  ExecBuildAggTransCall(state, aggstate, &scratch, trans_fcinfo,
3689  pertrans, transno, setno, setoff, true,
3690  nullcheck);
3691  setoff++;
3692  }
3693  }
3694 
3695  /* adjust early bail out jump target(s) */
3696  foreach(bail, adjust_bailout)
3697  {
3698  ExprEvalStep *as = &state->steps[lfirst_int(bail)];
3699 
3700  if (as->opcode == EEOP_JUMP_IF_NOT_TRUE)
3701  {
3702  Assert(as->d.jump.jumpdone == -1);
3703  as->d.jump.jumpdone = state->steps_len;
3704  }
3705  else if (as->opcode == EEOP_AGG_STRICT_INPUT_CHECK_ARGS ||
3707  {
3708  Assert(as->d.agg_strict_input_check.jumpnull == -1);
3709  as->d.agg_strict_input_check.jumpnull = state->steps_len;
3710  }
3711  else if (as->opcode == EEOP_AGG_STRICT_DESERIALIZE)
3712  {
3713  Assert(as->d.agg_deserialize.jumpnull == -1);
3714  as->d.agg_deserialize.jumpnull = state->steps_len;
3715  }
3716  else if (as->opcode == EEOP_AGG_PRESORTED_DISTINCT_SINGLE ||
3718  {
3719  Assert(as->d.agg_presorted_distinctcheck.jumpdistinct == -1);
3720  as->d.agg_presorted_distinctcheck.jumpdistinct = state->steps_len;
3721  }
3722  else
3723  Assert(false);
3724  }
3725  }
3726 
3727  scratch.resvalue = NULL;
3728  scratch.resnull = NULL;
3729  scratch.opcode = EEOP_DONE;
3730  ExprEvalPushStep(state, &scratch);
3731 
3733 
3734  return state;
3735 }
static Datum values[MAXATTR]
Definition: bootstrap.c:156
#define Max(x, y)
Definition: c.h:982
#define OidIsValid(objectId)
Definition: c.h:759
static void ExecPushExprSetupSteps(ExprState *state, ExprSetupInfo *info)
Definition: execExpr.c:2659
static void ExecInitExprRec(Expr *node, ExprState *state, Datum *resv, bool *resnull)
Definition: execExpr.c:889
static void ExecBuildAggTransCall(ExprState *state, AggState *aggstate, ExprEvalStep *scratch, FunctionCallInfo fcinfo, AggStatePerTrans pertrans, int transno, int setno, int setoff, bool ishash, bool nullcheck)
Definition: execExpr.c:3743
void ExprEvalPushStep(ExprState *es, const ExprEvalStep *s)
Definition: execExpr.c:2512
static bool expr_setup_walker(Node *node, ExprSetupInfo *info)
Definition: execExpr.c:2742
static void ExecReadyExpr(ExprState *state)
Definition: execExpr.c:872
@ EEOP_AGG_STRICT_DESERIALIZE
Definition: execExpr.h:245
@ EEOP_DONE
Definition: execExpr.h:68
@ EEOP_AGG_PRESORTED_DISTINCT_MULTI
Definition: execExpr.h:257
@ EEOP_AGG_STRICT_INPUT_CHECK_NULLS
Definition: execExpr.h:248
@ EEOP_AGG_STRICT_INPUT_CHECK_ARGS
Definition: execExpr.h:247
@ EEOP_AGG_DESERIALIZE
Definition: execExpr.h:246
@ EEOP_JUMP_IF_NOT_TRUE
Definition: execExpr.h:142
@ EEOP_AGG_PRESORTED_DISTINCT_SINGLE
Definition: execExpr.h:256
Assert(fmt[strlen(fmt) - 1] !='\n')
List * lappend_int(List *list, int datum)
Definition: list.c:356
#define DO_AGGSPLIT_COMBINE(as)
Definition: nodes.h:393
@ AGG_HASHED
Definition: nodes.h:364
#define makeNode(_type_)
Definition: nodes.h:176
void * arg
#define lfirst(lc)
Definition: pg_list.h:172
static int list_length(const List *l)
Definition: pg_list.h:152
#define NIL
Definition: pg_list.h:68
#define lfirst_int(lc)
Definition: pg_list.h:173
#define linitial(l)
Definition: pg_list.h:178
#define bail(...)
Definition: pg_regress.c:160
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
uintptr_t Datum
Definition: postgres.h:64
TupleTableSlot * sortslot
Definition: nodeAgg.h:141
Aggref * aggref
Definition: nodeAgg.h:44
FmgrInfo deserialfn
Definition: nodeAgg.h:92
FunctionCallInfo deserialfn_fcinfo
Definition: nodeAgg.h:175
FunctionCallInfo transfn_fcinfo
Definition: nodeAgg.h:170
ScanState ss
Definition: execnodes.h:2365
AggStatePerTrans pertrans
Definition: execnodes.h:2375
AggStrategy aggstrategy
Definition: execnodes.h:2369
int numtrans
Definition: execnodes.h:2368
AggSplit aggsplit
Definition: execnodes.h:2370
int num_hashes
Definition: execnodes.h:2406
int maxsets
Definition: execnodes.h:2395
List * aggdistinct
Definition: primnodes.h:452
List * aggdirectargs
Definition: primnodes.h:443
List * args
Definition: primnodes.h:446
Expr * aggfilter
Definition: primnodes.h:455
List * aggorder
Definition: primnodes.h:449
struct ExprEvalStep::@50::@88 agg_deserialize
struct ExprEvalStep::@50::@91 agg_presorted_distinctcheck
intptr_t opcode
Definition: execExpr.h:273
Datum * resvalue
Definition: execExpr.h:276
struct ExprEvalStep::@50::@60 jump
union ExprEvalStep::@50 d
bool * resnull
Definition: execExpr.h:277
struct ExprEvalStep::@50::@89 agg_strict_input_check
bool fn_strict
Definition: fmgr.h:61
FmgrInfo * flinfo
Definition: fmgr.h:87
NullableDatum args[FLEXIBLE_ARRAY_MEMBER]
Definition: fmgr.h:95
Definition: pg_list.h:54
Definition: nodes.h:129
Datum value
Definition: postgres.h:75
bool isnull
Definition: postgres.h:77
PlanState ps
Definition: execnodes.h:1461
Expr * expr
Definition: primnodes.h:1816
bool * tts_isnull
Definition: tuptable.h:128
Datum * tts_values
Definition: tuptable.h:126
Definition: regguts.h:318

References ExprEvalStep::agg_deserialize, AGG_HASHED, ExprEvalStep::agg_presorted_distinctcheck, ExprEvalStep::agg_strict_input_check, Aggref::aggdirectargs, Aggref::aggdistinct, Aggref::aggfilter, Aggref::aggorder, AggStatePerTransData::aggref, AggStatePerTransData::aggsortrequired, AggState::aggsplit, AggState::aggstrategy, arg, FunctionCallInfoBaseData::args, Aggref::args, Assert(), bail, ExprEvalStep::d, AggStatePerTransData::deserialfn, AggStatePerTransData::deserialfn_fcinfo, AggStatePerTransData::deserialfn_oid, DO_AGGSPLIT_COMBINE, EEOP_AGG_DESERIALIZE, EEOP_AGG_PRESORTED_DISTINCT_MULTI, EEOP_AGG_PRESORTED_DISTINCT_SINGLE, EEOP_AGG_STRICT_DESERIALIZE, EEOP_AGG_STRICT_INPUT_CHECK_ARGS, EEOP_AGG_STRICT_INPUT_CHECK_NULLS, EEOP_DONE, EEOP_JUMP_IF_NOT_TRUE, ExecBuildAggTransCall(), ExecInitExprRec(), ExecPushExprSetupSteps(), ExecReadyExpr(), TargetEntry::expr, expr_setup_walker(), ExprEvalPushStep(), FunctionCallInfoBaseData::flinfo, FmgrInfo::fn_strict, NullableDatum::isnull, ExprEvalStep::jump, lappend_int(), lfirst, lfirst_int, linitial, list_length(), makeNode, Max, AggState::maxsets, NIL, AggState::num_hashes, AggStatePerTransData::numDistinctCols, AggStatePerTransData::numInputs, AggStatePerPhaseData::numsets, AggStatePerTransData::numSortCols, AggState::numtrans, AggStatePerTransData::numTransInputs, OidIsValid, ExprEvalStep::opcode, AggState::pertrans, PointerGetDatum(), ScanState::ps, ExprEvalStep::resnull, ExprEvalStep::resvalue, AggStatePerTransData::sortslot, AggState::ss, AggStatePerTransData::transfn_fcinfo, TupleTableSlot::tts_isnull, TupleTableSlot::tts_values, NullableDatum::value, and values.

Referenced by ExecInitAgg(), and hashagg_recompile_expressions().

◆ ExecBuildAggTransCall()

static void ExecBuildAggTransCall ( ExprState state,
AggState aggstate,
ExprEvalStep scratch,
FunctionCallInfo  fcinfo,
AggStatePerTrans  pertrans,
int  transno,
int  setno,
int  setoff,
bool  ishash,
bool  nullcheck 
)
static

Definition at line 3743 of file execExpr.c.

3748 {
3749  ExprContext *aggcontext;
3750  int adjust_jumpnull = -1;
3751 
3752  if (ishash)
3753  aggcontext = aggstate->hashcontext;
3754  else
3755  aggcontext = aggstate->aggcontexts[setno];
3756 
3757  /* add check for NULL pointer? */
3758  if (nullcheck)
3759  {
3761  scratch->d.agg_plain_pergroup_nullcheck.setoff = setoff;
3762  /* adjust later */
3763  scratch->d.agg_plain_pergroup_nullcheck.jumpnull = -1;
3764  ExprEvalPushStep(state, scratch);
3765  adjust_jumpnull = state->steps_len - 1;
3766  }
3767 
3768  /*
3769  * Determine appropriate transition implementation.
3770  *
3771  * For non-ordered aggregates and ORDER BY / DISTINCT aggregates with
3772  * presorted input:
3773  *
3774  * If the initial value for the transition state doesn't exist in the
3775  * pg_aggregate table then we will let the first non-NULL value returned
3776  * from the outer procNode become the initial value. (This is useful for
3777  * aggregates like max() and min().) The noTransValue flag signals that we
3778  * need to do so. If true, generate a
3779  * EEOP_AGG_INIT_STRICT_PLAIN_TRANS{,_BYVAL} step. This step also needs to
3780  * do the work described next:
3781  *
3782  * If the function is strict, but does have an initial value, choose
3783  * EEOP_AGG_STRICT_PLAIN_TRANS{,_BYVAL}, which skips the transition
3784  * function if the transition value has become NULL (because a previous
3785  * transition function returned NULL). This step also needs to do the work
3786  * described next:
3787  *
3788  * Otherwise we call EEOP_AGG_PLAIN_TRANS{,_BYVAL}, which does not have to
3789  * perform either of the above checks.
3790  *
3791  * Having steps with overlapping responsibilities is not nice, but
3792  * aggregations are very performance sensitive, making this worthwhile.
3793  *
3794  * For ordered aggregates:
3795  *
3796  * Only need to choose between the faster path for a single ordered
3797  * column, and the one between multiple columns. Checking strictness etc
3798  * is done when finalizing the aggregate. See
3799  * process_ordered_aggregate_{single, multi} and
3800  * advance_transition_function.
3801  */
3802  if (!pertrans->aggsortrequired)
3803  {
3804  if (pertrans->transtypeByVal)
3805  {
3806  if (fcinfo->flinfo->fn_strict &&
3807  pertrans->initValueIsNull)
3809  else if (fcinfo->flinfo->fn_strict)
3811  else
3813  }
3814  else
3815  {
3816  if (fcinfo->flinfo->fn_strict &&
3817  pertrans->initValueIsNull)
3819  else if (fcinfo->flinfo->fn_strict)
3821  else
3823  }
3824  }
3825  else if (pertrans->numInputs == 1)
3827  else
3829 
3830  scratch->d.agg_trans.pertrans = pertrans;
3831  scratch->d.agg_trans.setno = setno;
3832  scratch->d.agg_trans.setoff = setoff;
3833  scratch->d.agg_trans.transno = transno;
3834  scratch->d.agg_trans.aggcontext = aggcontext;
3835  ExprEvalPushStep(state, scratch);
3836 
3837  /* fix up jumpnull */
3838  if (adjust_jumpnull != -1)
3839  {
3840  ExprEvalStep *as = &state->steps[adjust_jumpnull];
3841 
3843  Assert(as->d.agg_plain_pergroup_nullcheck.jumpnull == -1);
3844  as->d.agg_plain_pergroup_nullcheck.jumpnull = state->steps_len;
3845  }
3846 }
@ EEOP_AGG_PLAIN_PERGROUP_NULLCHECK
Definition: execExpr.h:249
@ EEOP_AGG_PLAIN_TRANS_BYREF
Definition: execExpr.h:255
@ EEOP_AGG_PLAIN_TRANS_BYVAL
Definition: execExpr.h:252
@ EEOP_AGG_ORDERED_TRANS_DATUM
Definition: execExpr.h:258
@ EEOP_AGG_PLAIN_TRANS_STRICT_BYREF
Definition: execExpr.h:254
@ EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL
Definition: execExpr.h:250
@ EEOP_AGG_PLAIN_TRANS_STRICT_BYVAL
Definition: execExpr.h:251
@ EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYREF
Definition: execExpr.h:253
@ EEOP_AGG_ORDERED_TRANS_TUPLE
Definition: execExpr.h:259
ExprContext * hashcontext
Definition: execnodes.h:2376
ExprContext ** aggcontexts
Definition: execnodes.h:2377
struct ExprEvalStep::@50::@90 agg_plain_pergroup_nullcheck
struct ExprEvalStep::@50::@92 agg_trans

References ExprEvalStep::agg_plain_pergroup_nullcheck, ExprEvalStep::agg_trans, AggState::aggcontexts, AggStatePerTransData::aggsortrequired, Assert(), ExprEvalStep::d, EEOP_AGG_ORDERED_TRANS_DATUM, EEOP_AGG_ORDERED_TRANS_TUPLE, EEOP_AGG_PLAIN_PERGROUP_NULLCHECK, EEOP_AGG_PLAIN_TRANS_BYREF, EEOP_AGG_PLAIN_TRANS_BYVAL, EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYREF, EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL, EEOP_AGG_PLAIN_TRANS_STRICT_BYREF, EEOP_AGG_PLAIN_TRANS_STRICT_BYVAL, ExprEvalPushStep(), FunctionCallInfoBaseData::flinfo, FmgrInfo::fn_strict, AggState::hashcontext, AggStatePerTransData::initValueIsNull, AggStatePerTransData::numInputs, ExprEvalStep::opcode, and AggStatePerTransData::transtypeByVal.

Referenced by ExecBuildAggTrans().

◆ ExecBuildGroupingEqual()

ExprState* ExecBuildGroupingEqual ( TupleDesc  ldesc,
TupleDesc  rdesc,
const TupleTableSlotOps lops,
const TupleTableSlotOps rops,
int  numCols,
const AttrNumber keyColIdx,
const Oid eqfunctions,
const Oid collations,
PlanState parent 
)

Definition at line 3860 of file execExpr.c.

3867 {
3869  ExprEvalStep scratch = {0};
3870  int maxatt = -1;
3871  List *adjust_jumps = NIL;
3872  ListCell *lc;
3873 
3874  /*
3875  * When no columns are actually compared, the result's always true. See
3876  * special case in ExecQual().
3877  */
3878  if (numCols == 0)
3879  return NULL;
3880 
3881  state->expr = NULL;
3882  state->flags = EEO_FLAG_IS_QUAL;
3883  state->parent = parent;
3884 
3885  scratch.resvalue = &state->resvalue;
3886  scratch.resnull = &state->resnull;
3887 
3888  /* compute max needed attribute */
3889  for (int natt = 0; natt < numCols; natt++)
3890  {
3891  int attno = keyColIdx[natt];
3892 
3893  if (attno > maxatt)
3894  maxatt = attno;
3895  }
3896  Assert(maxatt >= 0);
3897 
3898  /* push deform steps */
3899  scratch.opcode = EEOP_INNER_FETCHSOME;
3900  scratch.d.fetch.last_var = maxatt;
3901  scratch.d.fetch.fixed = false;
3902  scratch.d.fetch.known_desc = ldesc;
3903  scratch.d.fetch.kind = lops;
3904  if (ExecComputeSlotInfo(state, &scratch))
3905  ExprEvalPushStep(state, &scratch);
3906 
3907  scratch.opcode = EEOP_OUTER_FETCHSOME;
3908  scratch.d.fetch.last_var = maxatt;
3909  scratch.d.fetch.fixed = false;
3910  scratch.d.fetch.known_desc = rdesc;
3911  scratch.d.fetch.kind = rops;
3912  if (ExecComputeSlotInfo(state, &scratch))
3913  ExprEvalPushStep(state, &scratch);
3914 
3915  /*
3916  * Start comparing at the last field (least significant sort key). That's
3917  * the most likely to be different if we are dealing with sorted input.
3918  */
3919  for (int natt = numCols; --natt >= 0;)
3920  {
3921  int attno = keyColIdx[natt];
3922  Form_pg_attribute latt = TupleDescAttr(ldesc, attno - 1);
3923  Form_pg_attribute ratt = TupleDescAttr(rdesc, attno - 1);
3924  Oid foid = eqfunctions[natt];
3925  Oid collid = collations[natt];
3926  FmgrInfo *finfo;
3927  FunctionCallInfo fcinfo;
3928  AclResult aclresult;
3929 
3930  /* Check permission to call function */
3931  aclresult = object_aclcheck(ProcedureRelationId, foid, GetUserId(), ACL_EXECUTE);
3932  if (aclresult != ACLCHECK_OK)
3933  aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(foid));
3934 
3936 
3937  /* Set up the primary fmgr lookup information */
3938  finfo = palloc0(sizeof(FmgrInfo));
3939  fcinfo = palloc0(SizeForFunctionCallInfo(2));
3940  fmgr_info(foid, finfo);
3941  fmgr_info_set_expr(NULL, finfo);
3942  InitFunctionCallInfoData(*fcinfo, finfo, 2,
3943  collid, NULL, NULL);
3944 
3945  /* left arg */
3946  scratch.opcode = EEOP_INNER_VAR;
3947  scratch.d.var.attnum = attno - 1;
3948  scratch.d.var.vartype = latt->atttypid;
3949  scratch.resvalue = &fcinfo->args[0].value;
3950  scratch.resnull = &fcinfo->args[0].isnull;
3951  ExprEvalPushStep(state, &scratch);
3952 
3953  /* right arg */
3954  scratch.opcode = EEOP_OUTER_VAR;
3955  scratch.d.var.attnum = attno - 1;
3956  scratch.d.var.vartype = ratt->atttypid;
3957  scratch.resvalue = &fcinfo->args[1].value;
3958  scratch.resnull = &fcinfo->args[1].isnull;
3959  ExprEvalPushStep(state, &scratch);
3960 
3961  /* evaluate distinctness */
3962  scratch.opcode = EEOP_NOT_DISTINCT;
3963  scratch.d.func.finfo = finfo;
3964  scratch.d.func.fcinfo_data = fcinfo;
3965  scratch.d.func.fn_addr = finfo->fn_addr;
3966  scratch.d.func.nargs = 2;
3967  scratch.resvalue = &state->resvalue;
3968  scratch.resnull = &state->resnull;
3969  ExprEvalPushStep(state, &scratch);
3970 
3971  /* then emit EEOP_QUAL to detect if result is false (or null) */
3972  scratch.opcode = EEOP_QUAL;
3973  scratch.d.qualexpr.jumpdone = -1;
3974  scratch.resvalue = &state->resvalue;
3975  scratch.resnull = &state->resnull;
3976  ExprEvalPushStep(state, &scratch);
3977  adjust_jumps = lappend_int(adjust_jumps,
3978  state->steps_len - 1);
3979  }
3980 
3981  /* adjust jump targets */
3982  foreach(lc, adjust_jumps)
3983  {
3984  ExprEvalStep *as = &state->steps[lfirst_int(lc)];
3985 
3986  Assert(as->opcode == EEOP_QUAL);
3987  Assert(as->d.qualexpr.jumpdone == -1);
3988  as->d.qualexpr.jumpdone = state->steps_len;
3989  }
3990 
3991  scratch.resvalue = NULL;
3992  scratch.resnull = NULL;
3993  scratch.opcode = EEOP_DONE;
3994  ExprEvalPushStep(state, &scratch);
3995 
3997 
3998  return state;
3999 }
AclResult
Definition: acl.h:182
@ ACLCHECK_OK
Definition: acl.h:183
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:2673
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition: aclchk.c:3775
Oid collid
static bool ExecComputeSlotInfo(ExprState *state, ExprEvalStep *op)
Definition: execExpr.c:2806
@ EEOP_NOT_DISTINCT
Definition: execExpr.h:172
@ EEOP_INNER_VAR
Definition: execExpr.h:76
@ EEOP_QUAL
Definition: execExpr.h:134
@ EEOP_INNER_FETCHSOME
Definition: execExpr.h:71
@ EEOP_OUTER_FETCHSOME
Definition: execExpr.h:72
@ EEOP_OUTER_VAR
Definition: execExpr.h:77
#define EEO_FLAG_IS_QUAL
Definition: execnodes.h:75
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition: fmgr.c:127
#define SizeForFunctionCallInfo(nargs)
Definition: fmgr.h:102
#define InitFunctionCallInfoData(Fcinfo, Flinfo, Nargs, Collation, Context, Resultinfo)
Definition: fmgr.h:150
#define fmgr_info_set_expr(expr, finfo)
Definition: fmgr.h:135
char * get_func_name(Oid funcid)
Definition: lsyscache.c:1590
void * palloc0(Size size)
Definition: mcxt.c:1241
Oid GetUserId(void)
Definition: miscinit.c:510
#define InvokeFunctionExecuteHook(objectId)
Definition: objectaccess.h:213
@ OBJECT_FUNCTION
Definition: parsenodes.h:2101
#define ACL_EXECUTE
Definition: parsenodes.h:90
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:209
unsigned int Oid
Definition: postgres_ext.h:31
struct ExprEvalStep::@50::@51 fetch
struct ExprEvalStep::@50::@52 var
struct ExprEvalStep::@50::@59 qualexpr
struct ExprEvalStep::@50::@57 func
Definition: fmgr.h:57
PGFunction fn_addr
Definition: fmgr.h:58
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92

References ACL_EXECUTE, aclcheck_error(), ACLCHECK_OK, FunctionCallInfoBaseData::args, Assert(), collid, ExprEvalStep::d, EEO_FLAG_IS_QUAL, EEOP_DONE, EEOP_INNER_FETCHSOME, EEOP_INNER_VAR, EEOP_NOT_DISTINCT, EEOP_OUTER_FETCHSOME, EEOP_OUTER_VAR, EEOP_QUAL, ExecComputeSlotInfo(), ExecReadyExpr(), ExprEvalPushStep(), ExprEvalStep::fetch, fmgr_info(), fmgr_info_set_expr, FmgrInfo::fn_addr, ExprEvalStep::func, get_func_name(), GetUserId(), InitFunctionCallInfoData, InvokeFunctionExecuteHook, NullableDatum::isnull, lappend_int(), lfirst_int, makeNode, NIL, object_aclcheck(), OBJECT_FUNCTION, ExprEvalStep::opcode, palloc0(), ExprEvalStep::qualexpr, ExprEvalStep::resnull, ExprEvalStep::resvalue, SizeForFunctionCallInfo, TupleDescAttr, NullableDatum::value, and ExprEvalStep::var.

Referenced by BuildTupleHashTableExt(), ExecInitSubPlan(), and execTuplesMatchPrepare().

◆ ExecBuildParamSetEqual()

ExprState* ExecBuildParamSetEqual ( TupleDesc  desc,
const TupleTableSlotOps lops,
const TupleTableSlotOps rops,
const Oid eqfunctions,
const Oid collations,
const List param_exprs,
PlanState parent 
)

Definition at line 4017 of file execExpr.c.

4024 {
4026  ExprEvalStep scratch = {0};
4027  int maxatt = list_length(param_exprs);
4028  List *adjust_jumps = NIL;
4029  ListCell *lc;
4030 
4031  state->expr = NULL;
4032  state->flags = EEO_FLAG_IS_QUAL;
4033  state->parent = parent;
4034 
4035  scratch.resvalue = &state->resvalue;
4036  scratch.resnull = &state->resnull;
4037 
4038  /* push deform steps */
4039  scratch.opcode = EEOP_INNER_FETCHSOME;
4040  scratch.d.fetch.last_var = maxatt;
4041  scratch.d.fetch.fixed = false;
4042  scratch.d.fetch.known_desc = desc;
4043  scratch.d.fetch.kind = lops;
4044  if (ExecComputeSlotInfo(state, &scratch))
4045  ExprEvalPushStep(state, &scratch);
4046 
4047  scratch.opcode = EEOP_OUTER_FETCHSOME;
4048  scratch.d.fetch.last_var = maxatt;
4049  scratch.d.fetch.fixed = false;
4050  scratch.d.fetch.known_desc = desc;
4051  scratch.d.fetch.kind = rops;
4052  if (ExecComputeSlotInfo(state, &scratch))
4053  ExprEvalPushStep(state, &scratch);
4054 
4055  for (int attno = 0; attno < maxatt; attno++)
4056  {
4057  Form_pg_attribute att = TupleDescAttr(desc, attno);
4058  Oid foid = eqfunctions[attno];
4059  Oid collid = collations[attno];
4060  FmgrInfo *finfo;
4061  FunctionCallInfo fcinfo;
4062  AclResult aclresult;
4063 
4064  /* Check permission to call function */
4065  aclresult = object_aclcheck(ProcedureRelationId, foid, GetUserId(), ACL_EXECUTE);
4066  if (aclresult != ACLCHECK_OK)
4067  aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(foid));
4068 
4070 
4071  /* Set up the primary fmgr lookup information */
4072  finfo = palloc0(sizeof(FmgrInfo));
4073  fcinfo = palloc0(SizeForFunctionCallInfo(2));
4074  fmgr_info(foid, finfo);
4075  fmgr_info_set_expr(NULL, finfo);
4076  InitFunctionCallInfoData(*fcinfo, finfo, 2,
4077  collid, NULL, NULL);
4078 
4079  /* left arg */
4080  scratch.opcode = EEOP_INNER_VAR;
4081  scratch.d.var.attnum = attno;
4082  scratch.d.var.vartype = att->atttypid;
4083  scratch.resvalue = &fcinfo->args[0].value;
4084  scratch.resnull = &fcinfo->args[0].isnull;
4085  ExprEvalPushStep(state, &scratch);
4086 
4087  /* right arg */
4088  scratch.opcode = EEOP_OUTER_VAR;
4089  scratch.d.var.attnum = attno;
4090  scratch.d.var.vartype = att->atttypid;
4091  scratch.resvalue = &fcinfo->args[1].value;
4092  scratch.resnull = &fcinfo->args[1].isnull;
4093  ExprEvalPushStep(state, &scratch);
4094 
4095  /* evaluate distinctness */
4096  scratch.opcode = EEOP_NOT_DISTINCT;
4097  scratch.d.func.finfo = finfo;
4098  scratch.d.func.fcinfo_data = fcinfo;
4099  scratch.d.func.fn_addr = finfo->fn_addr;
4100  scratch.d.func.nargs = 2;
4101  scratch.resvalue = &state->resvalue;
4102  scratch.resnull = &state->resnull;
4103  ExprEvalPushStep(state, &scratch);
4104 
4105  /* then emit EEOP_QUAL to detect if result is false (or null) */
4106  scratch.opcode = EEOP_QUAL;
4107  scratch.d.qualexpr.jumpdone = -1;
4108  scratch.resvalue = &state->resvalue;
4109  scratch.resnull = &state->resnull;
4110  ExprEvalPushStep(state, &scratch);
4111  adjust_jumps = lappend_int(adjust_jumps,
4112  state->steps_len - 1);
4113  }
4114 
4115  /* adjust jump targets */
4116  foreach(lc, adjust_jumps)
4117  {
4118  ExprEvalStep *as = &state->steps[lfirst_int(lc)];
4119 
4120  Assert(as->opcode == EEOP_QUAL);
4121  Assert(as->d.qualexpr.jumpdone == -1);
4122  as->d.qualexpr.jumpdone = state->steps_len;
4123  }
4124 
4125  scratch.resvalue = NULL;
4126  scratch.resnull = NULL;
4127  scratch.opcode = EEOP_DONE;
4128  ExprEvalPushStep(state, &scratch);
4129 
4131 
4132  return state;
4133 }

References ACL_EXECUTE, aclcheck_error(), ACLCHECK_OK, FunctionCallInfoBaseData::args, Assert(), collid, ExprEvalStep::d, EEO_FLAG_IS_QUAL, EEOP_DONE, EEOP_INNER_FETCHSOME, EEOP_INNER_VAR, EEOP_NOT_DISTINCT, EEOP_OUTER_FETCHSOME, EEOP_OUTER_VAR, EEOP_QUAL, ExecComputeSlotInfo(), ExecReadyExpr(), ExprEvalPushStep(), ExprEvalStep::fetch, fmgr_info(), fmgr_info_set_expr, FmgrInfo::fn_addr, ExprEvalStep::func, get_func_name(), GetUserId(), InitFunctionCallInfoData, InvokeFunctionExecuteHook, NullableDatum::isnull, lappend_int(), lfirst_int, list_length(), makeNode, NIL, object_aclcheck(), OBJECT_FUNCTION, ExprEvalStep::opcode, palloc0(), ExprEvalStep::qualexpr, ExprEvalStep::resnull, ExprEvalStep::resvalue, SizeForFunctionCallInfo, TupleDescAttr, NullableDatum::value, and ExprEvalStep::var.

Referenced by ExecInitMemoize().

◆ ExecBuildProjectionInfo()

ProjectionInfo* ExecBuildProjectionInfo ( List targetList,
ExprContext econtext,
TupleTableSlot slot,
PlanState parent,
TupleDesc  inputDesc 
)

Definition at line 357 of file execExpr.c.

362 {
364  ExprState *state;
365  ExprEvalStep scratch = {0};
366  ListCell *lc;
367 
368  projInfo->pi_exprContext = econtext;
369  /* We embed ExprState into ProjectionInfo instead of doing extra palloc */
370  projInfo->pi_state.type = T_ExprState;
371  state = &projInfo->pi_state;
372  state->expr = (Expr *) targetList;
373  state->parent = parent;
374  state->ext_params = NULL;
375 
376  state->resultslot = slot;
377 
378  /* Insert setup steps as needed */
379  ExecCreateExprSetupSteps(state, (Node *) targetList);
380 
381  /* Now compile each tlist column */
382  foreach(lc, targetList)
383  {
384  TargetEntry *tle = lfirst_node(TargetEntry, lc);
385  Var *variable = NULL;
386  AttrNumber attnum = 0;
387  bool isSafeVar = false;
388 
389  /*
390  * If tlist expression is a safe non-system Var, use the fast-path
391  * ASSIGN_*_VAR opcodes. "Safe" means that we don't need to apply
392  * CheckVarSlotCompatibility() during plan startup. If a source slot
393  * was provided, we make the equivalent tests here; if a slot was not
394  * provided, we assume that no check is needed because we're dealing
395  * with a non-relation-scan-level expression.
396  */
397  if (tle->expr != NULL &&
398  IsA(tle->expr, Var) &&
399  ((Var *) tle->expr)->varattno > 0)
400  {
401  /* Non-system Var, but how safe is it? */
402  variable = (Var *) tle->expr;
403  attnum = variable->varattno;
404 
405  if (inputDesc == NULL)
406  isSafeVar = true; /* can't check, just assume OK */
407  else if (attnum <= inputDesc->natts)
408  {
409  Form_pg_attribute attr = TupleDescAttr(inputDesc, attnum - 1);
410 
411  /*
412  * If user attribute is dropped or has a type mismatch, don't
413  * use ASSIGN_*_VAR. Instead let the normal expression
414  * machinery handle it (which'll possibly error out).
415  */
416  if (!attr->attisdropped && variable->vartype == attr->atttypid)
417  {
418  isSafeVar = true;
419  }
420  }
421  }
422 
423  if (isSafeVar)
424  {
425  /* Fast-path: just generate an EEOP_ASSIGN_*_VAR step */
426  switch (variable->varno)
427  {
428  case INNER_VAR:
429  /* get the tuple from the inner node */
430  scratch.opcode = EEOP_ASSIGN_INNER_VAR;
431  break;
432 
433  case OUTER_VAR:
434  /* get the tuple from the outer node */
435  scratch.opcode = EEOP_ASSIGN_OUTER_VAR;
436  break;
437 
438  /* INDEX_VAR is handled by default case */
439 
440  default:
441  /* get the tuple from the relation being scanned */
442  scratch.opcode = EEOP_ASSIGN_SCAN_VAR;
443  break;
444  }
445 
446  scratch.d.assign_var.attnum = attnum - 1;
447  scratch.d.assign_var.resultnum = tle->resno - 1;
448  ExprEvalPushStep(state, &scratch);
449  }
450  else
451  {
452  /*
453  * Otherwise, compile the column expression normally.
454  *
455  * We can't tell the expression to evaluate directly into the
456  * result slot, as the result slot (and the exprstate for that
457  * matter) can change between executions. We instead evaluate
458  * into the ExprState's resvalue/resnull and then move.
459  */
460  ExecInitExprRec(tle->expr, state,
461  &state->resvalue, &state->resnull);
462 
463  /*
464  * Column might be referenced multiple times in upper nodes, so
465  * force value to R/O - but only if it could be an expanded datum.
466  */
467  if (get_typlen(exprType((Node *) tle->expr)) == -1)
469  else
470  scratch.opcode = EEOP_ASSIGN_TMP;
471  scratch.d.assign_tmp.resultnum = tle->resno - 1;
472  ExprEvalPushStep(state, &scratch);
473  }
474  }
475 
476  scratch.opcode = EEOP_DONE;
477  ExprEvalPushStep(state, &scratch);
478 
480 
481  return projInfo;
482 }
int16 AttrNumber
Definition: attnum.h:21
static void ExecCreateExprSetupSteps(ExprState *state, Node *node)
Definition: execExpr.c:2643
@ EEOP_ASSIGN_TMP
Definition: execExpr.h:98
@ EEOP_ASSIGN_SCAN_VAR
Definition: execExpr.h:95
@ EEOP_ASSIGN_OUTER_VAR
Definition: execExpr.h:94
@ EEOP_ASSIGN_TMP_MAKE_RO
Definition: execExpr.h:100
@ EEOP_ASSIGN_INNER_VAR
Definition: execExpr.h:93
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
int16 get_typlen(Oid typid)
Definition: lsyscache.c:2155
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:43
#define IsA(nodeptr, _type_)
Definition: nodes.h:179
int16 attnum
Definition: pg_attribute.h:74
#define lfirst_node(type, lc)
Definition: pg_list.h:176
#define OUTER_VAR
Definition: primnodes.h:215
#define INNER_VAR
Definition: primnodes.h:214
struct ExprEvalStep::@50::@54 assign_var
struct ExprEvalStep::@50::@55 assign_tmp
NodeTag type
Definition: execnodes.h:79
ExprState pi_state
Definition: execnodes.h:356
ExprContext * pi_exprContext
Definition: execnodes.h:358
AttrNumber resno
Definition: primnodes.h:1818
Definition: primnodes.h:226

References ExprEvalStep::assign_tmp, ExprEvalStep::assign_var, attnum, ExprEvalStep::d, EEOP_ASSIGN_INNER_VAR, EEOP_ASSIGN_OUTER_VAR, EEOP_ASSIGN_SCAN_VAR, EEOP_ASSIGN_TMP, EEOP_ASSIGN_TMP_MAKE_RO, EEOP_DONE, ExecCreateExprSetupSteps(), ExecInitExprRec(), ExecReadyExpr(), TargetEntry::expr, ExprEvalPushStep(), exprType(), get_typlen(), if(), INNER_VAR, IsA, lfirst_node, makeNode, ExprEvalStep::opcode, OUTER_VAR, ProjectionInfo::pi_exprContext, ProjectionInfo::pi_state, TargetEntry::resno, TupleDescAttr, and ExprState::type.

Referenced by ExecAssignProjectionInfo(), ExecInitInsertProjection(), ExecInitMerge(), ExecInitModifyTable(), ExecInitPartitionInfo(), and ExecInitSubPlan().

◆ ExecBuildUpdateProjection()

ProjectionInfo* ExecBuildUpdateProjection ( List targetList,
bool  evalTargetList,
List targetColnos,
TupleDesc  relDesc,
ExprContext econtext,
TupleTableSlot slot,
PlanState parent 
)

Definition at line 517 of file execExpr.c.

524 {
526  ExprState *state;
527  int nAssignableCols;
528  bool sawJunk;
529  Bitmapset *assignedCols;
530  ExprSetupInfo deform = {0, 0, 0, NIL};
531  ExprEvalStep scratch = {0};
532  int outerattnum;
533  ListCell *lc,
534  *lc2;
535 
536  projInfo->pi_exprContext = econtext;
537  /* We embed ExprState into ProjectionInfo instead of doing extra palloc */
538  projInfo->pi_state.type = T_ExprState;
539  state = &projInfo->pi_state;
540  if (evalTargetList)
541  state->expr = (Expr *) targetList;
542  else
543  state->expr = NULL; /* not used */
544  state->parent = parent;
545  state->ext_params = NULL;
546 
547  state->resultslot = slot;
548 
549  /*
550  * Examine the targetList to see how many non-junk columns there are, and
551  * to verify that the non-junk columns come before the junk ones.
552  */
553  nAssignableCols = 0;
554  sawJunk = false;
555  foreach(lc, targetList)
556  {
557  TargetEntry *tle = lfirst_node(TargetEntry, lc);
558 
559  if (tle->resjunk)
560  sawJunk = true;
561  else
562  {
563  if (sawJunk)
564  elog(ERROR, "subplan target list is out of order");
565  nAssignableCols++;
566  }
567  }
568 
569  /* We should have one targetColnos entry per non-junk column */
570  if (nAssignableCols != list_length(targetColnos))
571  elog(ERROR, "targetColnos does not match subplan target list");
572 
573  /*
574  * Build a bitmapset of the columns in targetColnos. (We could just use
575  * list_member_int() tests, but that risks O(N^2) behavior with many
576  * columns.)
577  */
578  assignedCols = NULL;
579  foreach(lc, targetColnos)
580  {
581  AttrNumber targetattnum = lfirst_int(lc);
582 
583  assignedCols = bms_add_member(assignedCols, targetattnum);
584  }
585 
586  /*
587  * We need to insert EEOP_*_FETCHSOME steps to ensure the input tuples are
588  * sufficiently deconstructed. The scan tuple must be deconstructed at
589  * least as far as the last old column we need.
590  */
591  for (int attnum = relDesc->natts; attnum > 0; attnum--)
592  {
593  Form_pg_attribute attr = TupleDescAttr(relDesc, attnum - 1);
594 
595  if (attr->attisdropped)
596  continue;
597  if (bms_is_member(attnum, assignedCols))
598  continue;
599  deform.last_scan = attnum;
600  break;
601  }
602 
603  /*
604  * If we're actually evaluating the tlist, incorporate its input
605  * requirements too; otherwise, we'll just need to fetch the appropriate
606  * number of columns of the "outer" tuple.
607  */
608  if (evalTargetList)
609  expr_setup_walker((Node *) targetList, &deform);
610  else
611  deform.last_outer = nAssignableCols;
612 
613  ExecPushExprSetupSteps(state, &deform);
614 
615  /*
616  * Now generate code to evaluate the tlist's assignable expressions or
617  * fetch them from the outer tuple, incidentally validating that they'll
618  * be of the right data type. The checks above ensure that the forboth()
619  * will iterate over exactly the non-junk columns. Note that we don't
620  * bother evaluating any remaining resjunk columns.
621  */
622  outerattnum = 0;
623  forboth(lc, targetList, lc2, targetColnos)
624  {
625  TargetEntry *tle = lfirst_node(TargetEntry, lc);
626  AttrNumber targetattnum = lfirst_int(lc2);
627  Form_pg_attribute attr;
628 
629  Assert(!tle->resjunk);
630 
631  /*
632  * Apply sanity checks comparable to ExecCheckPlanOutput().
633  */
634  if (targetattnum <= 0 || targetattnum > relDesc->natts)
635  ereport(ERROR,
636  (errcode(ERRCODE_DATATYPE_MISMATCH),
637  errmsg("table row type and query-specified row type do not match"),
638  errdetail("Query has too many columns.")));
639  attr = TupleDescAttr(relDesc, targetattnum - 1);
640 
641  if (attr->attisdropped)
642  ereport(ERROR,
643  (errcode(ERRCODE_DATATYPE_MISMATCH),
644  errmsg("table row type and query-specified row type do not match"),
645  errdetail("Query provides a value for a dropped column at ordinal position %d.",
646  targetattnum)));
647  if (exprType((Node *) tle->expr) != attr->atttypid)
648  ereport(ERROR,
649  (errcode(ERRCODE_DATATYPE_MISMATCH),
650  errmsg("table row type and query-specified row type do not match"),
651  errdetail("Table has type %s at ordinal position %d, but query expects %s.",
652  format_type_be(attr->atttypid),
653  targetattnum,
654  format_type_be(exprType((Node *) tle->expr)))));
655 
656  /* OK, generate code to perform the assignment. */
657  if (evalTargetList)
658  {
659  /*
660  * We must evaluate the TLE's expression and assign it. We do not
661  * bother jumping through hoops for "safe" Vars like
662  * ExecBuildProjectionInfo does; this is a relatively less-used
663  * path and it doesn't seem worth expending code for that.
664  */
665  ExecInitExprRec(tle->expr, state,
666  &state->resvalue, &state->resnull);
667  /* Needn't worry about read-only-ness here, either. */
668  scratch.opcode = EEOP_ASSIGN_TMP;
669  scratch.d.assign_tmp.resultnum = targetattnum - 1;
670  ExprEvalPushStep(state, &scratch);
671  }
672  else
673  {
674  /* Just assign from the outer tuple. */
675  scratch.opcode = EEOP_ASSIGN_OUTER_VAR;
676  scratch.d.assign_var.attnum = outerattnum;
677  scratch.d.assign_var.resultnum = targetattnum - 1;
678  ExprEvalPushStep(state, &scratch);
679  }
680  outerattnum++;
681  }
682 
683  /*
684  * Now generate code to copy over any old columns that were not assigned
685  * to, and to ensure that dropped columns are set to NULL.
686  */
687  for (int attnum = 1; attnum <= relDesc->natts; attnum++)
688  {
689  Form_pg_attribute attr = TupleDescAttr(relDesc, attnum - 1);
690 
691  if (attr->attisdropped)
692  {
693  /* Put a null into the ExprState's resvalue/resnull ... */
694  scratch.opcode = EEOP_CONST;
695  scratch.resvalue = &state->resvalue;
696  scratch.resnull = &state->resnull;
697  scratch.d.constval.value = (Datum) 0;
698  scratch.d.constval.isnull = true;
699  ExprEvalPushStep(state, &scratch);
700  /* ... then assign it to the result slot */
701  scratch.opcode = EEOP_ASSIGN_TMP;
702  scratch.d.assign_tmp.resultnum = attnum - 1;
703  ExprEvalPushStep(state, &scratch);
704  }
705  else if (!bms_is_member(attnum, assignedCols))
706  {
707  /* Certainly the right type, so needn't check */
708  scratch.opcode = EEOP_ASSIGN_SCAN_VAR;
709  scratch.d.assign_var.attnum = attnum - 1;
710  scratch.d.assign_var.resultnum = attnum - 1;
711  ExprEvalPushStep(state, &scratch);
712  }
713  }
714 
715  scratch.opcode = EEOP_DONE;
716  ExprEvalPushStep(state, &scratch);
717 
719 
720  return projInfo;
721 }
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:444
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:755
int errdetail(const char *fmt,...)
Definition: elog.c:1202
int errcode(int sqlerrcode)
Definition: elog.c:858
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
@ EEOP_CONST
Definition: execExpr.h:103
char * format_type_be(Oid type_oid)
Definition: format_type.c:339
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:467
struct ExprEvalStep::@50::@56 constval
AttrNumber last_scan
Definition: execExpr.c:60
AttrNumber last_outer
Definition: execExpr.c:59

References Assert(), ExprEvalStep::assign_tmp, ExprEvalStep::assign_var, attnum, bms_add_member(), bms_is_member(), ExprEvalStep::constval, ExprEvalStep::d, EEOP_ASSIGN_OUTER_VAR, EEOP_ASSIGN_SCAN_VAR, EEOP_ASSIGN_TMP, EEOP_CONST, EEOP_DONE, elog(), ereport, errcode(), errdetail(), errmsg(), ERROR, ExecInitExprRec(), ExecPushExprSetupSteps(), ExecReadyExpr(), TargetEntry::expr, expr_setup_walker(), ExprEvalPushStep(), exprType(), forboth, format_type_be(), ExprSetupInfo::last_outer, ExprSetupInfo::last_scan, lfirst_int, lfirst_node, list_length(), makeNode, TupleDescData::natts, NIL, ExprEvalStep::opcode, ProjectionInfo::pi_exprContext, ProjectionInfo::pi_state, ExprEvalStep::resnull, ExprEvalStep::resvalue, TupleDescAttr, and ExprState::type.

Referenced by ExecInitMerge(), ExecInitModifyTable(), ExecInitPartitionInfo(), and ExecInitUpdateProjection().

◆ ExecCheck()

bool ExecCheck ( ExprState state,
ExprContext econtext 
)

Definition at line 842 of file execExpr.c.

843 {
844  Datum ret;
845  bool isnull;
846 
847  /* short-circuit (here and in ExecInitCheck) for empty restriction list */
848  if (state == NULL)
849  return true;
850 
851  /* verify that expression was not compiled using ExecInitQual */
852  Assert(!(state->flags & EEO_FLAG_IS_QUAL));
853 
854  ret = ExecEvalExprSwitchContext(state, econtext, &isnull);
855 
856  if (isnull)
857  return true;
858 
859  return DatumGetBool(ret);
860 }
static Datum ExecEvalExprSwitchContext(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:346
static bool DatumGetBool(Datum X)
Definition: postgres.h:90

References Assert(), DatumGetBool(), EEO_FLAG_IS_QUAL, and ExecEvalExprSwitchContext().

Referenced by ATRewriteTable(), check_default_partition_contents(), domain_check_input(), ExecPartitionCheck(), and ExecRelCheck().

◆ ExecComputeSlotInfo()

static bool ExecComputeSlotInfo ( ExprState state,
ExprEvalStep op 
)
static

Definition at line 2806 of file execExpr.c.

2807 {
2808  PlanState *parent = state->parent;
2809  TupleDesc desc = NULL;
2810  const TupleTableSlotOps *tts_ops = NULL;
2811  bool isfixed = false;
2812  ExprEvalOp opcode = op->opcode;
2813 
2814  Assert(opcode == EEOP_INNER_FETCHSOME ||
2815  opcode == EEOP_OUTER_FETCHSOME ||
2816  opcode == EEOP_SCAN_FETCHSOME);
2817 
2818  if (op->d.fetch.known_desc != NULL)
2819  {
2820  desc = op->d.fetch.known_desc;
2821  tts_ops = op->d.fetch.kind;
2822  isfixed = op->d.fetch.kind != NULL;
2823  }
2824  else if (!parent)
2825  {
2826  isfixed = false;
2827  }
2828  else if (opcode == EEOP_INNER_FETCHSOME)
2829  {
2830  PlanState *is = innerPlanState(parent);
2831 
2832  if (parent->inneropsset && !parent->inneropsfixed)
2833  {
2834  isfixed = false;
2835  }
2836  else if (parent->inneropsset && parent->innerops)
2837  {
2838  isfixed = true;
2839  tts_ops = parent->innerops;
2840  desc = ExecGetResultType(is);
2841  }
2842  else if (is)
2843  {
2844  tts_ops = ExecGetResultSlotOps(is, &isfixed);
2845  desc = ExecGetResultType(is);
2846  }
2847  }
2848  else if (opcode == EEOP_OUTER_FETCHSOME)
2849  {
2850  PlanState *os = outerPlanState(parent);
2851 
2852  if (parent->outeropsset && !parent->outeropsfixed)
2853  {
2854  isfixed = false;
2855  }
2856  else if (parent->outeropsset && parent->outerops)
2857  {
2858  isfixed = true;
2859  tts_ops = parent->outerops;
2860  desc = ExecGetResultType(os);
2861  }
2862  else if (os)
2863  {
2864  tts_ops = ExecGetResultSlotOps(os, &isfixed);
2865  desc = ExecGetResultType(os);
2866  }
2867  }
2868  else if (opcode == EEOP_SCAN_FETCHSOME)
2869  {
2870  desc = parent->scandesc;
2871 
2872  if (parent->scanops)
2873  tts_ops = parent->scanops;
2874 
2875  if (parent->scanopsset)
2876  isfixed = parent->scanopsfixed;
2877  }
2878 
2879  if (isfixed && desc != NULL && tts_ops != NULL)
2880  {
2881  op->d.fetch.fixed = true;
2882  op->d.fetch.kind = tts_ops;
2883  op->d.fetch.known_desc = desc;
2884  }
2885  else
2886  {
2887  op->d.fetch.fixed = false;
2888  op->d.fetch.kind = NULL;
2889  op->d.fetch.known_desc = NULL;
2890  }
2891 
2892  /* if the slot is known to always virtual we never need to deform */
2893  if (op->d.fetch.fixed && op->d.fetch.kind == &TTSOpsVirtual)
2894  return false;
2895 
2896  return true;
2897 }
ExprEvalOp
Definition: execExpr.h:66
@ EEOP_SCAN_FETCHSOME
Definition: execExpr.h:73
const TupleTableSlotOps TTSOpsVirtual
Definition: execTuples.c:83
TupleDesc ExecGetResultType(PlanState *planstate)
Definition: execUtils.c:498
const TupleTableSlotOps * ExecGetResultSlotOps(PlanState *planstate, bool *isfixed)
Definition: execUtils.c:507
#define outerPlanState(node)
Definition: execnodes.h:1131
#define innerPlanState(node)
Definition: execnodes.h:1130
bool inneropsset
Definition: execnodes.h:1119
bool outeropsset
Definition: execnodes.h:1118
const TupleTableSlotOps * outerops
Definition: execnodes.h:1110
const TupleTableSlotOps * innerops
Definition: execnodes.h:1111
const TupleTableSlotOps * scanops
Definition: execnodes.h:1109
bool outeropsfixed
Definition: execnodes.h:1114
bool scanopsset
Definition: execnodes.h:1117
TupleDesc scandesc
Definition: execnodes.h:1084
bool scanopsfixed
Definition: execnodes.h:1113
bool inneropsfixed
Definition: execnodes.h:1115

References Assert(), ExprEvalStep::d, EEOP_INNER_FETCHSOME, EEOP_OUTER_FETCHSOME, EEOP_SCAN_FETCHSOME, ExecGetResultSlotOps(), ExecGetResultType(), ExprEvalStep::fetch, PlanState::innerops, PlanState::inneropsfixed, PlanState::inneropsset, innerPlanState, ExprEvalStep::opcode, PlanState::outerops, PlanState::outeropsfixed, PlanState::outeropsset, outerPlanState, PlanState::scandesc, PlanState::scanops, PlanState::scanopsfixed, PlanState::scanopsset, and TTSOpsVirtual.

Referenced by ExecBuildGroupingEqual(), ExecBuildParamSetEqual(), and ExecPushExprSetupSteps().

◆ ExecCreateExprSetupSteps()

static void ExecCreateExprSetupSteps ( ExprState state,
Node node 
)
static

Definition at line 2643 of file execExpr.c.

2644 {
2645  ExprSetupInfo info = {0, 0, 0, NIL};
2646 
2647  /* Prescan to find out what we need. */
2648  expr_setup_walker(node, &info);
2649 
2650  /* And generate those steps. */
2651  ExecPushExprSetupSteps(state, &info);
2652 }

References ExecPushExprSetupSteps(), expr_setup_walker(), and NIL.

Referenced by ExecBuildProjectionInfo(), ExecInitExpr(), ExecInitExprWithParams(), and ExecInitQual().

◆ ExecInitCheck()

ExprState* ExecInitCheck ( List qual,
PlanState parent 
)

Definition at line 302 of file execExpr.c.

303 {
304  /* short-circuit (here and in ExecCheck) for empty restriction list */
305  if (qual == NIL)
306  return NULL;
307 
308  Assert(IsA(qual, List));
309 
310  /*
311  * Just convert the implicit-AND list to an explicit AND (if there's more
312  * than one entry), and compile normally. Unlike ExecQual, we can't
313  * short-circuit on NULL results, so the regular AND behavior is needed.
314  */
315  return ExecInitExpr(make_ands_explicit(qual), parent);
316 }
ExprState * ExecInitExpr(Expr *node, PlanState *parent)
Definition: execExpr.c:127
Expr * make_ands_explicit(List *andclauses)
Definition: makefuncs.c:711

References Assert(), ExecInitExpr(), IsA, make_ands_explicit(), and NIL.

Referenced by ExecPrepareCheck().

◆ ExecInitCoerceToDomain()

static void ExecInitCoerceToDomain ( ExprEvalStep scratch,
CoerceToDomain ctest,
ExprState state,
Datum resv,
bool resnull 
)
static

Definition at line 3250 of file execExpr.c.

3252 {
3253  DomainConstraintRef *constraint_ref;
3254  Datum *domainval = NULL;
3255  bool *domainnull = NULL;
3256  ListCell *l;
3257 
3258  scratch->d.domaincheck.resulttype = ctest->resulttype;
3259  /* we'll allocate workspace only if needed */
3260  scratch->d.domaincheck.checkvalue = NULL;
3261  scratch->d.domaincheck.checknull = NULL;
3262 
3263  /*
3264  * Evaluate argument - it's fine to directly store it into resv/resnull,
3265  * if there's constraint failures there'll be errors, otherwise it's what
3266  * needs to be returned.
3267  */
3268  ExecInitExprRec(ctest->arg, state, resv, resnull);
3269 
3270  /*
3271  * Note: if the argument is of varlena type, it could be a R/W expanded
3272  * object. We want to return the R/W pointer as the final result, but we
3273  * have to pass a R/O pointer as the value to be tested by any functions
3274  * in check expressions. We don't bother to emit a MAKE_READONLY step
3275  * unless there's actually at least one check expression, though. Until
3276  * we've tested that, domainval/domainnull are NULL.
3277  */
3278 
3279  /*
3280  * Collect the constraints associated with the domain.
3281  *
3282  * Note: before PG v10 we'd recheck the set of constraints during each
3283  * evaluation of the expression. Now we bake them into the ExprState
3284  * during executor initialization. That means we don't need typcache.c to
3285  * provide compiled exprs.
3286  */
3287  constraint_ref = (DomainConstraintRef *)
3288  palloc(sizeof(DomainConstraintRef));
3290  constraint_ref,
3292  false);
3293 
3294  /*
3295  * Compile code to check each domain constraint. NOTNULL constraints can
3296  * just be applied on the resv/resnull value, but for CHECK constraints we
3297  * need more pushups.
3298  */
3299  foreach(l, constraint_ref->constraints)
3300  {
3302  Datum *save_innermost_domainval;
3303  bool *save_innermost_domainnull;
3304 
3305  scratch->d.domaincheck.constraintname = con->name;
3306 
3307  switch (con->constrainttype)
3308  {
3310  scratch->opcode = EEOP_DOMAIN_NOTNULL;
3311  ExprEvalPushStep(state, scratch);
3312  break;
3313  case DOM_CONSTRAINT_CHECK:
3314  /* Allocate workspace for CHECK output if we didn't yet */
3315  if (scratch->d.domaincheck.checkvalue == NULL)
3316  {
3317  scratch->d.domaincheck.checkvalue =
3318  (Datum *) palloc(sizeof(Datum));
3319  scratch->d.domaincheck.checknull =
3320  (bool *) palloc(sizeof(bool));
3321  }
3322 
3323  /*
3324  * If first time through, determine where CoerceToDomainValue
3325  * nodes should read from.
3326  */
3327  if (domainval == NULL)
3328  {
3329  /*
3330  * Since value might be read multiple times, force to R/O
3331  * - but only if it could be an expanded datum.
3332  */
3333  if (get_typlen(ctest->resulttype) == -1)
3334  {
3335  ExprEvalStep scratch2 = {0};
3336 
3337  /* Yes, so make output workspace for MAKE_READONLY */
3338  domainval = (Datum *) palloc(sizeof(Datum));
3339  domainnull = (bool *) palloc(sizeof(bool));
3340 
3341  /* Emit MAKE_READONLY */
3342  scratch2.opcode = EEOP_MAKE_READONLY;
3343  scratch2.resvalue = domainval;
3344  scratch2.resnull = domainnull;
3345  scratch2.d.make_readonly.value = resv;
3346  scratch2.d.make_readonly.isnull = resnull;
3347  ExprEvalPushStep(state, &scratch2);
3348  }
3349  else
3350  {
3351  /* No, so it's fine to read from resv/resnull */
3352  domainval = resv;
3353  domainnull = resnull;
3354  }
3355  }
3356 
3357  /*
3358  * Set up value to be returned by CoerceToDomainValue nodes.
3359  * We must save and restore innermost_domainval/null fields,
3360  * in case this node is itself within a check expression for
3361  * another domain.
3362  */
3363  save_innermost_domainval = state->innermost_domainval;
3364  save_innermost_domainnull = state->innermost_domainnull;
3365  state->innermost_domainval = domainval;
3366  state->innermost_domainnull = domainnull;
3367 
3368  /* evaluate check expression value */
3370  scratch->d.domaincheck.checkvalue,
3371  scratch->d.domaincheck.checknull);
3372 
3373  state->innermost_domainval = save_innermost_domainval;
3374  state->innermost_domainnull = save_innermost_domainnull;
3375 
3376  /* now test result */
3377  scratch->opcode = EEOP_DOMAIN_CHECK;
3378  ExprEvalPushStep(state, scratch);
3379 
3380  break;
3381  default:
3382  elog(ERROR, "unrecognized constraint type: %d",
3383  (int) con->constrainttype);
3384  break;
3385  }
3386  }
3387 }
@ EEOP_DOMAIN_CHECK
Definition: execExpr.h:231
@ EEOP_DOMAIN_NOTNULL
Definition: execExpr.h:228
@ EEOP_MAKE_READONLY
Definition: execExpr.h:167
@ DOM_CONSTRAINT_CHECK
Definition: execnodes.h:991
@ DOM_CONSTRAINT_NOTNULL
Definition: execnodes.h:990
MemoryContext CurrentMemoryContext
Definition: mcxt.c:135
void * palloc(Size size)
Definition: mcxt.c:1210
DomainConstraintType constrainttype
Definition: execnodes.h:997
struct ExprEvalStep::@50::@65 make_readonly
struct ExprEvalStep::@50::@78 domaincheck
void InitDomainConstraintRef(Oid type_id, DomainConstraintRef *ref, MemoryContext refctx, bool need_exprstate)
Definition: typcache.c:1305

References CoerceToDomain::arg, DomainConstraintState::check_expr, DomainConstraintRef::constraints, DomainConstraintState::constrainttype, CurrentMemoryContext, ExprEvalStep::d, DOM_CONSTRAINT_CHECK, DOM_CONSTRAINT_NOTNULL, ExprEvalStep::domaincheck, EEOP_DOMAIN_CHECK, EEOP_DOMAIN_NOTNULL, EEOP_MAKE_READONLY, elog(), ERROR, ExecInitExprRec(), ExprEvalPushStep(), get_typlen(), InitDomainConstraintRef(), lfirst, ExprEvalStep::make_readonly, DomainConstraintState::name, ExprEvalStep::opcode, palloc(), ExprEvalStep::resnull, CoerceToDomain::resulttype, and ExprEvalStep::resvalue.

Referenced by ExecInitExprRec().

◆ ExecInitExpr()

ExprState* ExecInitExpr ( Expr node,
PlanState parent 
)

Definition at line 127 of file execExpr.c.

128 {
129  ExprState *state;
130  ExprEvalStep scratch = {0};
131 
132  /* Special case: NULL expression produces a NULL ExprState pointer */
133  if (node == NULL)
134  return NULL;
135 
136  /* Initialize ExprState with empty step list */
138  state->expr = node;
139  state->parent = parent;
140  state->ext_params = NULL;
141 
142  /* Insert setup steps as needed */
144 
145  /* Compile the expression proper */
146  ExecInitExprRec(node, state, &state->resvalue, &state->resnull);
147 
148  /* Finally, append a DONE step */
149  scratch.opcode = EEOP_DONE;
150  ExprEvalPushStep(state, &scratch);
151 
153 
154  return state;
155 }

References EEOP_DONE, ExecCreateExprSetupSteps(), ExecInitExprRec(), ExecReadyExpr(), ExprEvalPushStep(), makeNode, and ExprEvalStep::opcode.

Referenced by ATRewriteTable(), BeginCopyFrom(), evaluate_expr(), ExecIndexBuildScanKeys(), ExecInitCheck(), ExecInitExprList(), ExecInitExprRec(), ExecInitLimit(), ExecInitMemoize(), ExecInitProjectSet(), ExecInitSampleScan(), ExecInitSubPlan(), ExecInitTableFuncScan(), ExecInitTableFunctionResult(), ExecInitWindowAgg(), ExecPrepareExpr(), get_cast_hashentry(), get_qual_for_range(), InitPartitionPruneContext(), MakeTidOpExpr(), MJExamineQuals(), operator_predicate_proof(), prep_domain_constraints(), slot_fill_defaults(), and TidExprListCreate().

◆ ExecInitExprList()

List* ExecInitExprList ( List nodes,
PlanState parent 
)

Definition at line 322 of file execExpr.c.

323 {
324  List *result = NIL;
325  ListCell *lc;
326 
327  foreach(lc, nodes)
328  {
329  Expr *e = lfirst(lc);
330 
331  result = lappend(result, ExecInitExpr(e, parent));
332  }
333 
334  return result;
335 }
List * lappend(List *list, void *datum)
Definition: list.c:338
e
Definition: preproc-init.c:82

References ExecInitExpr(), lappend(), lfirst, and NIL.

Referenced by ExecInitAgg(), ExecInitExprRec(), ExecInitFunctionResultSet(), ExecInitHash(), ExecInitHashJoin(), ExecInitIndexScan(), ExecInitSampleScan(), ExecInitSubPlan(), ExecInitTableFuncScan(), ExecInitTableFunctionResult(), ExecInitValuesScan(), prepare_query_params(), and ValuesNext().

◆ ExecInitExprRec()

static void ExecInitExprRec ( Expr node,
ExprState state,
Datum resv,
bool resnull 
)
static

Definition at line 889 of file execExpr.c.

891 {
892  ExprEvalStep scratch = {0};
893 
894  /* Guard against stack overflow due to overly complex expressions */
896 
897  /* Step's output location is always what the caller gave us */
898  Assert(resv != NULL && resnull != NULL);
899  scratch.resvalue = resv;
900  scratch.resnull = resnull;
901 
902  /* cases should be ordered as they are in enum NodeTag */
903  switch (nodeTag(node))
904  {
905  case T_Var:
906  {
907  Var *variable = (Var *) node;
908 
909  if (variable->varattno == InvalidAttrNumber)
910  {
911  /* whole-row Var */
912  ExecInitWholeRowVar(&scratch, variable, state);
913  }
914  else if (variable->varattno <= 0)
915  {
916  /* system column */
917  scratch.d.var.attnum = variable->varattno;
918  scratch.d.var.vartype = variable->vartype;
919  switch (variable->varno)
920  {
921  case INNER_VAR:
922  scratch.opcode = EEOP_INNER_SYSVAR;
923  break;
924  case OUTER_VAR:
925  scratch.opcode = EEOP_OUTER_SYSVAR;
926  break;
927 
928  /* INDEX_VAR is handled by default case */
929 
930  default:
931  scratch.opcode = EEOP_SCAN_SYSVAR;
932  break;
933  }
934  }
935  else
936  {
937  /* regular user column */
938  scratch.d.var.attnum = variable->varattno - 1;
939  scratch.d.var.vartype = variable->vartype;
940  switch (variable->varno)
941  {
942  case INNER_VAR:
943  scratch.opcode = EEOP_INNER_VAR;
944  break;
945  case OUTER_VAR:
946  scratch.opcode = EEOP_OUTER_VAR;
947  break;
948 
949  /* INDEX_VAR is handled by default case */
950 
951  default:
952  scratch.opcode = EEOP_SCAN_VAR;
953  break;
954  }
955  }
956 
957  ExprEvalPushStep(state, &scratch);
958  break;
959  }
960 
961  case T_Const:
962  {
963  Const *con = (Const *) node;
964 
965  scratch.opcode = EEOP_CONST;
966  scratch.d.constval.value = con->constvalue;
967  scratch.d.constval.isnull = con->constisnull;
968 
969  ExprEvalPushStep(state, &scratch);
970  break;
971  }
972 
973  case T_Param:
974  {
975  Param *param = (Param *) node;
976  ParamListInfo params;
977 
978  switch (param->paramkind)
979  {
980  case PARAM_EXEC:
981  scratch.opcode = EEOP_PARAM_EXEC;
982  scratch.d.param.paramid = param->paramid;
983  scratch.d.param.paramtype = param->paramtype;
984  ExprEvalPushStep(state, &scratch);
985  break;
986  case PARAM_EXTERN:
987 
988  /*
989  * If we have a relevant ParamCompileHook, use it;
990  * otherwise compile a standard EEOP_PARAM_EXTERN
991  * step. ext_params, if supplied, takes precedence
992  * over info from the parent node's EState (if any).
993  */
994  if (state->ext_params)
995  params = state->ext_params;
996  else if (state->parent &&
997  state->parent->state)
998  params = state->parent->state->es_param_list_info;
999  else
1000  params = NULL;
1001  if (params && params->paramCompile)
1002  {
1003  params->paramCompile(params, param, state,
1004  resv, resnull);
1005  }
1006  else
1007  {
1008  scratch.opcode = EEOP_PARAM_EXTERN;
1009  scratch.d.param.paramid = param->paramid;
1010  scratch.d.param.paramtype = param->paramtype;
1011  ExprEvalPushStep(state, &scratch);
1012  }
1013  break;
1014  default:
1015  elog(ERROR, "unrecognized paramkind: %d",
1016  (int) param->paramkind);
1017  break;
1018  }
1019  break;
1020  }
1021 
1022  case T_Aggref:
1023  {
1024  Aggref *aggref = (Aggref *) node;
1025 
1026  scratch.opcode = EEOP_AGGREF;
1027  scratch.d.aggref.aggno = aggref->aggno;
1028 
1029  if (state->parent && IsA(state->parent, AggState))
1030  {
1031  AggState *aggstate = (AggState *) state->parent;
1032 
1033  aggstate->aggs = lappend(aggstate->aggs, aggref);
1034  }
1035  else
1036  {
1037  /* planner messed up */
1038  elog(ERROR, "Aggref found in non-Agg plan node");
1039  }
1040 
1041  ExprEvalPushStep(state, &scratch);
1042  break;
1043  }
1044 
1045  case T_GroupingFunc:
1046  {
1047  GroupingFunc *grp_node = (GroupingFunc *) node;
1048  Agg *agg;
1049 
1050  if (!state->parent || !IsA(state->parent, AggState) ||
1051  !IsA(state->parent->plan, Agg))
1052  elog(ERROR, "GroupingFunc found in non-Agg plan node");
1053 
1054  scratch.opcode = EEOP_GROUPING_FUNC;
1055 
1056  agg = (Agg *) (state->parent->plan);
1057 
1058  if (agg->groupingSets)
1059  scratch.d.grouping_func.clauses = grp_node->cols;
1060  else
1061  scratch.d.grouping_func.clauses = NIL;
1062 
1063  ExprEvalPushStep(state, &scratch);
1064  break;
1065  }
1066 
1067  case T_WindowFunc:
1068  {
1069  WindowFunc *wfunc = (WindowFunc *) node;
1071 
1072  wfstate->wfunc = wfunc;
1073 
1074  if (state->parent && IsA(state->parent, WindowAggState))
1075  {
1076  WindowAggState *winstate = (WindowAggState *) state->parent;
1077  int nfuncs;
1078 
1079  winstate->funcs = lappend(winstate->funcs, wfstate);
1080  nfuncs = ++winstate->numfuncs;
1081  if (wfunc->winagg)
1082  winstate->numaggs++;
1083 
1084  /* for now initialize agg using old style expressions */
1085  wfstate->args = ExecInitExprList(wfunc->args,
1086  state->parent);
1087  wfstate->aggfilter = ExecInitExpr(wfunc->aggfilter,
1088  state->parent);
1089 
1090  /*
1091  * Complain if the windowfunc's arguments contain any
1092  * windowfuncs; nested window functions are semantically
1093  * nonsensical. (This should have been caught earlier,
1094  * but we defend against it here anyway.)
1095  */
1096  if (nfuncs != winstate->numfuncs)
1097  ereport(ERROR,
1098  (errcode(ERRCODE_WINDOWING_ERROR),
1099  errmsg("window function calls cannot be nested")));
1100  }
1101  else
1102  {
1103  /* planner messed up */
1104  elog(ERROR, "WindowFunc found in non-WindowAgg plan node");
1105  }
1106 
1107  scratch.opcode = EEOP_WINDOW_FUNC;
1108  scratch.d.window_func.wfstate = wfstate;
1109  ExprEvalPushStep(state, &scratch);
1110  break;
1111  }
1112 
1113  case T_SubscriptingRef:
1114  {
1115  SubscriptingRef *sbsref = (SubscriptingRef *) node;
1116 
1117  ExecInitSubscriptingRef(&scratch, sbsref, state, resv, resnull);
1118  break;
1119  }
1120 
1121  case T_FuncExpr:
1122  {
1123  FuncExpr *func = (FuncExpr *) node;
1124 
1125  ExecInitFunc(&scratch, node,
1126  func->args, func->funcid, func->inputcollid,
1127  state);
1128  ExprEvalPushStep(state, &scratch);
1129  break;
1130  }
1131 
1132  case T_OpExpr:
1133  {
1134  OpExpr *op = (OpExpr *) node;
1135 
1136  ExecInitFunc(&scratch, node,
1137  op->args, op->opfuncid, op->inputcollid,
1138  state);
1139  ExprEvalPushStep(state, &scratch);
1140  break;
1141  }
1142 
1143  case T_DistinctExpr:
1144  {
1145  DistinctExpr *op = (DistinctExpr *) node;
1146 
1147  ExecInitFunc(&scratch, node,
1148  op->args, op->opfuncid, op->inputcollid,
1149  state);
1150 
1151  /*
1152  * Change opcode of call instruction to EEOP_DISTINCT.
1153  *
1154  * XXX: historically we've not called the function usage
1155  * pgstat infrastructure - that seems inconsistent given that
1156  * we do so for normal function *and* operator evaluation. If
1157  * we decided to do that here, we'd probably want separate
1158  * opcodes for FUSAGE or not.
1159  */
1160  scratch.opcode = EEOP_DISTINCT;
1161  ExprEvalPushStep(state, &scratch);
1162  break;
1163  }
1164 
1165  case T_NullIfExpr:
1166  {
1167  NullIfExpr *op = (NullIfExpr *) node;
1168 
1169  ExecInitFunc(&scratch, node,
1170  op->args, op->opfuncid, op->inputcollid,
1171  state);
1172 
1173  /*
1174  * Change opcode of call instruction to EEOP_NULLIF.
1175  *
1176  * XXX: historically we've not called the function usage
1177  * pgstat infrastructure - that seems inconsistent given that
1178  * we do so for normal function *and* operator evaluation. If
1179  * we decided to do that here, we'd probably want separate
1180  * opcodes for FUSAGE or not.
1181  */
1182  scratch.opcode = EEOP_NULLIF;
1183  ExprEvalPushStep(state, &scratch);
1184  break;
1185  }
1186 
1187  case T_ScalarArrayOpExpr:
1188  {
1189  ScalarArrayOpExpr *opexpr = (ScalarArrayOpExpr *) node;
1190  Expr *scalararg;
1191  Expr *arrayarg;
1192  FmgrInfo *finfo;
1193  FunctionCallInfo fcinfo;
1194  AclResult aclresult;
1195  Oid cmpfuncid;
1196 
1197  /*
1198  * Select the correct comparison function. When we do hashed
1199  * NOT IN clauses, the opfuncid will be the inequality
1200  * comparison function and negfuncid will be set to equality.
1201  * We need to use the equality function for hash probes.
1202  */
1203  if (OidIsValid(opexpr->negfuncid))
1204  {
1205  Assert(OidIsValid(opexpr->hashfuncid));
1206  cmpfuncid = opexpr->negfuncid;
1207  }
1208  else
1209  cmpfuncid = opexpr->opfuncid;
1210 
1211  Assert(list_length(opexpr->args) == 2);
1212  scalararg = (Expr *) linitial(opexpr->args);
1213  arrayarg = (Expr *) lsecond(opexpr->args);
1214 
1215  /* Check permission to call function */
1216  aclresult = object_aclcheck(ProcedureRelationId, cmpfuncid,
1217  GetUserId(),
1218  ACL_EXECUTE);
1219  if (aclresult != ACLCHECK_OK)
1220  aclcheck_error(aclresult, OBJECT_FUNCTION,
1221  get_func_name(cmpfuncid));
1222  InvokeFunctionExecuteHook(cmpfuncid);
1223 
1224  if (OidIsValid(opexpr->hashfuncid))
1225  {
1226  aclresult = object_aclcheck(ProcedureRelationId, opexpr->hashfuncid,
1227  GetUserId(),
1228  ACL_EXECUTE);
1229  if (aclresult != ACLCHECK_OK)
1230  aclcheck_error(aclresult, OBJECT_FUNCTION,
1231  get_func_name(opexpr->hashfuncid));
1232  InvokeFunctionExecuteHook(opexpr->hashfuncid);
1233  }
1234 
1235  /* Set up the primary fmgr lookup information */
1236  finfo = palloc0(sizeof(FmgrInfo));
1237  fcinfo = palloc0(SizeForFunctionCallInfo(2));
1238  fmgr_info(cmpfuncid, finfo);
1239  fmgr_info_set_expr((Node *) node, finfo);
1240  InitFunctionCallInfoData(*fcinfo, finfo, 2,
1241  opexpr->inputcollid, NULL, NULL);
1242 
1243  /*
1244  * If hashfuncid is set, we create a EEOP_HASHED_SCALARARRAYOP
1245  * step instead of a EEOP_SCALARARRAYOP. This provides much
1246  * faster lookup performance than the normal linear search
1247  * when the number of items in the array is anything but very
1248  * small.
1249  */
1250  if (OidIsValid(opexpr->hashfuncid))
1251  {
1252  /* Evaluate scalar directly into left function argument */
1253  ExecInitExprRec(scalararg, state,
1254  &fcinfo->args[0].value, &fcinfo->args[0].isnull);
1255 
1256  /*
1257  * Evaluate array argument into our return value. There's
1258  * no danger in that, because the return value is
1259  * guaranteed to be overwritten by
1260  * EEOP_HASHED_SCALARARRAYOP, and will not be passed to
1261  * any other expression.
1262  */
1263  ExecInitExprRec(arrayarg, state, resv, resnull);
1264 
1265  /* And perform the operation */
1267  scratch.d.hashedscalararrayop.inclause = opexpr->useOr;
1268  scratch.d.hashedscalararrayop.finfo = finfo;
1269  scratch.d.hashedscalararrayop.fcinfo_data = fcinfo;
1270  scratch.d.hashedscalararrayop.saop = opexpr;
1271 
1272 
1273  ExprEvalPushStep(state, &scratch);
1274  }
1275  else
1276  {
1277  /* Evaluate scalar directly into left function argument */
1278  ExecInitExprRec(scalararg, state,
1279  &fcinfo->args[0].value,
1280  &fcinfo->args[0].isnull);
1281 
1282  /*
1283  * Evaluate array argument into our return value. There's
1284  * no danger in that, because the return value is
1285  * guaranteed to be overwritten by EEOP_SCALARARRAYOP, and
1286  * will not be passed to any other expression.
1287  */
1288  ExecInitExprRec(arrayarg, state, resv, resnull);
1289 
1290  /* And perform the operation */
1291  scratch.opcode = EEOP_SCALARARRAYOP;
1292  scratch.d.scalararrayop.element_type = InvalidOid;
1293  scratch.d.scalararrayop.useOr = opexpr->useOr;
1294  scratch.d.scalararrayop.finfo = finfo;
1295  scratch.d.scalararrayop.fcinfo_data = fcinfo;
1296  scratch.d.scalararrayop.fn_addr = finfo->fn_addr;
1297  ExprEvalPushStep(state, &scratch);
1298  }
1299  break;
1300  }
1301 
1302  case T_BoolExpr:
1303  {
1304  BoolExpr *boolexpr = (BoolExpr *) node;
1305  int nargs = list_length(boolexpr->args);
1306  List *adjust_jumps = NIL;
1307  int off;
1308  ListCell *lc;
1309 
1310  /* allocate scratch memory used by all steps of AND/OR */
1311  if (boolexpr->boolop != NOT_EXPR)
1312  scratch.d.boolexpr.anynull = (bool *) palloc(sizeof(bool));
1313 
1314  /*
1315  * For each argument evaluate the argument itself, then
1316  * perform the bool operation's appropriate handling.
1317  *
1318  * We can evaluate each argument into our result area, since
1319  * the short-circuiting logic means we only need to remember
1320  * previous NULL values.
1321  *
1322  * AND/OR is split into separate STEP_FIRST (one) / STEP (zero
1323  * or more) / STEP_LAST (one) steps, as each of those has to
1324  * perform different work. The FIRST/LAST split is valid
1325  * because AND/OR have at least two arguments.
1326  */
1327  off = 0;
1328  foreach(lc, boolexpr->args)
1329  {
1330  Expr *arg = (Expr *) lfirst(lc);
1331 
1332  /* Evaluate argument into our output variable */
1333  ExecInitExprRec(arg, state, resv, resnull);
1334 
1335  /* Perform the appropriate step type */
1336  switch (boolexpr->boolop)
1337  {
1338  case AND_EXPR:
1339  Assert(nargs >= 2);
1340 
1341  if (off == 0)
1342  scratch.opcode = EEOP_BOOL_AND_STEP_FIRST;
1343  else if (off + 1 == nargs)
1344  scratch.opcode = EEOP_BOOL_AND_STEP_LAST;
1345  else
1346  scratch.opcode = EEOP_BOOL_AND_STEP;
1347  break;
1348  case OR_EXPR:
1349  Assert(nargs >= 2);
1350 
1351  if (off == 0)
1352  scratch.opcode = EEOP_BOOL_OR_STEP_FIRST;
1353  else if (off + 1 == nargs)
1354  scratch.opcode = EEOP_BOOL_OR_STEP_LAST;
1355  else
1356  scratch.opcode = EEOP_BOOL_OR_STEP;
1357  break;
1358  case NOT_EXPR:
1359  Assert(nargs == 1);
1360 
1361  scratch.opcode = EEOP_BOOL_NOT_STEP;
1362  break;
1363  default:
1364  elog(ERROR, "unrecognized boolop: %d",
1365  (int) boolexpr->boolop);
1366  break;
1367  }
1368 
1369  scratch.d.boolexpr.jumpdone = -1;
1370  ExprEvalPushStep(state, &scratch);
1371  adjust_jumps = lappend_int(adjust_jumps,
1372  state->steps_len - 1);
1373  off++;
1374  }
1375 
1376  /* adjust jump targets */
1377  foreach(lc, adjust_jumps)
1378  {
1379  ExprEvalStep *as = &state->steps[lfirst_int(lc)];
1380 
1381  Assert(as->d.boolexpr.jumpdone == -1);
1382  as->d.boolexpr.jumpdone = state->steps_len;
1383  }
1384 
1385  break;
1386  }
1387 
1388  case T_SubPlan:
1389  {
1390  SubPlan *subplan = (SubPlan *) node;
1391  SubPlanState *sstate;
1392 
1393  /*
1394  * Real execution of a MULTIEXPR SubPlan has already been
1395  * done. What we have to do here is return a dummy NULL record
1396  * value in case this targetlist element is assigned
1397  * someplace.
1398  */
1399  if (subplan->subLinkType == MULTIEXPR_SUBLINK)
1400  {
1401  scratch.opcode = EEOP_CONST;
1402  scratch.d.constval.value = (Datum) 0;
1403  scratch.d.constval.isnull = true;
1404  ExprEvalPushStep(state, &scratch);
1405  break;
1406  }
1407 
1408  if (!state->parent)
1409  elog(ERROR, "SubPlan found with no parent plan");
1410 
1411  sstate = ExecInitSubPlan(subplan, state->parent);
1412 
1413  /* add SubPlanState nodes to state->parent->subPlan */
1414  state->parent->subPlan = lappend(state->parent->subPlan,
1415  sstate);
1416 
1417  scratch.opcode = EEOP_SUBPLAN;
1418  scratch.d.subplan.sstate = sstate;
1419 
1420  ExprEvalPushStep(state, &scratch);
1421  break;
1422  }
1423 
1424  case T_FieldSelect:
1425  {
1426  FieldSelect *fselect = (FieldSelect *) node;
1427 
1428  /* evaluate row/record argument into result area */
1429  ExecInitExprRec(fselect->arg, state, resv, resnull);
1430 
1431  /* and extract field */
1432  scratch.opcode = EEOP_FIELDSELECT;
1433  scratch.d.fieldselect.fieldnum = fselect->fieldnum;
1434  scratch.d.fieldselect.resulttype = fselect->resulttype;
1435  scratch.d.fieldselect.rowcache.cacheptr = NULL;
1436 
1437  ExprEvalPushStep(state, &scratch);
1438  break;
1439  }
1440 
1441  case T_FieldStore:
1442  {
1443  FieldStore *fstore = (FieldStore *) node;
1444  TupleDesc tupDesc;
1445  ExprEvalRowtypeCache *rowcachep;
1446  Datum *values;
1447  bool *nulls;
1448  int ncolumns;
1449  ListCell *l1,
1450  *l2;
1451 
1452  /* find out the number of columns in the composite type */
1453  tupDesc = lookup_rowtype_tupdesc(fstore->resulttype, -1);
1454  ncolumns = tupDesc->natts;
1455  ReleaseTupleDesc(tupDesc);
1456 
1457  /* create workspace for column values */
1458  values = (Datum *) palloc(sizeof(Datum) * ncolumns);
1459  nulls = (bool *) palloc(sizeof(bool) * ncolumns);
1460 
1461  /* create shared composite-type-lookup cache struct */
1462  rowcachep = palloc(sizeof(ExprEvalRowtypeCache));
1463  rowcachep->cacheptr = NULL;
1464 
1465  /* emit code to evaluate the composite input value */
1466  ExecInitExprRec(fstore->arg, state, resv, resnull);
1467 
1468  /* next, deform the input tuple into our workspace */
1469  scratch.opcode = EEOP_FIELDSTORE_DEFORM;
1470  scratch.d.fieldstore.fstore = fstore;
1471  scratch.d.fieldstore.rowcache = rowcachep;
1472  scratch.d.fieldstore.values = values;
1473  scratch.d.fieldstore.nulls = nulls;
1474  scratch.d.fieldstore.ncolumns = ncolumns;
1475  ExprEvalPushStep(state, &scratch);
1476 
1477  /* evaluate new field values, store in workspace columns */
1478  forboth(l1, fstore->newvals, l2, fstore->fieldnums)
1479  {
1480  Expr *e = (Expr *) lfirst(l1);
1481  AttrNumber fieldnum = lfirst_int(l2);
1482  Datum *save_innermost_caseval;
1483  bool *save_innermost_casenull;
1484 
1485  if (fieldnum <= 0 || fieldnum > ncolumns)
1486  elog(ERROR, "field number %d is out of range in FieldStore",
1487  fieldnum);
1488 
1489  /*
1490  * Use the CaseTestExpr mechanism to pass down the old
1491  * value of the field being replaced; this is needed in
1492  * case the newval is itself a FieldStore or
1493  * SubscriptingRef that has to obtain and modify the old
1494  * value. It's safe to reuse the CASE mechanism because
1495  * there cannot be a CASE between here and where the value
1496  * would be needed, and a field assignment can't be within
1497  * a CASE either. (So saving and restoring
1498  * innermost_caseval is just paranoia, but let's do it
1499  * anyway.)
1500  *
1501  * Another non-obvious point is that it's safe to use the
1502  * field's values[]/nulls[] entries as both the caseval
1503  * source and the result address for this subexpression.
1504  * That's okay only because (1) both FieldStore and
1505  * SubscriptingRef evaluate their arg or refexpr inputs
1506  * first, and (2) any such CaseTestExpr is directly the
1507  * arg or refexpr input. So any read of the caseval will
1508  * occur before there's a chance to overwrite it. Also,
1509  * if multiple entries in the newvals/fieldnums lists
1510  * target the same field, they'll effectively be applied
1511  * left-to-right which is what we want.
1512  */
1513  save_innermost_caseval = state->innermost_caseval;
1514  save_innermost_casenull = state->innermost_casenull;
1515  state->innermost_caseval = &values[fieldnum - 1];
1516  state->innermost_casenull = &nulls[fieldnum - 1];
1517 
1519  &values[fieldnum - 1],
1520  &nulls[fieldnum - 1]);
1521 
1522  state->innermost_caseval = save_innermost_caseval;
1523  state->innermost_casenull = save_innermost_casenull;
1524  }
1525 
1526  /* finally, form result tuple */
1527  scratch.opcode = EEOP_FIELDSTORE_FORM;
1528  scratch.d.fieldstore.fstore = fstore;
1529  scratch.d.fieldstore.rowcache = rowcachep;
1530  scratch.d.fieldstore.values = values;
1531  scratch.d.fieldstore.nulls = nulls;
1532  scratch.d.fieldstore.ncolumns = ncolumns;
1533  ExprEvalPushStep(state, &scratch);
1534  break;
1535  }
1536 
1537  case T_RelabelType:
1538  {
1539  /* relabel doesn't need to do anything at runtime */
1540  RelabelType *relabel = (RelabelType *) node;
1541 
1542  ExecInitExprRec(relabel->arg, state, resv, resnull);
1543  break;
1544  }
1545 
1546  case T_CoerceViaIO:
1547  {
1548  CoerceViaIO *iocoerce = (CoerceViaIO *) node;
1549  Oid iofunc;
1550  bool typisvarlena;
1551  Oid typioparam;
1552  FunctionCallInfo fcinfo_in;
1553 
1554  /* evaluate argument into step's result area */
1555  ExecInitExprRec(iocoerce->arg, state, resv, resnull);
1556 
1557  /*
1558  * Prepare both output and input function calls, to be
1559  * evaluated inside a single evaluation step for speed - this
1560  * can be a very common operation.
1561  *
1562  * We don't check permissions here as a type's input/output
1563  * function are assumed to be executable by everyone.
1564  */
1565  scratch.opcode = EEOP_IOCOERCE;
1566 
1567  /* lookup the source type's output function */
1568  scratch.d.iocoerce.finfo_out = palloc0(sizeof(FmgrInfo));
1569  scratch.d.iocoerce.fcinfo_data_out = palloc0(SizeForFunctionCallInfo(1));
1570 
1571  getTypeOutputInfo(exprType((Node *) iocoerce->arg),
1572  &iofunc, &typisvarlena);
1573  fmgr_info(iofunc, scratch.d.iocoerce.finfo_out);
1574  fmgr_info_set_expr((Node *) node, scratch.d.iocoerce.finfo_out);
1575  InitFunctionCallInfoData(*scratch.d.iocoerce.fcinfo_data_out,
1576  scratch.d.iocoerce.finfo_out,
1577  1, InvalidOid, NULL, NULL);
1578 
1579  /* lookup the result type's input function */
1580  scratch.d.iocoerce.finfo_in = palloc0(sizeof(FmgrInfo));
1581  scratch.d.iocoerce.fcinfo_data_in = palloc0(SizeForFunctionCallInfo(3));
1582 
1583  getTypeInputInfo(iocoerce->resulttype,
1584  &iofunc, &typioparam);
1585  fmgr_info(iofunc, scratch.d.iocoerce.finfo_in);
1586  fmgr_info_set_expr((Node *) node, scratch.d.iocoerce.finfo_in);
1587  InitFunctionCallInfoData(*scratch.d.iocoerce.fcinfo_data_in,
1588  scratch.d.iocoerce.finfo_in,
1589  3, InvalidOid, NULL, NULL);
1590 
1591  /*
1592  * We can preload the second and third arguments for the input
1593  * function, since they're constants.
1594  */
1595  fcinfo_in = scratch.d.iocoerce.fcinfo_data_in;
1596  fcinfo_in->args[1].value = ObjectIdGetDatum(typioparam);
1597  fcinfo_in->args[1].isnull = false;
1598  fcinfo_in->args[2].value = Int32GetDatum(-1);
1599  fcinfo_in->args[2].isnull = false;
1600 
1601  ExprEvalPushStep(state, &scratch);
1602  break;
1603  }
1604 
1605  case T_ArrayCoerceExpr:
1606  {
1607  ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node;
1608  Oid resultelemtype;
1609  ExprState *elemstate;
1610 
1611  /* evaluate argument into step's result area */
1612  ExecInitExprRec(acoerce->arg, state, resv, resnull);
1613 
1614  resultelemtype = get_element_type(acoerce->resulttype);
1615  if (!OidIsValid(resultelemtype))
1616  ereport(ERROR,
1617  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1618  errmsg("target type is not an array")));
1619 
1620  /*
1621  * Construct a sub-expression for the per-element expression;
1622  * but don't ready it until after we check it for triviality.
1623  * We assume it hasn't any Var references, but does have a
1624  * CaseTestExpr representing the source array element values.
1625  */
1626  elemstate = makeNode(ExprState);
1627  elemstate->expr = acoerce->elemexpr;
1628  elemstate->parent = state->parent;
1629  elemstate->ext_params = state->ext_params;
1630 
1631  elemstate->innermost_caseval = (Datum *) palloc(sizeof(Datum));
1632  elemstate->innermost_casenull = (bool *) palloc(sizeof(bool));
1633 
1634  ExecInitExprRec(acoerce->elemexpr, elemstate,
1635  &elemstate->resvalue, &elemstate->resnull);
1636 
1637  if (elemstate->steps_len == 1 &&
1638  elemstate->steps[0].opcode == EEOP_CASE_TESTVAL)
1639  {
1640  /* Trivial, so we need no per-element work at runtime */
1641  elemstate = NULL;
1642  }
1643  else
1644  {
1645  /* Not trivial, so append a DONE step */
1646  scratch.opcode = EEOP_DONE;
1647  ExprEvalPushStep(elemstate, &scratch);
1648  /* and ready the subexpression */
1649  ExecReadyExpr(elemstate);
1650  }
1651 
1652  scratch.opcode = EEOP_ARRAYCOERCE;
1653  scratch.d.arraycoerce.elemexprstate = elemstate;
1654  scratch.d.arraycoerce.resultelemtype = resultelemtype;
1655 
1656  if (elemstate)
1657  {
1658  /* Set up workspace for array_map */
1659  scratch.d.arraycoerce.amstate =
1660  (ArrayMapState *) palloc0(sizeof(ArrayMapState));
1661  }
1662  else
1663  {
1664  /* Don't need workspace if there's no subexpression */
1665  scratch.d.arraycoerce.amstate = NULL;
1666  }
1667 
1668  ExprEvalPushStep(state, &scratch);
1669  break;
1670  }
1671 
1672  case T_ConvertRowtypeExpr:
1673  {
1675  ExprEvalRowtypeCache *rowcachep;
1676 
1677  /* cache structs must be out-of-line for space reasons */
1678  rowcachep = palloc(2 * sizeof(ExprEvalRowtypeCache));
1679  rowcachep[0].cacheptr = NULL;
1680  rowcachep[1].cacheptr = NULL;
1681 
1682  /* evaluate argument into step's result area */
1683  ExecInitExprRec(convert->arg, state, resv, resnull);
1684 
1685  /* and push conversion step */
1686  scratch.opcode = EEOP_CONVERT_ROWTYPE;
1687  scratch.d.convert_rowtype.inputtype =
1688  exprType((Node *) convert->arg);
1689  scratch.d.convert_rowtype.outputtype = convert->resulttype;
1690  scratch.d.convert_rowtype.incache = &rowcachep[0];
1691  scratch.d.convert_rowtype.outcache = &rowcachep[1];
1692  scratch.d.convert_rowtype.map = NULL;
1693 
1694  ExprEvalPushStep(state, &scratch);
1695  break;
1696  }
1697 
1698  /* note that CaseWhen expressions are handled within this block */
1699  case T_CaseExpr:
1700  {
1701  CaseExpr *caseExpr = (CaseExpr *) node;
1702  List *adjust_jumps = NIL;
1703  Datum *caseval = NULL;
1704  bool *casenull = NULL;
1705  ListCell *lc;
1706 
1707  /*
1708  * If there's a test expression, we have to evaluate it and
1709  * save the value where the CaseTestExpr placeholders can find
1710  * it.
1711  */
1712  if (caseExpr->arg != NULL)
1713  {
1714  /* Evaluate testexpr into caseval/casenull workspace */
1715  caseval = palloc(sizeof(Datum));
1716  casenull = palloc(sizeof(bool));
1717 
1718  ExecInitExprRec(caseExpr->arg, state,
1719  caseval, casenull);
1720 
1721  /*
1722  * Since value might be read multiple times, force to R/O
1723  * - but only if it could be an expanded datum.
1724  */
1725  if (get_typlen(exprType((Node *) caseExpr->arg)) == -1)
1726  {
1727  /* change caseval in-place */
1728  scratch.opcode = EEOP_MAKE_READONLY;
1729  scratch.resvalue = caseval;
1730  scratch.resnull = casenull;
1731  scratch.d.make_readonly.value = caseval;
1732  scratch.d.make_readonly.isnull = casenull;
1733  ExprEvalPushStep(state, &scratch);
1734  /* restore normal settings of scratch fields */
1735  scratch.resvalue = resv;
1736  scratch.resnull = resnull;
1737  }
1738  }
1739 
1740  /*
1741  * Prepare to evaluate each of the WHEN clauses in turn; as
1742  * soon as one is true we return the value of the
1743  * corresponding THEN clause. If none are true then we return
1744  * the value of the ELSE clause, or NULL if there is none.
1745  */
1746  foreach(lc, caseExpr->args)
1747  {
1748  CaseWhen *when = (CaseWhen *) lfirst(lc);
1749  Datum *save_innermost_caseval;
1750  bool *save_innermost_casenull;
1751  int whenstep;
1752 
1753  /*
1754  * Make testexpr result available to CaseTestExpr nodes
1755  * within the condition. We must save and restore prior
1756  * setting of innermost_caseval fields, in case this node
1757  * is itself within a larger CASE.
1758  *
1759  * If there's no test expression, we don't actually need
1760  * to save and restore these fields; but it's less code to
1761  * just do so unconditionally.
1762  */
1763  save_innermost_caseval = state->innermost_caseval;
1764  save_innermost_casenull = state->innermost_casenull;
1765  state->innermost_caseval = caseval;
1766  state->innermost_casenull = casenull;
1767 
1768  /* evaluate condition into CASE's result variables */
1769  ExecInitExprRec(when->expr, state, resv, resnull);
1770 
1771  state->innermost_caseval = save_innermost_caseval;
1772  state->innermost_casenull = save_innermost_casenull;
1773 
1774  /* If WHEN result isn't true, jump to next CASE arm */
1775  scratch.opcode = EEOP_JUMP_IF_NOT_TRUE;
1776  scratch.d.jump.jumpdone = -1; /* computed later */
1777  ExprEvalPushStep(state, &scratch);
1778  whenstep = state->steps_len - 1;
1779 
1780  /*
1781  * If WHEN result is true, evaluate THEN result, storing
1782  * it into the CASE's result variables.
1783  */
1784  ExecInitExprRec(when->result, state, resv, resnull);
1785 
1786  /* Emit JUMP step to jump to end of CASE's code */
1787  scratch.opcode = EEOP_JUMP;
1788  scratch.d.jump.jumpdone = -1; /* computed later */
1789  ExprEvalPushStep(state, &scratch);
1790 
1791  /*
1792  * Don't know address for that jump yet, compute once the
1793  * whole CASE expression is built.
1794  */
1795  adjust_jumps = lappend_int(adjust_jumps,
1796  state->steps_len - 1);
1797 
1798  /*
1799  * But we can set WHEN test's jump target now, to make it
1800  * jump to the next WHEN subexpression or the ELSE.
1801  */
1802  state->steps[whenstep].d.jump.jumpdone = state->steps_len;
1803  }
1804 
1805  /* transformCaseExpr always adds a default */
1806  Assert(caseExpr->defresult);
1807 
1808  /* evaluate ELSE expr into CASE's result variables */
1809  ExecInitExprRec(caseExpr->defresult, state,
1810  resv, resnull);
1811 
1812  /* adjust jump targets */
1813  foreach(lc, adjust_jumps)
1814  {
1815  ExprEvalStep *as = &state->steps[lfirst_int(lc)];
1816 
1817  Assert(as->opcode == EEOP_JUMP);
1818  Assert(as->d.jump.jumpdone == -1);
1819  as->d.jump.jumpdone = state->steps_len;
1820  }
1821 
1822  break;
1823  }
1824 
1825  case T_CaseTestExpr:
1826  {
1827  /*
1828  * Read from location identified by innermost_caseval. Note
1829  * that innermost_caseval could be NULL, if this node isn't
1830  * actually within a CaseExpr, ArrayCoerceExpr, etc structure.
1831  * That can happen because some parts of the system abuse
1832  * CaseTestExpr to cause a read of a value externally supplied
1833  * in econtext->caseValue_datum. We'll take care of that
1834  * scenario at runtime.
1835  */
1836  scratch.opcode = EEOP_CASE_TESTVAL;
1837  scratch.d.casetest.value = state->innermost_caseval;
1838  scratch.d.casetest.isnull = state->innermost_casenull;
1839 
1840  ExprEvalPushStep(state, &scratch);
1841  break;
1842  }
1843 
1844  case T_ArrayExpr:
1845  {
1846  ArrayExpr *arrayexpr = (ArrayExpr *) node;
1847  int nelems = list_length(arrayexpr->elements);
1848  ListCell *lc;
1849  int elemoff;
1850 
1851  /*
1852  * Evaluate by computing each element, and then forming the
1853  * array. Elements are computed into scratch arrays
1854  * associated with the ARRAYEXPR step.
1855  */
1856  scratch.opcode = EEOP_ARRAYEXPR;
1857  scratch.d.arrayexpr.elemvalues =
1858  (Datum *) palloc(sizeof(Datum) * nelems);
1859  scratch.d.arrayexpr.elemnulls =
1860  (bool *) palloc(sizeof(bool) * nelems);
1861  scratch.d.arrayexpr.nelems = nelems;
1862 
1863  /* fill remaining fields of step */
1864  scratch.d.arrayexpr.multidims = arrayexpr->multidims;
1865  scratch.d.arrayexpr.elemtype = arrayexpr->element_typeid;
1866 
1867  /* do one-time catalog lookup for type info */
1868  get_typlenbyvalalign(arrayexpr->element_typeid,
1869  &scratch.d.arrayexpr.elemlength,
1870  &scratch.d.arrayexpr.elembyval,
1871  &scratch.d.arrayexpr.elemalign);
1872 
1873  /* prepare to evaluate all arguments */
1874  elemoff = 0;
1875  foreach(lc, arrayexpr->elements)
1876  {
1877  Expr *e = (Expr *) lfirst(lc);
1878 
1880  &scratch.d.arrayexpr.elemvalues[elemoff],
1881  &scratch.d.arrayexpr.elemnulls[elemoff]);
1882  elemoff++;
1883  }
1884 
1885  /* and then collect all into an array */
1886  ExprEvalPushStep(state, &scratch);
1887  break;
1888  }
1889 
1890  case T_RowExpr:
1891  {
1892  RowExpr *rowexpr = (RowExpr *) node;
1893  int nelems = list_length(rowexpr->args);
1894  TupleDesc tupdesc;
1895  int i;
1896  ListCell *l;
1897 
1898  /* Build tupdesc to describe result tuples */
1899  if (rowexpr->row_typeid == RECORDOID)
1900  {
1901  /* generic record, use types of given expressions */
1902  tupdesc = ExecTypeFromExprList(rowexpr->args);
1903  /* ... but adopt RowExpr's column aliases */
1904  ExecTypeSetColNames(tupdesc, rowexpr->colnames);
1905  /* Bless the tupdesc so it can be looked up later */
1906  BlessTupleDesc(tupdesc);
1907  }
1908  else
1909  {
1910  /* it's been cast to a named type, use that */
1911  tupdesc = lookup_rowtype_tupdesc_copy(rowexpr->row_typeid, -1);
1912  }
1913 
1914  /*
1915  * In the named-type case, the tupdesc could have more columns
1916  * than are in the args list, since the type might have had
1917  * columns added since the ROW() was parsed. We want those
1918  * extra columns to go to nulls, so we make sure that the
1919  * workspace arrays are large enough and then initialize any
1920  * extra columns to read as NULLs.
1921  */
1922  Assert(nelems <= tupdesc->natts);
1923  nelems = Max(nelems, tupdesc->natts);
1924 
1925  /*
1926  * Evaluate by first building datums for each field, and then
1927  * a final step forming the composite datum.
1928  */
1929  scratch.opcode = EEOP_ROW;
1930  scratch.d.row.tupdesc = tupdesc;
1931 
1932  /* space for the individual field datums */
1933  scratch.d.row.elemvalues =
1934  (Datum *) palloc(sizeof(Datum) * nelems);
1935  scratch.d.row.elemnulls =
1936  (bool *) palloc(sizeof(bool) * nelems);
1937  /* as explained above, make sure any extra columns are null */
1938  memset(scratch.d.row.elemnulls, true, sizeof(bool) * nelems);
1939 
1940  /* Set up evaluation, skipping any deleted columns */
1941  i = 0;
1942  foreach(l, rowexpr->args)
1943  {
1944  Form_pg_attribute att = TupleDescAttr(tupdesc, i);
1945  Expr *e = (Expr *) lfirst(l);
1946 
1947  if (!att->attisdropped)
1948  {
1949  /*
1950  * Guard against ALTER COLUMN TYPE on rowtype since
1951  * the RowExpr was created. XXX should we check
1952  * typmod too? Not sure we can be sure it'll be the
1953  * same.
1954  */
1955  if (exprType((Node *) e) != att->atttypid)
1956  ereport(ERROR,
1957  (errcode(ERRCODE_DATATYPE_MISMATCH),
1958  errmsg("ROW() column has type %s instead of type %s",
1959  format_type_be(exprType((Node *) e)),
1960  format_type_be(att->atttypid))));
1961  }
1962  else
1963  {
1964  /*
1965  * Ignore original expression and insert a NULL. We
1966  * don't really care what type of NULL it is, so
1967  * always make an int4 NULL.
1968  */
1969  e = (Expr *) makeNullConst(INT4OID, -1, InvalidOid);
1970  }
1971 
1972  /* Evaluate column expr into appropriate workspace slot */
1974  &scratch.d.row.elemvalues[i],
1975  &scratch.d.row.elemnulls[i]);
1976  i++;
1977  }
1978 
1979  /* And finally build the row value */
1980  ExprEvalPushStep(state, &scratch);
1981  break;
1982  }
1983 
1984  case T_RowCompareExpr:
1985  {
1986  RowCompareExpr *rcexpr = (RowCompareExpr *) node;
1987  int nopers = list_length(rcexpr->opnos);
1988  List *adjust_jumps = NIL;
1989  ListCell *l_left_expr,
1990  *l_right_expr,
1991  *l_opno,
1992  *l_opfamily,
1993  *l_inputcollid;
1994  ListCell *lc;
1995 
1996  /*
1997  * Iterate over each field, prepare comparisons. To handle
1998  * NULL results, prepare jumps to after the expression. If a
1999  * comparison yields a != 0 result, jump to the final step.
2000  */
2001  Assert(list_length(rcexpr->largs) == nopers);
2002  Assert(list_length(rcexpr->rargs) == nopers);
2003  Assert(list_length(rcexpr->opfamilies) == nopers);
2004  Assert(list_length(rcexpr->inputcollids) == nopers);
2005 
2006  forfive(l_left_expr, rcexpr->largs,
2007  l_right_expr, rcexpr->rargs,
2008  l_opno, rcexpr->opnos,
2009  l_opfamily, rcexpr->opfamilies,
2010  l_inputcollid, rcexpr->inputcollids)
2011  {
2012  Expr *left_expr = (Expr *) lfirst(l_left_expr);
2013  Expr *right_expr = (Expr *) lfirst(l_right_expr);
2014  Oid opno = lfirst_oid(l_opno);
2015  Oid opfamily = lfirst_oid(l_opfamily);
2016  Oid inputcollid = lfirst_oid(l_inputcollid);
2017  int strategy;
2018  Oid lefttype;
2019  Oid righttype;
2020  Oid proc;
2021  FmgrInfo *finfo;
2022  FunctionCallInfo fcinfo;
2023 
2024  get_op_opfamily_properties(opno, opfamily, false,
2025  &strategy,
2026  &lefttype,
2027  &righttype);
2028  proc = get_opfamily_proc(opfamily,
2029  lefttype,
2030  righttype,
2031  BTORDER_PROC);
2032  if (!OidIsValid(proc))
2033  elog(ERROR, "missing support function %d(%u,%u) in opfamily %u",
2034  BTORDER_PROC, lefttype, righttype, opfamily);
2035 
2036  /* Set up the primary fmgr lookup information */
2037  finfo = palloc0(sizeof(FmgrInfo));
2038  fcinfo = palloc0(SizeForFunctionCallInfo(2));
2039  fmgr_info(proc, finfo);
2040  fmgr_info_set_expr((Node *) node, finfo);
2041  InitFunctionCallInfoData(*fcinfo, finfo, 2,
2042  inputcollid, NULL, NULL);
2043 
2044  /*
2045  * If we enforced permissions checks on index support
2046  * functions, we'd need to make a check here. But the
2047  * index support machinery doesn't do that, and thus
2048  * neither does this code.
2049  */
2050 
2051  /* evaluate left and right args directly into fcinfo */
2052  ExecInitExprRec(left_expr, state,
2053  &fcinfo->args[0].value, &fcinfo->args[0].isnull);
2054  ExecInitExprRec(right_expr, state,
2055  &fcinfo->args[1].value, &fcinfo->args[1].isnull);
2056 
2057  scratch.opcode = EEOP_ROWCOMPARE_STEP;
2058  scratch.d.rowcompare_step.finfo = finfo;
2059  scratch.d.rowcompare_step.fcinfo_data = fcinfo;
2060  scratch.d.rowcompare_step.fn_addr = finfo->fn_addr;
2061  /* jump targets filled below */
2062  scratch.d.rowcompare_step.jumpnull = -1;
2063  scratch.d.rowcompare_step.jumpdone = -1;
2064 
2065  ExprEvalPushStep(state, &scratch);
2066  adjust_jumps = lappend_int(adjust_jumps,
2067  state->steps_len - 1);
2068  }
2069 
2070  /*
2071  * We could have a zero-column rowtype, in which case the rows
2072  * necessarily compare equal.
2073  */
2074  if (nopers == 0)
2075  {
2076  scratch.opcode = EEOP_CONST;
2077  scratch.d.constval.value = Int32GetDatum(0);
2078  scratch.d.constval.isnull = false;
2079  ExprEvalPushStep(state, &scratch);
2080  }
2081 
2082  /* Finally, examine the last comparison result */
2083  scratch.opcode = EEOP_ROWCOMPARE_FINAL;
2084  scratch.d.rowcompare_final.rctype = rcexpr->rctype;
2085  ExprEvalPushStep(state, &scratch);
2086 
2087  /* adjust jump targets */
2088  foreach(lc, adjust_jumps)
2089  {
2090  ExprEvalStep *as = &state->steps[lfirst_int(lc)];
2091 
2093  Assert(as->d.rowcompare_step.jumpdone == -1);
2094  Assert(as->d.rowcompare_step.jumpnull == -1);
2095 
2096  /* jump to comparison evaluation */
2097  as->d.rowcompare_step.jumpdone = state->steps_len - 1;
2098  /* jump to the following expression */
2099  as->d.rowcompare_step.jumpnull = state->steps_len;
2100  }
2101 
2102  break;
2103  }
2104 
2105  case T_CoalesceExpr:
2106  {
2107  CoalesceExpr *coalesce = (CoalesceExpr *) node;
2108  List *adjust_jumps = NIL;
2109  ListCell *lc;
2110 
2111  /* We assume there's at least one arg */
2112  Assert(coalesce->args != NIL);
2113 
2114  /*
2115  * Prepare evaluation of all coalesced arguments, after each
2116  * one push a step that short-circuits if not null.
2117  */
2118  foreach(lc, coalesce->args)
2119  {
2120  Expr *e = (Expr *) lfirst(lc);
2121 
2122  /* evaluate argument, directly into result datum */
2123  ExecInitExprRec(e, state, resv, resnull);
2124 
2125  /* if it's not null, skip to end of COALESCE expr */
2126  scratch.opcode = EEOP_JUMP_IF_NOT_NULL;
2127  scratch.d.jump.jumpdone = -1; /* adjust later */
2128  ExprEvalPushStep(state, &scratch);
2129 
2130  adjust_jumps = lappend_int(adjust_jumps,
2131  state->steps_len - 1);
2132  }
2133 
2134  /*
2135  * No need to add a constant NULL return - we only can get to
2136  * the end of the expression if a NULL already is being
2137  * returned.
2138  */
2139 
2140  /* adjust jump targets */
2141  foreach(lc, adjust_jumps)
2142  {
2143  ExprEvalStep *as = &state->steps[lfirst_int(lc)];
2144 
2146  Assert(as->d.jump.jumpdone == -1);
2147  as->d.jump.jumpdone = state->steps_len;
2148  }
2149 
2150  break;
2151  }
2152 
2153  case T_MinMaxExpr:
2154  {
2155  MinMaxExpr *minmaxexpr = (MinMaxExpr *) node;
2156  int nelems = list_length(minmaxexpr->args);
2157  TypeCacheEntry *typentry;
2158  FmgrInfo *finfo;
2159  FunctionCallInfo fcinfo;
2160  ListCell *lc;
2161  int off;
2162 
2163  /* Look up the btree comparison function for the datatype */
2164  typentry = lookup_type_cache(minmaxexpr->minmaxtype,
2166  if (!OidIsValid(typentry->cmp_proc))
2167  ereport(ERROR,
2168  (errcode(ERRCODE_UNDEFINED_FUNCTION),
2169  errmsg("could not identify a comparison function for type %s",
2170  format_type_be(minmaxexpr->minmaxtype))));
2171 
2172  /*
2173  * If we enforced permissions checks on index support
2174  * functions, we'd need to make a check here. But the index
2175  * support machinery doesn't do that, and thus neither does
2176  * this code.
2177  */
2178 
2179  /* Perform function lookup */
2180  finfo = palloc0(sizeof(FmgrInfo));
2181  fcinfo = palloc0(SizeForFunctionCallInfo(2));
2182  fmgr_info(typentry->cmp_proc, finfo);
2183  fmgr_info_set_expr((Node *) node, finfo);
2184  InitFunctionCallInfoData(*fcinfo, finfo, 2,
2185  minmaxexpr->inputcollid, NULL, NULL);
2186 
2187  scratch.opcode = EEOP_MINMAX;
2188  /* allocate space to store arguments */
2189  scratch.d.minmax.values =
2190  (Datum *) palloc(sizeof(Datum) * nelems);
2191  scratch.d.minmax.nulls =
2192  (bool *) palloc(sizeof(bool) * nelems);
2193  scratch.d.minmax.nelems = nelems;
2194 
2195  scratch.d.minmax.op = minmaxexpr->op;
2196  scratch.d.minmax.finfo = finfo;
2197  scratch.d.minmax.fcinfo_data = fcinfo;
2198 
2199  /* evaluate expressions into minmax->values/nulls */
2200  off = 0;
2201  foreach(lc, minmaxexpr->args)
2202  {
2203  Expr *e = (Expr *) lfirst(lc);
2204 
2206  &scratch.d.minmax.values[off],
2207  &scratch.d.minmax.nulls[off]);
2208  off++;
2209  }
2210 
2211  /* and push the final comparison */
2212  ExprEvalPushStep(state, &scratch);
2213  break;
2214  }
2215 
2216  case T_XmlExpr:
2217  {
2218  XmlExpr *xexpr = (XmlExpr *) node;
2219  int nnamed = list_length(xexpr->named_args);
2220  int nargs = list_length(xexpr->args);
2221  int off;
2222  ListCell *arg;
2223 
2224  scratch.opcode = EEOP_XMLEXPR;
2225  scratch.d.xmlexpr.xexpr = xexpr;
2226 
2227  /* allocate space for storing all the arguments */
2228  if (nnamed)
2229  {
2230  scratch.d.xmlexpr.named_argvalue =
2231  (Datum *) palloc(sizeof(Datum) * nnamed);
2232  scratch.d.xmlexpr.named_argnull =
2233  (bool *) palloc(sizeof(bool) * nnamed);
2234  }
2235  else
2236  {
2237  scratch.d.xmlexpr.named_argvalue = NULL;
2238  scratch.d.xmlexpr.named_argnull = NULL;
2239  }
2240 
2241  if (nargs)
2242  {
2243  scratch.d.xmlexpr.argvalue =
2244  (Datum *) palloc(sizeof(Datum) * nargs);
2245  scratch.d.xmlexpr.argnull =
2246  (bool *) palloc(sizeof(bool) * nargs);
2247  }
2248  else
2249  {
2250  scratch.d.xmlexpr.argvalue = NULL;
2251  scratch.d.xmlexpr.argnull = NULL;
2252  }
2253 
2254  /* prepare argument execution */
2255  off = 0;
2256  foreach(arg, xexpr->named_args)
2257  {
2258  Expr *e = (Expr *) lfirst(arg);
2259 
2261  &scratch.d.xmlexpr.named_argvalue[off],
2262  &scratch.d.xmlexpr.named_argnull[off]);
2263  off++;
2264  }
2265 
2266  off = 0;
2267  foreach(arg, xexpr->args)
2268  {
2269  Expr *e = (Expr *) lfirst(arg);
2270 
2272  &scratch.d.xmlexpr.argvalue[off],
2273  &scratch.d.xmlexpr.argnull[off]);
2274  off++;
2275  }
2276 
2277  /* and evaluate the actual XML expression */
2278  ExprEvalPushStep(state, &scratch);
2279  break;
2280  }
2281 
2282  case T_JsonValueExpr:
2283  {
2284  JsonValueExpr *jve = (JsonValueExpr *) node;
2285 
2286  ExecInitExprRec(jve->raw_expr, state, resv, resnull);
2287 
2288  if (jve->formatted_expr)
2289  {
2290  Datum *innermost_caseval = state->innermost_caseval;
2291  bool *innermost_isnull = state->innermost_casenull;
2292 
2293  state->innermost_caseval = resv;
2294  state->innermost_casenull = resnull;
2295 
2296  ExecInitExprRec(jve->formatted_expr, state, resv, resnull);
2297 
2298  state->innermost_caseval = innermost_caseval;
2299  state->innermost_casenull = innermost_isnull;
2300  }
2301  break;
2302  }
2303 
2304  case T_JsonConstructorExpr:
2305  {
2306  JsonConstructorExpr *ctor = (JsonConstructorExpr *) node;
2307  List *args = ctor->args;
2308  ListCell *lc;
2309  int nargs = list_length(args);
2310  int argno = 0;
2311 
2312  if (ctor->func)
2313  {
2314  ExecInitExprRec(ctor->func, state, resv, resnull);
2315  }
2316  else
2317  {
2318  JsonConstructorExprState *jcstate;
2319 
2320  jcstate = palloc0(sizeof(JsonConstructorExprState));
2321 
2322  scratch.opcode = EEOP_JSON_CONSTRUCTOR;
2323  scratch.d.json_constructor.jcstate = jcstate;
2324 
2325  jcstate->constructor = ctor;
2326  jcstate->arg_values = (Datum *) palloc(sizeof(Datum) * nargs);
2327  jcstate->arg_nulls = (bool *) palloc(sizeof(bool) * nargs);
2328  jcstate->arg_types = (Oid *) palloc(sizeof(Oid) * nargs);
2329  jcstate->nargs = nargs;
2330 
2331  foreach(lc, args)
2332  {
2333  Expr *arg = (Expr *) lfirst(lc);
2334 
2335  jcstate->arg_types[argno] = exprType((Node *) arg);
2336 
2337  if (IsA(arg, Const))
2338  {
2339  /* Don't evaluate const arguments every round */
2340  Const *con = (Const *) arg;
2341 
2342  jcstate->arg_values[argno] = con->constvalue;
2343  jcstate->arg_nulls[argno] = con->constisnull;
2344  }
2345  else
2346  {
2348  &jcstate->arg_values[argno],
2349  &jcstate->arg_nulls[argno]);
2350  }
2351  argno++;
2352  }
2353 
2354  ExprEvalPushStep(state, &scratch);
2355  }
2356 
2357  if (ctor->coercion)
2358  {
2359  Datum *innermost_caseval = state->innermost_caseval;
2360  bool *innermost_isnull = state->innermost_casenull;
2361 
2362  state->innermost_caseval = resv;
2363  state->innermost_casenull = resnull;
2364 
2365  ExecInitExprRec(ctor->coercion, state, resv, resnull);
2366 
2367  state->innermost_caseval = innermost_caseval;
2368  state->innermost_casenull = innermost_isnull;
2369  }
2370  }
2371  break;
2372 
2373  case T_NullTest:
2374  {
2375  NullTest *ntest = (NullTest *) node;
2376 
2377  if (ntest->nulltesttype == IS_NULL)
2378  {
2379  if (ntest->argisrow)
2380  scratch.opcode = EEOP_NULLTEST_ROWISNULL;
2381  else
2382  scratch.opcode = EEOP_NULLTEST_ISNULL;
2383  }
2384  else if (ntest->nulltesttype == IS_NOT_NULL)
2385  {
2386  if (ntest->argisrow)
2388  else
2389  scratch.opcode = EEOP_NULLTEST_ISNOTNULL;
2390  }
2391  else
2392  {
2393  elog(ERROR, "unrecognized nulltesttype: %d",
2394  (int) ntest->nulltesttype);
2395  }
2396  /* initialize cache in case it's a row test */
2397  scratch.d.nulltest_row.rowcache.cacheptr = NULL;
2398 
2399  /* first evaluate argument into result variable */
2400  ExecInitExprRec(ntest->arg, state,
2401  resv, resnull);
2402 
2403  /* then push the test of that argument */
2404  ExprEvalPushStep(state, &scratch);
2405  break;
2406  }
2407 
2408  case T_BooleanTest:
2409  {
2410  BooleanTest *btest = (BooleanTest *) node;
2411 
2412  /*
2413  * Evaluate argument, directly into result datum. That's ok,
2414  * because resv/resnull is definitely not used anywhere else,
2415  * and will get overwritten by the below EEOP_BOOLTEST_IS_*
2416  * step.
2417  */
2418  ExecInitExprRec(btest->arg, state, resv, resnull);
2419 
2420  switch (btest->booltesttype)
2421  {
2422  case IS_TRUE:
2423  scratch.opcode = EEOP_BOOLTEST_IS_TRUE;
2424  break;
2425  case IS_NOT_TRUE:
2427  break;
2428  case IS_FALSE:
2429  scratch.opcode = EEOP_BOOLTEST_IS_FALSE;
2430  break;
2431  case IS_NOT_FALSE:
2433  break;
2434  case IS_UNKNOWN:
2435  /* Same as scalar IS NULL test */
2436  scratch.opcode = EEOP_NULLTEST_ISNULL;
2437  break;
2438  case IS_NOT_UNKNOWN:
2439  /* Same as scalar IS NOT NULL test */
2440  scratch.opcode = EEOP_NULLTEST_ISNOTNULL;
2441  break;
2442  default:
2443  elog(ERROR, "unrecognized booltesttype: %d",
2444  (int) btest->booltesttype);
2445  }
2446 
2447  ExprEvalPushStep(state, &scratch);
2448  break;
2449  }
2450 
2451  case T_CoerceToDomain:
2452  {
2453  CoerceToDomain *ctest = (CoerceToDomain *) node;
2454 
2455  ExecInitCoerceToDomain(&scratch, ctest, state,
2456  resv, resnull);
2457  break;
2458  }
2459 
2460  case T_CoerceToDomainValue:
2461  {
2462  /*
2463  * Read from location identified by innermost_domainval. Note
2464  * that innermost_domainval could be NULL, if we're compiling
2465  * a standalone domain check rather than one embedded in a
2466  * larger expression. In that case we must read from
2467  * econtext->domainValue_datum. We'll take care of that
2468  * scenario at runtime.
2469  */
2470  scratch.opcode = EEOP_DOMAIN_TESTVAL;
2471  /* we share instruction union variant with case testval */
2472  scratch.d.casetest.value = state->innermost_domainval;
2473  scratch.d.casetest.isnull = state->innermost_domainnull;
2474 
2475  ExprEvalPushStep(state, &scratch);
2476  break;
2477  }
2478 
2479  case T_CurrentOfExpr:
2480  {
2481  scratch.opcode = EEOP_CURRENTOFEXPR;
2482  ExprEvalPushStep(state, &scratch);
2483  break;
2484  }
2485 
2486  case T_NextValueExpr:
2487  {
2488  NextValueExpr *nve = (NextValueExpr *) node;
2489 
2490  scratch.opcode = EEOP_NEXTVALUEEXPR;
2491  scratch.d.nextvalueexpr.seqid = nve->seqid;
2492  scratch.d.nextvalueexpr.seqtypid = nve->typeId;
2493 
2494  ExprEvalPushStep(state, &scratch);
2495  break;
2496  }
2497 
2498  default:
2499  elog(ERROR, "unrecognized node type: %d",
2500  (int) nodeTag(node));
2501  break;
2502  }
2503 }
#define InvalidAttrNumber
Definition: attnum.h:23
static void ExecInitCoerceToDomain(ExprEvalStep *scratch, CoerceToDomain *ctest, ExprState *state, Datum *resv, bool *resnull)
Definition: execExpr.c:3250
static void ExecInitWholeRowVar(ExprEvalStep *scratch, Var *variable, ExprState *state)
Definition: execExpr.c:2904
List * ExecInitExprList(List *nodes, PlanState *parent)
Definition: execExpr.c:322
static void ExecInitSubscriptingRef(ExprEvalStep *scratch, SubscriptingRef *sbsref, ExprState *state, Datum *resv, bool *resnull)
Definition: execExpr.c:2977
static void ExecInitFunc(ExprEvalStep *scratch, Expr *node, List *args, Oid funcid, Oid inputcollid, ExprState *state)
Definition: execExpr.c:2538
@ EEOP_SUBPLAN
Definition: execExpr.h:242
@ EEOP_CONVERT_ROWTYPE
Definition: execExpr.h:234
@ EEOP_ARRAYEXPR
Definition: execExpr.h:176
@ EEOP_DOMAIN_TESTVAL
Definition: execExpr.h:225
@ EEOP_PARAM_EXTERN
Definition: execExpr.h:160
@ EEOP_BOOL_AND_STEP
Definition: execExpr.h:122
@ EEOP_AGGREF
Definition: execExpr.h:239
@ EEOP_ROWCOMPARE_FINAL
Definition: execExpr.h:187
@ EEOP_IOCOERCE
Definition: execExpr.h:170
@ EEOP_GROUPING_FUNC
Definition: execExpr.h:240
@ EEOP_BOOLTEST_IS_NOT_FALSE
Definition: execExpr.h:156
@ EEOP_NEXTVALUEEXPR
Definition: execExpr.h:175
@ EEOP_SCAN_VAR
Definition: execExpr.h:78
@ EEOP_BOOL_NOT_STEP
Definition: execExpr.h:131
@ EEOP_SCAN_SYSVAR
Definition: execExpr.h:83
@ EEOP_SCALARARRAYOP
Definition: execExpr.h:235
@ EEOP_WINDOW_FUNC
Definition: execExpr.h:241
@ EEOP_NULLTEST_ROWISNOTNULL
Definition: execExpr.h:150
@ EEOP_ROW
Definition: execExpr.h:178
@ EEOP_FIELDSTORE_FORM
Definition: execExpr.h:206
@ EEOP_NULLIF
Definition: execExpr.h:173
@ EEOP_CURRENTOFEXPR
Definition: execExpr.h:174
@ EEOP_INNER_SYSVAR
Definition: execExpr.h:81
@ EEOP_BOOL_OR_STEP_LAST
Definition: execExpr.h:128
@ EEOP_BOOL_OR_STEP_FIRST
Definition: execExpr.h:126
@ EEOP_XMLEXPR
Definition: execExpr.h:237
@ EEOP_OUTER_SYSVAR
Definition: execExpr.h:82
@ EEOP_BOOL_OR_STEP
Definition: execExpr.h:127
@ EEOP_NULLTEST_ROWISNULL
Definition: execExpr.h:149
@ EEOP_BOOLTEST_IS_TRUE
Definition: execExpr.h:153
@ EEOP_NULLTEST_ISNOTNULL
Definition: execExpr.h:146
@ EEOP_ROWCOMPARE_STEP
Definition: execExpr.h:184
@ EEOP_DISTINCT
Definition: execExpr.h:171
@ EEOP_BOOL_AND_STEP_FIRST
Definition: execExpr.h:121
@ EEOP_JUMP
Definition: execExpr.h:137
@ EEOP_BOOL_AND_STEP_LAST
Definition: execExpr.h:123
@ EEOP_JUMP_IF_NOT_NULL
Definition: execExpr.h:141
@ EEOP_FIELDSTORE_DEFORM
Definition: execExpr.h:199
@ EEOP_BOOLTEST_IS_FALSE
Definition: execExpr.h:155
@ EEOP_BOOLTEST_IS_NOT_TRUE
Definition: execExpr.h:154
@ EEOP_PARAM_EXEC
Definition: execExpr.h:159
@ EEOP_JSON_CONSTRUCTOR
Definition: execExpr.h:238
@ EEOP_NULLTEST_ISNULL
Definition: execExpr.h:145
@ EEOP_MINMAX
Definition: execExpr.h:190
@ EEOP_ARRAYCOERCE
Definition: execExpr.h:177
@ EEOP_FIELDSELECT
Definition: execExpr.h:193
@ EEOP_CASE_TESTVAL
Definition: execExpr.h:164
@ EEOP_HASHED_SCALARARRAYOP
Definition: execExpr.h:236
TupleDesc BlessTupleDesc(TupleDesc tupdesc)
Definition: execTuples.c:2072
void ExecTypeSetColNames(TupleDesc typeInfo, List *namesList)
Definition: execTuples.c:2031
TupleDesc ExecTypeFromExprList(List *exprList)
Definition: execTuples.c:1998
int i
Definition: isn.c:73
void get_op_opfamily_properties(Oid opno, Oid opfamily, bool ordering_op, int *strategy, Oid *lefttype, Oid *righttype)
Definition: lsyscache.c:135
Oid get_element_type(Oid typid)
Definition: lsyscache.c:2717
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition: lsyscache.c:2865
void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, char *typalign)
Definition: lsyscache.c:2229
Oid get_opfamily_proc(Oid opfamily, Oid lefttype, Oid righttype, int16 procnum)
Definition: lsyscache.c:795
void getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam)
Definition: lsyscache.c:2832
Const * makeNullConst(Oid consttype, int32 consttypmod, Oid constcollid)
Definition: makefuncs.c:340
#define BTORDER_PROC
Definition: nbtree.h:708
SubPlanState * ExecInitSubPlan(SubPlan *subplan, PlanState *parent)
Definition: nodeSubplan.c:823
#define nodeTag(nodeptr)
Definition: nodes.h:133
#define lsecond(l)
Definition: pg_list.h:183
#define forfive(cell1, list1, cell2, list2, cell3, list3, cell4, list4, cell5, list5)
Definition: pg_list.h:537
#define lfirst_oid(lc)
Definition: pg_list.h:174
void check_stack_depth(void)
Definition: postgres.c:3461
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:212
#define InvalidOid
Definition: postgres_ext.h:36
@ IS_NOT_TRUE
Definition: primnodes.h:1631
@ IS_NOT_FALSE
Definition: primnodes.h:1631
@ IS_NOT_UNKNOWN
Definition: primnodes.h:1631
@ IS_TRUE
Definition: primnodes.h:1631
@ IS_UNKNOWN
Definition: primnodes.h:1631
@ IS_FALSE
Definition: primnodes.h:1631
@ MULTIEXPR_SUBLINK
Definition: primnodes.h:929
@ AND_EXPR
Definition: primnodes.h:858
@ OR_EXPR
Definition: primnodes.h:858
@ NOT_EXPR
Definition: primnodes.h:858
@ PARAM_EXTERN
Definition: primnodes.h:345
@ PARAM_EXEC
Definition: primnodes.h:346
@ IS_NULL
Definition: primnodes.h:1607
@ IS_NOT_NULL
Definition: primnodes.h:1607
List * aggs
Definition: execnodes.h:2366
Definition: plannodes.h:998
List * groupingSets
Definition: plannodes.h:1029
List * elements
Definition: primnodes.h:1305
BoolExprType boolop
Definition: primnodes.h:866
List * args
Definition: primnodes.h:867
BoolTestType booltesttype
Definition: primnodes.h:1638
Expr * arg
Definition: primnodes.h:1637
Expr * arg
Definition: primnodes.h:1240
Expr * defresult
Definition: primnodes.h:1242
List * args
Definition: primnodes.h:1241
List * args
Definition: primnodes.h:1417
Expr * arg
Definition: primnodes.h:1134
Oid resulttype
Definition: primnodes.h:1135
struct ExprEvalStep::@50::@70 row
struct ExprEvalStep::@50::@84 aggref
struct ExprEvalStep::@50::@73 minmax
struct ExprEvalStep::@50::@58 boolexpr
struct ExprEvalStep::@50::@71 rowcompare_step
struct ExprEvalStep::@50::@72 rowcompare_final
struct ExprEvalStep::@50::@61 nulltest_row
struct ExprEvalStep::@50::@80 scalararrayop
struct ExprEvalStep::@50::@69 arraycoerce
struct ExprEvalStep::@50::@67 nextvalueexpr
struct ExprEvalStep::@50::@75 fieldstore
struct ExprEvalStep::@50::@74 fieldselect
struct ExprEvalStep::@50::@83 json_constructor
struct ExprEvalStep::@50::@82 xmlexpr
struct ExprEvalStep::@50::@68 arrayexpr
struct ExprEvalStep::@50::@62 param
struct ExprEvalStep::@50::@85 grouping_func
struct ExprEvalStep::@50::@87 subplan
struct ExprEvalStep::@50::@66 iocoerce
struct ExprEvalStep::@50::@86 window_func
struct ExprEvalStep::@50::@81 hashedscalararrayop
struct ExprEvalStep::@50::@79 convert_rowtype
struct ExprEvalStep::@50::@64 casetest
Expr * expr
Definition: execnodes.h:110
Datum resvalue
Definition: execnodes.h:90
struct ExprEvalStep * steps
Definition: execnodes.h:101
bool resnull
Definition: execnodes.h:88
ParamListInfo ext_params
Definition: execnodes.h:125
struct PlanState * parent
Definition: execnodes.h:124
bool * innermost_casenull
Definition: execnodes.h:128
Datum * innermost_caseval
Definition: execnodes.h:127
int steps_len
Definition: execnodes.h:120
AttrNumber fieldnum
Definition: primnodes.h:1056
Expr * arg
Definition: primnodes.h:1055
List * newvals
Definition: primnodes.h:1087
Expr * arg
Definition: primnodes.h:1086
Oid funcid
Definition: primnodes.h:677
List * args
Definition: primnodes.h:695
JsonConstructorExpr * constructor
Definition: execExpr.h:729
Expr * formatted_expr
Definition: primnodes.h:1557
Expr * raw_expr
Definition: primnodes.h:1556
List * args
Definition: primnodes.h:1443
MinMaxOp op
Definition: primnodes.h:1441
NullTestType nulltesttype
Definition: primnodes.h:1614
Expr * arg
Definition: primnodes.h:1613
List * args
Definition: primnodes.h:763
ParamCompileHook paramCompile
Definition: params.h:114
int paramid
Definition: primnodes.h:355
Oid paramtype
Definition: primnodes.h:356
ParamKind paramkind
Definition: primnodes.h:354
Expr * arg
Definition: primnodes.h:1111
RowCompareType rctype
Definition: primnodes.h:1393
List * args
Definition: primnodes.h:1336
SubLinkType subLinkType
Definition: primnodes.h:992
WindowFunc * wfunc
Definition: execnodes.h:861
ExprState * aggfilter
Definition: execnodes.h:863
List * args
Definition: primnodes.h:553
Expr * aggfilter
Definition: primnodes.h:555
List * args
Definition: primnodes.h:1489
List * named_args
Definition: primnodes.h:1485
Definition: type.h:88
#define ReleaseTupleDesc(tupdesc)
Definition: tupdesc.h:122
TupleDesc lookup_rowtype_tupdesc(Oid type_id, int32 typmod)
Definition: typcache.c:1824
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition: typcache.c:339
TupleDesc lookup_rowtype_tupdesc_copy(Oid type_id, int32 typmod)
Definition: typcache.c:1858
#define TYPECACHE_CMP_PROC
Definition: typcache.h:139
static void convert(const int32 val, char *const buf)
Definition: zic.c:1992

References ACL_EXECUTE, aclcheck_error(), ACLCHECK_OK, WindowFuncExprState::aggfilter, WindowFunc::aggfilter, ExprEvalStep::aggref, AggState::aggs, AND_EXPR, arg, FieldSelect::arg, FieldStore::arg, RelabelType::arg, CoerceViaIO::arg, ArrayCoerceExpr::arg, CaseExpr::arg, NullTest::arg, BooleanTest::arg, JsonConstructorExprState::arg_nulls, JsonConstructorExprState::arg_types, JsonConstructorExprState::arg_values, generate_unaccent_rules::args, FunctionCallInfoBaseData::args, WindowFuncExprState::args, WindowFunc::args, FuncExpr::args, OpExpr::args, ScalarArrayOpExpr::args, BoolExpr::args, CaseExpr::args, RowExpr::args, CoalesceExpr::args, MinMaxExpr::args, XmlExpr::args, JsonConstructorExpr::args, ExprEvalStep::arraycoerce, ExprEvalStep::arrayexpr, Assert(), BlessTupleDesc(), ExprEvalStep::boolexpr, BoolExpr::boolop, BooleanTest::booltesttype, BTORDER_PROC, ExprEvalRowtypeCache::cacheptr, ExprEvalStep::casetest, check_stack_depth(), TypeCacheEntry::cmp_proc, JsonConstructorExpr::coercion, JsonConstructorExprState::constructor, ExprEvalStep::constval, convert(), ExprEvalStep::convert_rowtype, ExprEvalStep::d, CaseExpr::defresult, EEOP_AGGREF, EEOP_ARRAYCOERCE, EEOP_ARRAYEXPR, EEOP_BOOL_AND_STEP, EEOP_BOOL_AND_STEP_FIRST, EEOP_BOOL_AND_STEP_LAST, EEOP_BOOL_NOT_STEP, EEOP_BOOL_OR_STEP, EEOP_BOOL_OR_STEP_FIRST, EEOP_BOOL_OR_STEP_LAST, EEOP_BOOLTEST_IS_FALSE, EEOP_BOOLTEST_IS_NOT_FALSE, EEOP_BOOLTEST_IS_NOT_TRUE, EEOP_BOOLTEST_IS_TRUE, EEOP_CASE_TESTVAL, EEOP_CONST, EEOP_CONVERT_ROWTYPE, EEOP_CURRENTOFEXPR, EEOP_DISTINCT, EEOP_DOMAIN_TESTVAL, EEOP_DONE, EEOP_FIELDSELECT, EEOP_FIELDSTORE_DEFORM, EEOP_FIELDSTORE_FORM, EEOP_GROUPING_FUNC, EEOP_HASHED_SCALARARRAYOP, EEOP_INNER_SYSVAR, EEOP_INNER_VAR, EEOP_IOCOERCE, EEOP_JSON_CONSTRUCTOR, EEOP_JUMP, EEOP_JUMP_IF_NOT_NULL, EEOP_JUMP_IF_NOT_TRUE, EEOP_MAKE_READONLY, EEOP_MINMAX, EEOP_NEXTVALUEEXPR, EEOP_NULLIF, EEOP_NULLTEST_ISNOTNULL, EEOP_NULLTEST_ISNULL, EEOP_NULLTEST_ROWISNOTNULL, EEOP_NULLTEST_ROWISNULL, EEOP_OUTER_SYSVAR, EEOP_OUTER_VAR, EEOP_PARAM_EXEC, EEOP_PARAM_EXTERN, EEOP_ROW, EEOP_ROWCOMPARE_FINAL, EEOP_ROWCOMPARE_STEP, EEOP_SCALARARRAYOP, EEOP_SCAN_SYSVAR, EEOP_SCAN_VAR, EEOP_SUBPLAN, EEOP_WINDOW_FUNC, EEOP_XMLEXPR, ArrayExpr::elements, ArrayCoerceExpr::elemexpr, elog(), ereport, errcode(), errmsg(), ERROR, ExecInitCoerceToDomain(), ExecInitExpr(), ExecInitExprList(), ExecInitFunc(), ExecInitSubPlan(), ExecInitSubscriptingRef(), ExecInitWholeRowVar(), ExecReadyExpr(), ExecTypeFromExprList(), ExecTypeSetColNames(), ExprState::expr, ExprEvalPushStep(), exprType(), ExprState::ext_params, FieldSelect::fieldnum, ExprEvalStep::fieldselect, ExprEvalStep::fieldstore, fmgr_info(), fmgr_info_set_expr, FmgrInfo::fn_addr, forboth, forfive, format_type_be(), JsonValueExpr::formatted_expr, JsonConstructorExpr::func, FuncExpr::funcid, WindowAggState::funcs, get_element_type(), get_func_name(), get_op_opfamily_properties(), get_opfamily_proc(), get_typlen(), get_typlenbyvalalign(), getTypeInputInfo(), getTypeOutputInfo(), GetUserId(), ExprEvalStep::grouping_func, Agg::groupingSets, ExprEvalStep::hashedscalararrayop, i, InitFunctionCallInfoData, INNER_VAR, ExprState::innermost_casenull, ExprState::innermost_caseval, Int32GetDatum(), InvalidAttrNumber, InvalidOid, InvokeFunctionExecuteHook, ExprEvalStep::iocoerce, IS_FALSE, IS_NOT_FALSE, IS_NOT_NULL, IS_NOT_TRUE, IS_NOT_UNKNOWN, IS_NULL, IS_TRUE, IS_UNKNOWN, IsA, NullableDatum::isnull, ExprEvalStep::json_constructor, ExprEvalStep::jump, lappend(), lappend_int(), RowCompareExpr::largs, lfirst, lfirst_int, lfirst_oid, linitial, list_length(), lookup_rowtype_tupdesc(), lookup_rowtype_tupdesc_copy(), lookup_type_cache(), lsecond, ExprEvalStep::make_readonly, makeNode, makeNullConst(), Max, ExprEvalStep::minmax, MULTIEXPR_SUBLINK, XmlExpr::named_args, JsonConstructorExprState::nargs, TupleDescData::natts, FieldStore::newvals, ExprEvalStep::nextvalueexpr, NIL, nodeTag, NOT_EXPR, ExprEvalStep::nulltest_row, NullTest::nulltesttype, WindowAggState::numaggs, WindowAggState::numfuncs, object_aclcheck(), OBJECT_FUNCTION, ObjectIdGetDatum(), OidIsValid, MinMaxExpr::op, ExprEvalStep::opcode, OR_EXPR, OUTER_VAR, palloc(), palloc0(), ExprEvalStep::param, PARAM_EXEC, PARAM_EXTERN, ParamListInfoData::paramCompile, Param::paramid, Param::paramkind, Param::paramtype, ExprState::parent, RowCompareExpr::rargs, JsonValueExpr::raw_expr, RowCompareExpr::rctype, ReleaseTupleDesc, ExprEvalStep::resnull, ExprState::resnull, CoerceViaIO::resulttype, ArrayCoerceExpr::resulttype, ExprEvalStep::resvalue, ExprState::resvalue, ExprEvalStep::row, ExprEvalStep::rowcompare_final, ExprEvalStep::rowcompare_step, ExprEvalStep::scalararrayop, NextValueExpr::seqid, SizeForFunctionCallInfo, ExprState::steps, ExprState::steps_len, SubPlan::subLinkType, ExprEvalStep::subplan, TupleDescAttr, TYPECACHE_CMP_PROC, NextValueExpr::typeId, ScalarArrayOpExpr::useOr, NullableDatum::value, values, ExprEvalStep::var, WindowFuncExprState::wfunc, ExprEvalStep::window_func, and ExprEvalStep::xmlexpr.

Referenced by ExecBuildAggTrans(), ExecBuildProjectionInfo(), ExecBuildUpdateProjection(), ExecInitCoerceToDomain(), ExecInitExpr(), ExecInitExprWithParams(), ExecInitFunc(), ExecInitQual(), and ExecInitSubscriptingRef().

◆ ExecInitExprWithParams()

ExprState* ExecInitExprWithParams ( Expr node,
ParamListInfo  ext_params 
)

Definition at line 164 of file execExpr.c.

165 {
166  ExprState *state;
167  ExprEvalStep scratch = {0};
168 
169  /* Special case: NULL expression produces a NULL ExprState pointer */
170  if (node == NULL)
171  return NULL;
172 
173  /* Initialize ExprState with empty step list */
175  state->expr = node;
176  state->parent = NULL;
177  state->ext_params = ext_params;
178 
179  /* Insert setup steps as needed */
181 
182  /* Compile the expression proper */
183  ExecInitExprRec(node, state, &state->resvalue, &state->resnull);
184 
185  /* Finally, append a DONE step */
186  scratch.opcode = EEOP_DONE;
187  ExprEvalPushStep(state, &scratch);
188 
190 
191  return state;
192 }

References EEOP_DONE, ExecCreateExprSetupSteps(), ExecInitExprRec(), ExecReadyExpr(), ExprEvalPushStep(), makeNode, and ExprEvalStep::opcode.

Referenced by exec_eval_simple_expr(), and InitPartitionPruneContext().

◆ ExecInitFunc()

static void ExecInitFunc ( ExprEvalStep scratch,
Expr node,
List args,
Oid  funcid,
Oid  inputcollid,
ExprState state 
)
static

Definition at line 2538 of file execExpr.c.

2540 {
2541  int nargs = list_length(args);
2542  AclResult aclresult;
2543  FmgrInfo *flinfo;
2544  FunctionCallInfo fcinfo;
2545  int argno;
2546  ListCell *lc;
2547 
2548  /* Check permission to call function */
2549  aclresult = object_aclcheck(ProcedureRelationId, funcid, GetUserId(), ACL_EXECUTE);
2550  if (aclresult != ACLCHECK_OK)
2551  aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(funcid));
2552  InvokeFunctionExecuteHook(funcid);
2553 
2554  /*
2555  * Safety check on nargs. Under normal circumstances this should never
2556  * fail, as parser should check sooner. But possibly it might fail if
2557  * server has been compiled with FUNC_MAX_ARGS smaller than some functions
2558  * declared in pg_proc?
2559  */
2560  if (nargs > FUNC_MAX_ARGS)
2561  ereport(ERROR,
2562  (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
2563  errmsg_plural("cannot pass more than %d argument to a function",
2564  "cannot pass more than %d arguments to a function",
2565  FUNC_MAX_ARGS,
2566  FUNC_MAX_ARGS)));
2567 
2568  /* Allocate function lookup data and parameter workspace for this call */
2569  scratch->d.func.finfo = palloc0(sizeof(FmgrInfo));
2570  scratch->d.func.fcinfo_data = palloc0(SizeForFunctionCallInfo(nargs));
2571  flinfo = scratch->d.func.finfo;
2572  fcinfo = scratch->d.func.fcinfo_data;
2573 
2574  /* Set up the primary fmgr lookup information */
2575  fmgr_info(funcid, flinfo);
2576  fmgr_info_set_expr((Node *) node, flinfo);
2577 
2578  /* Initialize function call parameter structure too */
2579  InitFunctionCallInfoData(*fcinfo, flinfo,
2580  nargs, inputcollid, NULL, NULL);
2581 
2582  /* Keep extra copies of this info to save an indirection at runtime */
2583  scratch->d.func.fn_addr = flinfo->fn_addr;
2584  scratch->d.func.nargs = nargs;
2585 
2586  /* We only support non-set functions here */
2587  if (flinfo->fn_retset)
2588  ereport(ERROR,
2589  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2590  errmsg("set-valued function called in context that cannot accept a set"),
2591  state->parent ?
2592  executor_errposition(state->parent->state,
2593  exprLocation((Node *) node)) : 0));
2594 
2595  /* Build code to evaluate arguments directly into the fcinfo struct */
2596  argno = 0;
2597  foreach(lc, args)
2598  {
2599  Expr *arg = (Expr *) lfirst(lc);
2600 
2601  if (IsA(arg, Const))
2602  {
2603  /*
2604  * Don't evaluate const arguments every round; especially
2605  * interesting for constants in comparisons.
2606  */
2607  Const *con = (Const *) arg;
2608 
2609  fcinfo->args[argno].value = con->constvalue;
2610  fcinfo->args[argno].isnull = con->constisnull;
2611  }
2612  else
2613  {
2615  &fcinfo->args[argno].value,
2616  &fcinfo->args[argno].isnull);
2617  }
2618  argno++;
2619  }
2620 
2621  /* Insert appropriate opcode depending on strictness and stats level */
2622  if (pgstat_track_functions <= flinfo->fn_stats)
2623  {
2624  if (flinfo->fn_strict && nargs > 0)
2625  scratch->opcode = EEOP_FUNCEXPR_STRICT;
2626  else
2627  scratch->opcode = EEOP_FUNCEXPR;
2628  }
2629  else
2630  {
2631  if (flinfo->fn_strict && nargs > 0)
2633  else
2634  scratch->opcode = EEOP_FUNCEXPR_FUSAGE;
2635  }
2636 }
int errmsg_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition: elog.c:1179
@ EEOP_FUNCEXPR_STRICT_FUSAGE
Definition: execExpr.h:113
@ EEOP_FUNCEXPR_STRICT
Definition: execExpr.h:111
@ EEOP_FUNCEXPR
Definition: execExpr.h:110
@ EEOP_FUNCEXPR_FUSAGE
Definition: execExpr.h:112
int executor_errposition(EState *estate, int location)
Definition: execUtils.c:901
int exprLocation(const Node *expr)
Definition: nodeFuncs.c:1287
#define FUNC_MAX_ARGS
bool fn_retset
Definition: fmgr.h:62

References ACL_EXECUTE, aclcheck_error(), ACLCHECK_OK, arg, generate_unaccent_rules::args, FunctionCallInfoBaseData::args, ExprEvalStep::d, EEOP_FUNCEXPR, EEOP_FUNCEXPR_FUSAGE, EEOP_FUNCEXPR_STRICT, EEOP_FUNCEXPR_STRICT_FUSAGE, ereport, errcode(), errmsg(), errmsg_plural(), ERROR, ExecInitExprRec(), executor_errposition(), exprLocation(), fmgr_info(), fmgr_info_set_expr, FmgrInfo::fn_addr, FmgrInfo::fn_retset, FmgrInfo::fn_strict, ExprEvalStep::func, FUNC_MAX_ARGS, get_func_name(), GetUserId(), InitFunctionCallInfoData, InvokeFunctionExecuteHook, IsA, NullableDatum::isnull, lfirst, list_length(), object_aclcheck(), OBJECT_FUNCTION, ExprEvalStep::opcode, palloc0(), SizeForFunctionCallInfo, and NullableDatum::value.

Referenced by ExecInitExprRec().

◆ ExecInitQual()

ExprState* ExecInitQual ( List qual,
PlanState parent 
)

Definition at line 213 of file execExpr.c.

214 {
215  ExprState *state;
216  ExprEvalStep scratch = {0};
217  List *adjust_jumps = NIL;
218  ListCell *lc;
219 
220  /* short-circuit (here and in ExecQual) for empty restriction list */
221  if (qual == NIL)
222  return NULL;
223 
224  Assert(IsA(qual, List));
225 
227  state->expr = (Expr *) qual;
228  state->parent = parent;
229  state->ext_params = NULL;
230 
231  /* mark expression as to be used with ExecQual() */
232  state->flags = EEO_FLAG_IS_QUAL;
233 
234  /* Insert setup steps as needed */
236 
237  /*
238  * ExecQual() needs to return false for an expression returning NULL. That
239  * allows us to short-circuit the evaluation the first time a NULL is
240  * encountered. As qual evaluation is a hot-path this warrants using a
241  * special opcode for qual evaluation that's simpler than BOOL_AND (which
242  * has more complex NULL handling).
243  */
244  scratch.opcode = EEOP_QUAL;
245 
246  /*
247  * We can use ExprState's resvalue/resnull as target for each qual expr.
248  */
249  scratch.resvalue = &state->resvalue;
250  scratch.resnull = &state->resnull;
251 
252  foreach(lc, qual)
253  {
254  Expr *node = (Expr *) lfirst(lc);
255 
256  /* first evaluate expression */
257  ExecInitExprRec(node, state, &state->resvalue, &state->resnull);
258 
259  /* then emit EEOP_QUAL to detect if it's false (or null) */
260  scratch.d.qualexpr.jumpdone = -1;
261  ExprEvalPushStep(state, &scratch);
262  adjust_jumps = lappend_int(adjust_jumps,
263  state->steps_len - 1);
264  }
265 
266  /* adjust jump targets */
267  foreach(lc, adjust_jumps)
268  {
269  ExprEvalStep *as = &state->steps[lfirst_int(lc)];
270 
271  Assert(as->opcode == EEOP_QUAL);
272  Assert(as->d.qualexpr.jumpdone == -1);
273  as->d.qualexpr.jumpdone = state->steps_len;
274  }
275 
276  /*
277  * At the end, we don't need to do anything more. The last qual expr must
278  * have yielded TRUE, and since its result is stored in the desired output
279  * location, we're done.
280  */
281  scratch.opcode = EEOP_DONE;
282  ExprEvalPushStep(state, &scratch);
283 
285 
286  return state;
287 }

References Assert(), ExprEvalStep::d, EEO_FLAG_IS_QUAL, EEOP_DONE, EEOP_QUAL, ExecCreateExprSetupSteps(), ExecInitExprRec(), ExecReadyExpr(), ExprEvalPushStep(), IsA, lappend_int(), lfirst, lfirst_int, makeNode, NIL, ExprEvalStep::opcode, ExprEvalStep::qualexpr, ExprEvalStep::resnull, and ExprEvalStep::resvalue.

Referenced by CopyFrom(), ExecInitAgg(), ExecInitBitmapHeapScan(), ExecInitCteScan(), ExecInitCustomScan(), ExecInitForeignScan(), ExecInitFunctionScan(), ExecInitGroup(), ExecInitHashJoin(), ExecInitIndexOnlyScan(), ExecInitIndexScan(), ExecInitMerge(), ExecInitMergeJoin(), ExecInitModifyTable(), ExecInitNamedTuplestoreScan(), ExecInitNestLoop(), ExecInitPartitionInfo(), ExecInitResult(), ExecInitSampleScan(), ExecInitSeqScan(), ExecInitSubqueryScan(), ExecInitTableFuncScan(), ExecInitTidRangeScan(), ExecInitTidScan(), ExecInitValuesScan(), ExecInitWindowAgg(), ExecInitWorkTableScan(), and ExecPrepareQual().

◆ ExecInitSubscriptingRef()

static void ExecInitSubscriptingRef ( ExprEvalStep scratch,
SubscriptingRef sbsref,
ExprState state,
Datum resv,
bool resnull 
)
static

Definition at line 2977 of file execExpr.c.

2979 {
2980  bool isAssignment = (sbsref->refassgnexpr != NULL);
2981  int nupper = list_length(sbsref->refupperindexpr);
2982  int nlower = list_length(sbsref->reflowerindexpr);
2983  const SubscriptRoutines *sbsroutines;
2984  SubscriptingRefState *sbsrefstate;
2985  SubscriptExecSteps methods;
2986  char *ptr;
2987  List *adjust_jumps = NIL;
2988  ListCell *lc;
2989  int i;
2990 
2991  /* Look up the subscripting support methods */
2992  sbsroutines = getSubscriptingRoutines(sbsref->refcontainertype, NULL);
2993  if (!sbsroutines)
2994  ereport(ERROR,
2995  (errcode(ERRCODE_DATATYPE_MISMATCH),
2996  errmsg("cannot subscript type %s because it does not support subscripting",
2997  format_type_be(sbsref->refcontainertype)),
2998  state->parent ?
2999  executor_errposition(state->parent->state,
3000  exprLocation((Node *) sbsref)) : 0));
3001 
3002  /* Allocate sbsrefstate, with enough space for per-subscript arrays too */
3003  sbsrefstate = palloc0(MAXALIGN(sizeof(SubscriptingRefState)) +
3004  (nupper + nlower) * (sizeof(Datum) +
3005  2 * sizeof(bool)));
3006 
3007  /* Fill constant fields of SubscriptingRefState */
3008  sbsrefstate->isassignment = isAssignment;
3009  sbsrefstate->numupper = nupper;
3010  sbsrefstate->numlower = nlower;
3011  /* Set up per-subscript arrays */
3012  ptr = ((char *) sbsrefstate) + MAXALIGN(sizeof(SubscriptingRefState));
3013  sbsrefstate->upperindex = (Datum *) ptr;
3014  ptr += nupper * sizeof(Datum);
3015  sbsrefstate->lowerindex = (Datum *) ptr;
3016  ptr += nlower * sizeof(Datum);
3017  sbsrefstate->upperprovided = (bool *) ptr;
3018  ptr += nupper * sizeof(bool);
3019  sbsrefstate->lowerprovided = (bool *) ptr;
3020  ptr += nlower * sizeof(bool);
3021  sbsrefstate->upperindexnull = (bool *) ptr;
3022  ptr += nupper * sizeof(bool);
3023  sbsrefstate->lowerindexnull = (bool *) ptr;
3024  /* ptr += nlower * sizeof(bool); */
3025 
3026  /*
3027  * Let the container-type-specific code have a chance. It must fill the
3028  * "methods" struct with function pointers for us to possibly use in
3029  * execution steps below; and it can optionally set up some data pointed
3030  * to by the workspace field.
3031  */
3032  memset(&methods, 0, sizeof(methods));
3033  sbsroutines->exec_setup(sbsref, sbsrefstate, &methods);
3034 
3035  /*
3036  * Evaluate array input. It's safe to do so into resv/resnull, because we
3037  * won't use that as target for any of the other subexpressions, and it'll
3038  * be overwritten by the final EEOP_SBSREF_FETCH/ASSIGN step, which is
3039  * pushed last.
3040  */
3041  ExecInitExprRec(sbsref->refexpr, state, resv, resnull);
3042 
3043  /*
3044  * If refexpr yields NULL, and the operation should be strict, then result
3045  * is NULL. We can implement this with just JUMP_IF_NULL, since we
3046  * evaluated the array into the desired target location.
3047  */
3048  if (!isAssignment && sbsroutines->fetch_strict)
3049  {
3050  scratch->opcode = EEOP_JUMP_IF_NULL;
3051  scratch->d.jump.jumpdone = -1; /* adjust later */
3052  ExprEvalPushStep(state, scratch);
3053  adjust_jumps = lappend_int(adjust_jumps,
3054  state->steps_len - 1);
3055  }
3056 
3057  /* Evaluate upper subscripts */
3058  i = 0;
3059  foreach(lc, sbsref->refupperindexpr)
3060  {
3061  Expr *e = (Expr *) lfirst(lc);
3062 
3063  /* When slicing, individual subscript bounds can be omitted */
3064  if (!e)
3065  {
3066  sbsrefstate->upperprovided[i] = false;
3067  sbsrefstate->upperindexnull[i] = true;
3068  }
3069  else
3070  {
3071  sbsrefstate->upperprovided[i] = true;
3072  /* Each subscript is evaluated into appropriate array entry */
3074  &sbsrefstate->upperindex[i],
3075  &sbsrefstate->upperindexnull[i]);
3076  }
3077  i++;
3078  }
3079 
3080  /* Evaluate lower subscripts similarly */
3081  i = 0;
3082  foreach(lc, sbsref->reflowerindexpr)
3083  {
3084  Expr *e = (Expr *) lfirst(lc);
3085 
3086  /* When slicing, individual subscript bounds can be omitted */
3087  if (!e)
3088  {
3089  sbsrefstate->lowerprovided[i] = false;
3090  sbsrefstate->lowerindexnull[i] = true;
3091  }
3092  else
3093  {
3094  sbsrefstate->lowerprovided[i] = true;
3095  /* Each subscript is evaluated into appropriate array entry */
3097  &sbsrefstate->lowerindex[i],
3098  &sbsrefstate->lowerindexnull[i]);
3099  }
3100  i++;
3101  }
3102 
3103  /* SBSREF_SUBSCRIPTS checks and converts all the subscripts at once */
3104  if (methods.sbs_check_subscripts)
3105  {
3106  scratch->opcode = EEOP_SBSREF_SUBSCRIPTS;
3107  scratch->d.sbsref_subscript.subscriptfunc = methods.sbs_check_subscripts;
3108  scratch->d.sbsref_subscript.state = sbsrefstate;
3109  scratch->d.sbsref_subscript.jumpdone = -1; /* adjust later */
3110  ExprEvalPushStep(state, scratch);
3111  adjust_jumps = lappend_int(adjust_jumps,
3112  state->steps_len - 1);
3113  }
3114 
3115  if (isAssignment)
3116  {
3117  Datum *save_innermost_caseval;
3118  bool *save_innermost_casenull;
3119 
3120  /* Check for unimplemented methods */
3121  if (!methods.sbs_assign)
3122  ereport(ERROR,
3123  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3124  errmsg("type %s does not support subscripted assignment",
3125  format_type_be(sbsref->refcontainertype))));
3126 
3127  /*
3128  * We might have a nested-assignment situation, in which the
3129  * refassgnexpr is itself a FieldStore or SubscriptingRef that needs
3130  * to obtain and modify the previous value of the array element or
3131  * slice being replaced. If so, we have to extract that value from
3132  * the array and pass it down via the CaseTestExpr mechanism. It's
3133  * safe to reuse the CASE mechanism because there cannot be a CASE
3134  * between here and where the value would be needed, and an array
3135  * assignment can't be within a CASE either. (So saving and restoring
3136  * innermost_caseval is just paranoia, but let's do it anyway.)
3137  *
3138  * Since fetching the old element might be a nontrivial expense, do it
3139  * only if the argument actually needs it.
3140  */
3142  {
3143  if (!methods.sbs_fetch_old)
3144  ereport(ERROR,
3145  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3146  errmsg("type %s does not support subscripted assignment",
3147  format_type_be(sbsref->refcontainertype))));
3148  scratch->opcode = EEOP_SBSREF_OLD;
3149  scratch->d.sbsref.subscriptfunc = methods.sbs_fetch_old;
3150  scratch->d.sbsref.state = sbsrefstate;
3151  ExprEvalPushStep(state, scratch);
3152  }
3153 
3154  /* SBSREF_OLD puts extracted value into prevvalue/prevnull */
3155  save_innermost_caseval = state->innermost_caseval;
3156  save_innermost_casenull = state->innermost_casenull;
3157  state->innermost_caseval = &sbsrefstate->prevvalue;
3158  state->innermost_casenull = &sbsrefstate->prevnull;
3159 
3160  /* evaluate replacement value into replacevalue/replacenull */
3162  &sbsrefstate->replacevalue, &sbsrefstate->replacenull);
3163 
3164  state->innermost_caseval = save_innermost_caseval;
3165  state->innermost_casenull = save_innermost_casenull;
3166 
3167  /* and perform the assignment */
3168  scratch->opcode = EEOP_SBSREF_ASSIGN;
3169  scratch->d.sbsref.subscriptfunc = methods.sbs_assign;
3170  scratch->d.sbsref.state = sbsrefstate;
3171  ExprEvalPushStep(state, scratch);
3172  }
3173  else
3174  {
3175  /* array fetch is much simpler */
3176  scratch->opcode = EEOP_SBSREF_FETCH;
3177  scratch->d.sbsref.subscriptfunc = methods.sbs_fetch;
3178  scratch->d.sbsref.state = sbsrefstate;
3179  ExprEvalPushStep(state, scratch);
3180  }
3181 
3182  /* adjust jump targets */
3183  foreach(lc, adjust_jumps)
3184  {
3185  ExprEvalStep *as = &state->steps[lfirst_int(lc)];
3186 
3187  if (as->opcode == EEOP_SBSREF_SUBSCRIPTS)
3188  {
3189  Assert(as->d.sbsref_subscript.jumpdone == -1);
3190  as->d.sbsref_subscript.jumpdone = state->steps_len;
3191  }
3192  else
3193  {
3195  Assert(as->d.jump.jumpdone == -1);
3196  as->d.jump.jumpdone = state->steps_len;
3197  }
3198  }
3199 }
#define MAXALIGN(LEN)
Definition: c.h:795
unsigned char bool
Definition: c.h:440
static bool isAssignmentIndirectionExpr(Expr *expr)
Definition: execExpr.c:3219
@ EEOP_SBSREF_SUBSCRIPTS
Definition: execExpr.h:209
@ EEOP_SBSREF_FETCH
Definition: execExpr.h:222
@ EEOP_SBSREF_ASSIGN
Definition: execExpr.h:219
@ EEOP_SBSREF_OLD
Definition: execExpr.h:216
@ EEOP_JUMP_IF_NULL
Definition: execExpr.h:140
const struct SubscriptRoutines * getSubscriptingRoutines(Oid typid, Oid *typelemp)
Definition: lsyscache.c:3088
struct ExprEvalStep::@50::@76 sbsref_subscript
struct ExprEvalStep::@50::@77 sbsref
ExecEvalSubroutine sbs_fetch_old
Definition: execExpr.h:723
ExecEvalBoolSubroutine sbs_check_subscripts
Definition: execExpr.h:720
ExecEvalSubroutine sbs_assign
Definition: execExpr.h:722
ExecEvalSubroutine sbs_fetch
Definition: execExpr.h:721
SubscriptExecSetup exec_setup
Definition: subscripting.h:161
Expr * refassgnexpr
Definition: primnodes.h:630
List * refupperindexpr
Definition: primnodes.h:620
Expr * refexpr
Definition: primnodes.h:628
List * reflowerindexpr
Definition: primnodes.h:626

References Assert(), ExprEvalStep::d, EEOP_JUMP_IF_NULL, EEOP_SBSREF_ASSIGN, EEOP_SBSREF_FETCH, EEOP_SBSREF_OLD, EEOP_SBSREF_SUBSCRIPTS, ereport, errcode(), errmsg(), ERROR, SubscriptRoutines::exec_setup, ExecInitExprRec(), executor_errposition(), ExprEvalPushStep(), exprLocation(), SubscriptRoutines::fetch_strict, format_type_be(), getSubscriptingRoutines(), i, SubscriptingRefState::isassignment, isAssignmentIndirectionExpr(), ExprEvalStep::jump, lappend_int(), lfirst, lfirst_int, list_length(), SubscriptingRefState::lowerindex, SubscriptingRefState::lowerindexnull, SubscriptingRefState::lowerprovided, MAXALIGN, NIL, SubscriptingRefState::numlower, SubscriptingRefState::numupper, ExprEvalStep::opcode, palloc0(), SubscriptingRefState::prevnull, SubscriptingRefState::prevvalue, SubscriptingRef::refassgnexpr, SubscriptingRef::refexpr, SubscriptingRef::reflowerindexpr, SubscriptingRef::refupperindexpr, SubscriptingRefState::replacenull, SubscriptingRefState::replacevalue, SubscriptExecSteps::sbs_assign, SubscriptExecSteps::sbs_check_subscripts, SubscriptExecSteps::sbs_fetch, SubscriptExecSteps::sbs_fetch_old, ExprEvalStep::sbsref, ExprEvalStep::sbsref_subscript, SubscriptingRefState::upperindex, SubscriptingRefState::upperindexnull, and SubscriptingRefState::upperprovided.

Referenced by ExecInitExprRec().

◆ ExecInitWholeRowVar()

static void ExecInitWholeRowVar ( ExprEvalStep scratch,
Var variable,
ExprState state 
)
static

Definition at line 2904 of file execExpr.c.

2905 {
2906  PlanState *parent = state->parent;
2907 
2908  /* fill in all but the target */
2909  scratch->opcode = EEOP_WHOLEROW;
2910  scratch->d.wholerow.var = variable;
2911  scratch->d.wholerow.first = true;
2912  scratch->d.wholerow.slow = false;
2913  scratch->d.wholerow.tupdesc = NULL; /* filled at runtime */
2914  scratch->d.wholerow.junkFilter = NULL;
2915 
2916  /*
2917  * If the input tuple came from a subquery, it might contain "resjunk"
2918  * columns (such as GROUP BY or ORDER BY columns), which we don't want to
2919  * keep in the whole-row result. We can get rid of such columns by
2920  * passing the tuple through a JunkFilter --- but to make one, we have to
2921  * lay our hands on the subquery's targetlist. Fortunately, there are not
2922  * very many cases where this can happen, and we can identify all of them
2923  * by examining our parent PlanState. We assume this is not an issue in
2924  * standalone expressions that don't have parent plans. (Whole-row Vars
2925  * can occur in such expressions, but they will always be referencing
2926  * table rows.)
2927  */
2928  if (parent)
2929  {
2930  PlanState *subplan = NULL;
2931 
2932  switch (nodeTag(parent))
2933  {
2934  case T_SubqueryScanState:
2935  subplan = ((SubqueryScanState *) parent)->subplan;
2936  break;
2937  case T_CteScanState:
2938  subplan = ((CteScanState *) parent)->cteplanstate;
2939  break;
2940  default:
2941  break;
2942  }
2943 
2944  if (subplan)
2945  {
2946  bool junk_filter_needed = false;
2947  ListCell *tlist;
2948 
2949  /* Detect whether subplan tlist actually has any junk columns */
2950  foreach(tlist, subplan->plan->targetlist)
2951  {
2952  TargetEntry *tle = (TargetEntry *) lfirst(tlist);
2953 
2954  if (tle->resjunk)
2955  {
2956  junk_filter_needed = true;
2957  break;
2958  }
2959  }
2960 
2961  /* If so, build the junkfilter now */
2962  if (junk_filter_needed)
2963  {
2964  scratch->d.wholerow.junkFilter =
2966  ExecInitExtraTupleSlot(parent->state, NULL,
2967  &TTSOpsVirtual));
2968  }
2969  }
2970  }
2971 }
@ EEOP_WHOLEROW
Definition: execExpr.h:86
JunkFilter * ExecInitJunkFilter(List *targetList, TupleTableSlot *slot)
Definition: execJunk.c:60
TupleTableSlot * ExecInitExtraTupleSlot(EState *estate, TupleDesc tupledesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1832
struct ExprEvalStep::@50::@53 wholerow
Plan * plan
Definition: execnodes.h:1035
EState * state
Definition: execnodes.h:1037
List * targetlist
Definition: plannodes.h:156

References ExprEvalStep::d, EEOP_WHOLEROW, ExecInitExtraTupleSlot(), ExecInitJunkFilter(), lfirst, nodeTag, ExprEvalStep::opcode, PlanState::plan, PlanState::state, Plan::targetlist, TTSOpsVirtual, and ExprEvalStep::wholerow.

Referenced by ExecInitExprRec().

◆ ExecPrepareCheck()

ExprState* ExecPrepareCheck ( List qual,
EState estate 
)

Definition at line 786 of file execExpr.c.

787 {
788  ExprState *result;
789  MemoryContext oldcontext;
790 
791  oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
792 
793  qual = (List *) expression_planner((Expr *) qual);
794 
795  result = ExecInitCheck(qual, NULL);
796 
797  MemoryContextSwitchTo(oldcontext);
798 
799  return result;
800 }
ExprState * ExecInitCheck(List *qual, PlanState *parent)
Definition: execExpr.c:302
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:138
Expr * expression_planner(Expr *expr)
Definition: planner.c:6434
MemoryContext es_query_cxt
Definition: execnodes.h:660

References EState::es_query_cxt, ExecInitCheck(), expression_planner(), and MemoryContextSwitchTo().

Referenced by ExecPartitionCheck().

◆ ExecPrepareExpr()

ExprState* ExecPrepareExpr ( Expr node,
EState estate 
)

Definition at line 735 of file execExpr.c.

736 {
737  ExprState *result;
738  MemoryContext oldcontext;
739 
740  oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
741 
742  node = expression_planner(node);
743 
744  result = ExecInitExpr(node, NULL);
745 
746  MemoryContextSwitchTo(oldcontext);
747 
748  return result;
749 }

References EState::es_query_cxt, ExecInitExpr(), expression_planner(), and MemoryContextSwitchTo().

Referenced by ATRewriteTable(), check_default_partition_contents(), compute_expr_stats(), ExecInitStoredGenerated(), ExecPrepareExprList(), ExecRelCheck(), ExecuteCallStmt(), pgoutput_row_filter_init(), StoreAttrDefault(), and validateDomainConstraint().

◆ ExecPrepareExprList()

List* ExecPrepareExprList ( List nodes,
EState estate 
)

Definition at line 809 of file execExpr.c.

810 {
811  List *result = NIL;
812  MemoryContext oldcontext;
813  ListCell *lc;
814 
815  /* Ensure that the list cell nodes are in the right context too */
816  oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
817 
818  foreach(lc, nodes)
819  {
820  Expr *e = (Expr *) lfirst(lc);
821 
822  result = lappend(result, ExecPrepareExpr(e, estate));
823  }
824 
825  MemoryContextSwitchTo(oldcontext);
826 
827  return result;
828 }
ExprState * ExecPrepareExpr(Expr *node, EState *estate)
Definition: execExpr.c:735

References EState::es_query_cxt, ExecPrepareExpr(), lappend(), lfirst, MemoryContextSwitchTo(), and NIL.

Referenced by EvaluateParams(), FormIndexDatum(), FormPartitionKeyDatum(), and make_build_data().

◆ ExecPrepareQual()

ExprState* ExecPrepareQual ( List qual,
EState estate 
)

Definition at line 763 of file execExpr.c.

764 {
765  ExprState *result;
766  MemoryContext oldcontext;
767 
768  oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
769 
770  qual = (List *) expression_planner((Expr *) qual);
771 
772  result = ExecInitQual(qual, NULL);
773 
774  MemoryContextSwitchTo(oldcontext);
775 
776  return result;
777 }
ExprState * ExecInitQual(List *qual, PlanState *parent)
Definition: execExpr.c:213

References EState::es_query_cxt, ExecInitQual(), expression_planner(), and MemoryContextSwitchTo().

Referenced by compute_index_stats(), ExecCheckIndexConstraints(), ExecInsertIndexTuples(), heapam_index_build_range_scan(), heapam_index_validate_scan(), IndexCheckExclusion(), and TriggerEnabled().

◆ ExecPushExprSetupSteps()

static void ExecPushExprSetupSteps ( ExprState state,
ExprSetupInfo info 
)
static

Definition at line 2659 of file execExpr.c.

2660 {
2661  ExprEvalStep scratch = {0};
2662  ListCell *lc;
2663 
2664  scratch.resvalue = NULL;
2665  scratch.resnull = NULL;
2666 
2667  /*
2668  * Add steps deforming the ExprState's inner/outer/scan slots as much as
2669  * required by any Vars appearing in the expression.
2670  */
2671  if (info->last_inner > 0)
2672  {
2673  scratch.opcode = EEOP_INNER_FETCHSOME;
2674  scratch.d.fetch.last_var = info->last_inner;
2675  scratch.d.fetch.fixed = false;
2676  scratch.d.fetch.kind = NULL;
2677  scratch.d.fetch.known_desc = NULL;
2678  if (ExecComputeSlotInfo(state, &scratch))
2679  ExprEvalPushStep(state, &scratch);
2680  }
2681  if (info->last_outer > 0)
2682  {
2683  scratch.opcode = EEOP_OUTER_FETCHSOME;
2684  scratch.d.fetch.last_var = info->last_outer;
2685  scratch.d.fetch.fixed = false;
2686  scratch.d.fetch.kind = NULL;
2687  scratch.d.fetch.known_desc = NULL;
2688  if (ExecComputeSlotInfo(state, &scratch))
2689  ExprEvalPushStep(state, &scratch);
2690  }
2691  if (info->last_scan > 0)
2692  {
2693  scratch.opcode = EEOP_SCAN_FETCHSOME;
2694  scratch.d.fetch.last_var = info->last_scan;
2695  scratch.d.fetch.fixed = false;
2696  scratch.d.fetch.kind = NULL;
2697  scratch.d.fetch.known_desc = NULL;
2698  if (ExecComputeSlotInfo(state, &scratch))
2699  ExprEvalPushStep(state, &scratch);
2700  }
2701 
2702  /*
2703  * Add steps to execute any MULTIEXPR SubPlans appearing in the
2704  * expression. We need to evaluate these before any of the Params
2705  * referencing their outputs are used, but after we've prepared for any
2706  * Var references they may contain. (There cannot be cross-references
2707  * between MULTIEXPR SubPlans, so we needn't worry about their order.)
2708  */
2709  foreach(lc, info->multiexpr_subplans)
2710  {
2711  SubPlan *subplan = (SubPlan *) lfirst(lc);
2712  SubPlanState *sstate;
2713 
2714  Assert(subplan->subLinkType == MULTIEXPR_SUBLINK);
2715 
2716  /* This should match what ExecInitExprRec does for other SubPlans: */
2717 
2718  if (!state->parent)
2719  elog(ERROR, "SubPlan found with no parent plan");
2720 
2721  sstate = ExecInitSubPlan(subplan, state->parent);
2722 
2723  /* add SubPlanState nodes to state->parent->subPlan */
2724  state->parent->subPlan = lappend(state->parent->subPlan,
2725  sstate);
2726 
2727  scratch.opcode = EEOP_SUBPLAN;
2728  scratch.d.subplan.sstate = sstate;
2729 
2730  /* The result can be ignored, but we better put it somewhere */
2731  scratch.resvalue = &state->resvalue;
2732  scratch.resnull = &state->resnull;
2733 
2734  ExprEvalPushStep(state, &scratch);
2735  }
2736 }
AttrNumber last_inner
Definition: execExpr.c:58
List * multiexpr_subplans
Definition: execExpr.c:62

References Assert(), ExprEvalStep::d, EEOP_INNER_FETCHSOME, EEOP_OUTER_FETCHSOME, EEOP_SCAN_FETCHSOME, EEOP_SUBPLAN, elog(), ERROR, ExecComputeSlotInfo(), ExecInitSubPlan(), ExprEvalPushStep(), ExprEvalStep::fetch, lappend(), ExprSetupInfo::last_inner, ExprSetupInfo::last_outer, ExprSetupInfo::last_scan, lfirst, MULTIEXPR_SUBLINK, ExprSetupInfo::multiexpr_subplans, ExprEvalStep::opcode, ExprEvalStep::resnull, ExprEvalStep::resvalue, SubPlan::subLinkType, and ExprEvalStep::subplan.

Referenced by ExecBuildAggTrans(), ExecBuildUpdateProjection(), and ExecCreateExprSetupSteps().

◆ ExecReadyExpr()

static void ExecReadyExpr ( ExprState state)
static

Definition at line 872 of file execExpr.c.

873 {
874  if (jit_compile_expr(state))
875  return;
876 
878 }
void ExecReadyInterpretedExpr(ExprState *state)
bool jit_compile_expr(struct ExprState *state)
Definition: jit.c:153

References ExecReadyInterpretedExpr(), and jit_compile_expr().

Referenced by ExecBuildAggTrans(), ExecBuildGroupingEqual(), ExecBuildParamSetEqual(), ExecBuildProjectionInfo(), ExecBuildUpdateProjection(), ExecInitExpr(), ExecInitExprRec(), ExecInitExprWithParams(), and ExecInitQual().

◆ expr_setup_walker()

static bool expr_setup_walker ( Node node,
ExprSetupInfo info 
)
static

Definition at line 2742 of file execExpr.c.

2743 {
2744  if (node == NULL)
2745  return false;
2746  if (IsA(node, Var))
2747  {
2748  Var *variable = (Var *) node;
2749  AttrNumber attnum = variable->varattno;
2750 
2751  switch (variable->varno)
2752  {
2753  case INNER_VAR:
2754  info->last_inner = Max(info->last_inner, attnum);
2755  break;
2756 
2757  case OUTER_VAR:
2758  info->last_outer = Max(info->last_outer, attnum);
2759  break;
2760 
2761  /* INDEX_VAR is handled by default case */
2762 
2763  default:
2764  info->last_scan = Max(info->last_scan, attnum);
2765  break;
2766  }
2767  return false;
2768  }
2769 
2770  /* Collect all MULTIEXPR SubPlans, too */
2771  if (IsA(node, SubPlan))
2772  {
2773  SubPlan *subplan = (SubPlan *) node;
2774 
2775  if (subplan->subLinkType == MULTIEXPR_SUBLINK)
2777  subplan);
2778  }
2779 
2780  /*
2781  * Don't examine the arguments or filters of Aggrefs or WindowFuncs,
2782  * because those do not represent expressions to be evaluated within the
2783  * calling expression's econtext. GroupingFunc arguments are never
2784  * evaluated at all.
2785  */
2786  if (IsA(node, Aggref))
2787  return false;
2788  if (IsA(node, WindowFunc))
2789  return false;
2790  if (IsA(node, GroupingFunc))
2791  return false;
2793  (void *) info);
2794 }
#define expression_tree_walker(n, w, c)
Definition: nodeFuncs.h:151

References attnum, expression_tree_walker, INNER_VAR, IsA, lappend(), ExprSetupInfo::last_inner, ExprSetupInfo::last_outer, ExprSetupInfo::last_scan, Max, MULTIEXPR_SUBLINK, ExprSetupInfo::multiexpr_subplans, OUTER_VAR, and SubPlan::subLinkType.

Referenced by ExecBuildAggTrans(), ExecBuildUpdateProjection(), and ExecCreateExprSetupSteps().

◆ ExprEvalPushStep()

void ExprEvalPushStep ( ExprState es,
const ExprEvalStep s 
)

Definition at line 2512 of file execExpr.c.

2513 {
2514  if (es->steps_alloc == 0)
2515  {
2516  es->steps_alloc = 16;
2517  es->steps = palloc(sizeof(ExprEvalStep) * es->steps_alloc);
2518  }
2519  else if (es->steps_alloc == es->steps_len)
2520  {
2521  es->steps_alloc *= 2;
2522  es->steps = repalloc(es->steps,
2523  sizeof(ExprEvalStep) * es->steps_alloc);
2524  }
2525 
2526  memcpy(&es->steps[es->steps_len++], s, sizeof(ExprEvalStep));
2527 }
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1456
int steps_alloc
Definition: execnodes.h:121

References palloc(), repalloc(), ExprState::steps, ExprState::steps_alloc, and ExprState::steps_len.

Referenced by ExecBuildAggTrans(), ExecBuildAggTransCall(), ExecBuildGroupingEqual(), ExecBuildParamSetEqual(), ExecBuildProjectionInfo(), ExecBuildUpdateProjection(), ExecInitCoerceToDomain(), ExecInitExpr(), ExecInitExprRec(), ExecInitExprWithParams(), ExecInitQual(), ExecInitSubscriptingRef(), ExecPushExprSetupSteps(), and plpgsql_param_compile().

◆ isAssignmentIndirectionExpr()

static bool isAssignmentIndirectionExpr ( Expr expr)
static

Definition at line 3219 of file execExpr.c.

3220 {
3221  if (expr == NULL)
3222  return false; /* just paranoia */
3223  if (IsA(expr, FieldStore))
3224  {
3225  FieldStore *fstore = (FieldStore *) expr;
3226 
3227  if (fstore->arg && IsA(fstore->arg, CaseTestExpr))
3228  return true;
3229  }
3230  else if (IsA(expr, SubscriptingRef))
3231  {
3232  SubscriptingRef *sbsRef = (SubscriptingRef *) expr;
3233 
3234  if (sbsRef->refexpr && IsA(sbsRef->refexpr, CaseTestExpr))
3235  return true;
3236  }
3237  else if (IsA(expr, CoerceToDomain))
3238  {
3239  CoerceToDomain *cd = (CoerceToDomain *) expr;
3240