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/jsonfuncs.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 3451 of file execExpr.c.

3453 {
3455  PlanState *parent = &aggstate->ss.ps;
3456  ExprEvalStep scratch = {0};
3457  bool isCombine = DO_AGGSPLIT_COMBINE(aggstate->aggsplit);
3458  ExprSetupInfo deform = {0, 0, 0, NIL};
3459 
3460  state->expr = (Expr *) aggstate;
3461  state->parent = parent;
3462 
3463  scratch.resvalue = &state->resvalue;
3464  scratch.resnull = &state->resnull;
3465 
3466  /*
3467  * First figure out which slots, and how many columns from each, we're
3468  * going to need.
3469  */
3470  for (int transno = 0; transno < aggstate->numtrans; transno++)
3471  {
3472  AggStatePerTrans pertrans = &aggstate->pertrans[transno];
3473 
3474  expr_setup_walker((Node *) pertrans->aggref->aggdirectargs,
3475  &deform);
3476  expr_setup_walker((Node *) pertrans->aggref->args,
3477  &deform);
3478  expr_setup_walker((Node *) pertrans->aggref->aggorder,
3479  &deform);
3480  expr_setup_walker((Node *) pertrans->aggref->aggdistinct,
3481  &deform);
3482  expr_setup_walker((Node *) pertrans->aggref->aggfilter,
3483  &deform);
3484  }
3485  ExecPushExprSetupSteps(state, &deform);
3486 
3487  /*
3488  * Emit instructions for each transition value / grouping set combination.
3489  */
3490  for (int transno = 0; transno < aggstate->numtrans; transno++)
3491  {
3492  AggStatePerTrans pertrans = &aggstate->pertrans[transno];
3493  FunctionCallInfo trans_fcinfo = pertrans->transfn_fcinfo;
3494  List *adjust_bailout = NIL;
3495  NullableDatum *strictargs = NULL;
3496  bool *strictnulls = NULL;
3497  int argno;
3498  ListCell *bail;
3499 
3500  /*
3501  * If filter present, emit. Do so before evaluating the input, to
3502  * avoid potentially unneeded computations, or even worse, unintended
3503  * side-effects. When combining, all the necessary filtering has
3504  * already been done.
3505  */
3506  if (pertrans->aggref->aggfilter && !isCombine)
3507  {
3508  /* evaluate filter expression */
3509  ExecInitExprRec(pertrans->aggref->aggfilter, state,
3510  &state->resvalue, &state->resnull);
3511  /* and jump out if false */
3512  scratch.opcode = EEOP_JUMP_IF_NOT_TRUE;
3513  scratch.d.jump.jumpdone = -1; /* adjust later */
3514  ExprEvalPushStep(state, &scratch);
3515  adjust_bailout = lappend_int(adjust_bailout,
3516  state->steps_len - 1);
3517  }
3518 
3519  /*
3520  * Evaluate arguments to aggregate/combine function.
3521  */
3522  argno = 0;
3523  if (isCombine)
3524  {
3525  /*
3526  * Combining two aggregate transition values. Instead of directly
3527  * coming from a tuple the input is a, potentially deserialized,
3528  * transition value.
3529  */
3530  TargetEntry *source_tle;
3531 
3532  Assert(pertrans->numSortCols == 0);
3533  Assert(list_length(pertrans->aggref->args) == 1);
3534 
3535  strictargs = trans_fcinfo->args + 1;
3536  source_tle = (TargetEntry *) linitial(pertrans->aggref->args);
3537 
3538  /*
3539  * deserialfn_oid will be set if we must deserialize the input
3540  * state before calling the combine function.
3541  */
3542  if (!OidIsValid(pertrans->deserialfn_oid))
3543  {
3544  /*
3545  * Start from 1, since the 0th arg will be the transition
3546  * value
3547  */
3548  ExecInitExprRec(source_tle->expr, state,
3549  &trans_fcinfo->args[argno + 1].value,
3550  &trans_fcinfo->args[argno + 1].isnull);
3551  }
3552  else
3553  {
3554  FunctionCallInfo ds_fcinfo = pertrans->deserialfn_fcinfo;
3555 
3556  /* evaluate argument */
3557  ExecInitExprRec(source_tle->expr, state,
3558  &ds_fcinfo->args[0].value,
3559  &ds_fcinfo->args[0].isnull);
3560 
3561  /* Dummy second argument for type-safety reasons */
3562  ds_fcinfo->args[1].value = PointerGetDatum(NULL);
3563  ds_fcinfo->args[1].isnull = false;
3564 
3565  /*
3566  * Don't call a strict deserialization function with NULL
3567  * input
3568  */
3569  if (pertrans->deserialfn.fn_strict)
3571  else
3572  scratch.opcode = EEOP_AGG_DESERIALIZE;
3573 
3574  scratch.d.agg_deserialize.fcinfo_data = ds_fcinfo;
3575  scratch.d.agg_deserialize.jumpnull = -1; /* adjust later */
3576  scratch.resvalue = &trans_fcinfo->args[argno + 1].value;
3577  scratch.resnull = &trans_fcinfo->args[argno + 1].isnull;
3578 
3579  ExprEvalPushStep(state, &scratch);
3580  /* don't add an adjustment unless the function is strict */
3581  if (pertrans->deserialfn.fn_strict)
3582  adjust_bailout = lappend_int(adjust_bailout,
3583  state->steps_len - 1);
3584 
3585  /* restore normal settings of scratch fields */
3586  scratch.resvalue = &state->resvalue;
3587  scratch.resnull = &state->resnull;
3588  }
3589  argno++;
3590 
3591  Assert(pertrans->numInputs == argno);
3592  }
3593  else if (!pertrans->aggsortrequired)
3594  {
3595  ListCell *arg;
3596 
3597  /*
3598  * Normal transition function without ORDER BY / DISTINCT or with
3599  * ORDER BY / DISTINCT but the planner has given us pre-sorted
3600  * input.
3601  */
3602  strictargs = trans_fcinfo->args + 1;
3603 
3604  foreach(arg, pertrans->aggref->args)
3605  {
3606  TargetEntry *source_tle = (TargetEntry *) lfirst(arg);
3607 
3608  /*
3609  * Don't initialize args for any ORDER BY clause that might
3610  * exist in a presorted aggregate.
3611  */
3612  if (argno == pertrans->numTransInputs)
3613  break;
3614 
3615  /*
3616  * Start from 1, since the 0th arg will be the transition
3617  * value
3618  */
3619  ExecInitExprRec(source_tle->expr, state,
3620  &trans_fcinfo->args[argno + 1].value,
3621  &trans_fcinfo->args[argno + 1].isnull);
3622  argno++;
3623  }
3624  Assert(pertrans->numTransInputs == argno);
3625  }
3626  else if (pertrans->numInputs == 1)
3627  {
3628  /*
3629  * Non-presorted DISTINCT and/or ORDER BY case, with a single
3630  * column sorted on.
3631  */
3632  TargetEntry *source_tle =
3633  (TargetEntry *) linitial(pertrans->aggref->args);
3634 
3635  Assert(list_length(pertrans->aggref->args) == 1);
3636 
3637  ExecInitExprRec(source_tle->expr, state,
3638  &state->resvalue,
3639  &state->resnull);
3640  strictnulls = &state->resnull;
3641  argno++;
3642 
3643  Assert(pertrans->numInputs == argno);
3644  }
3645  else
3646  {
3647  /*
3648  * Non-presorted DISTINCT and/or ORDER BY case, with multiple
3649  * columns sorted on.
3650  */
3651  Datum *values = pertrans->sortslot->tts_values;
3652  bool *nulls = pertrans->sortslot->tts_isnull;
3653  ListCell *arg;
3654 
3655  strictnulls = nulls;
3656 
3657  foreach(arg, pertrans->aggref->args)
3658  {
3659  TargetEntry *source_tle = (TargetEntry *) lfirst(arg);
3660 
3661  ExecInitExprRec(source_tle->expr, state,
3662  &values[argno], &nulls[argno]);
3663  argno++;
3664  }
3665  Assert(pertrans->numInputs == argno);
3666  }
3667 
3668  /*
3669  * For a strict transfn, nothing happens when there's a NULL input; we
3670  * just keep the prior transValue. This is true for both plain and
3671  * sorted/distinct aggregates.
3672  */
3673  if (trans_fcinfo->flinfo->fn_strict && pertrans->numTransInputs > 0)
3674  {
3675  if (strictnulls)
3677  else
3679  scratch.d.agg_strict_input_check.nulls = strictnulls;
3680  scratch.d.agg_strict_input_check.args = strictargs;
3681  scratch.d.agg_strict_input_check.jumpnull = -1; /* adjust later */
3682  scratch.d.agg_strict_input_check.nargs = pertrans->numTransInputs;
3683  ExprEvalPushStep(state, &scratch);
3684  adjust_bailout = lappend_int(adjust_bailout,
3685  state->steps_len - 1);
3686  }
3687 
3688  /* Handle DISTINCT aggregates which have pre-sorted input */
3689  if (pertrans->numDistinctCols > 0 && !pertrans->aggsortrequired)
3690  {
3691  if (pertrans->numDistinctCols > 1)
3693  else
3695 
3696  scratch.d.agg_presorted_distinctcheck.pertrans = pertrans;
3697  scratch.d.agg_presorted_distinctcheck.jumpdistinct = -1; /* adjust later */
3698  ExprEvalPushStep(state, &scratch);
3699  adjust_bailout = lappend_int(adjust_bailout,
3700  state->steps_len - 1);
3701  }
3702 
3703  /*
3704  * Call transition function (once for each concurrently evaluated
3705  * grouping set). Do so for both sort and hash based computations, as
3706  * applicable.
3707  */
3708  if (doSort)
3709  {
3710  int processGroupingSets = Max(phase->numsets, 1);
3711  int setoff = 0;
3712 
3713  for (int setno = 0; setno < processGroupingSets; setno++)
3714  {
3715  ExecBuildAggTransCall(state, aggstate, &scratch, trans_fcinfo,
3716  pertrans, transno, setno, setoff, false,
3717  nullcheck);
3718  setoff++;
3719  }
3720  }
3721 
3722  if (doHash)
3723  {
3724  int numHashes = aggstate->num_hashes;
3725  int setoff;
3726 
3727  /* in MIXED mode, there'll be preceding transition values */
3728  if (aggstate->aggstrategy != AGG_HASHED)
3729  setoff = aggstate->maxsets;
3730  else
3731  setoff = 0;
3732 
3733  for (int setno = 0; setno < numHashes; setno++)
3734  {
3735  ExecBuildAggTransCall(state, aggstate, &scratch, trans_fcinfo,
3736  pertrans, transno, setno, setoff, true,
3737  nullcheck);
3738  setoff++;
3739  }
3740  }
3741 
3742  /* adjust early bail out jump target(s) */
3743  foreach(bail, adjust_bailout)
3744  {
3745  ExprEvalStep *as = &state->steps[lfirst_int(bail)];
3746 
3747  if (as->opcode == EEOP_JUMP_IF_NOT_TRUE)
3748  {
3749  Assert(as->d.jump.jumpdone == -1);
3750  as->d.jump.jumpdone = state->steps_len;
3751  }
3752  else if (as->opcode == EEOP_AGG_STRICT_INPUT_CHECK_ARGS ||
3754  {
3755  Assert(as->d.agg_strict_input_check.jumpnull == -1);
3756  as->d.agg_strict_input_check.jumpnull = state->steps_len;
3757  }
3758  else if (as->opcode == EEOP_AGG_STRICT_DESERIALIZE)
3759  {
3760  Assert(as->d.agg_deserialize.jumpnull == -1);
3761  as->d.agg_deserialize.jumpnull = state->steps_len;
3762  }
3763  else if (as->opcode == EEOP_AGG_PRESORTED_DISTINCT_SINGLE ||
3765  {
3766  Assert(as->d.agg_presorted_distinctcheck.jumpdistinct == -1);
3767  as->d.agg_presorted_distinctcheck.jumpdistinct = state->steps_len;
3768  }
3769  else
3770  Assert(false);
3771  }
3772  }
3773 
3774  scratch.resvalue = NULL;
3775  scratch.resnull = NULL;
3776  scratch.opcode = EEOP_DONE;
3777  ExprEvalPushStep(state, &scratch);
3778 
3780 
3781  return state;
3782 }
static Datum values[MAXATTR]
Definition: bootstrap.c:156
#define Max(x, y)
Definition: c.h:987
#define OidIsValid(objectId)
Definition: c.h:764
static void ExecPushExprSetupSteps(ExprState *state, ExprSetupInfo *info)
Definition: execExpr.c:2700
static void ExecInitExprRec(Expr *node, ExprState *state, Datum *resv, bool *resnull)
Definition: execExpr.c:890
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:3790
void ExprEvalPushStep(ExprState *es, const ExprEvalStep *s)
Definition: execExpr.c:2553
static bool expr_setup_walker(Node *node, ExprSetupInfo *info)
Definition: execExpr.c:2783
static void ExecReadyExpr(ExprState *state)
Definition: execExpr.c:873
@ EEOP_AGG_STRICT_DESERIALIZE
Definition: execExpr.h:247
@ EEOP_DONE
Definition: execExpr.h:68
@ EEOP_AGG_PRESORTED_DISTINCT_MULTI
Definition: execExpr.h:259
@ EEOP_AGG_STRICT_INPUT_CHECK_NULLS
Definition: execExpr.h:250
@ EEOP_AGG_STRICT_INPUT_CHECK_ARGS
Definition: execExpr.h:249
@ EEOP_AGG_DESERIALIZE
Definition: execExpr.h:248
@ EEOP_JUMP_IF_NOT_TRUE
Definition: execExpr.h:142
@ EEOP_AGG_PRESORTED_DISTINCT_SINGLE
Definition: execExpr.h:258
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:395
@ AGG_HASHED
Definition: nodes.h:366
#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:2379
AggStatePerTrans pertrans
Definition: execnodes.h:2389
AggStrategy aggstrategy
Definition: execnodes.h:2383
int numtrans
Definition: execnodes.h:2382
AggSplit aggsplit
Definition: execnodes.h:2384
int num_hashes
Definition: execnodes.h:2420
int maxsets
Definition: execnodes.h:2409
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::@51::@93 agg_presorted_distinctcheck
struct ExprEvalStep::@51::@90 agg_deserialize
union ExprEvalStep::@51 d
intptr_t opcode
Definition: execExpr.h:275
Datum * resvalue
Definition: execExpr.h:278
struct ExprEvalStep::@51::@61 jump
struct ExprEvalStep::@51::@91 agg_strict_input_check
bool * resnull
Definition: execExpr.h:279
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:1474
Expr * expr
Definition: primnodes.h:1895
bool * tts_isnull
Definition: tuptable.h:127
Datum * tts_values
Definition: tuptable.h:125
Definition: regguts.h:323

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 3790 of file execExpr.c.

3795 {
3796  ExprContext *aggcontext;
3797  int adjust_jumpnull = -1;
3798 
3799  if (ishash)
3800  aggcontext = aggstate->hashcontext;
3801  else
3802  aggcontext = aggstate->aggcontexts[setno];
3803 
3804  /* add check for NULL pointer? */
3805  if (nullcheck)
3806  {
3808  scratch->d.agg_plain_pergroup_nullcheck.setoff = setoff;
3809  /* adjust later */
3810  scratch->d.agg_plain_pergroup_nullcheck.jumpnull = -1;
3811  ExprEvalPushStep(state, scratch);
3812  adjust_jumpnull = state->steps_len - 1;
3813  }
3814 
3815  /*
3816  * Determine appropriate transition implementation.
3817  *
3818  * For non-ordered aggregates and ORDER BY / DISTINCT aggregates with
3819  * presorted input:
3820  *
3821  * If the initial value for the transition state doesn't exist in the
3822  * pg_aggregate table then we will let the first non-NULL value returned
3823  * from the outer procNode become the initial value. (This is useful for
3824  * aggregates like max() and min().) The noTransValue flag signals that we
3825  * need to do so. If true, generate a
3826  * EEOP_AGG_INIT_STRICT_PLAIN_TRANS{,_BYVAL} step. This step also needs to
3827  * do the work described next:
3828  *
3829  * If the function is strict, but does have an initial value, choose
3830  * EEOP_AGG_STRICT_PLAIN_TRANS{,_BYVAL}, which skips the transition
3831  * function if the transition value has become NULL (because a previous
3832  * transition function returned NULL). This step also needs to do the work
3833  * described next:
3834  *
3835  * Otherwise we call EEOP_AGG_PLAIN_TRANS{,_BYVAL}, which does not have to
3836  * perform either of the above checks.
3837  *
3838  * Having steps with overlapping responsibilities is not nice, but
3839  * aggregations are very performance sensitive, making this worthwhile.
3840  *
3841  * For ordered aggregates:
3842  *
3843  * Only need to choose between the faster path for a single ordered
3844  * column, and the one between multiple columns. Checking strictness etc
3845  * is done when finalizing the aggregate. See
3846  * process_ordered_aggregate_{single, multi} and
3847  * advance_transition_function.
3848  */
3849  if (!pertrans->aggsortrequired)
3850  {
3851  if (pertrans->transtypeByVal)
3852  {
3853  if (fcinfo->flinfo->fn_strict &&
3854  pertrans->initValueIsNull)
3856  else if (fcinfo->flinfo->fn_strict)
3858  else
3860  }
3861  else
3862  {
3863  if (fcinfo->flinfo->fn_strict &&
3864  pertrans->initValueIsNull)
3866  else if (fcinfo->flinfo->fn_strict)
3868  else
3870  }
3871  }
3872  else if (pertrans->numInputs == 1)
3874  else
3876 
3877  scratch->d.agg_trans.pertrans = pertrans;
3878  scratch->d.agg_trans.setno = setno;
3879  scratch->d.agg_trans.setoff = setoff;
3880  scratch->d.agg_trans.transno = transno;
3881  scratch->d.agg_trans.aggcontext = aggcontext;
3882  ExprEvalPushStep(state, scratch);
3883 
3884  /* fix up jumpnull */
3885  if (adjust_jumpnull != -1)
3886  {
3887  ExprEvalStep *as = &state->steps[adjust_jumpnull];
3888 
3890  Assert(as->d.agg_plain_pergroup_nullcheck.jumpnull == -1);
3891  as->d.agg_plain_pergroup_nullcheck.jumpnull = state->steps_len;
3892  }
3893 }
@ EEOP_AGG_PLAIN_PERGROUP_NULLCHECK
Definition: execExpr.h:251
@ EEOP_AGG_PLAIN_TRANS_BYREF
Definition: execExpr.h:257
@ EEOP_AGG_PLAIN_TRANS_BYVAL
Definition: execExpr.h:254
@ EEOP_AGG_ORDERED_TRANS_DATUM
Definition: execExpr.h:260
@ EEOP_AGG_PLAIN_TRANS_STRICT_BYREF
Definition: execExpr.h:256
@ EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL
Definition: execExpr.h:252
@ EEOP_AGG_PLAIN_TRANS_STRICT_BYVAL
Definition: execExpr.h:253
@ EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYREF
Definition: execExpr.h:255
@ EEOP_AGG_ORDERED_TRANS_TUPLE
Definition: execExpr.h:261
ExprContext * hashcontext
Definition: execnodes.h:2390
ExprContext ** aggcontexts
Definition: execnodes.h:2391
struct ExprEvalStep::@51::@92 agg_plain_pergroup_nullcheck
struct ExprEvalStep::@51::@94 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 3907 of file execExpr.c.

3914 {
3916  ExprEvalStep scratch = {0};
3917  int maxatt = -1;
3918  List *adjust_jumps = NIL;
3919  ListCell *lc;
3920 
3921  /*
3922  * When no columns are actually compared, the result's always true. See
3923  * special case in ExecQual().
3924  */
3925  if (numCols == 0)
3926  return NULL;
3927 
3928  state->expr = NULL;
3929  state->flags = EEO_FLAG_IS_QUAL;
3930  state->parent = parent;
3931 
3932  scratch.resvalue = &state->resvalue;
3933  scratch.resnull = &state->resnull;
3934 
3935  /* compute max needed attribute */
3936  for (int natt = 0; natt < numCols; natt++)
3937  {
3938  int attno = keyColIdx[natt];
3939 
3940  if (attno > maxatt)
3941  maxatt = attno;
3942  }
3943  Assert(maxatt >= 0);
3944 
3945  /* push deform steps */
3946  scratch.opcode = EEOP_INNER_FETCHSOME;
3947  scratch.d.fetch.last_var = maxatt;
3948  scratch.d.fetch.fixed = false;
3949  scratch.d.fetch.known_desc = ldesc;
3950  scratch.d.fetch.kind = lops;
3951  if (ExecComputeSlotInfo(state, &scratch))
3952  ExprEvalPushStep(state, &scratch);
3953 
3954  scratch.opcode = EEOP_OUTER_FETCHSOME;
3955  scratch.d.fetch.last_var = maxatt;
3956  scratch.d.fetch.fixed = false;
3957  scratch.d.fetch.known_desc = rdesc;
3958  scratch.d.fetch.kind = rops;
3959  if (ExecComputeSlotInfo(state, &scratch))
3960  ExprEvalPushStep(state, &scratch);
3961 
3962  /*
3963  * Start comparing at the last field (least significant sort key). That's
3964  * the most likely to be different if we are dealing with sorted input.
3965  */
3966  for (int natt = numCols; --natt >= 0;)
3967  {
3968  int attno = keyColIdx[natt];
3969  Form_pg_attribute latt = TupleDescAttr(ldesc, attno - 1);
3970  Form_pg_attribute ratt = TupleDescAttr(rdesc, attno - 1);
3971  Oid foid = eqfunctions[natt];
3972  Oid collid = collations[natt];
3973  FmgrInfo *finfo;
3974  FunctionCallInfo fcinfo;
3975  AclResult aclresult;
3976 
3977  /* Check permission to call function */
3978  aclresult = object_aclcheck(ProcedureRelationId, foid, GetUserId(), ACL_EXECUTE);
3979  if (aclresult != ACLCHECK_OK)
3980  aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(foid));
3981 
3983 
3984  /* Set up the primary fmgr lookup information */
3985  finfo = palloc0(sizeof(FmgrInfo));
3986  fcinfo = palloc0(SizeForFunctionCallInfo(2));
3987  fmgr_info(foid, finfo);
3988  fmgr_info_set_expr(NULL, finfo);
3989  InitFunctionCallInfoData(*fcinfo, finfo, 2,
3990  collid, NULL, NULL);
3991 
3992  /* left arg */
3993  scratch.opcode = EEOP_INNER_VAR;
3994  scratch.d.var.attnum = attno - 1;
3995  scratch.d.var.vartype = latt->atttypid;
3996  scratch.resvalue = &fcinfo->args[0].value;
3997  scratch.resnull = &fcinfo->args[0].isnull;
3998  ExprEvalPushStep(state, &scratch);
3999 
4000  /* right arg */
4001  scratch.opcode = EEOP_OUTER_VAR;
4002  scratch.d.var.attnum = attno - 1;
4003  scratch.d.var.vartype = ratt->atttypid;
4004  scratch.resvalue = &fcinfo->args[1].value;
4005  scratch.resnull = &fcinfo->args[1].isnull;
4006  ExprEvalPushStep(state, &scratch);
4007 
4008  /* evaluate distinctness */
4009  scratch.opcode = EEOP_NOT_DISTINCT;
4010  scratch.d.func.finfo = finfo;
4011  scratch.d.func.fcinfo_data = fcinfo;
4012  scratch.d.func.fn_addr = finfo->fn_addr;
4013  scratch.d.func.nargs = 2;
4014  scratch.resvalue = &state->resvalue;
4015  scratch.resnull = &state->resnull;
4016  ExprEvalPushStep(state, &scratch);
4017 
4018  /* then emit EEOP_QUAL to detect if result is false (or null) */
4019  scratch.opcode = EEOP_QUAL;
4020  scratch.d.qualexpr.jumpdone = -1;
4021  scratch.resvalue = &state->resvalue;
4022  scratch.resnull = &state->resnull;
4023  ExprEvalPushStep(state, &scratch);
4024  adjust_jumps = lappend_int(adjust_jumps,
4025  state->steps_len - 1);
4026  }
4027 
4028  /* adjust jump targets */
4029  foreach(lc, adjust_jumps)
4030  {
4031  ExprEvalStep *as = &state->steps[lfirst_int(lc)];
4032 
4033  Assert(as->opcode == EEOP_QUAL);
4034  Assert(as->d.qualexpr.jumpdone == -1);
4035  as->d.qualexpr.jumpdone = state->steps_len;
4036  }
4037 
4038  scratch.resvalue = NULL;
4039  scratch.resnull = NULL;
4040  scratch.opcode = EEOP_DONE;
4041  ExprEvalPushStep(state, &scratch);
4042 
4044 
4045  return state;
4046 }
AclResult
Definition: acl.h:181
@ ACLCHECK_OK
Definition: acl.h:182
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:2669
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition: aclchk.c:3760
Oid collid
static bool ExecComputeSlotInfo(ExprState *state, ExprEvalStep *op)
Definition: execExpr.c:2847
@ 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:1612
void * palloc0(Size size)
Definition: mcxt.c:1257
Oid GetUserId(void)
Definition: miscinit.c:509
#define InvokeFunctionExecuteHook(objectId)
Definition: objectaccess.h:213
@ OBJECT_FUNCTION
Definition: parsenodes.h:2139
#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::@51::@52 fetch
struct ExprEvalStep::@51::@60 qualexpr
struct ExprEvalStep::@51::@53 var
struct ExprEvalStep::@51::@58 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 4064 of file execExpr.c.

4071 {
4073  ExprEvalStep scratch = {0};
4074  int maxatt = list_length(param_exprs);
4075  List *adjust_jumps = NIL;
4076  ListCell *lc;
4077 
4078  state->expr = NULL;
4079  state->flags = EEO_FLAG_IS_QUAL;
4080  state->parent = parent;
4081 
4082  scratch.resvalue = &state->resvalue;
4083  scratch.resnull = &state->resnull;
4084 
4085  /* push deform steps */
4086  scratch.opcode = EEOP_INNER_FETCHSOME;
4087  scratch.d.fetch.last_var = maxatt;
4088  scratch.d.fetch.fixed = false;
4089  scratch.d.fetch.known_desc = desc;
4090  scratch.d.fetch.kind = lops;
4091  if (ExecComputeSlotInfo(state, &scratch))
4092  ExprEvalPushStep(state, &scratch);
4093 
4094  scratch.opcode = EEOP_OUTER_FETCHSOME;
4095  scratch.d.fetch.last_var = maxatt;
4096  scratch.d.fetch.fixed = false;
4097  scratch.d.fetch.known_desc = desc;
4098  scratch.d.fetch.kind = rops;
4099  if (ExecComputeSlotInfo(state, &scratch))
4100  ExprEvalPushStep(state, &scratch);
4101 
4102  for (int attno = 0; attno < maxatt; attno++)
4103  {
4104  Form_pg_attribute att = TupleDescAttr(desc, attno);
4105  Oid foid = eqfunctions[attno];
4106  Oid collid = collations[attno];
4107  FmgrInfo *finfo;
4108  FunctionCallInfo fcinfo;
4109  AclResult aclresult;
4110 
4111  /* Check permission to call function */
4112  aclresult = object_aclcheck(ProcedureRelationId, foid, GetUserId(), ACL_EXECUTE);
4113  if (aclresult != ACLCHECK_OK)
4114  aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(foid));
4115 
4117 
4118  /* Set up the primary fmgr lookup information */
4119  finfo = palloc0(sizeof(FmgrInfo));
4120  fcinfo = palloc0(SizeForFunctionCallInfo(2));
4121  fmgr_info(foid, finfo);
4122  fmgr_info_set_expr(NULL, finfo);
4123  InitFunctionCallInfoData(*fcinfo, finfo, 2,
4124  collid, NULL, NULL);
4125 
4126  /* left arg */
4127  scratch.opcode = EEOP_INNER_VAR;
4128  scratch.d.var.attnum = attno;
4129  scratch.d.var.vartype = att->atttypid;
4130  scratch.resvalue = &fcinfo->args[0].value;
4131  scratch.resnull = &fcinfo->args[0].isnull;
4132  ExprEvalPushStep(state, &scratch);
4133 
4134  /* right arg */
4135  scratch.opcode = EEOP_OUTER_VAR;
4136  scratch.d.var.attnum = attno;
4137  scratch.d.var.vartype = att->atttypid;
4138  scratch.resvalue = &fcinfo->args[1].value;
4139  scratch.resnull = &fcinfo->args[1].isnull;
4140  ExprEvalPushStep(state, &scratch);
4141 
4142  /* evaluate distinctness */
4143  scratch.opcode = EEOP_NOT_DISTINCT;
4144  scratch.d.func.finfo = finfo;
4145  scratch.d.func.fcinfo_data = fcinfo;
4146  scratch.d.func.fn_addr = finfo->fn_addr;
4147  scratch.d.func.nargs = 2;
4148  scratch.resvalue = &state->resvalue;
4149  scratch.resnull = &state->resnull;
4150  ExprEvalPushStep(state, &scratch);
4151 
4152  /* then emit EEOP_QUAL to detect if result is false (or null) */
4153  scratch.opcode = EEOP_QUAL;
4154  scratch.d.qualexpr.jumpdone = -1;
4155  scratch.resvalue = &state->resvalue;
4156  scratch.resnull = &state->resnull;
4157  ExprEvalPushStep(state, &scratch);
4158  adjust_jumps = lappend_int(adjust_jumps,
4159  state->steps_len - 1);
4160  }
4161 
4162  /* adjust jump targets */
4163  foreach(lc, adjust_jumps)
4164  {
4165  ExprEvalStep *as = &state->steps[lfirst_int(lc)];
4166 
4167  Assert(as->opcode == EEOP_QUAL);
4168  Assert(as->d.qualexpr.jumpdone == -1);
4169  as->d.qualexpr.jumpdone = state->steps_len;
4170  }
4171 
4172  scratch.resvalue = NULL;
4173  scratch.resnull = NULL;
4174  scratch.opcode = EEOP_DONE;
4175  ExprEvalPushStep(state, &scratch);
4176 
4178 
4179  return state;
4180 }

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 358 of file execExpr.c.

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

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

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 843 of file execExpr.c.

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

2848 {
2849  PlanState *parent = state->parent;
2850  TupleDesc desc = NULL;
2851  const TupleTableSlotOps *tts_ops = NULL;
2852  bool isfixed = false;
2853  ExprEvalOp opcode = op->opcode;
2854 
2855  Assert(opcode == EEOP_INNER_FETCHSOME ||
2856  opcode == EEOP_OUTER_FETCHSOME ||
2857  opcode == EEOP_SCAN_FETCHSOME);
2858 
2859  if (op->d.fetch.known_desc != NULL)
2860  {
2861  desc = op->d.fetch.known_desc;
2862  tts_ops = op->d.fetch.kind;
2863  isfixed = op->d.fetch.kind != NULL;
2864  }
2865  else if (!parent)
2866  {
2867  isfixed = false;
2868  }
2869  else if (opcode == EEOP_INNER_FETCHSOME)
2870  {
2871  PlanState *is = innerPlanState(parent);
2872 
2873  if (parent->inneropsset && !parent->inneropsfixed)
2874  {
2875  isfixed = false;
2876  }
2877  else if (parent->inneropsset && parent->innerops)
2878  {
2879  isfixed = true;
2880  tts_ops = parent->innerops;
2881  desc = ExecGetResultType(is);
2882  }
2883  else if (is)
2884  {
2885  tts_ops = ExecGetResultSlotOps(is, &isfixed);
2886  desc = ExecGetResultType(is);
2887  }
2888  }
2889  else if (opcode == EEOP_OUTER_FETCHSOME)
2890  {
2891  PlanState *os = outerPlanState(parent);
2892 
2893  if (parent->outeropsset && !parent->outeropsfixed)
2894  {
2895  isfixed = false;
2896  }
2897  else if (parent->outeropsset && parent->outerops)
2898  {
2899  isfixed = true;
2900  tts_ops = parent->outerops;
2901  desc = ExecGetResultType(os);
2902  }
2903  else if (os)
2904  {
2905  tts_ops = ExecGetResultSlotOps(os, &isfixed);
2906  desc = ExecGetResultType(os);
2907  }
2908  }
2909  else if (opcode == EEOP_SCAN_FETCHSOME)
2910  {
2911  desc = parent->scandesc;
2912 
2913  if (parent->scanops)
2914  tts_ops = parent->scanops;
2915 
2916  if (parent->scanopsset)
2917  isfixed = parent->scanopsfixed;
2918  }
2919 
2920  if (isfixed && desc != NULL && tts_ops != NULL)
2921  {
2922  op->d.fetch.fixed = true;
2923  op->d.fetch.kind = tts_ops;
2924  op->d.fetch.known_desc = desc;
2925  }
2926  else
2927  {
2928  op->d.fetch.fixed = false;
2929  op->d.fetch.kind = NULL;
2930  op->d.fetch.known_desc = NULL;
2931  }
2932 
2933  /* if the slot is known to always virtual we never need to deform */
2934  if (op->d.fetch.fixed && op->d.fetch.kind == &TTSOpsVirtual)
2935  return false;
2936 
2937  return true;
2938 }
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:1133
#define innerPlanState(node)
Definition: execnodes.h:1132
bool inneropsset
Definition: execnodes.h:1121
bool outeropsset
Definition: execnodes.h:1120
const TupleTableSlotOps * outerops
Definition: execnodes.h:1112
const TupleTableSlotOps * innerops
Definition: execnodes.h:1113
const TupleTableSlotOps * scanops
Definition: execnodes.h:1111
bool outeropsfixed
Definition: execnodes.h:1116
bool scanopsset
Definition: execnodes.h:1119
TupleDesc scandesc
Definition: execnodes.h:1086
bool scanopsfixed
Definition: execnodes.h:1115
bool inneropsfixed
Definition: execnodes.h:1117

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 2684 of file execExpr.c.

2685 {
2686  ExprSetupInfo info = {0, 0, 0, NIL};
2687 
2688  /* Prescan to find out what we need. */
2689  expr_setup_walker(node, &info);
2690 
2691  /* And generate those steps. */
2692  ExecPushExprSetupSteps(state, &info);
2693 }

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

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

◆ ExecInitCheck()

ExprState* ExecInitCheck ( List qual,
PlanState parent 
)

Definition at line 303 of file execExpr.c.

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

3299 {
3300  DomainConstraintRef *constraint_ref;
3301  Datum *domainval = NULL;
3302  bool *domainnull = NULL;
3303  ListCell *l;
3304 
3305  scratch->d.domaincheck.resulttype = ctest->resulttype;
3306  /* we'll allocate workspace only if needed */
3307  scratch->d.domaincheck.checkvalue = NULL;
3308  scratch->d.domaincheck.checknull = NULL;
3309 
3310  /*
3311  * Evaluate argument - it's fine to directly store it into resv/resnull,
3312  * if there's constraint failures there'll be errors, otherwise it's what
3313  * needs to be returned.
3314  */
3315  ExecInitExprRec(ctest->arg, state, resv, resnull);
3316 
3317  /*
3318  * Note: if the argument is of varlena type, it could be a R/W expanded
3319  * object. We want to return the R/W pointer as the final result, but we
3320  * have to pass a R/O pointer as the value to be tested by any functions
3321  * in check expressions. We don't bother to emit a MAKE_READONLY step
3322  * unless there's actually at least one check expression, though. Until
3323  * we've tested that, domainval/domainnull are NULL.
3324  */
3325 
3326  /*
3327  * Collect the constraints associated with the domain.
3328  *
3329  * Note: before PG v10 we'd recheck the set of constraints during each
3330  * evaluation of the expression. Now we bake them into the ExprState
3331  * during executor initialization. That means we don't need typcache.c to
3332  * provide compiled exprs.
3333  */
3334  constraint_ref = (DomainConstraintRef *)
3335  palloc(sizeof(DomainConstraintRef));
3337  constraint_ref,
3339  false);
3340 
3341  /*
3342  * Compile code to check each domain constraint. NOTNULL constraints can
3343  * just be applied on the resv/resnull value, but for CHECK constraints we
3344  * need more pushups.
3345  */
3346  foreach(l, constraint_ref->constraints)
3347  {
3349  Datum *save_innermost_domainval;
3350  bool *save_innermost_domainnull;
3351 
3352  scratch->d.domaincheck.constraintname = con->name;
3353 
3354  switch (con->constrainttype)
3355  {
3357  scratch->opcode = EEOP_DOMAIN_NOTNULL;
3358  ExprEvalPushStep(state, scratch);
3359  break;
3360  case DOM_CONSTRAINT_CHECK:
3361  /* Allocate workspace for CHECK output if we didn't yet */
3362  if (scratch->d.domaincheck.checkvalue == NULL)
3363  {
3364  scratch->d.domaincheck.checkvalue =
3365  (Datum *) palloc(sizeof(Datum));
3366  scratch->d.domaincheck.checknull =
3367  (bool *) palloc(sizeof(bool));
3368  }
3369 
3370  /*
3371  * If first time through, determine where CoerceToDomainValue
3372  * nodes should read from.
3373  */
3374  if (domainval == NULL)
3375  {
3376  /*
3377  * Since value might be read multiple times, force to R/O
3378  * - but only if it could be an expanded datum.
3379  */
3380  if (get_typlen(ctest->resulttype) == -1)
3381  {
3382  ExprEvalStep scratch2 = {0};
3383 
3384  /* Yes, so make output workspace for MAKE_READONLY */
3385  domainval = (Datum *) palloc(sizeof(Datum));
3386  domainnull = (bool *) palloc(sizeof(bool));
3387 
3388  /* Emit MAKE_READONLY */
3389  scratch2.opcode = EEOP_MAKE_READONLY;
3390  scratch2.resvalue = domainval;
3391  scratch2.resnull = domainnull;
3392  scratch2.d.make_readonly.value = resv;
3393  scratch2.d.make_readonly.isnull = resnull;
3394  ExprEvalPushStep(state, &scratch2);
3395  }
3396  else
3397  {
3398  /* No, so it's fine to read from resv/resnull */
3399  domainval = resv;
3400  domainnull = resnull;
3401  }
3402  }
3403 
3404  /*
3405  * Set up value to be returned by CoerceToDomainValue nodes.
3406  * We must save and restore innermost_domainval/null fields,
3407  * in case this node is itself within a check expression for
3408  * another domain.
3409  */
3410  save_innermost_domainval = state->innermost_domainval;
3411  save_innermost_domainnull = state->innermost_domainnull;
3412  state->innermost_domainval = domainval;
3413  state->innermost_domainnull = domainnull;
3414 
3415  /* evaluate check expression value */
3417  scratch->d.domaincheck.checkvalue,
3418  scratch->d.domaincheck.checknull);
3419 
3420  state->innermost_domainval = save_innermost_domainval;
3421  state->innermost_domainnull = save_innermost_domainnull;
3422 
3423  /* now test result */
3424  scratch->opcode = EEOP_DOMAIN_CHECK;
3425  ExprEvalPushStep(state, scratch);
3426 
3427  break;
3428  default:
3429  elog(ERROR, "unrecognized constraint type: %d",
3430  (int) con->constrainttype);
3431  break;
3432  }
3433  }
3434 }
@ EEOP_DOMAIN_CHECK
Definition: execExpr.h:232
@ EEOP_DOMAIN_NOTNULL
Definition: execExpr.h:229
@ EEOP_MAKE_READONLY
Definition: execExpr.h:167
@ DOM_CONSTRAINT_CHECK
Definition: execnodes.h:993
@ DOM_CONSTRAINT_NOTNULL
Definition: execnodes.h:992
MemoryContext CurrentMemoryContext
Definition: mcxt.c:135
void * palloc(Size size)
Definition: mcxt.c:1226
DomainConstraintType constrainttype
Definition: execnodes.h:999
struct ExprEvalStep::@51::@66 make_readonly
struct ExprEvalStep::@51::@80 domaincheck
void InitDomainConstraintRef(Oid type_id, DomainConstraintRef *ref, MemoryContext refctx, bool need_exprstate)
Definition: typcache.c:1310

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 128 of file execExpr.c.

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

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 323 of file execExpr.c.

324 {
325  List *result = NIL;
326  ListCell *lc;
327 
328  foreach(lc, nodes)
329  {
330  Expr *e = lfirst(lc);
331 
332  result = lappend(result, ExecInitExpr(e, parent));
333  }
334 
335  return result;
336 }
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 890 of file execExpr.c.

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

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

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 2579 of file execExpr.c.

2581 {
2582  int nargs = list_length(args);
2583  AclResult aclresult;
2584  FmgrInfo *flinfo;
2585  FunctionCallInfo fcinfo;
2586  int argno;
2587  ListCell *lc;
2588 
2589  /* Check permission to call function */
2590  aclresult = object_aclcheck(ProcedureRelationId, funcid, GetUserId(), ACL_EXECUTE);
2591  if (aclresult != ACLCHECK_OK)
2592  aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(funcid));
2593  InvokeFunctionExecuteHook(funcid);
2594 
2595  /*
2596  * Safety check on nargs. Under normal circumstances this should never
2597  * fail, as parser should check sooner. But possibly it might fail if
2598  * server has been compiled with FUNC_MAX_ARGS smaller than some functions
2599  * declared in pg_proc?
2600  */
2601  if (nargs > FUNC_MAX_ARGS)
2602  ereport(ERROR,
2603  (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
2604  errmsg_plural("cannot pass more than %d argument to a function",
2605  "cannot pass more than %d arguments to a function",
2606  FUNC_MAX_ARGS,
2607  FUNC_MAX_ARGS)));
2608 
2609  /* Allocate function lookup data and parameter workspace for this call */
2610  scratch->d.func.finfo = palloc0(sizeof(FmgrInfo));
2611  scratch->d.func.fcinfo_data = palloc0(SizeForFunctionCallInfo(nargs));
2612  flinfo = scratch->d.func.finfo;
2613  fcinfo = scratch->d.func.fcinfo_data;
2614 
2615  /* Set up the primary fmgr lookup information */
2616  fmgr_info(funcid, flinfo);
2617  fmgr_info_set_expr((Node *) node, flinfo);
2618 
2619  /* Initialize function call parameter structure too */
2620  InitFunctionCallInfoData(*fcinfo, flinfo,
2621  nargs, inputcollid, NULL, NULL);
2622 
2623  /* Keep extra copies of this info to save an indirection at runtime */
2624  scratch->d.func.fn_addr = flinfo->fn_addr;
2625  scratch->d.func.nargs = nargs;
2626 
2627  /* We only support non-set functions here */
2628  if (flinfo->fn_retset)
2629  ereport(ERROR,
2630  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2631  errmsg("set-valued function called in context that cannot accept a set"),
2632  state->parent ?
2633  executor_errposition(state->parent->state,
2634  exprLocation((Node *) node)) : 0));
2635 
2636  /* Build code to evaluate arguments directly into the fcinfo struct */
2637  argno = 0;
2638  foreach(lc, args)
2639  {
2640  Expr *arg = (Expr *) lfirst(lc);
2641 
2642  if (IsA(arg, Const))
2643  {
2644  /*
2645  * Don't evaluate const arguments every round; especially
2646  * interesting for constants in comparisons.
2647  */
2648  Const *con = (Const *) arg;
2649 
2650  fcinfo->args[argno].value = con->constvalue;
2651  fcinfo->args[argno].isnull = con->constisnull;
2652  }
2653  else
2654  {
2656  &fcinfo->args[argno].value,
2657  &fcinfo->args[argno].isnull);
2658  }
2659  argno++;
2660  }
2661 
2662  /* Insert appropriate opcode depending on strictness and stats level */
2663  if (pgstat_track_functions <= flinfo->fn_stats)
2664  {
2665  if (flinfo->fn_strict && nargs > 0)
2666  scratch->opcode = EEOP_FUNCEXPR_STRICT;
2667  else
2668  scratch->opcode = EEOP_FUNCEXPR;
2669  }
2670  else
2671  {
2672  if (flinfo->fn_strict && nargs > 0)
2674  else
2675  scratch->opcode = EEOP_FUNCEXPR_FUSAGE;
2676  }
2677 }
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:875
int exprLocation(const Node *expr)
Definition: nodeFuncs.c:1312
#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 214 of file execExpr.c.

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

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 3018 of file execExpr.c.

3020 {
3021  bool isAssignment = (sbsref->refassgnexpr != NULL);
3022  int nupper = list_length(sbsref->refupperindexpr);
3023  int nlower = list_length(sbsref->reflowerindexpr);
3024  const SubscriptRoutines *sbsroutines;
3025  SubscriptingRefState *sbsrefstate;
3026  SubscriptExecSteps methods;
3027  char *ptr;
3028  List *adjust_jumps = NIL;
3029  ListCell *lc;
3030  int i;
3031 
3032  /* Look up the subscripting support methods */
3033  sbsroutines = getSubscriptingRoutines(sbsref->refcontainertype, NULL);
3034  if (!sbsroutines)
3035  ereport(ERROR,
3036  (errcode(ERRCODE_DATATYPE_MISMATCH),
3037  errmsg("cannot subscript type %s because it does not support subscripting",
3038  format_type_be(sbsref->refcontainertype)),
3039  state->parent ?
3040  executor_errposition(state->parent->state,
3041  exprLocation((Node *) sbsref)) : 0));
3042 
3043  /* Allocate sbsrefstate, with enough space for per-subscript arrays too */
3044  sbsrefstate = palloc0(MAXALIGN(sizeof(SubscriptingRefState)) +
3045  (nupper + nlower) * (sizeof(Datum) +
3046  2 * sizeof(bool)));
3047 
3048  /* Fill constant fields of SubscriptingRefState */
3049  sbsrefstate->isassignment = isAssignment;
3050  sbsrefstate->numupper = nupper;
3051  sbsrefstate->numlower = nlower;
3052  /* Set up per-subscript arrays */
3053  ptr = ((char *) sbsrefstate) + MAXALIGN(sizeof(SubscriptingRefState));
3054  sbsrefstate->upperindex = (Datum *) ptr;
3055  ptr += nupper * sizeof(Datum);
3056  sbsrefstate->lowerindex = (Datum *) ptr;
3057  ptr += nlower * sizeof(Datum);
3058  sbsrefstate->upperprovided = (bool *) ptr;
3059  ptr += nupper * sizeof(bool);
3060  sbsrefstate->lowerprovided = (bool *) ptr;
3061  ptr += nlower * sizeof(bool);
3062  sbsrefstate->upperindexnull = (bool *) ptr;
3063  ptr += nupper * sizeof(bool);
3064  sbsrefstate->lowerindexnull = (bool *) ptr;
3065  /* ptr += nlower * sizeof(bool); */
3066 
3067  /*
3068  * Let the container-type-specific code have a chance. It must fill the
3069  * "methods" struct with function pointers for us to possibly use in
3070  * execution steps below; and it can optionally set up some data pointed
3071  * to by the workspace field.
3072  */
3073  memset(&methods, 0, sizeof(methods));
3074  sbsroutines->exec_setup(sbsref, sbsrefstate, &methods);
3075 
3076  /*
3077  * Evaluate array input. It's safe to do so into resv/resnull, because we
3078  * won't use that as target for any of the other subexpressions, and it'll
3079  * be overwritten by the final EEOP_SBSREF_FETCH/ASSIGN step, which is
3080  * pushed last.
3081  */
3082  ExecInitExprRec(sbsref->refexpr, state, resv, resnull);
3083 
3084  /*
3085  * If refexpr yields NULL, and the operation should be strict, then result
3086  * is NULL. We can implement this with just JUMP_IF_NULL, since we
3087  * evaluated the array into the desired target location.
3088  */
3089  if (!isAssignment && sbsroutines->fetch_strict)
3090  {
3091  scratch->opcode = EEOP_JUMP_IF_NULL;
3092  scratch->d.jump.jumpdone = -1; /* adjust later */
3093  ExprEvalPushStep(state, scratch);
3094  adjust_jumps = lappend_int(adjust_jumps,
3095  state->steps_len - 1);
3096  }
3097 
3098  /* Evaluate upper subscripts */
3099  i = 0;
3100  foreach(lc, sbsref->refupperindexpr)
3101  {
3102  Expr *e = (Expr *) lfirst(lc);
3103 
3104  /* When slicing, individual subscript bounds can be omitted */
3105  if (!e)
3106  {
3107  sbsrefstate->upperprovided[i] = false;
3108  sbsrefstate->upperindexnull[i] = true;
3109  }
3110  else
3111  {
3112  sbsrefstate->upperprovided[i] = true;
3113  /* Each subscript is evaluated into appropriate array entry */
3115  &sbsrefstate->upperindex[i],
3116  &sbsrefstate->upperindexnull[i]);
3117  }
3118  i++;
3119  }
3120 
3121  /* Evaluate lower subscripts similarly */
3122  i = 0;
3123  foreach(lc, sbsref->reflowerindexpr)
3124  {
3125  Expr *e = (Expr *) lfirst(lc);
3126 
3127  /* When slicing, individual subscript bounds can be omitted */
3128  if (!e)
3129  {
3130  sbsrefstate->lowerprovided[i] = false;
3131  sbsrefstate->lowerindexnull[i] = true;
3132  }
3133  else
3134  {
3135  sbsrefstate->lowerprovided[i] = true;
3136  /* Each subscript is evaluated into appropriate array entry */
3138  &sbsrefstate->lowerindex[i],
3139  &sbsrefstate->lowerindexnull[i]);
3140  }
3141  i++;
3142  }
3143 
3144  /* SBSREF_SUBSCRIPTS checks and converts all the subscripts at once */
3145  if (methods.sbs_check_subscripts)
3146  {
3147  scratch->opcode = EEOP_SBSREF_SUBSCRIPTS;
3148  scratch->d.sbsref_subscript.subscriptfunc = methods.sbs_check_subscripts;
3149  scratch->d.sbsref_subscript.state = sbsrefstate;
3150  scratch->d.sbsref_subscript.jumpdone = -1; /* adjust later */
3151  ExprEvalPushStep(state, scratch);
3152  adjust_jumps = lappend_int(adjust_jumps,
3153  state->steps_len - 1);
3154  }
3155 
3156  if (isAssignment)
3157  {
3158  Datum *save_innermost_caseval;
3159  bool *save_innermost_casenull;
3160 
3161  /* Check for unimplemented methods */
3162  if (!methods.sbs_assign)
3163  ereport(ERROR,
3164  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3165  errmsg("type %s does not support subscripted assignment",
3166  format_type_be(sbsref->refcontainertype))));
3167 
3168  /*
3169  * We might have a nested-assignment situation, in which the
3170  * refassgnexpr is itself a FieldStore or SubscriptingRef that needs
3171  * to obtain and modify the previous value of the array element or
3172  * slice being replaced. If so, we have to extract that value from
3173  * the array and pass it down via the CaseTestExpr mechanism. It's
3174  * safe to reuse the CASE mechanism because there cannot be a CASE
3175  * between here and where the value would be needed, and an array
3176  * assignment can't be within a CASE either. (So saving and restoring
3177  * innermost_caseval is just paranoia, but let's do it anyway.)
3178  *
3179  * Since fetching the old element might be a nontrivial expense, do it
3180  * only if the argument actually needs it.
3181  */
3183  {
3184  if (!methods.sbs_fetch_old)
3185  ereport(ERROR,
3186  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3187  errmsg("type %s does not support subscripted assignment",
3188  format_type_be(sbsref->refcontainertype))));
3189  scratch->opcode = EEOP_SBSREF_OLD;
3190  scratch->d.sbsref.subscriptfunc = methods.sbs_fetch_old;
3191  scratch->d.sbsref.state = sbsrefstate;
3192  ExprEvalPushStep(state, scratch);
3193  }
3194 
3195  /* SBSREF_OLD puts extracted value into prevvalue/prevnull */
3196  save_innermost_caseval = state->innermost_caseval;
3197  save_innermost_casenull = state->innermost_casenull;
3198  state->innermost_caseval = &sbsrefstate->prevvalue;
3199  state->innermost_casenull = &sbsrefstate->prevnull;
3200 
3201  /* evaluate replacement value into replacevalue/replacenull */
3203  &sbsrefstate->replacevalue, &sbsrefstate->replacenull);
3204 
3205  state->innermost_caseval = save_innermost_caseval;
3206  state->innermost_casenull = save_innermost_casenull;
3207 
3208  /* and perform the assignment */
3209  scratch->opcode = EEOP_SBSREF_ASSIGN;
3210  scratch->d.sbsref.subscriptfunc = methods.sbs_assign;
3211  scratch->d.sbsref.state = sbsrefstate;
3212  ExprEvalPushStep(state, scratch);
3213  }
3214  else
3215  {
3216  /* array fetch is much simpler */
3217  scratch->opcode = EEOP_SBSREF_FETCH;
3218  scratch->d.sbsref.subscriptfunc = methods.sbs_fetch;
3219  scratch->d.sbsref.state = sbsrefstate;
3220  ExprEvalPushStep(state, scratch);
3221  }
3222 
3223  /* adjust jump targets */
3224  foreach(lc, adjust_jumps)
3225  {
3226  ExprEvalStep *as = &state->steps[lfirst_int(lc)];
3227 
3228  if (as->opcode == EEOP_SBSREF_SUBSCRIPTS)
3229  {
3230  Assert(as->d.sbsref_subscript.jumpdone == -1);
3231  as->d.sbsref_subscript.jumpdone = state->steps_len;
3232  }
3233  else
3234  {
3236  Assert(as->d.jump.jumpdone == -1);
3237  as->d.jump.jumpdone = state->steps_len;
3238  }
3239  }
3240 }
#define MAXALIGN(LEN)
Definition: c.h:800
unsigned char bool
Definition: c.h:445
static bool isAssignmentIndirectionExpr(Expr *expr)
Definition: execExpr.c:3260
@ EEOP_SBSREF_SUBSCRIPTS
Definition: execExpr.h:210
@ EEOP_SBSREF_FETCH
Definition: execExpr.h:223
@ EEOP_SBSREF_ASSIGN
Definition: execExpr.h:220
@ EEOP_SBSREF_OLD
Definition: execExpr.h:217
@ EEOP_JUMP_IF_NULL
Definition: execExpr.h:140
const struct SubscriptRoutines * getSubscriptingRoutines(Oid typid, Oid *typelemp)
Definition: lsyscache.c:3112
struct ExprEvalStep::@51::@78 sbsref_subscript
struct ExprEvalStep::@51::@79 sbsref
ExecEvalSubroutine sbs_fetch_old
Definition: execExpr.h:737
ExecEvalBoolSubroutine sbs_check_subscripts
Definition: execExpr.h:734
ExecEvalSubroutine sbs_assign
Definition: execExpr.h:736
ExecEvalSubroutine sbs_fetch
Definition: execExpr.h:735
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 2945 of file execExpr.c.

2946 {
2947  PlanState *parent = state->parent;
2948 
2949  /* fill in all but the target */
2950  scratch->opcode = EEOP_WHOLEROW;
2951  scratch->d.wholerow.var = variable;
2952  scratch->d.wholerow.first = true;
2953  scratch->d.wholerow.slow = false;
2954  scratch->d.wholerow.tupdesc = NULL; /* filled at runtime */
2955  scratch->d.wholerow.junkFilter = NULL;
2956 
2957  /*
2958  * If the input tuple came from a subquery, it might contain "resjunk"
2959  * columns (such as GROUP BY or ORDER BY columns), which we don't want to
2960  * keep in the whole-row result. We can get rid of such columns by
2961  * passing the tuple through a JunkFilter --- but to make one, we have to
2962  * lay our hands on the subquery's targetlist. Fortunately, there are not
2963  * very many cases where this can happen, and we can identify all of them
2964  * by examining our parent PlanState. We assume this is not an issue in
2965  * standalone expressions that don't have parent plans. (Whole-row Vars
2966  * can occur in such expressions, but they will always be referencing
2967  * table rows.)
2968  */
2969  if (parent)
2970  {
2971  PlanState *subplan = NULL;
2972 
2973  switch (nodeTag(parent))
2974  {
2975  case T_SubqueryScanState:
2976  subplan = ((SubqueryScanState *) parent)->subplan;
2977  break;
2978  case T_CteScanState:
2979  subplan = ((CteScanState *) parent)->cteplanstate;
2980  break;
2981  default:
2982  break;
2983  }
2984 
2985  if (subplan)
2986  {
2987  bool junk_filter_needed = false;
2988  ListCell *tlist;
2989 
2990  /* Detect whether subplan tlist actually has any junk columns */
2991  foreach(tlist, subplan->plan->targetlist)
2992  {
2993  TargetEntry *tle = (TargetEntry *) lfirst(tlist);
2994 
2995  if (tle->resjunk)
2996  {
2997  junk_filter_needed = true;
2998  break;
2999  }
3000  }
3001 
3002  /* If so, build the junkfilter now */
3003  if (junk_filter_needed)
3004  {
3005  scratch->d.wholerow.junkFilter =
3007  ExecInitExtraTupleSlot(parent->state, NULL,
3008  &TTSOpsVirtual));
3009  }
3010  }
3011  }
3012 }
@ 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::@51::@54 wholerow
Plan * plan
Definition: execnodes.h:1037
EState * state
Definition: execnodes.h:1039
List * targetlist
Definition: plannodes.h:153

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 787 of file execExpr.c.

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

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

Referenced by ExecPartitionCheck().

◆ ExecPrepareExpr()

ExprState* ExecPrepareExpr ( Expr node,
EState estate 
)

Definition at line 736 of file execExpr.c.

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

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 810 of file execExpr.c.

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

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 764 of file execExpr.c.

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

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 2700 of file execExpr.c.

2701 {
2702  ExprEvalStep scratch = {0};
2703  ListCell *lc;
2704 
2705  scratch.resvalue = NULL;
2706  scratch.resnull = NULL;
2707 
2708  /*
2709  * Add steps deforming the ExprState's inner/outer/scan slots as much as
2710  * required by any Vars appearing in the expression.
2711  */
2712  if (info->last_inner > 0)
2713  {
2714  scratch.opcode = EEOP_INNER_FETCHSOME;
2715  scratch.d.fetch.last_var = info->last_inner;
2716  scratch.d.fetch.fixed = false;
2717  scratch.d.fetch.kind = NULL;
2718  scratch.d.fetch.known_desc = NULL;
2719  if (ExecComputeSlotInfo(state, &scratch))
2720  ExprEvalPushStep(state, &scratch);
2721  }
2722  if (info->last_outer > 0)
2723  {
2724  scratch.opcode = EEOP_OUTER_FETCHSOME;
2725  scratch.d.fetch.last_var = info->last_outer;
2726  scratch.d.fetch.fixed = false;
2727  scratch.d.fetch.kind = NULL;
2728  scratch.d.fetch.known_desc = NULL;
2729  if (ExecComputeSlotInfo(state, &scratch))
2730  ExprEvalPushStep(state, &scratch);
2731  }
2732  if (info->last_scan > 0)
2733  {
2734  scratch.opcode = EEOP_SCAN_FETCHSOME;
2735  scratch.d.fetch.last_var = info->last_scan;
2736  scratch.d.fetch.fixed = false;
2737  scratch.d.fetch.kind = NULL;
2738  scratch.d.fetch.known_desc = NULL;
2739  if (ExecComputeSlotInfo(state, &scratch))
2740  ExprEvalPushStep(state, &scratch);
2741  }
2742 
2743  /*
2744  * Add steps to execute any MULTIEXPR SubPlans appearing in the
2745  * expression. We need to evaluate these before any of the Params
2746  * referencing their outputs are used, but after we've prepared for any
2747  * Var references they may contain. (There cannot be cross-references
2748  * between MULTIEXPR SubPlans, so we needn't worry about their order.)
2749  */
2750  foreach(lc, info->multiexpr_subplans)
2751  {
2752  SubPlan *subplan = (SubPlan *) lfirst(lc);
2753  SubPlanState *sstate;
2754 
2755  Assert(subplan->subLinkType == MULTIEXPR_SUBLINK);
2756 
2757  /* This should match what ExecInitExprRec does for other SubPlans: */
2758 
2759  if (!state->parent)
2760  elog(ERROR, "SubPlan found with no parent plan");
2761 
2762  sstate = ExecInitSubPlan(subplan, state->parent);
2763 
2764  /* add SubPlanState nodes to state->parent->subPlan */
2765  state->parent->subPlan = lappend(state->parent->subPlan,
2766  sstate);
2767 
2768  scratch.opcode = EEOP_SUBPLAN;
2769  scratch.d.subplan.sstate = sstate;
2770 
2771  /* The result can be ignored, but we better put it somewhere */
2772  scratch.resvalue = &state->resvalue;
2773  scratch.resnull = &state->resnull;
2774 
2775  ExprEvalPushStep(state, &scratch);
2776  }
2777 }
AttrNumber last_inner
Definition: execExpr.c:59
List * multiexpr_subplans
Definition: execExpr.c:63

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 873 of file execExpr.c.

874 {
875  if (jit_compile_expr(state))
876  return;
877 
879 }
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 2783 of file execExpr.c.

2784 {
2785  if (node == NULL)
2786  return false;
2787  if (IsA(node, Var))
2788  {
2789  Var *variable = (Var *) node;
2790  AttrNumber attnum = variable->varattno;
2791 
2792  switch (variable->varno)
2793  {
2794  case INNER_VAR:
2795  info->last_inner = Max(info->last_inner, attnum);
2796  break;
2797 
2798  case OUTER_VAR:
2799  info->last_outer = Max(info->last_outer, attnum);
2800  break;
2801 
2802  /* INDEX_VAR is handled by default case */
2803 
2804  default:
2805  info->last_scan = Max(info->last_scan, attnum);
2806  break;
2807  }
2808  return