PostgreSQL Source Code git master
Loading...
Searching...
No Matches
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/jsonpath.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 ExecInitSubPlanExpr (SubPlan *subplan, ExprState *state, Datum *resv, bool *resnull)
 
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)
 
static void ExecInitJsonExpr (JsonExpr *jsexpr, ExprState *state, Datum *resv, bool *resnull, ExprEvalStep *scratch)
 
static void ExecInitJsonCoercion (ExprState *state, JsonReturning *returning, ErrorSaveContext *escontext, bool omit_quotes, bool exists_coerce, Datum *resv, bool *resnull)
 
ExprStateExecInitExpr (Expr *node, PlanState *parent)
 
ExprStateExecInitExprWithContext (Expr *node, PlanState *parent, Node *escontext)
 
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)
 
ExprStateExecPrepareExprWithContext (Expr *node, EState *estate, Node *escontext)
 
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)
 
ExprStateExecBuildHash32FromAttrs (TupleDesc desc, const TupleTableSlotOps *ops, FmgrInfo *hashfunctions, Oid *collations, int numCols, AttrNumber *keyColIdx, PlanState *parent, uint32 init_value)
 
ExprStateExecBuildHash32Expr (TupleDesc desc, const TupleTableSlotOps *ops, const Oid *hashfunc_oids, const List *collations, const List *hash_exprs, const bool *opstrict, PlanState *parent, uint32 init_value)
 
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

Function Documentation

◆ ExecBuildAggTrans()

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

Definition at line 3704 of file execExpr.c.

3706{
3708 PlanState *parent = &aggstate->ss.ps;
3709 ExprEvalStep scratch = {0};
3710 bool isCombine = DO_AGGSPLIT_COMBINE(aggstate->aggsplit);
3711 ExprSetupInfo deform = {0, 0, 0, 0, 0, NIL};
3712
3713 state->expr = (Expr *) aggstate;
3714 state->parent = parent;
3715
3716 scratch.resvalue = &state->resvalue;
3717 scratch.resnull = &state->resnull;
3718
3719 /*
3720 * First figure out which slots, and how many columns from each, we're
3721 * going to need.
3722 */
3723 for (int transno = 0; transno < aggstate->numtrans; transno++)
3724 {
3725 AggStatePerTrans pertrans = &aggstate->pertrans[transno];
3726
3728 &deform);
3729 expr_setup_walker((Node *) pertrans->aggref->args,
3730 &deform);
3731 expr_setup_walker((Node *) pertrans->aggref->aggorder,
3732 &deform);
3734 &deform);
3735 expr_setup_walker((Node *) pertrans->aggref->aggfilter,
3736 &deform);
3737 }
3739
3740 /*
3741 * Emit instructions for each transition value / grouping set combination.
3742 */
3743 for (int transno = 0; transno < aggstate->numtrans; transno++)
3744 {
3745 AggStatePerTrans pertrans = &aggstate->pertrans[transno];
3749 bool *strictnulls = NULL;
3750 int argno;
3751 ListCell *bail;
3752
3753 /*
3754 * If filter present, emit. Do so before evaluating the input, to
3755 * avoid potentially unneeded computations, or even worse, unintended
3756 * side-effects. When combining, all the necessary filtering has
3757 * already been done.
3758 */
3759 if (pertrans->aggref->aggfilter && !isCombine)
3760 {
3761 /* evaluate filter expression */
3763 &state->resvalue, &state->resnull);
3764 /* and jump out if false */
3766 scratch.d.jump.jumpdone = -1; /* adjust later */
3769 state->steps_len - 1);
3770 }
3771
3772 /*
3773 * Evaluate arguments to aggregate/combine function.
3774 */
3775 argno = 0;
3776 if (isCombine)
3777 {
3778 /*
3779 * Combining two aggregate transition values. Instead of directly
3780 * coming from a tuple the input is a, potentially deserialized,
3781 * transition value.
3782 */
3784
3785 Assert(pertrans->numSortCols == 0);
3786 Assert(list_length(pertrans->aggref->args) == 1);
3787
3788 strictargs = trans_fcinfo->args + 1;
3789 source_tle = (TargetEntry *) linitial(pertrans->aggref->args);
3790
3791 /*
3792 * deserialfn_oid will be set if we must deserialize the input
3793 * state before calling the combine function.
3794 */
3795 if (!OidIsValid(pertrans->deserialfn_oid))
3796 {
3797 /*
3798 * Start from 1, since the 0th arg will be the transition
3799 * value
3800 */
3802 &trans_fcinfo->args[argno + 1].value,
3803 &trans_fcinfo->args[argno + 1].isnull);
3804 }
3805 else
3806 {
3808
3809 /* evaluate argument */
3811 &ds_fcinfo->args[0].value,
3812 &ds_fcinfo->args[0].isnull);
3813
3814 /* Dummy second argument for type-safety reasons */
3815 ds_fcinfo->args[1].value = PointerGetDatum(NULL);
3816 ds_fcinfo->args[1].isnull = false;
3817
3818 /*
3819 * Don't call a strict deserialization function with NULL
3820 * input
3821 */
3822 if (pertrans->deserialfn.fn_strict)
3824 else
3826
3827 scratch.d.agg_deserialize.fcinfo_data = ds_fcinfo;
3828 scratch.d.agg_deserialize.jumpnull = -1; /* adjust later */
3829 scratch.resvalue = &trans_fcinfo->args[argno + 1].value;
3830 scratch.resnull = &trans_fcinfo->args[argno + 1].isnull;
3831
3833 /* don't add an adjustment unless the function is strict */
3834 if (pertrans->deserialfn.fn_strict)
3836 state->steps_len - 1);
3837
3838 /* restore normal settings of scratch fields */
3839 scratch.resvalue = &state->resvalue;
3840 scratch.resnull = &state->resnull;
3841 }
3842 argno++;
3843
3844 Assert(pertrans->numInputs == argno);
3845 }
3846 else if (!pertrans->aggsortrequired)
3847 {
3848 ListCell *arg;
3849
3850 /*
3851 * Normal transition function without ORDER BY / DISTINCT or with
3852 * ORDER BY / DISTINCT but the planner has given us pre-sorted
3853 * input.
3854 */
3855 strictargs = trans_fcinfo->args + 1;
3856
3857 foreach(arg, pertrans->aggref->args)
3858 {
3860
3861 /*
3862 * Don't initialize args for any ORDER BY clause that might
3863 * exist in a presorted aggregate.
3864 */
3865 if (argno == pertrans->numTransInputs)
3866 break;
3867
3868 /*
3869 * Start from 1, since the 0th arg will be the transition
3870 * value
3871 */
3873 &trans_fcinfo->args[argno + 1].value,
3874 &trans_fcinfo->args[argno + 1].isnull);
3875 argno++;
3876 }
3877 Assert(pertrans->numTransInputs == argno);
3878 }
3879 else if (pertrans->numInputs == 1)
3880 {
3881 /*
3882 * Non-presorted DISTINCT and/or ORDER BY case, with a single
3883 * column sorted on.
3884 */
3886 (TargetEntry *) linitial(pertrans->aggref->args);
3887
3888 Assert(list_length(pertrans->aggref->args) == 1);
3889
3891 &state->resvalue,
3892 &state->resnull);
3893 strictnulls = &state->resnull;
3894 argno++;
3895
3896 Assert(pertrans->numInputs == argno);
3897 }
3898 else
3899 {
3900 /*
3901 * Non-presorted DISTINCT and/or ORDER BY case, with multiple
3902 * columns sorted on.
3903 */
3904 Datum *values = pertrans->sortslot->tts_values;
3905 bool *nulls = pertrans->sortslot->tts_isnull;
3906 ListCell *arg;
3907
3908 strictnulls = nulls;
3909
3910 foreach(arg, pertrans->aggref->args)
3911 {
3913
3915 &values[argno], &nulls[argno]);
3916 argno++;
3917 }
3918 Assert(pertrans->numInputs == argno);
3919 }
3920
3921 /*
3922 * For a strict transfn, nothing happens when there's a NULL input; we
3923 * just keep the prior transValue. This is true for both plain and
3924 * sorted/distinct aggregates.
3925 */
3926 if (trans_fcinfo->flinfo->fn_strict && pertrans->numTransInputs > 0)
3927 {
3928 if (strictnulls)
3930 else if (strictargs && pertrans->numTransInputs == 1)
3932 else
3934 scratch.d.agg_strict_input_check.nulls = strictnulls;
3935 scratch.d.agg_strict_input_check.args = strictargs;
3936 scratch.d.agg_strict_input_check.jumpnull = -1; /* adjust later */
3937 scratch.d.agg_strict_input_check.nargs = pertrans->numTransInputs;
3940 state->steps_len - 1);
3941 }
3942
3943 /* Handle DISTINCT aggregates which have pre-sorted input */
3944 if (pertrans->numDistinctCols > 0 && !pertrans->aggsortrequired)
3945 {
3946 if (pertrans->numDistinctCols > 1)
3948 else
3950
3951 scratch.d.agg_presorted_distinctcheck.pertrans = pertrans;
3952 scratch.d.agg_presorted_distinctcheck.jumpdistinct = -1; /* adjust later */
3955 state->steps_len - 1);
3956 }
3957
3958 /*
3959 * Call transition function (once for each concurrently evaluated
3960 * grouping set). Do so for both sort and hash based computations, as
3961 * applicable.
3962 */
3963 if (doSort)
3964 {
3965 int processGroupingSets = Max(phase->numsets, 1);
3966 int setoff = 0;
3967
3968 for (int setno = 0; setno < processGroupingSets; setno++)
3969 {
3971 pertrans, transno, setno, setoff, false,
3972 nullcheck);
3973 setoff++;
3974 }
3975 }
3976
3977 if (doHash)
3978 {
3979 int numHashes = aggstate->num_hashes;
3980 int setoff;
3981
3982 /* in MIXED mode, there'll be preceding transition values */
3983 if (aggstate->aggstrategy != AGG_HASHED)
3984 setoff = aggstate->maxsets;
3985 else
3986 setoff = 0;
3987
3988 for (int setno = 0; setno < numHashes; setno++)
3989 {
3991 pertrans, transno, setno, setoff, true,
3992 nullcheck);
3993 setoff++;
3994 }
3995 }
3996
3997 /* adjust early bail out jump target(s) */
3998 foreach(bail, adjust_bailout)
3999 {
4000 ExprEvalStep *as = &state->steps[lfirst_int(bail)];
4001
4002 if (as->opcode == EEOP_JUMP_IF_NOT_TRUE)
4003 {
4004 Assert(as->d.jump.jumpdone == -1);
4005 as->d.jump.jumpdone = state->steps_len;
4006 }
4007 else if (as->opcode == EEOP_AGG_STRICT_INPUT_CHECK_ARGS ||
4010 {
4011 Assert(as->d.agg_strict_input_check.jumpnull == -1);
4012 as->d.agg_strict_input_check.jumpnull = state->steps_len;
4013 }
4014 else if (as->opcode == EEOP_AGG_STRICT_DESERIALIZE)
4015 {
4016 Assert(as->d.agg_deserialize.jumpnull == -1);
4017 as->d.agg_deserialize.jumpnull = state->steps_len;
4018 }
4019 else if (as->opcode == EEOP_AGG_PRESORTED_DISTINCT_SINGLE ||
4021 {
4022 Assert(as->d.agg_presorted_distinctcheck.jumpdistinct == -1);
4023 as->d.agg_presorted_distinctcheck.jumpdistinct = state->steps_len;
4024 }
4025 else
4026 Assert(false);
4027 }
4028 }
4029
4030 scratch.resvalue = NULL;
4031 scratch.resnull = NULL;
4034
4036
4037 return state;
4038}
static Datum values[MAXATTR]
Definition bootstrap.c:188
#define Max(x, y)
Definition c.h:1087
#define Assert(condition)
Definition c.h:945
#define OidIsValid(objectId)
Definition c.h:860
Datum arg
Definition elog.c:1322
static void ExecPushExprSetupSteps(ExprState *state, ExprSetupInfo *info)
Definition execExpr.c:2925
static void ExecInitExprRec(Expr *node, ExprState *state, Datum *resv, bool *resnull)
Definition execExpr.c:952
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:4046
void ExprEvalPushStep(ExprState *es, const ExprEvalStep *s)
Definition execExpr.c:2704
static bool expr_setup_walker(Node *node, ExprSetupInfo *info)
Definition execExpr.c:3011
static void ExecReadyExpr(ExprState *state)
Definition execExpr.c:935
@ EEOP_AGG_STRICT_DESERIALIZE
Definition execExpr.h:278
@ EEOP_AGG_PRESORTED_DISTINCT_MULTI
Definition execExpr.h:291
@ EEOP_AGG_STRICT_INPUT_CHECK_NULLS
Definition execExpr.h:282
@ EEOP_AGG_STRICT_INPUT_CHECK_ARGS_1
Definition execExpr.h:281
@ EEOP_AGG_STRICT_INPUT_CHECK_ARGS
Definition execExpr.h:280
@ EEOP_AGG_DESERIALIZE
Definition execExpr.h:279
@ EEOP_JUMP_IF_NOT_TRUE
Definition execExpr.h:156
@ EEOP_AGG_PRESORTED_DISTINCT_SINGLE
Definition execExpr.h:290
@ EEOP_DONE_NO_RETURN
Definition execExpr.h:72
List * lappend_int(List *list, int datum)
Definition list.c:357
#define DO_AGGSPLIT_COMBINE(as)
Definition nodes.h:395
@ AGG_HASHED
Definition nodes.h:366
#define makeNode(_type_)
Definition nodes.h:161
#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:167
static Datum PointerGetDatum(const void *X)
Definition postgres.h:342
uint64_t Datum
Definition postgres.h:70
static int fb(int x)
TupleTableSlot * sortslot
Definition nodeAgg.h:141
FmgrInfo deserialfn
Definition nodeAgg.h:92
FunctionCallInfo deserialfn_fcinfo
Definition nodeAgg.h:175
FunctionCallInfo transfn_fcinfo
Definition nodeAgg.h:170
List * aggdistinct
Definition primnodes.h:494
List * aggdirectargs
Definition primnodes.h:485
List * args
Definition primnodes.h:488
Expr * aggfilter
Definition primnodes.h:497
List * aggorder
Definition primnodes.h:491
bool fn_strict
Definition fmgr.h:61
Definition pg_list.h:54
Definition nodes.h:135
bool * tts_isnull
Definition tuptable.h:133
Datum * tts_values
Definition tuptable.h:131

References AGG_HASHED, Aggref::aggdirectargs, Aggref::aggdistinct, Aggref::aggfilter, Aggref::aggorder, AggStatePerTransData::aggref, AggStatePerTransData::aggsortrequired, arg, Aggref::args, Assert, bail, 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_ARGS_1, EEOP_AGG_STRICT_INPUT_CHECK_NULLS, EEOP_DONE_NO_RETURN, EEOP_JUMP_IF_NOT_TRUE, ExecBuildAggTransCall(), ExecInitExprRec(), ExecPushExprSetupSteps(), ExecReadyExpr(), expr_setup_walker(), ExprEvalPushStep(), fb(), FmgrInfo::fn_strict, lappend_int(), lfirst, lfirst_int, linitial, list_length(), makeNode, Max, NIL, AggStatePerTransData::numDistinctCols, AggStatePerTransData::numInputs, AggStatePerPhaseData::numsets, AggStatePerTransData::numSortCols, AggStatePerTransData::numTransInputs, OidIsValid, PointerGetDatum(), AggStatePerTransData::sortslot, AggStatePerTransData::transfn_fcinfo, TupleTableSlot::tts_isnull, TupleTableSlot::tts_values, 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 4046 of file execExpr.c.

4051{
4052 ExprContext *aggcontext;
4053 int adjust_jumpnull = -1;
4054
4055 if (ishash)
4056 aggcontext = aggstate->hashcontext;
4057 else
4058 aggcontext = aggstate->aggcontexts[setno];
4059
4060 /* add check for NULL pointer? */
4061 if (nullcheck)
4062 {
4064 scratch->d.agg_plain_pergroup_nullcheck.setoff = setoff;
4065 /* adjust later */
4066 scratch->d.agg_plain_pergroup_nullcheck.jumpnull = -1;
4068 adjust_jumpnull = state->steps_len - 1;
4069 }
4070
4071 /*
4072 * Determine appropriate transition implementation.
4073 *
4074 * For non-ordered aggregates and ORDER BY / DISTINCT aggregates with
4075 * presorted input:
4076 *
4077 * If the initial value for the transition state doesn't exist in the
4078 * pg_aggregate table then we will let the first non-NULL value returned
4079 * from the outer procNode become the initial value. (This is useful for
4080 * aggregates like max() and min().) The noTransValue flag signals that we
4081 * need to do so. If true, generate a
4082 * EEOP_AGG_INIT_STRICT_PLAIN_TRANS{,_BYVAL} step. This step also needs to
4083 * do the work described next:
4084 *
4085 * If the function is strict, but does have an initial value, choose
4086 * EEOP_AGG_STRICT_PLAIN_TRANS{,_BYVAL}, which skips the transition
4087 * function if the transition value has become NULL (because a previous
4088 * transition function returned NULL). This step also needs to do the work
4089 * described next:
4090 *
4091 * Otherwise we call EEOP_AGG_PLAIN_TRANS{,_BYVAL}, which does not have to
4092 * perform either of the above checks.
4093 *
4094 * Having steps with overlapping responsibilities is not nice, but
4095 * aggregations are very performance sensitive, making this worthwhile.
4096 *
4097 * For ordered aggregates:
4098 *
4099 * Only need to choose between the faster path for a single ordered
4100 * column, and the one between multiple columns. Checking strictness etc
4101 * is done when finalizing the aggregate. See
4102 * process_ordered_aggregate_{single, multi} and
4103 * advance_transition_function.
4104 */
4105 if (!pertrans->aggsortrequired)
4106 {
4107 if (pertrans->transtypeByVal)
4108 {
4109 if (fcinfo->flinfo->fn_strict &&
4110 pertrans->initValueIsNull)
4112 else if (fcinfo->flinfo->fn_strict)
4114 else
4116 }
4117 else
4118 {
4119 if (fcinfo->flinfo->fn_strict &&
4120 pertrans->initValueIsNull)
4122 else if (fcinfo->flinfo->fn_strict)
4124 else
4126 }
4127 }
4128 else if (pertrans->numInputs == 1)
4130 else
4132
4133 scratch->d.agg_trans.pertrans = pertrans;
4134 scratch->d.agg_trans.setno = setno;
4135 scratch->d.agg_trans.setoff = setoff;
4136 scratch->d.agg_trans.transno = transno;
4137 scratch->d.agg_trans.aggcontext = aggcontext;
4139
4140 /* fix up jumpnull */
4141 if (adjust_jumpnull != -1)
4142 {
4144
4146 Assert(as->d.agg_plain_pergroup_nullcheck.jumpnull == -1);
4147 as->d.agg_plain_pergroup_nullcheck.jumpnull = state->steps_len;
4148 }
4149}
@ EEOP_AGG_PLAIN_PERGROUP_NULLCHECK
Definition execExpr.h:283
@ EEOP_AGG_PLAIN_TRANS_BYREF
Definition execExpr.h:289
@ EEOP_AGG_PLAIN_TRANS_BYVAL
Definition execExpr.h:286
@ EEOP_AGG_ORDERED_TRANS_DATUM
Definition execExpr.h:292
@ EEOP_AGG_PLAIN_TRANS_STRICT_BYREF
Definition execExpr.h:288
@ EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL
Definition execExpr.h:284
@ EEOP_AGG_PLAIN_TRANS_STRICT_BYVAL
Definition execExpr.h:285
@ EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYREF
Definition execExpr.h:287
@ EEOP_AGG_ORDERED_TRANS_TUPLE
Definition execExpr.h:293
FmgrInfo * flinfo
Definition fmgr.h:87

References AggStatePerTransData::aggsortrequired, Assert, 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(), fb(), FunctionCallInfoBaseData::flinfo, FmgrInfo::fn_strict, AggStatePerTransData::initValueIsNull, AggStatePerTransData::numInputs, 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 4494 of file execExpr.c.

4501{
4503 ExprEvalStep scratch = {0};
4504 int maxatt = -1;
4506 ListCell *lc;
4507
4508 /*
4509 * When no columns are actually compared, the result's always true. See
4510 * special case in ExecQual().
4511 */
4512 if (numCols == 0)
4513 return NULL;
4514
4515 state->expr = NULL;
4516 state->flags = EEO_FLAG_IS_QUAL;
4517 state->parent = parent;
4518
4519 scratch.resvalue = &state->resvalue;
4520 scratch.resnull = &state->resnull;
4521
4522 /* compute max needed attribute */
4523 for (int natt = 0; natt < numCols; natt++)
4524 {
4525 int attno = keyColIdx[natt];
4526
4527 if (attno > maxatt)
4528 maxatt = attno;
4529 }
4530 Assert(maxatt >= 0);
4531
4532 /* push deform steps */
4534 scratch.d.fetch.last_var = maxatt;
4535 scratch.d.fetch.fixed = false;
4536 scratch.d.fetch.known_desc = ldesc;
4537 scratch.d.fetch.kind = lops;
4540
4542 scratch.d.fetch.last_var = maxatt;
4543 scratch.d.fetch.fixed = false;
4544 scratch.d.fetch.known_desc = rdesc;
4545 scratch.d.fetch.kind = rops;
4548
4549 /*
4550 * Start comparing at the last field (least significant sort key). That's
4551 * the most likely to be different if we are dealing with sorted input.
4552 */
4553 for (int natt = numCols; --natt >= 0;)
4554 {
4555 int attno = keyColIdx[natt];
4558 Oid foid = eqfunctions[natt];
4559 Oid collid = collations[natt];
4560 FmgrInfo *finfo;
4561 FunctionCallInfo fcinfo;
4563
4564 /* Check permission to call function */
4566 if (aclresult != ACLCHECK_OK)
4568
4570
4571 /* Set up the primary fmgr lookup information */
4572 finfo = palloc0_object(FmgrInfo);
4573 fcinfo = palloc0(SizeForFunctionCallInfo(2));
4574 fmgr_info(foid, finfo);
4575 fmgr_info_set_expr(NULL, finfo);
4576 InitFunctionCallInfoData(*fcinfo, finfo, 2,
4577 collid, NULL, NULL);
4578
4579 /* left arg */
4580 scratch.opcode = EEOP_INNER_VAR;
4581 scratch.d.var.attnum = attno - 1;
4582 scratch.d.var.vartype = latt->atttypid;
4583 scratch.d.var.varreturningtype = VAR_RETURNING_DEFAULT;
4584 scratch.resvalue = &fcinfo->args[0].value;
4585 scratch.resnull = &fcinfo->args[0].isnull;
4587
4588 /* right arg */
4589 scratch.opcode = EEOP_OUTER_VAR;
4590 scratch.d.var.attnum = attno - 1;
4591 scratch.d.var.vartype = ratt->atttypid;
4592 scratch.d.var.varreturningtype = VAR_RETURNING_DEFAULT;
4593 scratch.resvalue = &fcinfo->args[1].value;
4594 scratch.resnull = &fcinfo->args[1].isnull;
4596
4597 /* evaluate distinctness */
4598 scratch.opcode = EEOP_NOT_DISTINCT;
4599 scratch.d.func.finfo = finfo;
4600 scratch.d.func.fcinfo_data = fcinfo;
4601 scratch.d.func.fn_addr = finfo->fn_addr;
4602 scratch.d.func.nargs = 2;
4603 scratch.resvalue = &state->resvalue;
4604 scratch.resnull = &state->resnull;
4606
4607 /* then emit EEOP_QUAL to detect if result is false (or null) */
4608 scratch.opcode = EEOP_QUAL;
4609 scratch.d.qualexpr.jumpdone = -1;
4610 scratch.resvalue = &state->resvalue;
4611 scratch.resnull = &state->resnull;
4614 state->steps_len - 1);
4615 }
4616
4617 /* adjust jump targets */
4618 foreach(lc, adjust_jumps)
4619 {
4620 ExprEvalStep *as = &state->steps[lfirst_int(lc)];
4621
4622 Assert(as->opcode == EEOP_QUAL);
4623 Assert(as->d.qualexpr.jumpdone == -1);
4624 as->d.qualexpr.jumpdone = state->steps_len;
4625 }
4626
4627 scratch.resvalue = NULL;
4628 scratch.resnull = NULL;
4629 scratch.opcode = EEOP_DONE_RETURN;
4631
4633
4634 return state;
4635}
AclResult
Definition acl.h:183
@ ACLCHECK_OK
Definition acl.h:184
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition aclchk.c:2672
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition aclchk.c:3879
Oid collid
static bool ExecComputeSlotInfo(ExprState *state, ExprEvalStep *op)
Definition execExpr.c:3090
@ EEOP_NOT_DISTINCT
Definition execExpr.h:190
@ EEOP_DONE_RETURN
Definition execExpr.h:69
@ EEOP_INNER_VAR
Definition execExpr.h:82
@ EEOP_QUAL
Definition execExpr.h:148
@ EEOP_INNER_FETCHSOME
Definition execExpr.h:75
@ EEOP_OUTER_FETCHSOME
Definition execExpr.h:76
@ EEOP_OUTER_VAR
Definition execExpr.h:83
#define EEO_FLAG_IS_QUAL
Definition execnodes.h:85
#define palloc0_object(type)
Definition fe_memutils.h:75
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition fmgr.c:129
#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:1828
void * palloc0(Size size)
Definition mcxt.c:1417
Oid GetUserId(void)
Definition miscinit.c:470
#define InvokeFunctionExecuteHook(objectId)
@ OBJECT_FUNCTION
#define ACL_EXECUTE
Definition parsenodes.h:83
FormData_pg_attribute * Form_pg_attribute
unsigned int Oid
@ VAR_RETURNING_DEFAULT
Definition primnodes.h:257
PGFunction fn_addr
Definition fmgr.h:58
NullableDatum args[FLEXIBLE_ARRAY_MEMBER]
Definition fmgr.h:95
Datum value
Definition postgres.h:87
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition tupdesc.h:178

References ACL_EXECUTE, aclcheck_error(), ACLCHECK_OK, FunctionCallInfoBaseData::args, Assert, collid, EEO_FLAG_IS_QUAL, EEOP_DONE_RETURN, EEOP_INNER_FETCHSOME, EEOP_INNER_VAR, EEOP_NOT_DISTINCT, EEOP_OUTER_FETCHSOME, EEOP_OUTER_VAR, EEOP_QUAL, ExecComputeSlotInfo(), ExecReadyExpr(), ExprEvalPushStep(), fb(), fmgr_info(), fmgr_info_set_expr, FmgrInfo::fn_addr, get_func_name(), GetUserId(), InitFunctionCallInfoData, InvokeFunctionExecuteHook, NullableDatum::isnull, lappend_int(), lfirst_int, makeNode, NIL, object_aclcheck(), OBJECT_FUNCTION, palloc0(), palloc0_object, SizeForFunctionCallInfo, TupleDescAttr(), NullableDatum::value, and VAR_RETURNING_DEFAULT.

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

◆ ExecBuildHash32Expr()

ExprState * ExecBuildHash32Expr ( TupleDesc  desc,
const TupleTableSlotOps ops,
const Oid hashfunc_oids,
const List collations,
const List hash_exprs,
const bool opstrict,
PlanState parent,
uint32  init_value 
)

Definition at line 4329 of file execExpr.c.

4333{
4335 ExprEvalStep scratch = {0};
4336 NullableDatum *iresult = NULL;
4338 ListCell *lc;
4339 ListCell *lc2;
4341 intptr_t opcode;
4343
4344 Assert(num_exprs == list_length(collations));
4345
4346 state->parent = parent;
4347
4348 /* Insert setup steps as needed. */
4350
4351 /*
4352 * Make a place to store intermediate hash values between subsequent
4353 * hashing of individual expressions. We only need this if there is more
4354 * than one expression to hash or an initial value plus one expression.
4355 */
4356 if ((int64) num_exprs + (init_value != 0) > 1)
4357 iresult = palloc_object(NullableDatum);
4358
4359 if (init_value == 0)
4360 {
4361 /*
4362 * No initial value, so we can assign the result of the hash function
4363 * for the first hash_expr without having to concern ourselves with
4364 * combining the result with any initial value.
4365 */
4367 opcode = EEOP_HASHDATUM_FIRST;
4368 }
4369 else
4370 {
4371 /*
4372 * Set up operation to set the initial value. Normally we store this
4373 * in the intermediate hash value location, but if there are no exprs
4374 * to hash, store it in the ExprState's result field.
4375 */
4377 scratch.d.hashdatum_initvalue.init_value = UInt32GetDatum(init_value);
4378 scratch.resvalue = num_exprs > 0 ? &iresult->value : &state->resvalue;
4379 scratch.resnull = num_exprs > 0 ? &iresult->isnull : &state->resnull;
4380
4382
4383 /*
4384 * When using an initial value use the NEXT32/NEXT32_STRICT ops as the
4385 * FIRST/FIRST_STRICT ops would overwrite the stored initial value.
4386 */
4388 opcode = EEOP_HASHDATUM_NEXT32;
4389 }
4390
4391 forboth(lc, hash_exprs, lc2, collations)
4392 {
4393 Expr *expr = (Expr *) lfirst(lc);
4394 FmgrInfo *finfo;
4395 FunctionCallInfo fcinfo;
4396 int i = foreach_current_index(lc);
4397 Oid funcid;
4398 Oid inputcollid = lfirst_oid(lc2);
4399
4400 funcid = hashfunc_oids[i];
4401
4402 /* Allocate hash function lookup data. */
4403 finfo = palloc0_object(FmgrInfo);
4404 fcinfo = palloc0(SizeForFunctionCallInfo(1));
4405
4406 fmgr_info(funcid, finfo);
4407
4408 /*
4409 * Build the steps to evaluate the hash function's argument, placing
4410 * the value in the 0th argument of the hash func.
4411 */
4412 ExecInitExprRec(expr,
4413 state,
4414 &fcinfo->args[0].value,
4415 &fcinfo->args[0].isnull);
4416
4417 if (i == num_exprs - 1)
4418 {
4419 /* the result for hashing the final expr is stored in the state */
4420 scratch.resvalue = &state->resvalue;
4421 scratch.resnull = &state->resnull;
4422 }
4423 else
4424 {
4425 Assert(iresult != NULL);
4426
4427 /* intermediate values are stored in an intermediate result */
4428 scratch.resvalue = &iresult->value;
4429 scratch.resnull = &iresult->isnull;
4430 }
4431
4432 /*
4433 * NEXT32 opcodes need to look at the intermediate result. We might
4434 * as well just set this for all ops. FIRSTs won't look at it.
4435 */
4436 scratch.d.hashdatum.iresult = iresult;
4437
4438 /* Initialize function call parameter structure too */
4439 InitFunctionCallInfoData(*fcinfo, finfo, 1, inputcollid, NULL, NULL);
4440
4441 scratch.d.hashdatum.finfo = finfo;
4442 scratch.d.hashdatum.fcinfo_data = fcinfo;
4443 scratch.d.hashdatum.fn_addr = finfo->fn_addr;
4444
4445 scratch.opcode = opstrict[i] ? strict_opcode : opcode;
4446 scratch.d.hashdatum.jumpdone = -1;
4447
4449 adjust_jumps = lappend_int(adjust_jumps, state->steps_len - 1);
4450
4451 /*
4452 * For subsequent keys we must combine the hash value with the
4453 * previous hashes.
4454 */
4456 opcode = EEOP_HASHDATUM_NEXT32;
4457 }
4458
4459 /* adjust jump targets */
4460 foreach(lc, adjust_jumps)
4461 {
4462 ExprEvalStep *as = &state->steps[lfirst_int(lc)];
4463
4464 Assert(as->opcode == EEOP_HASHDATUM_FIRST ||
4465 as->opcode == EEOP_HASHDATUM_FIRST_STRICT ||
4466 as->opcode == EEOP_HASHDATUM_NEXT32 ||
4467 as->opcode == EEOP_HASHDATUM_NEXT32_STRICT);
4468 Assert(as->d.hashdatum.jumpdone == -1);
4469 as->d.hashdatum.jumpdone = state->steps_len;
4470 }
4471
4472 scratch.resvalue = NULL;
4473 scratch.resnull = NULL;
4474 scratch.opcode = EEOP_DONE_RETURN;
4476
4478
4479 return state;
4480}
int64_t int64
Definition c.h:615
static void ExecCreateExprSetupSteps(ExprState *state, Node *node)
Definition execExpr.c:2909
@ EEOP_HASHDATUM_NEXT32_STRICT
Definition execExpr.h:259
@ EEOP_HASHDATUM_FIRST_STRICT
Definition execExpr.h:257
@ EEOP_HASHDATUM_NEXT32
Definition execExpr.h:258
@ EEOP_HASHDATUM_FIRST
Definition execExpr.h:256
@ EEOP_HASHDATUM_SET_INITVAL
Definition execExpr.h:255
#define palloc_object(type)
Definition fe_memutils.h:74
int i
Definition isn.c:77
#define forboth(cell1, list1, cell2, list2)
Definition pg_list.h:518
#define foreach_current_index(var_or_cell)
Definition pg_list.h:403
#define lfirst_oid(lc)
Definition pg_list.h:174
static Datum UInt32GetDatum(uint32 X)
Definition postgres.h:232

References FunctionCallInfoBaseData::args, Assert, EEOP_DONE_RETURN, EEOP_HASHDATUM_FIRST, EEOP_HASHDATUM_FIRST_STRICT, EEOP_HASHDATUM_NEXT32, EEOP_HASHDATUM_NEXT32_STRICT, EEOP_HASHDATUM_SET_INITVAL, ExecCreateExprSetupSteps(), ExecInitExprRec(), ExecReadyExpr(), ExprEvalPushStep(), fb(), fmgr_info(), FmgrInfo::fn_addr, forboth, foreach_current_index, i, InitFunctionCallInfoData, NullableDatum::isnull, lappend_int(), lfirst, lfirst_int, lfirst_oid, list_length(), makeNode, NIL, palloc0(), palloc0_object, palloc_object, SizeForFunctionCallInfo, UInt32GetDatum(), and NullableDatum::value.

Referenced by ExecInitHashJoin().

◆ ExecBuildHash32FromAttrs()

ExprState * ExecBuildHash32FromAttrs ( TupleDesc  desc,
const TupleTableSlotOps ops,
FmgrInfo hashfunctions,
Oid collations,
int  numCols,
AttrNumber keyColIdx,
PlanState parent,
uint32  init_value 
)

Definition at line 4168 of file execExpr.c.

4172{
4174 ExprEvalStep scratch = {0};
4175 NullableDatum *iresult = NULL;
4176 intptr_t opcode;
4178
4179 Assert(numCols >= 0);
4180
4181 state->parent = parent;
4182
4183 /*
4184 * Make a place to store intermediate hash values between subsequent
4185 * hashing of individual columns. We only need this if there is more than
4186 * one column to hash or an initial value plus one column.
4187 */
4188 if ((int64) numCols + (init_value != 0) > 1)
4189 iresult = palloc_object(NullableDatum);
4190
4191 /* find the highest attnum so we deform the tuple to that point */
4192 for (int i = 0; i < numCols; i++)
4193 last_attnum = Max(last_attnum, keyColIdx[i]);
4194
4196 scratch.d.fetch.last_var = last_attnum;
4197 scratch.d.fetch.fixed = false;
4198 scratch.d.fetch.kind = ops;
4199 scratch.d.fetch.known_desc = desc;
4202
4203 if (init_value == 0)
4204 {
4205 /*
4206 * No initial value, so we can assign the result of the hash function
4207 * for the first attribute without having to concern ourselves with
4208 * combining the result with any initial value.
4209 */
4210 opcode = EEOP_HASHDATUM_FIRST;
4211 }
4212 else
4213 {
4214 /*
4215 * Set up operation to set the initial value. Normally we store this
4216 * in the intermediate hash value location, but if there are no
4217 * columns to hash, store it in the ExprState's result field.
4218 */
4220 scratch.d.hashdatum_initvalue.init_value = UInt32GetDatum(init_value);
4221 scratch.resvalue = numCols > 0 ? &iresult->value : &state->resvalue;
4222 scratch.resnull = numCols > 0 ? &iresult->isnull : &state->resnull;
4223
4225
4226 /*
4227 * When using an initial value use the NEXT32 ops as the FIRST ops
4228 * would overwrite the stored initial value.
4229 */
4230 opcode = EEOP_HASHDATUM_NEXT32;
4231 }
4232
4233 for (int i = 0; i < numCols; i++)
4234 {
4235 FmgrInfo *finfo;
4236 FunctionCallInfo fcinfo;
4237 Oid inputcollid = collations[i];
4238 AttrNumber attnum = keyColIdx[i] - 1;
4239
4240 finfo = &hashfunctions[i];
4241 fcinfo = palloc0(SizeForFunctionCallInfo(1));
4242
4243 /* Initialize function call parameter structure too */
4244 InitFunctionCallInfoData(*fcinfo, finfo, 1, inputcollid, NULL, NULL);
4245
4246 /*
4247 * Fetch inner Var for this attnum and store it in the 1st arg of the
4248 * hash func.
4249 */
4250 scratch.opcode = EEOP_INNER_VAR;
4251 scratch.resvalue = &fcinfo->args[0].value;
4252 scratch.resnull = &fcinfo->args[0].isnull;
4253 scratch.d.var.attnum = attnum;
4254 scratch.d.var.vartype = TupleDescAttr(desc, attnum)->atttypid;
4255 scratch.d.var.varreturningtype = VAR_RETURNING_DEFAULT;
4256
4258
4259 /* Call the hash function */
4260 scratch.opcode = opcode;
4261
4262 if (i == numCols - 1)
4263 {
4264 /*
4265 * The result for hashing the final column is stored in the
4266 * ExprState.
4267 */
4268 scratch.resvalue = &state->resvalue;
4269 scratch.resnull = &state->resnull;
4270 }
4271 else
4272 {
4273 Assert(iresult != NULL);
4274
4275 /* intermediate values are stored in an intermediate result */
4276 scratch.resvalue = &iresult->value;
4277 scratch.resnull = &iresult->isnull;
4278 }
4279
4280 /*
4281 * NEXT32 opcodes need to look at the intermediate result. We might
4282 * as well just set this for all ops. FIRSTs won't look at it.
4283 */
4284 scratch.d.hashdatum.iresult = iresult;
4285
4286 scratch.d.hashdatum.finfo = finfo;
4287 scratch.d.hashdatum.fcinfo_data = fcinfo;
4288 scratch.d.hashdatum.fn_addr = finfo->fn_addr;
4289 scratch.d.hashdatum.jumpdone = -1;
4290
4292
4293 /* subsequent attnums must be combined with the previous */
4294 opcode = EEOP_HASHDATUM_NEXT32;
4295 }
4296
4297 scratch.resvalue = NULL;
4298 scratch.resnull = NULL;
4299 scratch.opcode = EEOP_DONE_RETURN;
4301
4303
4304 return state;
4305}
int16 AttrNumber
Definition attnum.h:21
int16 attnum

References FunctionCallInfoBaseData::args, Assert, attnum, EEOP_DONE_RETURN, EEOP_HASHDATUM_FIRST, EEOP_HASHDATUM_NEXT32, EEOP_HASHDATUM_SET_INITVAL, EEOP_INNER_FETCHSOME, EEOP_INNER_VAR, ExecComputeSlotInfo(), ExecReadyExpr(), ExprEvalPushStep(), fb(), FmgrInfo::fn_addr, i, InitFunctionCallInfoData, NullableDatum::isnull, makeNode, Max, palloc0(), palloc_object, SizeForFunctionCallInfo, TupleDescAttr(), UInt32GetDatum(), NullableDatum::value, and VAR_RETURNING_DEFAULT.

Referenced by BuildTupleHashTable(), and ExecInitSubPlan().

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

4660{
4662 ExprEvalStep scratch = {0};
4663 int maxatt = list_length(param_exprs);
4665 ListCell *lc;
4666
4667 state->expr = NULL;
4668 state->flags = EEO_FLAG_IS_QUAL;
4669 state->parent = parent;
4670
4671 scratch.resvalue = &state->resvalue;
4672 scratch.resnull = &state->resnull;
4673
4674 /* push deform steps */
4676 scratch.d.fetch.last_var = maxatt;
4677 scratch.d.fetch.fixed = false;
4678 scratch.d.fetch.known_desc = desc;
4679 scratch.d.fetch.kind = lops;
4682
4684 scratch.d.fetch.last_var = maxatt;
4685 scratch.d.fetch.fixed = false;
4686 scratch.d.fetch.known_desc = desc;
4687 scratch.d.fetch.kind = rops;
4690
4691 for (int attno = 0; attno < maxatt; attno++)
4692 {
4693 Form_pg_attribute att = TupleDescAttr(desc, attno);
4694 Oid foid = eqfunctions[attno];
4695 Oid collid = collations[attno];
4696 FmgrInfo *finfo;
4697 FunctionCallInfo fcinfo;
4699
4700 /* Check permission to call function */
4702 if (aclresult != ACLCHECK_OK)
4704
4706
4707 /* Set up the primary fmgr lookup information */
4708 finfo = palloc0_object(FmgrInfo);
4709 fcinfo = palloc0(SizeForFunctionCallInfo(2));
4710 fmgr_info(foid, finfo);
4711 fmgr_info_set_expr(NULL, finfo);
4712 InitFunctionCallInfoData(*fcinfo, finfo, 2,
4713 collid, NULL, NULL);
4714
4715 /* left arg */
4716 scratch.opcode = EEOP_INNER_VAR;
4717 scratch.d.var.attnum = attno;
4718 scratch.d.var.vartype = att->atttypid;
4719 scratch.d.var.varreturningtype = VAR_RETURNING_DEFAULT;
4720 scratch.resvalue = &fcinfo->args[0].value;
4721 scratch.resnull = &fcinfo->args[0].isnull;
4723
4724 /* right arg */
4725 scratch.opcode = EEOP_OUTER_VAR;
4726 scratch.d.var.attnum = attno;
4727 scratch.d.var.vartype = att->atttypid;
4728 scratch.d.var.varreturningtype = VAR_RETURNING_DEFAULT;
4729 scratch.resvalue = &fcinfo->args[1].value;
4730 scratch.resnull = &fcinfo->args[1].isnull;
4732
4733 /* evaluate distinctness */
4734 scratch.opcode = EEOP_NOT_DISTINCT;
4735 scratch.d.func.finfo = finfo;
4736 scratch.d.func.fcinfo_data = fcinfo;
4737 scratch.d.func.fn_addr = finfo->fn_addr;
4738 scratch.d.func.nargs = 2;
4739 scratch.resvalue = &state->resvalue;
4740 scratch.resnull = &state->resnull;
4742
4743 /* then emit EEOP_QUAL to detect if result is false (or null) */
4744 scratch.opcode = EEOP_QUAL;
4745 scratch.d.qualexpr.jumpdone = -1;
4746 scratch.resvalue = &state->resvalue;
4747 scratch.resnull = &state->resnull;
4750 state->steps_len - 1);
4751 }
4752
4753 /* adjust jump targets */
4754 foreach(lc, adjust_jumps)
4755 {
4756 ExprEvalStep *as = &state->steps[lfirst_int(lc)];
4757
4758 Assert(as->opcode == EEOP_QUAL);
4759 Assert(as->d.qualexpr.jumpdone == -1);
4760 as->d.qualexpr.jumpdone = state->steps_len;
4761 }
4762
4763 scratch.resvalue = NULL;
4764 scratch.resnull = NULL;
4765 scratch.opcode = EEOP_DONE_RETURN;
4767
4769
4770 return state;
4771}

References ACL_EXECUTE, aclcheck_error(), ACLCHECK_OK, FunctionCallInfoBaseData::args, Assert, collid, EEO_FLAG_IS_QUAL, EEOP_DONE_RETURN, EEOP_INNER_FETCHSOME, EEOP_INNER_VAR, EEOP_NOT_DISTINCT, EEOP_OUTER_FETCHSOME, EEOP_OUTER_VAR, EEOP_QUAL, ExecComputeSlotInfo(), ExecReadyExpr(), ExprEvalPushStep(), fb(), fmgr_info(), fmgr_info_set_expr, FmgrInfo::fn_addr, get_func_name(), GetUserId(), InitFunctionCallInfoData, InvokeFunctionExecuteHook, NullableDatum::isnull, lappend_int(), lfirst_int, list_length(), makeNode, NIL, object_aclcheck(), OBJECT_FUNCTION, palloc0(), palloc0_object, SizeForFunctionCallInfo, TupleDescAttr(), NullableDatum::value, and VAR_RETURNING_DEFAULT.

Referenced by ExecInitMemoize().

◆ ExecBuildProjectionInfo()

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

Definition at line 391 of file execExpr.c.

396{
399 ExprEvalStep scratch = {0};
400 ListCell *lc;
401
402 projInfo->pi_exprContext = econtext;
403 /* We embed ExprState into ProjectionInfo instead of doing extra palloc */
404 projInfo->pi_state.type = T_ExprState;
405 state = &projInfo->pi_state;
406 state->expr = (Expr *) targetList;
407 state->parent = parent;
408 state->ext_params = NULL;
409
410 state->resultslot = slot;
411
412 /* Insert setup steps as needed */
413 ExecCreateExprSetupSteps(state, (Node *) targetList);
414
415 /* Now compile each tlist column */
416 foreach(lc, targetList)
417 {
419 Var *variable = NULL;
420 AttrNumber attnum = 0;
421 bool isSafeVar = false;
422
423 /*
424 * If tlist expression is a safe non-system Var, use the fast-path
425 * ASSIGN_*_VAR opcodes. "Safe" means that we don't need to apply
426 * CheckVarSlotCompatibility() during plan startup. If a source slot
427 * was provided, we make the equivalent tests here; if a slot was not
428 * provided, we assume that no check is needed because we're dealing
429 * with a non-relation-scan-level expression.
430 */
431 if (tle->expr != NULL &&
432 IsA(tle->expr, Var) &&
433 ((Var *) tle->expr)->varattno > 0)
434 {
435 /* Non-system Var, but how safe is it? */
436 variable = (Var *) tle->expr;
437 attnum = variable->varattno;
438
439 if (inputDesc == NULL)
440 isSafeVar = true; /* can't check, just assume OK */
441 else if (attnum <= inputDesc->natts)
442 {
444
445 /*
446 * If user attribute is dropped or has a type mismatch, don't
447 * use ASSIGN_*_VAR. Instead let the normal expression
448 * machinery handle it (which'll possibly error out).
449 */
450 if (!attr->attisdropped && variable->vartype == attr->atttypid)
451 {
452 isSafeVar = true;
453 }
454 }
455 }
456
457 if (isSafeVar)
458 {
459 /* Fast-path: just generate an EEOP_ASSIGN_*_VAR step */
460 switch (variable->varno)
461 {
462 case INNER_VAR:
463 /* get the tuple from the inner node */
465 break;
466
467 case OUTER_VAR:
468 /* get the tuple from the outer node */
470 break;
471
472 /* INDEX_VAR is handled by default case */
473
474 default:
475
476 /*
477 * Get the tuple from the relation being scanned, or the
478 * old/new tuple slot, if old/new values were requested.
479 */
480 switch (variable->varreturningtype)
481 {
484 break;
487 state->flags |= EEO_FLAG_HAS_OLD;
488 break;
491 state->flags |= EEO_FLAG_HAS_NEW;
492 break;
493 }
494 break;
495 }
496
497 scratch.d.assign_var.attnum = attnum - 1;
498 scratch.d.assign_var.resultnum = tle->resno - 1;
500 }
501 else
502 {
503 /*
504 * Otherwise, compile the column expression normally.
505 *
506 * We can't tell the expression to evaluate directly into the
507 * result slot, as the result slot (and the exprstate for that
508 * matter) can change between executions. We instead evaluate
509 * into the ExprState's resvalue/resnull and then move.
510 */
512 &state->resvalue, &state->resnull);
513
514 /*
515 * Column might be referenced multiple times in upper nodes, so
516 * force value to R/O - but only if it could be an expanded datum.
517 */
518 if (get_typlen(exprType((Node *) tle->expr)) == -1)
520 else
521 scratch.opcode = EEOP_ASSIGN_TMP;
522 scratch.d.assign_tmp.resultnum = tle->resno - 1;
524 }
525 }
526
529
531
532 return projInfo;
533}
@ EEOP_ASSIGN_TMP
Definition execExpr.h:110
@ EEOP_ASSIGN_SCAN_VAR
Definition execExpr.h:105
@ EEOP_ASSIGN_OUTER_VAR
Definition execExpr.h:104
@ EEOP_ASSIGN_OLD_VAR
Definition execExpr.h:106
@ EEOP_ASSIGN_TMP_MAKE_RO
Definition execExpr.h:112
@ EEOP_ASSIGN_INNER_VAR
Definition execExpr.h:103
@ EEOP_ASSIGN_NEW_VAR
Definition execExpr.h:107
#define EEO_FLAG_HAS_OLD
Definition execnodes.h:87
#define EEO_FLAG_HAS_NEW
Definition execnodes.h:89
int16 get_typlen(Oid typid)
Definition lsyscache.c:2417
Oid exprType(const Node *expr)
Definition nodeFuncs.c:42
#define IsA(nodeptr, _type_)
Definition nodes.h:164
#define lfirst_node(type, lc)
Definition pg_list.h:176
@ VAR_RETURNING_OLD
Definition primnodes.h:258
@ VAR_RETURNING_NEW
Definition primnodes.h:259
#define OUTER_VAR
Definition primnodes.h:244
#define INNER_VAR
Definition primnodes.h:243
NodeTag type
Definition execnodes.h:280

References attnum, EEO_FLAG_HAS_NEW, EEO_FLAG_HAS_OLD, EEOP_ASSIGN_INNER_VAR, EEOP_ASSIGN_NEW_VAR, EEOP_ASSIGN_OLD_VAR, EEOP_ASSIGN_OUTER_VAR, EEOP_ASSIGN_SCAN_VAR, EEOP_ASSIGN_TMP, EEOP_ASSIGN_TMP_MAKE_RO, EEOP_DONE_NO_RETURN, ExecCreateExprSetupSteps(), ExecInitExprRec(), ExecReadyExpr(), ExprEvalPushStep(), exprType(), fb(), get_typlen(), INNER_VAR, IsA, lfirst_node, makeNode, OUTER_VAR, TupleDescAttr(), ExprContext::type, VAR_RETURNING_DEFAULT, VAR_RETURNING_NEW, and VAR_RETURNING_OLD.

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

575{
578 int nAssignableCols;
579 bool sawJunk;
581 ExprSetupInfo deform = {0, 0, 0, 0, 0, NIL};
582 ExprEvalStep scratch = {0};
583 int outerattnum;
584 ListCell *lc,
585 *lc2;
586
587 projInfo->pi_exprContext = econtext;
588 /* We embed ExprState into ProjectionInfo instead of doing extra palloc */
589 projInfo->pi_state.type = T_ExprState;
590 state = &projInfo->pi_state;
591 if (evalTargetList)
592 state->expr = (Expr *) targetList;
593 else
594 state->expr = NULL; /* not used */
595 state->parent = parent;
596 state->ext_params = NULL;
597
598 state->resultslot = slot;
599
600 /*
601 * Examine the targetList to see how many non-junk columns there are, and
602 * to verify that the non-junk columns come before the junk ones.
603 */
604 nAssignableCols = 0;
605 sawJunk = false;
606 foreach(lc, targetList)
607 {
609
610 if (tle->resjunk)
611 sawJunk = true;
612 else
613 {
614 if (sawJunk)
615 elog(ERROR, "subplan target list is out of order");
617 }
618 }
619
620 /* We should have one targetColnos entry per non-junk column */
622 elog(ERROR, "targetColnos does not match subplan target list");
623
624 /*
625 * Build a bitmapset of the columns in targetColnos. (We could just use
626 * list_member_int() tests, but that risks O(N^2) behavior with many
627 * columns.)
628 */
630 foreach(lc, targetColnos)
631 {
633
635 }
636
637 /*
638 * We need to insert EEOP_*_FETCHSOME steps to ensure the input tuples are
639 * sufficiently deconstructed. The scan tuple must be deconstructed at
640 * least as far as the last old column we need.
641 */
642 for (int attnum = relDesc->natts; attnum > 0; attnum--)
643 {
645
646 if (attr->attisdropped)
647 continue;
649 continue;
650 deform.last_scan = attnum;
651 break;
652 }
653
654 /*
655 * If we're actually evaluating the tlist, incorporate its input
656 * requirements too; otherwise, we'll just need to fetch the appropriate
657 * number of columns of the "outer" tuple.
658 */
659 if (evalTargetList)
660 expr_setup_walker((Node *) targetList, &deform);
661 else
662 deform.last_outer = nAssignableCols;
663
665
666 /*
667 * Now generate code to evaluate the tlist's assignable expressions or
668 * fetch them from the outer tuple, incidentally validating that they'll
669 * be of the right data type. The checks above ensure that the forboth()
670 * will iterate over exactly the non-junk columns. Note that we don't
671 * bother evaluating any remaining resjunk columns.
672 */
673 outerattnum = 0;
674 forboth(lc, targetList, lc2, targetColnos)
675 {
679
680 Assert(!tle->resjunk);
681
682 /*
683 * Apply sanity checks comparable to ExecCheckPlanOutput().
684 */
688 errmsg("table row type and query-specified row type do not match"),
689 errdetail("Query has too many columns.")));
691
692 if (attr->attisdropped)
695 errmsg("table row type and query-specified row type do not match"),
696 errdetail("Query provides a value for a dropped column at ordinal position %d.",
697 targetattnum)));
698 if (exprType((Node *) tle->expr) != attr->atttypid)
701 errmsg("table row type and query-specified row type do not match"),
702 errdetail("Table has type %s at ordinal position %d, but query expects %s.",
703 format_type_be(attr->atttypid),
705 format_type_be(exprType((Node *) tle->expr)))));
706
707 /* OK, generate code to perform the assignment. */
708 if (evalTargetList)
709 {
710 /*
711 * We must evaluate the TLE's expression and assign it. We do not
712 * bother jumping through hoops for "safe" Vars like
713 * ExecBuildProjectionInfo does; this is a relatively less-used
714 * path and it doesn't seem worth expending code for that.
715 */
717 &state->resvalue, &state->resnull);
718 /* Needn't worry about read-only-ness here, either. */
719 scratch.opcode = EEOP_ASSIGN_TMP;
720 scratch.d.assign_tmp.resultnum = targetattnum - 1;
722 }
723 else
724 {
725 /* Just assign from the outer tuple. */
727 scratch.d.assign_var.attnum = outerattnum;
728 scratch.d.assign_var.resultnum = targetattnum - 1;
730 }
731 outerattnum++;
732 }
733
734 /*
735 * Now generate code to copy over any old columns that were not assigned
736 * to, and to ensure that dropped columns are set to NULL.
737 */
738 for (int attnum = 1; attnum <= relDesc->natts; attnum++)
739 {
741
742 if (attr->attisdropped)
743 {
744 /* Put a null into the ExprState's resvalue/resnull ... */
745 scratch.opcode = EEOP_CONST;
746 scratch.resvalue = &state->resvalue;
747 scratch.resnull = &state->resnull;
748 scratch.d.constval.value = (Datum) 0;
749 scratch.d.constval.isnull = true;
751 /* ... then assign it to the result slot */
752 scratch.opcode = EEOP_ASSIGN_TMP;
753 scratch.d.assign_tmp.resultnum = attnum - 1;
755 }
757 {
758 /* Certainly the right type, so needn't check */
760 scratch.d.assign_var.attnum = attnum - 1;
761 scratch.d.assign_var.resultnum = attnum - 1;
763 }
764 }
765
768
770
771 return projInfo;
772}
bool bms_is_member(int x, const Bitmapset *a)
Definition bitmapset.c:510
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition bitmapset.c:799
int errcode(int sqlerrcode)
Definition elog.c:874
int errdetail(const char *fmt,...) pg_attribute_printf(1
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:226
#define ereport(elevel,...)
Definition elog.h:150
@ EEOP_CONST
Definition execExpr.h:115
char * format_type_be(Oid type_oid)
static char * errmsg
bool attisdropped
Definition tupdesc.h:78
static CompactAttribute * TupleDescCompactAttr(TupleDesc tupdesc, int i)
Definition tupdesc.h:193

References Assert, CompactAttribute::attisdropped, attnum, bms_add_member(), bms_is_member(), EEOP_ASSIGN_OUTER_VAR, EEOP_ASSIGN_SCAN_VAR, EEOP_ASSIGN_TMP, EEOP_CONST, EEOP_DONE_NO_RETURN, elog, ereport, errcode(), errdetail(), errmsg, ERROR, ExecInitExprRec(), ExecPushExprSetupSteps(), ExecReadyExpr(), expr_setup_walker(), ExprEvalPushStep(), exprType(), fb(), forboth, format_type_be(), lfirst_int, lfirst_node, list_length(), makeNode, NIL, TupleDescAttr(), TupleDescCompactAttr(), and ExprContext::type.

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

◆ ExecCheck()

bool ExecCheck ( ExprState state,
ExprContext econtext 
)

Definition at line 905 of file execExpr.c.

906{
907 Datum ret;
908 bool isnull;
909
910 /* short-circuit (here and in ExecInitCheck) for empty restriction list */
911 if (state == NULL)
912 return true;
913
914 /* verify that expression was not compiled using ExecInitQual */
915 Assert(!(state->flags & EEO_FLAG_IS_QUAL));
916
917 ret = ExecEvalExprSwitchContext(state, econtext, &isnull);
918
919 if (isnull)
920 return true;
921
922 return DatumGetBool(ret);
923}
static Datum ExecEvalExprSwitchContext(ExprState *state, ExprContext *econtext, bool *isNull)
Definition executor.h:439
static bool DatumGetBool(Datum X)
Definition postgres.h:100

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

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

◆ ExecComputeSlotInfo()

static bool ExecComputeSlotInfo ( ExprState state,
ExprEvalStep op 
)
static

Definition at line 3090 of file execExpr.c.

3091{
3092 PlanState *parent = state->parent;
3093 TupleDesc desc = NULL;
3094 const TupleTableSlotOps *tts_ops = NULL;
3095 bool isfixed = false;
3096 ExprEvalOp opcode = op->opcode;
3097
3098 Assert(opcode == EEOP_INNER_FETCHSOME ||
3099 opcode == EEOP_OUTER_FETCHSOME ||
3100 opcode == EEOP_SCAN_FETCHSOME ||
3101 opcode == EEOP_OLD_FETCHSOME ||
3102 opcode == EEOP_NEW_FETCHSOME);
3103
3104 if (op->d.fetch.known_desc != NULL)
3105 {
3106 desc = op->d.fetch.known_desc;
3107 tts_ops = op->d.fetch.kind;
3108 isfixed = op->d.fetch.kind != NULL;
3109 }
3110 else if (!parent)
3111 {
3112 isfixed = false;
3113 }
3114 else if (opcode == EEOP_INNER_FETCHSOME)
3115 {
3116 PlanState *is = innerPlanState(parent);
3117
3118 if (parent->inneropsset && !parent->inneropsfixed)
3119 {
3120 isfixed = false;
3121 }
3122 else if (parent->inneropsset && parent->innerops)
3123 {
3124 isfixed = true;
3125 tts_ops = parent->innerops;
3126 desc = ExecGetResultType(is);
3127 }
3128 else if (is)
3129 {
3130 tts_ops = ExecGetResultSlotOps(is, &isfixed);
3131 desc = ExecGetResultType(is);
3132 }
3133 }
3134 else if (opcode == EEOP_OUTER_FETCHSOME)
3135 {
3136 PlanState *os = outerPlanState(parent);
3137
3138 if (parent->outeropsset && !parent->outeropsfixed)
3139 {
3140 isfixed = false;
3141 }
3142 else if (parent->outeropsset && parent->outerops)
3143 {
3144 isfixed = true;
3145 tts_ops = parent->outerops;
3146 desc = ExecGetResultType(os);
3147 }
3148 else if (os)
3149 {
3150 tts_ops = ExecGetResultSlotOps(os, &isfixed);
3151 desc = ExecGetResultType(os);
3152 }
3153 }
3154 else if (opcode == EEOP_SCAN_FETCHSOME ||
3155 opcode == EEOP_OLD_FETCHSOME ||
3156 opcode == EEOP_NEW_FETCHSOME)
3157 {
3158 desc = parent->scandesc;
3159
3160 if (parent->scanops)
3161 tts_ops = parent->scanops;
3162
3163 if (parent->scanopsset)
3164 isfixed = parent->scanopsfixed;
3165 }
3166
3167 if (isfixed && desc != NULL && tts_ops != NULL)
3168 {
3169 op->d.fetch.fixed = true;
3170 op->d.fetch.kind = tts_ops;
3171 op->d.fetch.known_desc = desc;
3172 }
3173 else
3174 {
3175 op->d.fetch.fixed = false;
3176 op->d.fetch.kind = NULL;
3177 op->d.fetch.known_desc = NULL;
3178 }
3179
3180 /* if the slot is known to always virtual we never need to deform */
3181 if (op->d.fetch.fixed && op->d.fetch.kind == &TTSOpsVirtual)
3182 return false;
3183
3184 return true;
3185}
ExprEvalOp
Definition execExpr.h:67
@ EEOP_NEW_FETCHSOME
Definition execExpr.h:79
@ EEOP_OLD_FETCHSOME
Definition execExpr.h:78
@ EEOP_SCAN_FETCHSOME
Definition execExpr.h:77
const TupleTableSlotOps TTSOpsVirtual
Definition execTuples.c:84
TupleDesc ExecGetResultType(PlanState *planstate)
Definition execUtils.c:500
const TupleTableSlotOps * ExecGetResultSlotOps(PlanState *planstate, bool *isfixed)
Definition execUtils.c:509
#define outerPlanState(node)
Definition execnodes.h:1273
#define innerPlanState(node)
Definition execnodes.h:1272
union ExprEvalStep::@60 d
intptr_t opcode
Definition execExpr.h:307
TupleDesc known_desc
Definition execExpr.h:329
const TupleTableSlotOps * kind
Definition execExpr.h:331
struct ExprEvalStep::@60::@61 fetch
bool inneropsset
Definition execnodes.h:1261
bool outeropsset
Definition execnodes.h:1260
const TupleTableSlotOps * outerops
Definition execnodes.h:1252
const TupleTableSlotOps * innerops
Definition execnodes.h:1253
const TupleTableSlotOps * scanops
Definition execnodes.h:1251
bool outeropsfixed
Definition execnodes.h:1256
bool scanopsset
Definition execnodes.h:1259
TupleDesc scandesc
Definition execnodes.h:1226
bool scanopsfixed
Definition execnodes.h:1255
bool inneropsfixed
Definition execnodes.h:1257

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

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

◆ ExecCreateExprSetupSteps()

static void ExecCreateExprSetupSteps ( ExprState state,
Node node 
)
static

Definition at line 2909 of file execExpr.c.

2910{
2911 ExprSetupInfo info = {0, 0, 0, 0, 0, NIL};
2912
2913 /* Prescan to find out what we need. */
2914 expr_setup_walker(node, &info);
2915
2916 /* And generate those steps. */
2918}

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

Referenced by ExecBuildHash32Expr(), ExecBuildProjectionInfo(), ExecInitExprWithContext(), ExecInitExprWithParams(), and ExecInitQual().

◆ ExecInitCheck()

ExprState * ExecInitCheck ( List qual,
PlanState parent 
)

Definition at line 336 of file execExpr.c.

337{
338 /* short-circuit (here and in ExecCheck) for empty restriction list */
339 if (qual == NIL)
340 return NULL;
341
342 Assert(IsA(qual, List));
343
344 /*
345 * Just convert the implicit-AND list to an explicit AND (if there's more
346 * than one entry), and compile normally. Unlike ExecQual, we can't
347 * short-circuit on NULL results, so the regular AND behavior is needed.
348 */
349 return ExecInitExpr(make_ands_explicit(qual), parent);
350}
ExprState * ExecInitExpr(Expr *node, PlanState *parent)
Definition execExpr.c:143
Expr * make_ands_explicit(List *andclauses)
Definition makefuncs.c:799

References Assert, ExecInitExpr(), fb(), 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 3550 of file execExpr.c.

3552{
3553 DomainConstraintRef *constraint_ref;
3554 Datum *domainval = NULL;
3555 bool *domainnull = NULL;
3556 ListCell *l;
3557
3558 scratch->d.domaincheck.resulttype = ctest->resulttype;
3559 /* we'll allocate workspace only if needed */
3560 scratch->d.domaincheck.checkvalue = NULL;
3561 scratch->d.domaincheck.checknull = NULL;
3562 scratch->d.domaincheck.escontext = state->escontext;
3563
3564 /*
3565 * Evaluate argument - it's fine to directly store it into resv/resnull,
3566 * if there's constraint failures there'll be errors, otherwise it's what
3567 * needs to be returned.
3568 */
3569 ExecInitExprRec(ctest->arg, state, resv, resnull);
3570
3571 /*
3572 * Note: if the argument is of varlena type, it could be a R/W expanded
3573 * object. We want to return the R/W pointer as the final result, but we
3574 * have to pass a R/O pointer as the value to be tested by any functions
3575 * in check expressions. We don't bother to emit a MAKE_READONLY step
3576 * unless there's actually at least one check expression, though. Until
3577 * we've tested that, domainval/domainnull are NULL.
3578 */
3579
3580 /*
3581 * Collect the constraints associated with the domain.
3582 *
3583 * Note: before PG v10 we'd recheck the set of constraints during each
3584 * evaluation of the expression. Now we bake them into the ExprState
3585 * during executor initialization. That means we don't need typcache.c to
3586 * provide compiled exprs.
3587 */
3588 constraint_ref = palloc_object(DomainConstraintRef);
3589 InitDomainConstraintRef(ctest->resulttype,
3590 constraint_ref,
3592 false);
3593
3594 /*
3595 * Compile code to check each domain constraint. NOTNULL constraints can
3596 * just be applied on the resv/resnull value, but for CHECK constraints we
3597 * need more pushups.
3598 */
3599 foreach(l, constraint_ref->constraints)
3600 {
3604
3605 scratch->d.domaincheck.constraintname = con->name;
3606
3607 switch (con->constrainttype)
3608 {
3610 scratch->opcode = EEOP_DOMAIN_NOTNULL;
3612 break;
3614 /* Allocate workspace for CHECK output if we didn't yet */
3615 if (scratch->d.domaincheck.checkvalue == NULL)
3616 {
3617 scratch->d.domaincheck.checkvalue =
3619 scratch->d.domaincheck.checknull =
3620 palloc_object(bool);
3621 }
3622
3623 /*
3624 * If first time through, determine where CoerceToDomainValue
3625 * nodes should read from.
3626 */
3627 if (domainval == NULL)
3628 {
3629 /*
3630 * Since value might be read multiple times, force to R/O
3631 * - but only if it could be an expanded datum.
3632 */
3633 if (get_typlen(ctest->resulttype) == -1)
3634 {
3635 ExprEvalStep scratch2 = {0};
3636
3637 /* Yes, so make output workspace for MAKE_READONLY */
3639 domainnull = palloc_object(bool);
3640
3641 /* Emit MAKE_READONLY */
3643 scratch2.resvalue = domainval;
3644 scratch2.resnull = domainnull;
3645 scratch2.d.make_readonly.value = resv;
3646 scratch2.d.make_readonly.isnull = resnull;
3648 }
3649 else
3650 {
3651 /* No, so it's fine to read from resv/resnull */
3652 domainval = resv;
3653 domainnull = resnull;
3654 }
3655 }
3656
3657 /*
3658 * Set up value to be returned by CoerceToDomainValue nodes.
3659 * We must save and restore innermost_domainval/null fields,
3660 * in case this node is itself within a check expression for
3661 * another domain.
3662 */
3663 save_innermost_domainval = state->innermost_domainval;
3664 save_innermost_domainnull = state->innermost_domainnull;
3665 state->innermost_domainval = domainval;
3666 state->innermost_domainnull = domainnull;
3667
3668 /* evaluate check expression value */
3670 scratch->d.domaincheck.checkvalue,
3671 scratch->d.domaincheck.checknull);
3672
3673 state->innermost_domainval = save_innermost_domainval;
3674 state->innermost_domainnull = save_innermost_domainnull;
3675
3676 /* now test result */
3677 scratch->opcode = EEOP_DOMAIN_CHECK;
3679
3680 break;
3681 default:
3682 elog(ERROR, "unrecognized constraint type: %d",
3683 (int) con->constrainttype);
3684 break;
3685 }
3686 }
3687}
@ EEOP_DOMAIN_CHECK
Definition execExpr.h:252
@ EEOP_DOMAIN_NOTNULL
Definition execExpr.h:249
@ EEOP_MAKE_READONLY
Definition execExpr.h:184
@ DOM_CONSTRAINT_CHECK
Definition execnodes.h:1062
@ DOM_CONSTRAINT_NOTNULL
Definition execnodes.h:1061
MemoryContext CurrentMemoryContext
Definition mcxt.c:160
DomainConstraintType constrainttype
Definition execnodes.h:1068
void InitDomainConstraintRef(Oid type_id, DomainConstraintRef *ref, MemoryContext refctx, bool need_exprstate)
Definition typcache.c:1404

References DomainConstraintState::check_expr, DomainConstraintRef::constraints, DomainConstraintState::constrainttype, CurrentMemoryContext, DOM_CONSTRAINT_CHECK, DOM_CONSTRAINT_NOTNULL, EEOP_DOMAIN_CHECK, EEOP_DOMAIN_NOTNULL, EEOP_MAKE_READONLY, elog, ERROR, ExecInitExprRec(), ExprEvalPushStep(), fb(), get_typlen(), InitDomainConstraintRef(), lfirst, DomainConstraintState::name, and palloc_object.

Referenced by ExecInitExprRec().

◆ ExecInitExpr()

◆ ExecInitExprList()

List * ExecInitExprList ( List nodes,
PlanState parent 
)

Definition at line 356 of file execExpr.c.

357{
358 List *result = NIL;
359 ListCell *lc;
360
361 foreach(lc, nodes)
362 {
363 Expr *e = lfirst(lc);
364
365 result = lappend(result, ExecInitExpr(e, parent));
366 }
367
368 return result;
369}
List * lappend(List *list, void *datum)
Definition list.c:339
e

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

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

◆ ExecInitExprRec()

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

Definition at line 952 of file execExpr.c.

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

References ACL_EXECUTE, aclcheck_error(), ACLCHECK_OK, WindowFuncExprState::aggfilter, WindowFunc::aggfilter, AND_EXPR, arg, FieldStore::arg, CoerceViaIO::arg, JsonConstructorExprState::arg_nulls, JsonConstructorExprState::arg_type_cache, JsonConstructorExprState::arg_types, JsonConstructorExprState::arg_values, FunctionCallInfoBaseData::args, WindowFuncExprState::args, WindowFunc::args, FuncExpr::args, OpExpr::args, ScalarArrayOpExpr::args, BoolExpr::args, RowExpr::args, XmlExpr::args, Assert, BlessTupleDesc(), BoolExpr::boolop, BTORDER_PROC, castNode, JsonConstructorExprState::category, check_stack_depth(), CMD_MERGE, TypeCacheEntry::cmp_proc, JsonConstructorExprState::constructor, convert(), EEO_FLAG_HAS_NEW, EEO_FLAG_HAS_OLD, EEO_FLAG_NEW_IS_NULL, EEO_FLAG_OLD_IS_NULL, 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_CASE_TESTVAL_EXT, EEOP_CONST, EEOP_CONVERT_ROWTYPE, EEOP_CURRENTOFEXPR, EEOP_DISTINCT, EEOP_DOMAIN_TESTVAL, EEOP_DOMAIN_TESTVAL_EXT, EEOP_DONE_RETURN, 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_NEW_SYSVAR, EEOP_NEW_VAR, EEOP_NEXTVALUEEXPR, EEOP_NULLIF, EEOP_NULLTEST_ISNOTNULL, EEOP_NULLTEST_ISNULL, EEOP_NULLTEST_ROWISNOTNULL, EEOP_NULLTEST_ROWISNULL, EEOP_OLD_SYSVAR, EEOP_OLD_VAR, EEOP_OUTER_SYSVAR, EEOP_OUTER_VAR, EEOP_PARAM_EXEC, EEOP_PARAM_EXTERN, EEOP_RETURNINGEXPR, EEOP_ROW, EEOP_ROWCOMPARE_FINAL, EEOP_ROWCOMPARE_STEP, EEOP_SCALARARRAYOP, EEOP_SCAN_SYSVAR, EEOP_SCAN_VAR, EEOP_SQLVALUEFUNCTION, EEOP_WINDOW_FUNC, EEOP_XMLEXPR, elog, ereport, errcode(), errmsg, ERROR, ExecInitCoerceToDomain(), ExecInitExpr(), ExecInitExprList(), ExecInitExprRec(), ExecInitFunc(), ExecInitJsonExpr(), ExecInitSubPlanExpr(), ExecInitSubscriptingRef(), ExecInitWholeRowVar(), ExecReadyExpr(), ExecTypeFromExprList(), ExecTypeSetColNames(), JsonIsPredicate::expr, ExprEvalPushStep(), exprType(), fb(), fmgr_info(), fmgr_info_set_expr, FmgrInfo::fn_addr, forboth, forfive, format_type_be(), JsonExpr::formatted_expr, FuncExpr::funcid, WindowAggState::funcs, get_element_type(), get_func_name(), get_op_opfamily_properties(), get_opfamily_proc(), get_typlen(), get_typlenbyvalalign(), getTypeInputInfo(), getTypeOutputInfo(), GetUserId(), i, InitFunctionCallInfoData, INNER_VAR, Int32GetDatum(), InvalidAttrNumber, InvalidOid, InvokeFunctionExecuteHook, IS_FALSE, 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(), JSON_TABLE_OP, lappend(), lappend_int(), lfirst, lfirst_int, lfirst_oid, linitial, list_length(), lookup_rowtype_tupdesc(), lookup_rowtype_tupdesc_copy(), lookup_type_cache(), lsecond, makeNode, makeNullConst(), Max, MULTIEXPR_SUBLINK, XmlExpr::named_args, JsonConstructorExprState::nargs, TupleDescData::natts, FieldStore::newvals, NIL, nodeTag, NOT_EXPR, WindowAggState::numaggs, WindowAggState::numfuncs, object_aclcheck(), OBJECT_FUNCTION, ObjectIdGetDatum(), OidIsValid, JsonExpr::op, OR_EXPR, OUTER_VAR, JsonConstructorExprState::outfuncid, palloc(), palloc0(), palloc0_object, palloc_array, palloc_object, PARAM_EXEC, PARAM_EXTERN, ParamListInfoData::paramCompile, Param::paramid, Param::paramkind, Param::paramtype, ReleaseTupleDesc, CoerceViaIO::resulttype, ReturningExpr::retexpr, ReturningExpr::retold, SizeForFunctionCallInfo, SubPlan::subLinkType, TupleDescAttr(), TYPECACHE_CMP_PROC, ScalarArrayOpExpr::useOr, NullableDatum::value, values, VAR_RETURNING_DEFAULT, VAR_RETURNING_NEW, VAR_RETURNING_OLD, and WindowFuncExprState::wfunc.

Referenced by ExecBuildAggTrans(), ExecBuildHash32Expr(), ExecBuildProjectionInfo(), ExecBuildUpdateProjection(), ExecInitCoerceToDomain(), ExecInitExprRec(), ExecInitExprWithContext(), ExecInitExprWithParams(), ExecInitFunc(), ExecInitJsonExpr(), ExecInitQual(), ExecInitSubPlanExpr(), and ExecInitSubscriptingRef().

◆ ExecInitExprWithContext()

ExprState * ExecInitExprWithContext ( Expr node,
PlanState parent,
Node escontext 
)

Definition at line 163 of file execExpr.c.

164{
166 ExprEvalStep scratch = {0};
167
168 /* Special case: NULL expression produces a NULL ExprState pointer */
169 if (node == NULL)
170 return NULL;
171
172 /* Initialize ExprState with empty step list */
174 state->expr = node;
175 state->parent = parent;
176 state->ext_params = NULL;
177 state->escontext = (ErrorSaveContext *) escontext;
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_RETURN;
188
190
191 return state;
192}

References EEOP_DONE_RETURN, ExecCreateExprSetupSteps(), ExecInitExprRec(), ExecReadyExpr(), ExprEvalPushStep(), fb(), and makeNode.

Referenced by ExecInitExpr(), and ExecPrepareExprWithContext().

◆ ExecInitExprWithParams()

ExprState * ExecInitExprWithParams ( Expr node,
ParamListInfo  ext_params 
)

Definition at line 201 of file execExpr.c.

202{
204 ExprEvalStep scratch = {0};
205
206 /* Special case: NULL expression produces a NULL ExprState pointer */
207 if (node == NULL)
208 return NULL;
209
210 /* Initialize ExprState with empty step list */
212 state->expr = node;
213 state->parent = NULL;
214 state->ext_params = ext_params;
215
216 /* Insert setup steps as needed */
218
219 /* Compile the expression proper */
220 ExecInitExprRec(node, state, &state->resvalue, &state->resnull);
221
222 /* Finally, append a DONE step */
223 scratch.opcode = EEOP_DONE_RETURN;
225
227
228 return state;
229}

References EEOP_DONE_RETURN, ExecCreateExprSetupSteps(), ExecInitExprRec(), ExecReadyExpr(), ExprEvalPushStep(), fb(), and makeNode.

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

2732{
2733 int nargs = list_length(args);
2735 FmgrInfo *flinfo;
2736 FunctionCallInfo fcinfo;
2737 int argno;
2738 ListCell *lc;
2739
2740 /* Check permission to call function */
2742 if (aclresult != ACLCHECK_OK)
2745
2746 /*
2747 * Safety check on nargs. Under normal circumstances this should never
2748 * fail, as parser should check sooner. But possibly it might fail if
2749 * server has been compiled with FUNC_MAX_ARGS smaller than some functions
2750 * declared in pg_proc?
2751 */
2752 if (nargs > FUNC_MAX_ARGS)
2753 ereport(ERROR,
2755 errmsg_plural("cannot pass more than %d argument to a function",
2756 "cannot pass more than %d arguments to a function",
2758 FUNC_MAX_ARGS)));
2759
2760 /* Allocate function lookup data and parameter workspace for this call */
2761 scratch->d.func.finfo = palloc0_object(FmgrInfo);
2762 scratch->d.func.fcinfo_data = palloc0(SizeForFunctionCallInfo(nargs));
2763 flinfo = scratch->d.func.finfo;
2764 fcinfo = scratch->d.func.fcinfo_data;
2765
2766 /* Set up the primary fmgr lookup information */
2767 fmgr_info(funcid, flinfo);
2768 fmgr_info_set_expr((Node *) node, flinfo);
2769
2770 /* Initialize function call parameter structure too */
2771 InitFunctionCallInfoData(*fcinfo, flinfo,
2772 nargs, inputcollid, NULL, NULL);
2773
2774 /* Keep extra copies of this info to save an indirection at runtime */
2775 scratch->d.func.fn_addr = flinfo->fn_addr;
2776 scratch->d.func.nargs = nargs;
2777
2778 /* We only support non-set functions here */
2779 if (flinfo->fn_retset)
2780 ereport(ERROR,
2782 errmsg("set-valued function called in context that cannot accept a set"),
2783 state->parent ?
2784 executor_errposition(state->parent->state,
2785 exprLocation((Node *) node)) : 0));
2786
2787 /* Build code to evaluate arguments directly into the fcinfo struct */
2788 argno = 0;
2789 foreach(lc, args)
2790 {
2791 Expr *arg = (Expr *) lfirst(lc);
2792
2793 if (IsA(arg, Const))
2794 {
2795 /*
2796 * Don't evaluate const arguments every round; especially
2797 * interesting for constants in comparisons.
2798 */
2799 Const *con = (Const *) arg;
2800
2801 fcinfo->args[argno].value = con->constvalue;
2802 fcinfo->args[argno].isnull = con->constisnull;
2803 }
2804 else
2805 {
2807 &fcinfo->args[argno].value,
2808 &fcinfo->args[argno].isnull);
2809 }
2810 argno++;
2811 }
2812
2813 /* Insert appropriate opcode depending on strictness and stats level */
2815 {
2816 if (flinfo->fn_strict && nargs > 0)
2817 {
2818 /* Choose nargs optimized implementation if available. */
2819 if (nargs == 1)
2821 else if (nargs == 2)
2823 else
2824 scratch->opcode = EEOP_FUNCEXPR_STRICT;
2825 }
2826 else
2827 scratch->opcode = EEOP_FUNCEXPR;
2828 }
2829 else
2830 {
2831 if (flinfo->fn_strict && nargs > 0)
2833 else
2834 scratch->opcode = EEOP_FUNCEXPR_FUSAGE;
2835 }
2836}
int int int errmsg_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...) pg_attribute_printf(1
@ EEOP_FUNCEXPR_STRICT_FUSAGE
Definition execExpr.h:127
@ EEOP_FUNCEXPR_STRICT_1
Definition execExpr.h:124
@ EEOP_FUNCEXPR_STRICT_2
Definition execExpr.h:125
@ EEOP_FUNCEXPR_STRICT
Definition execExpr.h:123
@ EEOP_FUNCEXPR
Definition execExpr.h:122
@ EEOP_FUNCEXPR_FUSAGE
Definition execExpr.h:126
int executor_errposition(EState *estate, int location)
Definition execUtils.c:941
int exprLocation(const Node *expr)
Definition nodeFuncs.c:1392
#define FUNC_MAX_ARGS
bool fn_retset
Definition fmgr.h:62

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

Referenced by ExecInitExprRec().

◆ ExecInitJsonCoercion()

static void ExecInitJsonCoercion ( ExprState state,
JsonReturning returning,
ErrorSaveContext escontext,
bool  omit_quotes,
bool  exists_coerce,
Datum resv,
bool resnull 
)
static

Definition at line 5079 of file execExpr.c.

5083{
5084 ExprEvalStep scratch = {0};
5085
5086 /* For json_populate_type() */
5088 scratch.resvalue = resv;
5089 scratch.resnull = resnull;
5090 scratch.d.jsonexpr_coercion.targettype = returning->typid;
5091 scratch.d.jsonexpr_coercion.targettypmod = returning->typmod;
5092 scratch.d.jsonexpr_coercion.json_coercion_cache = NULL;
5093 scratch.d.jsonexpr_coercion.escontext = escontext;
5094 scratch.d.jsonexpr_coercion.omit_quotes = omit_quotes;
5095 scratch.d.jsonexpr_coercion.exists_coerce = exists_coerce;
5096 scratch.d.jsonexpr_coercion.exists_cast_to_int = exists_coerce &&
5097 getBaseType(returning->typid) == INT4OID;
5098 scratch.d.jsonexpr_coercion.exists_check_domain = exists_coerce &&
5099 DomainHasConstraints(returning->typid, NULL);
5101}
@ EEOP_JSONEXPR_COERCION
Definition execExpr.h:269
Oid getBaseType(Oid typid)
Definition lsyscache.c:2743
bool DomainHasConstraints(Oid type_id, bool *has_volatile)
Definition typcache.c:1495

References DomainHasConstraints(), EEOP_JSONEXPR_COERCION, ExprEvalPushStep(), fb(), getBaseType(), ExprEvalStep::opcode, JsonReturning::typid, and JsonReturning::typmod.

Referenced by ExecInitJsonExpr().

◆ ExecInitJsonExpr()

static void ExecInitJsonExpr ( JsonExpr jsexpr,
ExprState state,
Datum resv,
bool resnull,
ExprEvalStep scratch 
)
static

Definition at line 4777 of file execExpr.c.

4780{
4786 ListCell *lc;
4787 ErrorSaveContext *escontext;
4788 bool returning_domain =
4790
4791 Assert(jsexpr->on_error != NULL);
4792
4793 jsestate->jsexpr = jsexpr;
4794
4795 /*
4796 * Evaluate formatted_expr storing the result into
4797 * jsestate->formatted_expr.
4798 */
4800 &jsestate->formatted_expr.value,
4801 &jsestate->formatted_expr.isnull);
4802
4803 /* JUMP to return NULL if formatted_expr evaluates to NULL */
4805 scratch->opcode = EEOP_JUMP_IF_NULL;
4806 scratch->resnull = &jsestate->formatted_expr.isnull;
4807 scratch->d.jump.jumpdone = -1; /* set below */
4809
4810 /*
4811 * Evaluate pathspec expression storing the result into
4812 * jsestate->pathspec.
4813 */
4814 ExecInitExprRec((Expr *) jsexpr->path_spec, state,
4815 &jsestate->pathspec.value,
4816 &jsestate->pathspec.isnull);
4817
4818 /* JUMP to return NULL if path_spec evaluates to NULL */
4820 scratch->opcode = EEOP_JUMP_IF_NULL;
4821 scratch->resnull = &jsestate->pathspec.isnull;
4822 scratch->d.jump.jumpdone = -1; /* set below */
4824
4825 /* Steps to compute PASSING args. */
4826 jsestate->args = NIL;
4828 argnamelc, jsexpr->passing_names)
4829 {
4831 String *argname = lfirst_node(String, argnamelc);
4833
4834 var->name = argname->sval;
4835 var->namelen = strlen(var->name);
4836 var->typid = exprType((Node *) argexpr);
4837 var->typmod = exprTypmod((Node *) argexpr);
4838
4839 ExecInitExprRec(argexpr, state, &var->value, &var->isnull);
4840
4841 jsestate->args = lappend(jsestate->args, var);
4842 }
4843
4844 /* Step for jsonpath evaluation; see ExecEvalJsonExprPath(). */
4845 scratch->opcode = EEOP_JSONEXPR_PATH;
4846 scratch->resvalue = resv;
4847 scratch->resnull = resnull;
4848 scratch->d.jsonexpr.jsestate = jsestate;
4850
4851 /*
4852 * Step to return NULL after jumping to skip the EEOP_JSONEXPR_PATH step
4853 * when either formatted_expr or pathspec is NULL. Adjust jump target
4854 * addresses of JUMPs that we added above.
4855 */
4856 foreach(lc, jumps_return_null)
4857 {
4858 ExprEvalStep *as = &state->steps[lfirst_int(lc)];
4859
4860 as->d.jump.jumpdone = state->steps_len;
4861 }
4862 scratch->opcode = EEOP_CONST;
4863 scratch->resvalue = resv;
4864 scratch->resnull = resnull;
4865 scratch->d.constval.value = (Datum) 0;
4866 scratch->d.constval.isnull = true;
4868
4869 escontext = jsexpr->on_error->btype != JSON_BEHAVIOR_ERROR ?
4870 &jsestate->escontext : NULL;
4871
4872 /*
4873 * To handle coercion errors softly, use the following ErrorSaveContext to
4874 * pass to ExecInitExprRec() when initializing the coercion expressions
4875 * and in the EEOP_JSONEXPR_COERCION step.
4876 */
4877 jsestate->escontext.type = T_ErrorSaveContext;
4878
4879 /*
4880 * Steps to coerce the result value computed by EEOP_JSONEXPR_PATH or the
4881 * NULL returned on NULL input as described above.
4882 */
4883 jsestate->jump_eval_coercion = -1;
4884 if (jsexpr->use_json_coercion)
4885 {
4886 jsestate->jump_eval_coercion = state->steps_len;
4887
4888 ExecInitJsonCoercion(state, jsexpr->returning, escontext,
4889 jsexpr->omit_quotes,
4890 jsexpr->op == JSON_EXISTS_OP,
4891 resv, resnull);
4892 }
4893 else if (jsexpr->use_io_coercion)
4894 {
4895 /*
4896 * Here we only need to initialize the FunctionCallInfo for the target
4897 * type's input function, which is called by ExecEvalJsonExprPath()
4898 * itself, so no additional step is necessary.
4899 */
4900 Oid typinput;
4901 Oid typioparam;
4902 FmgrInfo *finfo;
4903 FunctionCallInfo fcinfo;
4904
4905 getTypeInputInfo(jsexpr->returning->typid, &typinput, &typioparam);
4906 finfo = palloc0_object(FmgrInfo);
4907 fcinfo = palloc0(SizeForFunctionCallInfo(3));
4908 fmgr_info(typinput, finfo);
4909 fmgr_info_set_expr((Node *) jsexpr->returning, finfo);
4910 InitFunctionCallInfoData(*fcinfo, finfo, 3, InvalidOid, NULL, NULL);
4911
4912 /*
4913 * We can preload the second and third arguments for the input
4914 * function, since they're constants.
4915 */
4916 fcinfo->args[1].value = ObjectIdGetDatum(typioparam);
4917 fcinfo->args[1].isnull = false;
4918 fcinfo->args[2].value = Int32GetDatum(jsexpr->returning->typmod);
4919 fcinfo->args[2].isnull = false;
4920 fcinfo->context = (Node *) escontext;
4921
4922 jsestate->input_fcinfo = fcinfo;
4923 }
4924
4925 /*
4926 * Add a special step, if needed, to check if the coercion evaluation ran
4927 * into an error but was not thrown because the ON ERROR behavior is not
4928 * ERROR. It will set jsestate->error if an error did occur.
4929 */
4930 if (jsestate->jump_eval_coercion >= 0 && escontext != NULL)
4931 {
4933 scratch->d.jsonexpr.jsestate = jsestate;
4935 }
4936
4937 jsestate->jump_empty = jsestate->jump_error = -1;
4938
4939 /*
4940 * Step to check jsestate->error and return the ON ERROR expression if
4941 * there is one. This handles both the errors that occur during jsonpath
4942 * evaluation in EEOP_JSONEXPR_PATH and subsequent coercion evaluation.
4943 *
4944 * Speed up common cases by avoiding extra steps for a NULL-valued ON
4945 * ERROR expression unless RETURNING a domain type, where constraints must
4946 * be checked. ExecEvalJsonExprPath() already returns NULL on error,
4947 * making additional steps unnecessary in typical scenarios. Note that the
4948 * default ON ERROR behavior for JSON_VALUE() and JSON_QUERY() is to
4949 * return NULL.
4950 */
4951 if (jsexpr->on_error->btype != JSON_BEHAVIOR_ERROR &&
4952 (!(IsA(jsexpr->on_error->expr, Const) &&
4953 ((Const *) jsexpr->on_error->expr)->constisnull) ||
4955 {
4957
4958 jsestate->jump_error = state->steps_len;
4959
4960 /* JUMP to end if false, that is, skip the ON ERROR expression. */
4963 scratch->resvalue = &jsestate->error.value;
4964 scratch->resnull = &jsestate->error.isnull;
4965 scratch->d.jump.jumpdone = -1; /* set below */
4967
4968 /*
4969 * Steps to evaluate the ON ERROR expression; handle errors softly to
4970 * rethrow them in COERCION_FINISH step that will be added later.
4971 */
4972 saved_escontext = state->escontext;
4973 state->escontext = escontext;
4974 ExecInitExprRec((Expr *) jsexpr->on_error->expr,
4975 state, resv, resnull);
4976 state->escontext = saved_escontext;
4977
4978 /* Step to coerce the ON ERROR expression if needed */
4979 if (jsexpr->on_error->coerce)
4980 ExecInitJsonCoercion(state, jsexpr->returning, escontext,
4981 jsexpr->omit_quotes, false,
4982 resv, resnull);
4983
4984 /*
4985 * Add a COERCION_FINISH step to check for errors that may occur when
4986 * coercing and rethrow them.
4987 */
4988 if (jsexpr->on_error->coerce ||
4989 IsA(jsexpr->on_error->expr, CoerceViaIO) ||
4990 IsA(jsexpr->on_error->expr, CoerceToDomain))
4991 {
4993 scratch->resvalue = resv;
4994 scratch->resnull = resnull;
4995 scratch->d.jsonexpr.jsestate = jsestate;
4997 }
4998
4999 /* JUMP to end to skip the ON EMPTY steps added below. */
5001 scratch->opcode = EEOP_JUMP;
5002 scratch->d.jump.jumpdone = -1;
5004 }
5005
5006 /*
5007 * Step to check jsestate->empty and return the ON EMPTY expression if
5008 * there is one.
5009 *
5010 * See the comment above for details on the optimization for NULL-valued
5011 * expressions.
5012 */
5013 if (jsexpr->on_empty != NULL &&
5014 jsexpr->on_empty->btype != JSON_BEHAVIOR_ERROR &&
5015 (!(IsA(jsexpr->on_empty->expr, Const) &&
5016 ((Const *) jsexpr->on_empty->expr)->constisnull) ||
5018 {
5020
5021 jsestate->jump_empty = state->steps_len;
5022
5023 /* JUMP to end if false, that is, skip the ON EMPTY expression. */
5026 scratch->resvalue = &jsestate->empty.value;
5027 scratch->resnull = &jsestate->empty.isnull;
5028 scratch->d.jump.jumpdone = -1; /* set below */
5030
5031 /*
5032 * Steps to evaluate the ON EMPTY expression; handle errors softly to
5033 * rethrow them in COERCION_FINISH step that will be added later.
5034 */
5035 saved_escontext = state->escontext;
5036 state->escontext = escontext;
5037 ExecInitExprRec((Expr *) jsexpr->on_empty->expr,
5038 state, resv, resnull);
5039 state->escontext = saved_escontext;
5040
5041 /* Step to coerce the ON EMPTY expression if needed */
5042 if (jsexpr->on_empty->coerce)
5043 ExecInitJsonCoercion(state, jsexpr->returning, escontext,
5044 jsexpr->omit_quotes, false,
5045 resv, resnull);
5046
5047 /*
5048 * Add a COERCION_FINISH step to check for errors that may occur when
5049 * coercing and rethrow them.
5050 */
5051 if (jsexpr->on_empty->coerce ||
5052 IsA(jsexpr->on_empty->expr, CoerceViaIO) ||
5053 IsA(jsexpr->on_empty->expr, CoerceToDomain))
5054 {
5055
5057 scratch->resvalue = resv;
5058 scratch->resnull = resnull;
5059 scratch->d.jsonexpr.jsestate = jsestate;
5061 }
5062 }
5063
5064 foreach(lc, jumps_to_end)
5065 {
5066 ExprEvalStep *as = &state->steps[lfirst_int(lc)];
5067
5068 as->d.jump.jumpdone = state->steps_len;
5069 }
5070
5071 jsestate->jump_end = state->steps_len;
5072}
static void ExecInitJsonCoercion(ExprState *state, JsonReturning *returning, ErrorSaveContext *escontext, bool omit_quotes, bool exists_coerce, Datum *resv, bool *resnull)
Definition execExpr.c:5079
@ EEOP_JSONEXPR_PATH
Definition execExpr.h:268
@ EEOP_JSONEXPR_COERCION_FINISH
Definition execExpr.h:270
@ EEOP_JUMP_IF_NULL
Definition execExpr.h:154
char get_typtype(Oid typid)
Definition lsyscache.c:2851
int32 exprTypmod(const Node *expr)
Definition nodeFuncs.c:304
@ JSON_BEHAVIOR_ERROR
Definition primnodes.h:1793
@ JSON_EXISTS_OP
Definition primnodes.h:1829
JsonBehaviorType btype
Definition primnodes.h:1817
int jump_eval_coercion
Definition execnodes.h:1119
NullableDatum empty
Definition execnodes.h:1105
FunctionCallInfo input_fcinfo
Definition execnodes.h:1133
JsonExpr * jsexpr
Definition execnodes.h:1083
NullableDatum error
Definition execnodes.h:1102
NullableDatum pathspec
Definition execnodes.h:1089
ErrorSaveContext escontext
Definition execnodes.h:1142
NullableDatum formatted_expr
Definition execnodes.h:1086
List * passing_values
Definition primnodes.h:1863
JsonBehavior * on_empty
Definition primnodes.h:1866
List * passing_names
Definition primnodes.h:1862
Node * path_spec
Definition primnodes.h:1856
bool use_io_coercion
Definition primnodes.h:1873
JsonReturning * returning
Definition primnodes.h:1859
bool use_json_coercion
Definition primnodes.h:1874
JsonBehavior * on_error
Definition primnodes.h:1867
bool omit_quotes
Definition primnodes.h:1880
Definition value.h:64
char * sval
Definition value.h:68

References FunctionCallInfoBaseData::args, JsonExprState::args, Assert, JsonBehavior::btype, JsonBehavior::coerce, FunctionCallInfoBaseData::context, EEOP_CONST, EEOP_JSONEXPR_COERCION_FINISH, EEOP_JSONEXPR_PATH, EEOP_JUMP, EEOP_JUMP_IF_NOT_TRUE, EEOP_JUMP_IF_NULL, JsonExprState::empty, JsonExprState::error, JsonExprState::escontext, ExecInitExprRec(), ExecInitJsonCoercion(), JsonBehavior::expr, ExprEvalPushStep(), exprType(), exprTypmod(), fb(), fmgr_info(), fmgr_info_set_expr, forboth, JsonExprState::formatted_expr, JsonExpr::formatted_expr, get_typtype(), getTypeInputInfo(), InitFunctionCallInfoData, JsonExprState::input_fcinfo, Int32GetDatum(), InvalidOid, IsA, NullableDatum::isnull, JsonPathVariable::isnull, JsonExprState::jsexpr, JSON_BEHAVIOR_ERROR, JSON_EXISTS_OP, JsonExprState::jump_empty, JsonExprState::jump_end, JsonExprState::jump_error, JsonExprState::jump_eval_coercion, lappend(), lappend_int(), lfirst, lfirst_int, lfirst_node, JsonPathVariable::name, JsonPathVariable::namelen, NIL, ObjectIdGetDatum(), JsonExpr::omit_quotes, JsonExpr::on_empty, JsonExpr::on_error, JsonExpr::op, palloc0(), palloc0_object, palloc_object, JsonExpr::passing_names, JsonExpr::passing_values, JsonExpr::path_spec, JsonExprState::pathspec, JsonExpr::returning, SizeForFunctionCallInfo, String::sval, ErrorSaveContext::type, JsonReturning::typid, JsonPathVariable::typid, JsonReturning::typmod, JsonPathVariable::typmod, JsonExpr::use_io_coercion, JsonExpr::use_json_coercion, NullableDatum::value, and JsonPathVariable::value.

Referenced by ExecInitExprRec().

◆ ExecInitQual()

ExprState * ExecInitQual ( List qual,
PlanState parent 
)

Definition at line 250 of file execExpr.c.

251{
253 ExprEvalStep scratch = {0};
255
256 /* short-circuit (here and in ExecQual) for empty restriction list */
257 if (qual == NIL)
258 return NULL;
259
260 Assert(IsA(qual, List));
261
263 state->expr = (Expr *) qual;
264 state->parent = parent;
265 state->ext_params = NULL;
266
267 /* mark expression as to be used with ExecQual() */
268 state->flags = EEO_FLAG_IS_QUAL;
269
270 /* Insert setup steps as needed */
272
273 /*
274 * ExecQual() needs to return false for an expression returning NULL. That
275 * allows us to short-circuit the evaluation the first time a NULL is
276 * encountered. As qual evaluation is a hot-path this warrants using a
277 * special opcode for qual evaluation that's simpler than BOOL_AND (which
278 * has more complex NULL handling).
279 */
280 scratch.opcode = EEOP_QUAL;
281
282 /*
283 * We can use ExprState's resvalue/resnull as target for each qual expr.
284 */
285 scratch.resvalue = &state->resvalue;
286 scratch.resnull = &state->resnull;
287
288 foreach_ptr(Expr, node, qual)
289 {
290 /* first evaluate expression */
291 ExecInitExprRec(node, state, &state->resvalue, &state->resnull);
292
293 /* then emit EEOP_QUAL to detect if it's false (or null) */
294 scratch.d.qualexpr.jumpdone = -1;
297 state->steps_len - 1);
298 }
299
300 /* adjust jump targets */
302 {
303 ExprEvalStep *as = &state->steps[jump];
304
305 Assert(as->opcode == EEOP_QUAL);
306 Assert(as->d.qualexpr.jumpdone == -1);
307 as->d.qualexpr.jumpdone = state->steps_len;
308 }
309
310 /*
311 * At the end, we don't need to do anything more. The last qual expr must
312 * have yielded TRUE, and since its result is stored in the desired output
313 * location, we're done.
314 */
315 scratch.opcode = EEOP_DONE_RETURN;
317
319
320 return state;
321}
#define foreach_ptr(type, var, lst)
Definition pg_list.h:469
#define foreach_int(var, lst)
Definition pg_list.h:470

References Assert, EEO_FLAG_IS_QUAL, EEOP_DONE_RETURN, EEOP_QUAL, ExecCreateExprSetupSteps(), ExecInitExprRec(), ExecReadyExpr(), ExprEvalPushStep(), fb(), foreach_int, foreach_ptr, IsA, lappend_int(), makeNode, and NIL.

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().

◆ ExecInitSubPlanExpr()

static void ExecInitSubPlanExpr ( SubPlan subplan,
ExprState state,
Datum resv,
bool resnull 
)
static

Definition at line 2847 of file execExpr.c.

2850{
2851 ExprEvalStep scratch = {0};
2852 SubPlanState *sstate;
2853 ListCell *pvar;
2854 ListCell *l;
2855
2856 if (!state->parent)
2857 elog(ERROR, "SubPlan found with no parent plan");
2858
2859 /*
2860 * Generate steps to evaluate input arguments for the subplan.
2861 *
2862 * We evaluate the argument expressions into resv/resnull, and then use
2863 * PARAM_SET to update the parameter. We do that, instead of evaluating
2864 * directly into the param, to avoid depending on the pointer value
2865 * remaining stable / being included in the generated expression. It's ok
2866 * to use resv/resnull for multiple params, as each parameter evaluation
2867 * is immediately followed by an EEOP_PARAM_SET (and thus are saved before
2868 * they could be overwritten again).
2869 *
2870 * Any calculation we have to do can be done in the parent econtext, since
2871 * the Param values don't need to have per-query lifetime.
2872 */
2873 Assert(list_length(subplan->parParam) == list_length(subplan->args));
2874 forboth(l, subplan->parParam, pvar, subplan->args)
2875 {
2876 int paramid = lfirst_int(l);
2877 Expr *arg = (Expr *) lfirst(pvar);
2878
2879 ExecInitExprRec(arg, state, resv, resnull);
2880
2881 scratch.opcode = EEOP_PARAM_SET;
2882 scratch.resvalue = resv;
2883 scratch.resnull = resnull;
2884 scratch.d.param.paramid = paramid;
2885 /* paramtype's not actually used, but we might as well fill it */
2886 scratch.d.param.paramtype = exprType((Node *) arg);
2888 }
2889
2890 sstate = ExecInitSubPlan(subplan, state->parent);
2891
2892 /* add SubPlanState nodes to state->parent->subPlan */
2893 state->parent->subPlan = lappend(state->parent->subPlan,
2894 sstate);
2895
2896 scratch.opcode = EEOP_SUBPLAN;
2897 scratch.resvalue = resv;
2898 scratch.resnull = resnull;
2899 scratch.d.subplan.sstate = sstate;
2900
2902}
@ EEOP_SUBPLAN
Definition execExpr.h:275
@ EEOP_PARAM_SET
Definition execExpr.h:177
SubPlanState * ExecInitSubPlan(SubPlan *subplan, PlanState *parent)
List * args
Definition primnodes.h:1125
List * parParam
Definition primnodes.h:1124

References arg, SubPlan::args, Assert, EEOP_PARAM_SET, EEOP_SUBPLAN, elog, ERROR, ExecInitExprRec(), ExecInitSubPlan(), ExprEvalPushStep(), exprType(), fb(), forboth, lappend(), lfirst, lfirst_int, list_length(), and SubPlan::parParam.

Referenced by ExecInitExprRec(), and ExecPushExprSetupSteps().

◆ ExecInitSubscriptingRef()

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

Definition at line 3271 of file execExpr.c.

3273{
3274 bool isAssignment = (sbsref->refassgnexpr != NULL);
3275 int nupper = list_length(sbsref->refupperindexpr);
3276 int nlower = list_length(sbsref->reflowerindexpr);
3279 SubscriptExecSteps methods;
3280 char *ptr;
3282 ListCell *lc;
3283 int i;
3284
3285 /* Look up the subscripting support methods */
3286 sbsroutines = getSubscriptingRoutines(sbsref->refcontainertype, NULL);
3287 if (!sbsroutines)
3288 ereport(ERROR,
3290 errmsg("cannot subscript type %s because it does not support subscripting",
3291 format_type_be(sbsref->refcontainertype)),
3292 state->parent ?
3293 executor_errposition(state->parent->state,
3294 exprLocation((Node *) sbsref)) : 0));
3295
3296 /* Allocate sbsrefstate, with enough space for per-subscript arrays too */
3298 (nupper + nlower) * (sizeof(Datum) +
3299 2 * sizeof(bool)));
3300
3301 /* Fill constant fields of SubscriptingRefState */
3302 sbsrefstate->isassignment = isAssignment;
3303 sbsrefstate->numupper = nupper;
3304 sbsrefstate->numlower = nlower;
3305 /* Set up per-subscript arrays */
3306 ptr = ((char *) sbsrefstate) + MAXALIGN(sizeof(SubscriptingRefState));
3307 sbsrefstate->upperindex = (Datum *) ptr;
3308 ptr += nupper * sizeof(Datum);
3309 sbsrefstate->lowerindex = (Datum *) ptr;
3310 ptr += nlower * sizeof(Datum);
3311 sbsrefstate->upperprovided = (bool *) ptr;
3312 ptr += nupper * sizeof(bool);
3313 sbsrefstate->lowerprovided = (bool *) ptr;
3314 ptr += nlower * sizeof(bool);
3315 sbsrefstate->upperindexnull = (bool *) ptr;
3316 ptr += nupper * sizeof(bool);
3317 sbsrefstate->lowerindexnull = (bool *) ptr;
3318 /* ptr += nlower * sizeof(bool); */
3319
3320 /*
3321 * Let the container-type-specific code have a chance. It must fill the
3322 * "methods" struct with function pointers for us to possibly use in
3323 * execution steps below; and it can optionally set up some data pointed
3324 * to by the workspace field.
3325 */
3326 memset(&methods, 0, sizeof(methods));
3327 sbsroutines->exec_setup(sbsref, sbsrefstate, &methods);
3328
3329 /*
3330 * Evaluate array input. It's safe to do so into resv/resnull, because we
3331 * won't use that as target for any of the other subexpressions, and it'll
3332 * be overwritten by the final EEOP_SBSREF_FETCH/ASSIGN step, which is
3333 * pushed last.
3334 */
3335 ExecInitExprRec(sbsref->refexpr, state, resv, resnull);
3336
3337 /*
3338 * If refexpr yields NULL, and the operation should be strict, then result
3339 * is NULL. We can implement this with just JUMP_IF_NULL, since we
3340 * evaluated the array into the desired target location.
3341 */
3342 if (!isAssignment && sbsroutines->fetch_strict)
3343 {
3344 scratch->opcode = EEOP_JUMP_IF_NULL;
3345 scratch->d.jump.jumpdone = -1; /* adjust later */
3348 state->steps_len - 1);
3349 }
3350
3351 /* Evaluate upper subscripts */
3352 i = 0;
3353 foreach(lc, sbsref->refupperindexpr)
3354 {
3355 Expr *e = (Expr *) lfirst(lc);
3356
3357 /* When slicing, individual subscript bounds can be omitted */
3358 if (!e)
3359 {
3360 sbsrefstate->upperprovided[i] = false;
3361 sbsrefstate->upperindexnull[i] = true;
3362 }
3363 else
3364 {
3365 sbsrefstate->upperprovided[i] = true;
3366 /* Each subscript is evaluated into appropriate array entry */
3368 &sbsrefstate->upperindex[i],
3369 &sbsrefstate->upperindexnull[i]);
3370 }
3371 i++;
3372 }
3373
3374 /* Evaluate lower subscripts similarly */
3375 i = 0;
3376 foreach(lc, sbsref->reflowerindexpr)
3377 {
3378 Expr *e = (Expr *) lfirst(lc);
3379
3380 /* When slicing, individual subscript bounds can be omitted */
3381 if (!e)
3382 {
3383 sbsrefstate->lowerprovided[i] = false;
3384 sbsrefstate->lowerindexnull[i] = true;
3385 }
3386 else
3387 {
3388 sbsrefstate->lowerprovided[i] = true;
3389 /* Each subscript is evaluated into appropriate array entry */
3391 &sbsrefstate->lowerindex[i],
3392 &sbsrefstate->lowerindexnull[i]);
3393 }
3394 i++;
3395 }
3396
3397 /* SBSREF_SUBSCRIPTS checks and converts all the subscripts at once */
3398 if (methods.sbs_check_subscripts)
3399 {
3401 scratch->d.sbsref_subscript.subscriptfunc = methods.sbs_check_subscripts;
3402 scratch->d.sbsref_subscript.state = sbsrefstate;
3403 scratch->d.sbsref_subscript.jumpdone = -1; /* adjust later */
3406 state->steps_len - 1);
3407 }
3408
3409 if (isAssignment)
3410 {
3413
3414 /* Check for unimplemented methods */
3415 if (!methods.sbs_assign)
3416 ereport(ERROR,
3418 errmsg("type %s does not support subscripted assignment",
3419 format_type_be(sbsref->refcontainertype))));
3420
3421 /*
3422 * We might have a nested-assignment situation, in which the
3423 * refassgnexpr is itself a FieldStore or SubscriptingRef that needs
3424 * to obtain and modify the previous value of the array element or
3425 * slice being replaced. If so, we have to extract that value from
3426 * the array and pass it down via the CaseTestExpr mechanism. It's
3427 * safe to reuse the CASE mechanism because there cannot be a CASE
3428 * between here and where the value would be needed, and an array
3429 * assignment can't be within a CASE either. (So saving and restoring
3430 * innermost_caseval is just paranoia, but let's do it anyway.)
3431 *
3432 * Since fetching the old element might be a nontrivial expense, do it
3433 * only if the argument actually needs it.
3434 */
3435 if (isAssignmentIndirectionExpr(sbsref->refassgnexpr))
3436 {
3437 if (!methods.sbs_fetch_old)
3438 ereport(ERROR,
3440 errmsg("type %s does not support subscripted assignment",
3441 format_type_be(sbsref->refcontainertype))));
3442 scratch->opcode = EEOP_SBSREF_OLD;
3443 scratch->d.sbsref.subscriptfunc = methods.sbs_fetch_old;
3444 scratch->d.sbsref.state = sbsrefstate;
3446 }
3447
3448 /* SBSREF_OLD puts extracted value into prevvalue/prevnull */
3449 save_innermost_caseval = state->innermost_caseval;
3450 save_innermost_casenull = state->innermost_casenull;
3451 state->innermost_caseval = &sbsrefstate->prevvalue;
3452 state->innermost_casenull = &sbsrefstate->prevnull;
3453
3454 /* evaluate replacement value into replacevalue/replacenull */
3455 ExecInitExprRec(sbsref->refassgnexpr, state,
3456 &sbsrefstate->replacevalue, &sbsrefstate->replacenull);
3457
3458 state->innermost_caseval = save_innermost_caseval;
3459 state->innermost_casenull = save_innermost_casenull;
3460
3461 /* and perform the assignment */
3462 scratch->opcode = EEOP_SBSREF_ASSIGN;
3463 scratch->d.sbsref.subscriptfunc = methods.sbs_assign;
3464 scratch->d.sbsref.state = sbsrefstate;
3466 }
3467 else
3468 {
3469 /* array fetch is much simpler */
3470 scratch->opcode = EEOP_SBSREF_FETCH;
3471 scratch->d.sbsref.subscriptfunc = methods.sbs_fetch;
3472 scratch->d.sbsref.state = sbsrefstate;
3474 }
3475
3476 /* adjust jump targets */
3477 foreach(lc, adjust_jumps)
3478 {
3479 ExprEvalStep *as = &state->steps[lfirst_int(lc)];
3480
3481 if (as->opcode == EEOP_SBSREF_SUBSCRIPTS)
3482 {
3483 Assert(as->d.sbsref_subscript.jumpdone == -1);
3484 as->d.sbsref_subscript.jumpdone = state->steps_len;
3485 }
3486 else
3487 {
3488 Assert(as->opcode == EEOP_JUMP_IF_NULL);
3489 Assert(as->d.jump.jumpdone == -1);
3490 as->d.jump.jumpdone = state->steps_len;
3491 }
3492 }
3493}
#define MAXALIGN(LEN)
Definition c.h:898
static bool isAssignmentIndirectionExpr(Expr *expr)
Definition execExpr.c:3513
@ EEOP_SBSREF_SUBSCRIPTS
Definition execExpr.h:229
@ EEOP_SBSREF_FETCH
Definition execExpr.h:242
@ EEOP_SBSREF_ASSIGN
Definition execExpr.h:239
@ EEOP_SBSREF_OLD
Definition execExpr.h:236
const struct SubscriptRoutines * getSubscriptingRoutines(Oid typid, Oid *typelemp)
Definition lsyscache.c:3352
ExecEvalSubroutine sbs_fetch_old
Definition execExpr.h:817
ExecEvalBoolSubroutine sbs_check_subscripts
Definition execExpr.h:814
ExecEvalSubroutine sbs_assign
Definition execExpr.h:816
ExecEvalSubroutine sbs_fetch
Definition execExpr.h:815
Expr * refassgnexpr
Definition primnodes.h:736
List * refupperindexpr
Definition primnodes.h:726
List * reflowerindexpr
Definition primnodes.h:732

References Assert, EEOP_JUMP_IF_NULL, EEOP_SBSREF_ASSIGN, EEOP_SBSREF_FETCH, EEOP_SBSREF_OLD, EEOP_SBSREF_SUBSCRIPTS, ereport, errcode(), errmsg, ERROR, ExecInitExprRec(), executor_errposition(), ExprEvalPushStep(), exprLocation(), fb(), format_type_be(), getSubscriptingRoutines(), i, isAssignmentIndirectionExpr(), lappend_int(), lfirst, lfirst_int, list_length(), MAXALIGN, NIL, palloc0(), SubscriptingRef::refassgnexpr, SubscriptingRef::refexpr, SubscriptingRef::reflowerindexpr, SubscriptingRef::refupperindexpr, SubscriptExecSteps::sbs_assign, SubscriptExecSteps::sbs_check_subscripts, SubscriptExecSteps::sbs_fetch, and SubscriptExecSteps::sbs_fetch_old.

Referenced by ExecInitExprRec().

◆ ExecInitWholeRowVar()

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

Definition at line 3192 of file execExpr.c.

3193{
3194 PlanState *parent = state->parent;
3195
3196 /* fill in all but the target */
3197 scratch->opcode = EEOP_WHOLEROW;
3198 scratch->d.wholerow.var = variable;
3199 scratch->d.wholerow.first = true;
3200 scratch->d.wholerow.slow = false;
3201 scratch->d.wholerow.tupdesc = NULL; /* filled at runtime */
3202 scratch->d.wholerow.junkFilter = NULL;
3203
3204 /* update ExprState flags if Var refers to OLD/NEW */
3205 if (variable->varreturningtype == VAR_RETURNING_OLD)
3206 state->flags |= EEO_FLAG_HAS_OLD;
3207 else if (variable->varreturningtype == VAR_RETURNING_NEW)
3208 state->flags |= EEO_FLAG_HAS_NEW;
3209
3210 /*
3211 * If the input tuple came from a subquery, it might contain "resjunk"
3212 * columns (such as GROUP BY or ORDER BY columns), which we don't want to
3213 * keep in the whole-row result. We can get rid of such columns by
3214 * passing the tuple through a JunkFilter --- but to make one, we have to
3215 * lay our hands on the subquery's targetlist. Fortunately, there are not
3216 * very many cases where this can happen, and we can identify all of them
3217 * by examining our parent PlanState. We assume this is not an issue in
3218 * standalone expressions that don't have parent plans. (Whole-row Vars
3219 * can occur in such expressions, but they will always be referencing
3220 * table rows.)
3221 */
3222 if (parent)
3223 {
3224 PlanState *subplan = NULL;
3225
3226 switch (nodeTag(parent))
3227 {
3229 subplan = ((SubqueryScanState *) parent)->subplan;
3230 break;
3231 case T_CteScanState:
3232 subplan = ((CteScanState *) parent)->cteplanstate;
3233 break;
3234 default:
3235 break;
3236 }
3237
3238 if (subplan)
3239 {
3240 bool junk_filter_needed = false;
3241 ListCell *tlist;
3242
3243 /* Detect whether subplan tlist actually has any junk columns */
3244 foreach(tlist, subplan->plan->targetlist)
3245 {
3246 TargetEntry *tle = (TargetEntry *) lfirst(tlist);
3247
3248 if (tle->resjunk)
3249 {
3250 junk_filter_needed = true;
3251 break;
3252 }
3253 }
3254
3255 /* If so, build the junkfilter now */
3257 {
3258 scratch->d.wholerow.junkFilter =
3261 &TTSOpsVirtual));
3262 }
3263 }
3264 }
3265}
@ EEOP_WHOLEROW
Definition execExpr.h:96
JunkFilter * ExecInitJunkFilter(List *targetList, TupleTableSlot *slot)
Definition execJunk.c:60
TupleTableSlot * ExecInitExtraTupleSlot(EState *estate, TupleDesc tupledesc, const TupleTableSlotOps *tts_ops)
Plan * plan
Definition execnodes.h:1177
EState * state
Definition execnodes.h:1179
List * targetlist
Definition plannodes.h:233

References EEO_FLAG_HAS_NEW, EEO_FLAG_HAS_OLD, EEOP_WHOLEROW, ExecInitExtraTupleSlot(), ExecInitJunkFilter(), fb(), lfirst, nodeTag, PlanState::plan, PlanState::state, Plan::targetlist, TTSOpsVirtual, VAR_RETURNING_NEW, and VAR_RETURNING_OLD.

Referenced by ExecInitExprRec().

◆ ExecPrepareCheck()

ExprState * ExecPrepareCheck ( List qual,
EState estate 
)

Definition at line 849 of file execExpr.c.

850{
851 ExprState *result;
852 MemoryContext oldcontext;
853
854 oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
855
856 qual = (List *) expression_planner((Expr *) qual);
857
858 result = ExecInitCheck(qual, NULL);
859
860 MemoryContextSwitchTo(oldcontext);
861
862 return result;
863}
ExprState * ExecInitCheck(List *qual, PlanState *parent)
Definition execExpr.c:336
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:124
Expr * expression_planner(Expr *expr)
Definition planner.c:6819
MemoryContext es_query_cxt
Definition execnodes.h:722

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

Referenced by ExecPartitionCheck().

◆ ExecPrepareExpr()

◆ ExecPrepareExprList()

List * ExecPrepareExprList ( List nodes,
EState estate 
)

Definition at line 872 of file execExpr.c.

873{
874 List *result = NIL;
875 MemoryContext oldcontext;
876 ListCell *lc;
877
878 /* Ensure that the list cell nodes are in the right context too */
879 oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
880
881 foreach(lc, nodes)
882 {
883 Expr *e = (Expr *) lfirst(lc);
884
885 result = lappend(result, ExecPrepareExpr(e, estate));
886 }
887
888 MemoryContextSwitchTo(oldcontext);
889
890 return result;
891}
ExprState * ExecPrepareExpr(Expr *node, EState *estate)
Definition execExpr.c:786

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

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

◆ ExecPrepareExprWithContext()

ExprState * ExecPrepareExprWithContext ( Expr node,
EState estate,
Node escontext 
)

Definition at line 798 of file execExpr.c.

799{
800 ExprState *result;
801 MemoryContext oldcontext;
802
803 oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
804
805 node = expression_planner(node);
806
807 result = ExecInitExprWithContext(node, NULL, escontext);
808
809 MemoryContextSwitchTo(oldcontext);
810
811 return result;
812}

References EState::es_query_cxt, ExecInitExprWithContext(), expression_planner(), fb(), and MemoryContextSwitchTo().

Referenced by ATExecAddColumn(), and ExecPrepareExpr().

◆ ExecPrepareQual()

ExprState * ExecPrepareQual ( List qual,
EState estate 
)

Definition at line 826 of file execExpr.c.

827{
828 ExprState *result;
829 MemoryContext oldcontext;
830
831 oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
832
833 qual = (List *) expression_planner((Expr *) qual);
834
835 result = ExecInitQual(qual, NULL);
836
837 MemoryContextSwitchTo(oldcontext);
838
839 return result;
840}
ExprState * ExecInitQual(List *qual, PlanState *parent)
Definition execExpr.c:250

References EState::es_query_cxt, ExecInitQual(), expression_planner(), fb(), 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 2925 of file execExpr.c.

2926{
2927 ExprEvalStep scratch = {0};
2928 ListCell *lc;
2929
2930 scratch.resvalue = NULL;
2931 scratch.resnull = NULL;
2932
2933 /*
2934 * Add steps deforming the ExprState's inner/outer/scan/old/new slots as
2935 * much as required by any Vars appearing in the expression.
2936 */
2937 if (info->last_inner > 0)
2938 {
2940 scratch.d.fetch.last_var = info->last_inner;
2941 scratch.d.fetch.fixed = false;
2942 scratch.d.fetch.kind = NULL;
2943 scratch.d.fetch.known_desc = NULL;
2946 }
2947 if (info->last_outer > 0)
2948 {
2950 scratch.d.fetch.last_var = info->last_outer;
2951 scratch.d.fetch.fixed = false;
2952 scratch.d.fetch.kind = NULL;
2953 scratch.d.fetch.known_desc = NULL;
2956 }
2957 if (info->last_scan > 0)
2958 {
2960 scratch.d.fetch.last_var = info->last_scan;
2961 scratch.d.fetch.fixed = false;
2962 scratch.d.fetch.kind = NULL;
2963 scratch.d.fetch.known_desc = NULL;
2966 }
2967 if (info->last_old > 0)
2968 {
2969 scratch.opcode = EEOP_OLD_FETCHSOME;
2970 scratch.d.fetch.last_var = info->last_old;
2971 scratch.d.fetch.fixed = false;
2972 scratch.d.fetch.kind = NULL;
2973 scratch.d.fetch.known_desc = NULL;
2976 }
2977 if (info->last_new > 0)
2978 {
2979 scratch.opcode = EEOP_NEW_FETCHSOME;
2980 scratch.d.fetch.last_var = info->last_new;
2981 scratch.d.fetch.fixed = false;
2982 scratch.d.fetch.kind = NULL;
2983 scratch.d.fetch.known_desc = NULL;
2986 }
2987
2988 /*
2989 * Add steps to execute any MULTIEXPR SubPlans appearing in the
2990 * expression. We need to evaluate these before any of the Params
2991 * referencing their outputs are used, but after we've prepared for any
2992 * Var references they may contain. (There cannot be cross-references
2993 * between MULTIEXPR SubPlans, so we needn't worry about their order.)
2994 */
2995 foreach(lc, info->multiexpr_subplans)
2996 {
2997 SubPlan *subplan = (SubPlan *) lfirst(lc);
2998
3000
3001 /* The result can be ignored, but we better put it somewhere */
3002 ExecInitSubPlanExpr(subplan, state,
3003 &state->resvalue, &state->resnull);
3004 }
3005}
AttrNumber last_inner
Definition execExpr.c:62
AttrNumber last_new
Definition execExpr.c:66
List * multiexpr_subplans
Definition execExpr.c:68
AttrNumber last_scan
Definition execExpr.c:64
AttrNumber last_outer
Definition execExpr.c:63
AttrNumber last_old
Definition execExpr.c:65

References Assert, EEOP_INNER_FETCHSOME, EEOP_NEW_FETCHSOME, EEOP_OLD_FETCHSOME, EEOP_OUTER_FETCHSOME, EEOP_SCAN_FETCHSOME, ExecComputeSlotInfo(), ExecInitSubPlanExpr(), ExprEvalPushStep(), fb(), ExprSetupInfo::last_inner, ExprSetupInfo::last_new, ExprSetupInfo::last_old, ExprSetupInfo::last_outer, ExprSetupInfo::last_scan, lfirst, MULTIEXPR_SUBLINK, ExprSetupInfo::multiexpr_subplans, and SubPlan::subLinkType.

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

◆ ExecReadyExpr()

◆ expr_setup_walker()

static bool expr_setup_walker ( Node node,
ExprSetupInfo info 
)
static

Definition at line 3011 of file execExpr.c.

3012{
3013 if (node == NULL)
3014 return false;
3015 if (IsA(node, Var))
3016 {
3017 Var *variable = (Var *) node;
3018 AttrNumber attnum = variable->varattno;
3019
3020 switch (variable->varno)
3021 {
3022 case INNER_VAR:
3023 info->last_inner = Max(info->last_inner, attnum);
3024 break;
3025
3026 case OUTER_VAR:
3027 info->last_outer = Max(info->last_outer, attnum);
3028 break;
3029
3030 /* INDEX_VAR is handled by default case */
3031
3032 default:
3033 switch (variable->varreturningtype)
3034 {
3036 info->last_scan = Max(info->last_scan, attnum);
3037 break;
3038 case VAR_RETURNING_OLD:
3039 info->last_old = Max(info->last_old, attnum);
3040 break;
3041 case VAR_RETURNING_NEW:
3042 info->last_new = Max(info->last_new, attnum);
3043 break;
3044 }
3045 break;
3046 }
3047 return false;
3048 }
3049
3050 /* Collect all MULTIEXPR SubPlans, too */
3051 if (IsA(node, SubPlan))
3052 {
3053 SubPlan *subplan = (SubPlan *) node;
3054
3055 if (subplan->subLinkType == MULTIEXPR_SUBLINK)
3057 subplan);
3058 }
3059
3060 /*
3061 * Don't examine the arguments or filters of Aggrefs or WindowFuncs,
3062 * because those do not represent expressions to be evaluated within the
3063 * calling expression's econtext. GroupingFunc arguments are never
3064 * evaluated at all.
3065 */
3066 if (IsA(node, Aggref))
3067 return false;
3068 if (IsA(node, WindowFunc))
3069 return false;
3070 if (IsA(node, GroupingFunc))
3071 return false;
3072 return expression_tree_walker(node, expr_setup_walker, info);
3073}
#define expression_tree_walker(n, w, c)
Definition nodeFuncs.h:153

References attnum, expr_setup_walker(), expression_tree_walker, fb(), INNER_VAR, IsA, lappend(), ExprSetupInfo::last_inner, ExprSetupInfo::last_new, ExprSetupInfo::last_old, ExprSetupInfo::last_outer, ExprSetupInfo::last_scan, Max, MULTIEXPR_SUBLINK, ExprSetupInfo::multiexpr_subplans, OUTER_VAR, SubPlan::subLinkType, VAR_RETURNING_DEFAULT, VAR_RETURNING_NEW, and VAR_RETURNING_OLD.

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

◆ ExprEvalPushStep()

◆ isAssignmentIndirectionExpr()

static bool isAssignmentIndirectionExpr ( Expr expr)
static

Definition at line 3513 of file execExpr.c.

3514{
3515 if (expr == NULL)
3516 return false; /* just paranoia */
3517 if (IsA(expr, FieldStore))
3518 {
3519 FieldStore *fstore = (FieldStore *) expr;
3520
3521 if (fstore->arg && IsA(fstore->arg, CaseTestExpr))
3522 return true;
3523 }
3524 else if (IsA(expr, SubscriptingRef))
3525 {
3527
3528 if (sbsRef->refexpr && IsA(sbsRef->refexpr, CaseTestExpr))
3529 return true;
3530 }
3531 else if (IsA(expr, CoerceToDomain))
3532 {
3533 CoerceToDomain *cd = (CoerceToDomain *) expr;
3534
3535 return isAssignmentIndirectionExpr(cd->arg);
3536 }
3537 else if (IsA(expr, RelabelType))
3538 {
3539 RelabelType *r = (RelabelType *) expr;
3540
3542 }
3543 return false;
3544}

References FieldStore::arg, RelabelType::arg, CoerceToDomain::arg, fb(), IsA, and isAssignmentIndirectionExpr().

Referenced by ExecInitSubscriptingRef(), and isAssignmentIndirectionExpr().