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

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

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

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

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

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

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

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

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

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

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

◆ ExecCheck()

bool ExecCheck ( ExprState state,
ExprContext econtext 
)

Definition at line 839 of file execExpr.c.

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

2862 {
2863  PlanState *parent = state->parent;
2864  TupleDesc desc = NULL;
2865  const TupleTableSlotOps *tts_ops = NULL;
2866  bool isfixed = false;
2867  ExprEvalOp opcode = op->opcode;
2868 
2869  Assert(opcode == EEOP_INNER_FETCHSOME ||
2870  opcode == EEOP_OUTER_FETCHSOME ||
2871  opcode == EEOP_SCAN_FETCHSOME);
2872 
2873  if (op->d.fetch.known_desc != NULL)
2874  {
2875  desc = op->d.fetch.known_desc;
2876  tts_ops = op->d.fetch.kind;
2877  isfixed = op->d.fetch.kind != NULL;
2878  }
2879  else if (!parent)
2880  {
2881  isfixed = false;
2882  }
2883  else if (opcode == EEOP_INNER_FETCHSOME)
2884  {
2885  PlanState *is = innerPlanState(parent);
2886 
2887  if (parent->inneropsset && !parent->inneropsfixed)
2888  {
2889  isfixed = false;
2890  }
2891  else if (parent->inneropsset && parent->innerops)
2892  {
2893  isfixed = true;
2894  tts_ops = parent->innerops;
2895  desc = ExecGetResultType(is);
2896  }
2897  else if (is)
2898  {
2899  tts_ops = ExecGetResultSlotOps(is, &isfixed);
2900  desc = ExecGetResultType(is);
2901  }
2902  }
2903  else if (opcode == EEOP_OUTER_FETCHSOME)
2904  {
2905  PlanState *os = outerPlanState(parent);
2906 
2907  if (parent->outeropsset && !parent->outeropsfixed)
2908  {
2909  isfixed = false;
2910  }
2911  else if (parent->outeropsset && parent->outerops)
2912  {
2913  isfixed = true;
2914  tts_ops = parent->outerops;
2915  desc = ExecGetResultType(os);
2916  }
2917  else if (os)
2918  {
2919  tts_ops = ExecGetResultSlotOps(os, &isfixed);
2920  desc = ExecGetResultType(os);
2921  }
2922  }
2923  else if (opcode == EEOP_SCAN_FETCHSOME)
2924  {
2925  desc = parent->scandesc;
2926 
2927  if (parent->scanops)
2928  tts_ops = parent->scanops;
2929 
2930  if (parent->scanopsset)
2931  isfixed = parent->scanopsfixed;
2932  }
2933 
2934  if (isfixed && desc != NULL && tts_ops != NULL)
2935  {
2936  op->d.fetch.fixed = true;
2937  op->d.fetch.kind = tts_ops;
2938  op->d.fetch.known_desc = desc;
2939  }
2940  else
2941  {
2942  op->d.fetch.fixed = false;
2943  op->d.fetch.kind = NULL;
2944  op->d.fetch.known_desc = NULL;
2945  }
2946 
2947  /* if the slot is known to always virtual we never need to deform */
2948  if (op->d.fetch.fixed && op->d.fetch.kind == &TTSOpsVirtual)
2949  return false;
2950 
2951  return true;
2952 }
ExprEvalOp
Definition: execExpr.h:67
@ EEOP_SCAN_FETCHSOME
Definition: execExpr.h:74
const TupleTableSlotOps TTSOpsVirtual
Definition: execTuples.c:83
TupleDesc ExecGetResultType(PlanState *planstate)
Definition: execUtils.c:493
const TupleTableSlotOps * ExecGetResultSlotOps(PlanState *planstate, bool *isfixed)
Definition: execUtils.c:502
#define outerPlanState(node)
Definition: execnodes.h:1139
#define innerPlanState(node)
Definition: execnodes.h:1138
bool inneropsset
Definition: execnodes.h:1127
bool outeropsset
Definition: execnodes.h:1126
const TupleTableSlotOps * outerops
Definition: execnodes.h:1118
const TupleTableSlotOps * innerops
Definition: execnodes.h:1119
const TupleTableSlotOps * scanops
Definition: execnodes.h:1117
bool outeropsfixed
Definition: execnodes.h:1122
bool scanopsset
Definition: execnodes.h:1125
TupleDesc scandesc
Definition: execnodes.h:1092
bool scanopsfixed
Definition: execnodes.h:1121
bool inneropsfixed
Definition: execnodes.h:1123

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

2699 {
2700  ExprSetupInfo info = {0, 0, 0, NIL};
2701 
2702  /* Prescan to find out what we need. */
2703  expr_setup_walker(node, &info);
2704 
2705  /* And generate those steps. */
2706  ExecPushExprSetupSteps(state, &info);
2707 }

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

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

◆ ExecInitCheck()

ExprState* ExecInitCheck ( List qual,
PlanState parent 
)

Definition at line 299 of file execExpr.c.

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

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

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

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

Referenced by ExecInitExprRec().

◆ ExecInitExpr()

ExprState* ExecInitExpr ( Expr node,
PlanState parent 
)

Definition at line 127 of file execExpr.c.

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

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

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

◆ ExecInitExprList()

List* ExecInitExprList ( List nodes,
PlanState parent 
)

Definition at line 319 of file execExpr.c.

320 {
321  List *result = NIL;
322  ListCell *lc;
323 
324  foreach(lc, nodes)
325  {
326  Expr *e = lfirst(lc);
327 
328  result = lappend(result, ExecInitExpr(e, parent));
329  }
330 
331  return result;
332 }
List * lappend(List *list, void *datum)
Definition: list.c:339
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 886 of file execExpr.c.

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

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

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

Referenced by exec_eval_simple_expr(), and InitPartitionPruneContext().

◆ ExecInitFunc()

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

Definition at line 2593 of file execExpr.c.

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

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

Referenced by ExecInitExprRec().

◆ ExecInitQual()

ExprState* ExecInitQual ( List qual,
PlanState parent 
)

Definition at line 213 of file execExpr.c.

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

References Assert(), ExprEvalStep::d, EEO_FLAG_IS_QUAL, EEOP_DONE, EEOP_QUAL, ExecCreateExprSetupSteps(), ExecInitExprRec(), ExecReadyExpr(), ExprEvalPushStep(), foreach_int, foreach_ptr, IsA, lappend_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 3032 of file execExpr.c.

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

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

2960 {
2961  PlanState *parent = state->parent;
2962 
2963  /* fill in all but the target */
2964  scratch->opcode = EEOP_WHOLEROW;
2965  scratch->d.wholerow.var = variable;
2966  scratch->d.wholerow.first = true;
2967  scratch->d.wholerow.slow = false;
2968  scratch->d.wholerow.tupdesc = NULL; /* filled at runtime */
2969  scratch->d.wholerow.junkFilter = NULL;
2970 
2971  /*
2972  * If the input tuple came from a subquery, it might contain "resjunk"
2973  * columns (such as GROUP BY or ORDER BY columns), which we don't want to
2974  * keep in the whole-row result. We can get rid of such columns by
2975  * passing the tuple through a JunkFilter --- but to make one, we have to
2976  * lay our hands on the subquery's targetlist. Fortunately, there are not
2977  * very many cases where this can happen, and we can identify all of them
2978  * by examining our parent PlanState. We assume this is not an issue in
2979  * standalone expressions that don't have parent plans. (Whole-row Vars
2980  * can occur in such expressions, but they will always be referencing
2981  * table rows.)
2982  */
2983  if (parent)
2984  {
2985  PlanState *subplan = NULL;
2986 
2987  switch (nodeTag(parent))
2988  {
2989  case T_SubqueryScanState:
2990  subplan = ((SubqueryScanState *) parent)->subplan;
2991  break;
2992  case T_CteScanState:
2993  subplan = ((CteScanState *) parent)->cteplanstate;
2994  break;
2995  default:
2996  break;
2997  }
2998 
2999  if (subplan)
3000  {
3001  bool junk_filter_needed = false;
3002  ListCell *tlist;
3003 
3004  /* Detect whether subplan tlist actually has any junk columns */
3005  foreach(tlist, subplan->plan->targetlist)
3006  {
3007  TargetEntry *tle = (TargetEntry *) lfirst(tlist);
3008 
3009  if (tle->resjunk)
3010  {
3011  junk_filter_needed = true;
3012  break;
3013  }
3014  }
3015 
3016  /* If so, build the junkfilter now */
3017  if (junk_filter_needed)
3018  {
3019  scratch->d.wholerow.junkFilter =
3021  ExecInitExtraTupleSlot(parent->state, NULL,
3022  &TTSOpsVirtual));
3023  }
3024  }
3025  }
3026 }
@ EEOP_WHOLEROW
Definition: execExpr.h:87
JunkFilter * ExecInitJunkFilter(List *targetList, TupleTableSlot *slot)
Definition: execJunk.c:60
TupleTableSlot * ExecInitExtraTupleSlot(EState *estate, TupleDesc tupledesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1830
struct ExprEvalStep::@51::@54 wholerow
Plan * plan
Definition: execnodes.h:1043
EState * state
Definition: execnodes.h:1045
List * targetlist
Definition: plannodes.h:152

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

784 {
785  ExprState *result;
786  MemoryContext oldcontext;
787 
788  oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
789 
790  qual = (List *) expression_planner((Expr *) qual);
791 
792  result = ExecInitCheck(qual, NULL);
793 
794  MemoryContextSwitchTo(oldcontext);
795 
796  return result;
797 }
ExprState * ExecInitCheck(List *qual, PlanState *parent)
Definition: execExpr.c:299
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
Expr * expression_planner(Expr *expr)
Definition: planner.c:6400
MemoryContext es_query_cxt
Definition: execnodes.h:665

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

Referenced by ExecPartitionCheck().

◆ ExecPrepareExpr()

ExprState* ExecPrepareExpr ( Expr node,
EState estate 
)

Definition at line 732 of file execExpr.c.

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

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

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

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

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

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

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

◆ ExecPushExprSetupSteps()

static void ExecPushExprSetupSteps ( ExprState state,
ExprSetupInfo info 
)
static

Definition at line 2714 of file execExpr.c.

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

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

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

◆ ExecReadyExpr()

static void ExecReadyExpr ( ExprState state)
static

Definition at line 869 of file execExpr.c.

870 {
871  if (jit_compile_expr(state))
872  return;
873 
875 }
void ExecReadyInterpretedExpr(ExprState *state)
bool jit_compile_expr(struct ExprState *state)
Definition: jit.c:151

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

2798 {
2799  if (node == NULL)
2800  return false;
2801  if (IsA(node, Var))
2802  {
2803  Var *variable = (Var *) node;
2804  AttrNumber attnum = variable->varattno;
2805 
2806  switch (variable->varno)
2807  {
2808  case INNER_VAR:
2809  info->last_inner = Max(info->last_inner, attnum);
2810  break;
2811 
2812  case OUTER_VAR:
2813  info->last_outer = Max(info->last_outer, attnum);
2814  break;
2815 
2816  /* INDEX_VAR is handled by default case */
2817 
2818  default:
2819  info->last_scan = Max(info->last_scan, attnum);
2820  break;
2821  }
2822  return false;
2823  }
2824 
2825  /* Collect all MULTIEXPR SubPlans, too */
2826  if (IsA(node, SubPlan))
2827  {
2828  SubPlan *subplan = (SubPlan *) node;
2829 
2830  if (subplan->subLinkType == MULTIEXPR_SUBLINK)
2832  subplan);
2833  }
2834 
2835  /*
2836  * Don't examine the arguments or filters of Aggrefs or WindowFuncs,
2837  * because those do not represent expressions to be evaluated within the
2838  * calling expression's econtext. GroupingFunc arguments are never
2839  * evaluated at all.
2840  */
2841  if (IsA(node, Aggref))
2842  return false;
2843  if (IsA(node, WindowFunc))
2844  return false;
2845  if (IsA(node, GroupingFunc))
2846  return false;
2848  (void *) info);
2849 }
#define expression_tree_walker(n, w, c)
Definition: nodeFuncs.h:151

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

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

◆ ExprEvalPushStep()

void ExprEvalPushStep ( ExprState es,
const ExprEvalStep s 
)

Definition at line 2567 of file execExpr.c.

2568 {
2569  if (es->steps_alloc == 0)
2570  {
2571  es->steps_alloc = 16;
2572  es->steps = palloc(sizeof(ExprEvalStep) * es->steps_alloc);
2573  }
2574  else if (es->steps_alloc == es->steps_len)
2575  {
2576  es->steps_alloc *= 2;
2577  es->steps = repalloc(es->steps,
2578  sizeof(ExprEvalStep) * es->steps_alloc);
2579  }
2580 
2581  memcpy(&es->steps[es->steps_len++], s, sizeof(ExprEvalStep));
2582 }
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1528
int steps_alloc
Definition: execnodes.h:122

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

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

◆ isAssignmentIndirectionExpr()

static bool isAssignmentIndirectionExpr ( Expr expr)
static

Definition at line 3274 of file execExpr.c.

3275 {
3276  if (expr == NULL)
3277  return false; /* just paranoia */
3278  if (IsA(expr, FieldStore))
3279  {
3280  FieldStore *fstore = (FieldStore *) expr;
3281 
3282  if (fstore->arg && IsA(fstore->arg, CaseTestExpr))
3283  return true;
3284  }
3285  else if (IsA(expr, SubscriptingRef))
3286  {
3287  SubscriptingRef *sbsRef = (SubscriptingRef *) expr;
3288 
3289  if (sbsRef->refexpr && IsA(sbsRef->refexpr, CaseTestExpr))
3290  return true;
3291  }
3292  else if (IsA(expr, CoerceToDomain))
3293  {
3294  CoerceToDomain *cd = (CoerceToDomain *) expr;
3295 
3296  return isAssignmentIndirectionExpr(cd->arg);
3297  }
3298  else if (IsA(expr, RelabelType))
3299  {
3300  RelabelType *r = (RelabelType *) expr;
3301 
3302  return isAssignmentIndirectionExpr(r->arg);
3303  }
3304  return false;
3305 }

References FieldStore::arg, RelabelType::arg, CoerceToDomain::arg, IsA, and SubscriptingRef::refexpr.

Referenced by ExecInitSubscriptingRef().