PostgreSQL Source Code git master
execExpr.c File Reference
#include "postgres.h"
#include "access/nbtree.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "executor/execExpr.h"
#include "executor/nodeSubplan.h"
#include "funcapi.h"
#include "jit/jit.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "nodes/subscripting.h"
#include "optimizer/optimizer.h"
#include "pgstat.h"
#include "utils/acl.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/jsonfuncs.h"
#include "utils/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)
 
ExprStateExecInitExprWithParams (Expr *node, ParamListInfo ext_params)
 
ExprStateExecInitQual (List *qual, PlanState *parent)
 
ExprStateExecInitCheck (List *qual, PlanState *parent)
 
ListExecInitExprList (List *nodes, PlanState *parent)
 
ProjectionInfoExecBuildProjectionInfo (List *targetList, ExprContext *econtext, TupleTableSlot *slot, PlanState *parent, TupleDesc inputDesc)
 
ProjectionInfoExecBuildUpdateProjection (List *targetList, bool evalTargetList, List *targetColnos, TupleDesc relDesc, ExprContext *econtext, TupleTableSlot *slot, PlanState *parent)
 
ExprStateExecPrepareExpr (Expr *node, EState *estate)
 
ExprStateExecPrepareQual (List *qual, EState *estate)
 
ExprStateExecPrepareCheck (List *qual, EState *estate)
 
ListExecPrepareExprList (List *nodes, EState *estate)
 
bool ExecCheck (ExprState *state, ExprContext *econtext)
 
void ExprEvalPushStep (ExprState *es, const ExprEvalStep *s)
 
ExprStateExecBuildAggTrans (AggState *aggstate, AggStatePerPhase phase, bool doSort, bool doHash, bool nullcheck)
 
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, bool keep_nulls)
 
ExprStateExecBuildGroupingEqual (TupleDesc ldesc, TupleDesc rdesc, const TupleTableSlotOps *lops, const TupleTableSlotOps *rops, int numCols, const AttrNumber *keyColIdx, const Oid *eqfunctions, const Oid *collations, PlanState *parent)
 
ExprStateExecBuildParamSetEqual (TupleDesc desc, const TupleTableSlotOps *lops, const TupleTableSlotOps *rops, const Oid *eqfunctions, const Oid *collations, const List *param_exprs, PlanState *parent)
 

Typedef Documentation

◆ ExprSetupInfo

typedef struct ExprSetupInfo ExprSetupInfo

Function Documentation

◆ ExecBuildAggTrans()

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

Definition at line 3669 of file execExpr.c.

3671{
3673 PlanState *parent = &aggstate->ss.ps;
3674 ExprEvalStep scratch = {0};
3675 bool isCombine = DO_AGGSPLIT_COMBINE(aggstate->aggsplit);
3676 ExprSetupInfo deform = {0, 0, 0, 0, 0, NIL};
3677
3678 state->expr = (Expr *) aggstate;
3679 state->parent = parent;
3680
3681 scratch.resvalue = &state->resvalue;
3682 scratch.resnull = &state->resnull;
3683
3684 /*
3685 * First figure out which slots, and how many columns from each, we're
3686 * going to need.
3687 */
3688 for (int transno = 0; transno < aggstate->numtrans; transno++)
3689 {
3690 AggStatePerTrans pertrans = &aggstate->pertrans[transno];
3691
3693 &deform);
3694 expr_setup_walker((Node *) pertrans->aggref->args,
3695 &deform);
3696 expr_setup_walker((Node *) pertrans->aggref->aggorder,
3697 &deform);
3699 &deform);
3700 expr_setup_walker((Node *) pertrans->aggref->aggfilter,
3701 &deform);
3702 }
3703 ExecPushExprSetupSteps(state, &deform);
3704
3705 /*
3706 * Emit instructions for each transition value / grouping set combination.
3707 */
3708 for (int transno = 0; transno < aggstate->numtrans; transno++)
3709 {
3710 AggStatePerTrans pertrans = &aggstate->pertrans[transno];
3711 FunctionCallInfo trans_fcinfo = pertrans->transfn_fcinfo;
3712 List *adjust_bailout = NIL;
3713 NullableDatum *strictargs = NULL;
3714 bool *strictnulls = NULL;
3715 int argno;
3716 ListCell *bail;
3717
3718 /*
3719 * If filter present, emit. Do so before evaluating the input, to
3720 * avoid potentially unneeded computations, or even worse, unintended
3721 * side-effects. When combining, all the necessary filtering has
3722 * already been done.
3723 */
3724 if (pertrans->aggref->aggfilter && !isCombine)
3725 {
3726 /* evaluate filter expression */
3728 &state->resvalue, &state->resnull);
3729 /* and jump out if false */
3730 scratch.opcode = EEOP_JUMP_IF_NOT_TRUE;
3731 scratch.d.jump.jumpdone = -1; /* adjust later */
3732 ExprEvalPushStep(state, &scratch);
3733 adjust_bailout = lappend_int(adjust_bailout,
3734 state->steps_len - 1);
3735 }
3736
3737 /*
3738 * Evaluate arguments to aggregate/combine function.
3739 */
3740 argno = 0;
3741 if (isCombine)
3742 {
3743 /*
3744 * Combining two aggregate transition values. Instead of directly
3745 * coming from a tuple the input is a, potentially deserialized,
3746 * transition value.
3747 */
3748 TargetEntry *source_tle;
3749
3750 Assert(pertrans->numSortCols == 0);
3751 Assert(list_length(pertrans->aggref->args) == 1);
3752
3753 strictargs = trans_fcinfo->args + 1;
3754 source_tle = (TargetEntry *) linitial(pertrans->aggref->args);
3755
3756 /*
3757 * deserialfn_oid will be set if we must deserialize the input
3758 * state before calling the combine function.
3759 */
3760 if (!OidIsValid(pertrans->deserialfn_oid))
3761 {
3762 /*
3763 * Start from 1, since the 0th arg will be the transition
3764 * value
3765 */
3766 ExecInitExprRec(source_tle->expr, state,
3767 &trans_fcinfo->args[argno + 1].value,
3768 &trans_fcinfo->args[argno + 1].isnull);
3769 }
3770 else
3771 {
3772 FunctionCallInfo ds_fcinfo = pertrans->deserialfn_fcinfo;
3773
3774 /* evaluate argument */
3775 ExecInitExprRec(source_tle->expr, state,
3776 &ds_fcinfo->args[0].value,
3777 &ds_fcinfo->args[0].isnull);
3778
3779 /* Dummy second argument for type-safety reasons */
3780 ds_fcinfo->args[1].value = PointerGetDatum(NULL);
3781 ds_fcinfo->args[1].isnull = false;
3782
3783 /*
3784 * Don't call a strict deserialization function with NULL
3785 * input
3786 */
3787 if (pertrans->deserialfn.fn_strict)
3789 else
3790 scratch.opcode = EEOP_AGG_DESERIALIZE;
3791
3792 scratch.d.agg_deserialize.fcinfo_data = ds_fcinfo;
3793 scratch.d.agg_deserialize.jumpnull = -1; /* adjust later */
3794 scratch.resvalue = &trans_fcinfo->args[argno + 1].value;
3795 scratch.resnull = &trans_fcinfo->args[argno + 1].isnull;
3796
3797 ExprEvalPushStep(state, &scratch);
3798 /* don't add an adjustment unless the function is strict */
3799 if (pertrans->deserialfn.fn_strict)
3800 adjust_bailout = lappend_int(adjust_bailout,
3801 state->steps_len - 1);
3802
3803 /* restore normal settings of scratch fields */
3804 scratch.resvalue = &state->resvalue;
3805 scratch.resnull = &state->resnull;
3806 }
3807 argno++;
3808
3809 Assert(pertrans->numInputs == argno);
3810 }
3811 else if (!pertrans->aggsortrequired)
3812 {
3813 ListCell *arg;
3814
3815 /*
3816 * Normal transition function without ORDER BY / DISTINCT or with
3817 * ORDER BY / DISTINCT but the planner has given us pre-sorted
3818 * input.
3819 */
3820 strictargs = trans_fcinfo->args + 1;
3821
3822 foreach(arg, pertrans->aggref->args)
3823 {
3824 TargetEntry *source_tle = (TargetEntry *) lfirst(arg);
3825
3826 /*
3827 * Don't initialize args for any ORDER BY clause that might
3828 * exist in a presorted aggregate.
3829 */
3830 if (argno == pertrans->numTransInputs)
3831 break;
3832
3833 /*
3834 * Start from 1, since the 0th arg will be the transition
3835 * value
3836 */
3837 ExecInitExprRec(source_tle->expr, state,
3838 &trans_fcinfo->args[argno + 1].value,
3839 &trans_fcinfo->args[argno + 1].isnull);
3840 argno++;
3841 }
3842 Assert(pertrans->numTransInputs == argno);
3843 }
3844 else if (pertrans->numInputs == 1)
3845 {
3846 /*
3847 * Non-presorted DISTINCT and/or ORDER BY case, with a single
3848 * column sorted on.
3849 */
3850 TargetEntry *source_tle =
3851 (TargetEntry *) linitial(pertrans->aggref->args);
3852
3853 Assert(list_length(pertrans->aggref->args) == 1);
3854
3855 ExecInitExprRec(source_tle->expr, state,
3856 &state->resvalue,
3857 &state->resnull);
3858 strictnulls = &state->resnull;
3859 argno++;
3860
3861 Assert(pertrans->numInputs == argno);
3862 }
3863 else
3864 {
3865 /*
3866 * Non-presorted DISTINCT and/or ORDER BY case, with multiple
3867 * columns sorted on.
3868 */
3869 Datum *values = pertrans->sortslot->tts_values;
3870 bool *nulls = pertrans->sortslot->tts_isnull;
3871 ListCell *arg;
3872
3873 strictnulls = nulls;
3874
3875 foreach(arg, pertrans->aggref->args)
3876 {
3877 TargetEntry *source_tle = (TargetEntry *) lfirst(arg);
3878
3879 ExecInitExprRec(source_tle->expr, state,
3880 &values[argno], &nulls[argno]);
3881 argno++;
3882 }
3883 Assert(pertrans->numInputs == argno);
3884 }
3885
3886 /*
3887 * For a strict transfn, nothing happens when there's a NULL input; we
3888 * just keep the prior transValue. This is true for both plain and
3889 * sorted/distinct aggregates.
3890 */
3891 if (trans_fcinfo->flinfo->fn_strict && pertrans->numTransInputs > 0)
3892 {
3893 if (strictnulls)
3895 else
3897 scratch.d.agg_strict_input_check.nulls = strictnulls;
3898 scratch.d.agg_strict_input_check.args = strictargs;
3899 scratch.d.agg_strict_input_check.jumpnull = -1; /* adjust later */
3900 scratch.d.agg_strict_input_check.nargs = pertrans->numTransInputs;
3901 ExprEvalPushStep(state, &scratch);
3902 adjust_bailout = lappend_int(adjust_bailout,
3903 state->steps_len - 1);
3904 }
3905
3906 /* Handle DISTINCT aggregates which have pre-sorted input */
3907 if (pertrans->numDistinctCols > 0 && !pertrans->aggsortrequired)
3908 {
3909 if (pertrans->numDistinctCols > 1)
3911 else
3913
3914 scratch.d.agg_presorted_distinctcheck.pertrans = pertrans;
3915 scratch.d.agg_presorted_distinctcheck.jumpdistinct = -1; /* adjust later */
3916 ExprEvalPushStep(state, &scratch);
3917 adjust_bailout = lappend_int(adjust_bailout,
3918 state->steps_len - 1);
3919 }
3920
3921 /*
3922 * Call transition function (once for each concurrently evaluated
3923 * grouping set). Do so for both sort and hash based computations, as
3924 * applicable.
3925 */
3926 if (doSort)
3927 {
3928 int processGroupingSets = Max(phase->numsets, 1);
3929 int setoff = 0;
3930
3931 for (int setno = 0; setno < processGroupingSets; setno++)
3932 {
3933 ExecBuildAggTransCall(state, aggstate, &scratch, trans_fcinfo,
3934 pertrans, transno, setno, setoff, false,
3935 nullcheck);
3936 setoff++;
3937 }
3938 }
3939
3940 if (doHash)
3941 {
3942 int numHashes = aggstate->num_hashes;
3943 int setoff;
3944
3945 /* in MIXED mode, there'll be preceding transition values */
3946 if (aggstate->aggstrategy != AGG_HASHED)
3947 setoff = aggstate->maxsets;
3948 else
3949 setoff = 0;
3950
3951 for (int setno = 0; setno < numHashes; setno++)
3952 {
3953 ExecBuildAggTransCall(state, aggstate, &scratch, trans_fcinfo,
3954 pertrans, transno, setno, setoff, true,
3955 nullcheck);
3956 setoff++;
3957 }
3958 }
3959
3960 /* adjust early bail out jump target(s) */
3961 foreach(bail, adjust_bailout)
3962 {
3963 ExprEvalStep *as = &state->steps[lfirst_int(bail)];
3964
3965 if (as->opcode == EEOP_JUMP_IF_NOT_TRUE)
3966 {
3967 Assert(as->d.jump.jumpdone == -1);
3968 as->d.jump.jumpdone = state->steps_len;
3969 }
3970 else if (as->opcode == EEOP_AGG_STRICT_INPUT_CHECK_ARGS ||
3972 {
3974 as->d.agg_strict_input_check.jumpnull = state->steps_len;
3975 }
3976 else if (as->opcode == EEOP_AGG_STRICT_DESERIALIZE)
3977 {
3978 Assert(as->d.agg_deserialize.jumpnull == -1);
3979 as->d.agg_deserialize.jumpnull = state->steps_len;
3980 }
3983 {
3986 }
3987 else
3988 Assert(false);
3989 }
3990 }
3991
3992 scratch.resvalue = NULL;
3993 scratch.resnull = NULL;
3994 scratch.opcode = EEOP_DONE;
3995 ExprEvalPushStep(state, &scratch);
3996
3998
3999 return state;
4000}
static Datum values[MAXATTR]
Definition: bootstrap.c:151
#define Max(x, y)
Definition: c.h:955
#define Assert(condition)
Definition: c.h:815
#define OidIsValid(objectId)
Definition: c.h:732
static void ExecPushExprSetupSteps(ExprState *state, ExprSetupInfo *info)
Definition: execExpr.c:2889
static void ExecInitExprRec(Expr *node, ExprState *state, Datum *resv, bool *resnull)
Definition: execExpr.c:919
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:4008
void ExprEvalPushStep(ExprState *es, const ExprEvalStep *s)
Definition: execExpr.c:2678
static bool expr_setup_walker(Node *node, ExprSetupInfo *info)
Definition: execExpr.c:2975
static void ExecReadyExpr(ExprState *state)
Definition: execExpr.c:902
@ EEOP_AGG_STRICT_DESERIALIZE
Definition: execExpr.h:273
@ EEOP_DONE
Definition: execExpr.h:69
@ EEOP_AGG_PRESORTED_DISTINCT_MULTI
Definition: execExpr.h:285
@ EEOP_AGG_STRICT_INPUT_CHECK_NULLS
Definition: execExpr.h:276
@ EEOP_AGG_STRICT_INPUT_CHECK_ARGS
Definition: execExpr.h:275
@ EEOP_AGG_DESERIALIZE
Definition: execExpr.h:274
@ EEOP_JUMP_IF_NOT_TRUE
Definition: execExpr.h:151
@ EEOP_AGG_PRESORTED_DISTINCT_SINGLE
Definition: execExpr.h:284
List * lappend_int(List *list, int datum)
Definition: list.c:357
#define DO_AGGSPLIT_COMBINE(as)
Definition: nodes.h:385
@ AGG_HASHED
Definition: nodes.h:356
#define makeNode(_type_)
Definition: nodes.h:155
void * arg
#define lfirst(lc)
Definition: pg_list.h:172
static int list_length(const List *l)
Definition: pg_list.h:152
#define NIL
Definition: pg_list.h:68
#define lfirst_int(lc)
Definition: pg_list.h:173
#define linitial(l)
Definition: pg_list.h:178
#define bail(...)
Definition: pg_regress.c:167
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:327
uintptr_t Datum
Definition: postgres.h:69
TupleTableSlot * sortslot
Definition: nodeAgg.h:141
Aggref * aggref
Definition: nodeAgg.h:44
FmgrInfo deserialfn
Definition: nodeAgg.h:92
FunctionCallInfo deserialfn_fcinfo
Definition: nodeAgg.h:175
FunctionCallInfo transfn_fcinfo
Definition: nodeAgg.h:170
ScanState ss
Definition: execnodes.h:2530
AggStatePerTrans pertrans
Definition: execnodes.h:2540
AggStrategy aggstrategy
Definition: execnodes.h:2534
int numtrans
Definition: execnodes.h:2533
AggSplit aggsplit
Definition: execnodes.h:2535
int num_hashes
Definition: execnodes.h:2571
int maxsets
Definition: execnodes.h:2560
List * aggdistinct
Definition: primnodes.h:491
List * aggdirectargs
Definition: primnodes.h:482
List * args
Definition: primnodes.h:485
Expr * aggfilter
Definition: primnodes.h:494
List * aggorder
Definition: primnodes.h:488
struct ExprEvalStep::@55::@66 jump
AggStatePerTrans pertrans
Definition: execExpr.h:725
intptr_t opcode
Definition: execExpr.h:301
NullableDatum * args
Definition: execExpr.h:709
bool * nulls
Definition: execExpr.h:525
Datum * resvalue
Definition: execExpr.h:304
int jumpnull
Definition: execExpr.h:509
FunctionCallInfo fcinfo_data
Definition: execExpr.h:383
int jumpdistinct
Definition: execExpr.h:727
struct ExprEvalStep::@55::@97 agg_deserialize
int jumpdone
Definition: execExpr.h:368
union ExprEvalStep::@55 d
struct ExprEvalStep::@55::@98 agg_strict_input_check
struct ExprEvalStep::@55::@100 agg_presorted_distinctcheck
bool * resnull
Definition: execExpr.h:305
bool fn_strict
Definition: fmgr.h:61
FmgrInfo * flinfo
Definition: fmgr.h:87
NullableDatum args[FLEXIBLE_ARRAY_MEMBER]
Definition: fmgr.h:95
Definition: pg_list.h:54
Definition: nodes.h:129
Datum value
Definition: postgres.h:80
bool isnull
Definition: postgres.h:82
PlanState ps
Definition: execnodes.h:1609
Expr * expr
Definition: primnodes.h:2219
bool * tts_isnull
Definition: tuptable.h:127
Datum * tts_values
Definition: tuptable.h:125
Definition: regguts.h:323

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

Referenced by ExecInitAgg(), and hashagg_recompile_expressions().

◆ ExecBuildAggTransCall()

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

Definition at line 4008 of file execExpr.c.

4013{
4014 ExprContext *aggcontext;
4015 int adjust_jumpnull = -1;
4016
4017 if (ishash)
4018 aggcontext = aggstate->hashcontext;
4019 else
4020 aggcontext = aggstate->aggcontexts[setno];
4021
4022 /* add check for NULL pointer? */
4023 if (nullcheck)
4024 {
4026 scratch->d.agg_plain_pergroup_nullcheck.setoff = setoff;
4027 /* adjust later */
4029 ExprEvalPushStep(state, scratch);
4030 adjust_jumpnull = state->steps_len - 1;
4031 }
4032
4033 /*
4034 * Determine appropriate transition implementation.
4035 *
4036 * For non-ordered aggregates and ORDER BY / DISTINCT aggregates with
4037 * presorted input:
4038 *
4039 * If the initial value for the transition state doesn't exist in the
4040 * pg_aggregate table then we will let the first non-NULL value returned
4041 * from the outer procNode become the initial value. (This is useful for
4042 * aggregates like max() and min().) The noTransValue flag signals that we
4043 * need to do so. If true, generate a
4044 * EEOP_AGG_INIT_STRICT_PLAIN_TRANS{,_BYVAL} step. This step also needs to
4045 * do the work described next:
4046 *
4047 * If the function is strict, but does have an initial value, choose
4048 * EEOP_AGG_STRICT_PLAIN_TRANS{,_BYVAL}, which skips the transition
4049 * function if the transition value has become NULL (because a previous
4050 * transition function returned NULL). This step also needs to do the work
4051 * described next:
4052 *
4053 * Otherwise we call EEOP_AGG_PLAIN_TRANS{,_BYVAL}, which does not have to
4054 * perform either of the above checks.
4055 *
4056 * Having steps with overlapping responsibilities is not nice, but
4057 * aggregations are very performance sensitive, making this worthwhile.
4058 *
4059 * For ordered aggregates:
4060 *
4061 * Only need to choose between the faster path for a single ordered
4062 * column, and the one between multiple columns. Checking strictness etc
4063 * is done when finalizing the aggregate. See
4064 * process_ordered_aggregate_{single, multi} and
4065 * advance_transition_function.
4066 */
4067 if (!pertrans->aggsortrequired)
4068 {
4069 if (pertrans->transtypeByVal)
4070 {
4071 if (fcinfo->flinfo->fn_strict &&
4072 pertrans->initValueIsNull)
4074 else if (fcinfo->flinfo->fn_strict)
4076 else
4078 }
4079 else
4080 {
4081 if (fcinfo->flinfo->fn_strict &&
4082 pertrans->initValueIsNull)
4084 else if (fcinfo->flinfo->fn_strict)
4086 else
4088 }
4089 }
4090 else if (pertrans->numInputs == 1)
4092 else
4094
4095 scratch->d.agg_trans.pertrans = pertrans;
4096 scratch->d.agg_trans.setno = setno;
4097 scratch->d.agg_trans.setoff = setoff;
4098 scratch->d.agg_trans.transno = transno;
4099 scratch->d.agg_trans.aggcontext = aggcontext;
4100 ExprEvalPushStep(state, scratch);
4101
4102 /* fix up jumpnull */
4103 if (adjust_jumpnull != -1)
4104 {
4105 ExprEvalStep *as = &state->steps[adjust_jumpnull];
4106
4110 }
4111}
@ EEOP_AGG_PLAIN_PERGROUP_NULLCHECK
Definition: execExpr.h:277
@ EEOP_AGG_PLAIN_TRANS_BYREF
Definition: execExpr.h:283
@ EEOP_AGG_PLAIN_TRANS_BYVAL
Definition: execExpr.h:280
@ EEOP_AGG_ORDERED_TRANS_DATUM
Definition: execExpr.h:286
@ EEOP_AGG_PLAIN_TRANS_STRICT_BYREF
Definition: execExpr.h:282
@ EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL
Definition: execExpr.h:278
@ EEOP_AGG_PLAIN_TRANS_STRICT_BYVAL
Definition: execExpr.h:279
@ EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYREF
Definition: execExpr.h:281
@ EEOP_AGG_ORDERED_TRANS_TUPLE
Definition: execExpr.h:287
ExprContext * hashcontext
Definition: execnodes.h:2541
ExprContext ** aggcontexts
Definition: execnodes.h:2542
struct ExprEvalStep::@55::@99 agg_plain_pergroup_nullcheck
struct ExprEvalStep::@55::@101 agg_trans
ExprContext * aggcontext
Definition: execExpr.h:726

References ExprEvalStep::agg_plain_pergroup_nullcheck, ExprEvalStep::agg_trans, ExprEvalStep::aggcontext, AggState::aggcontexts, AggStatePerTransData::aggsortrequired, Assert, ExprEvalStep::d, EEOP_AGG_ORDERED_TRANS_DATUM, EEOP_AGG_ORDERED_TRANS_TUPLE, EEOP_AGG_PLAIN_PERGROUP_NULLCHECK, EEOP_AGG_PLAIN_TRANS_BYREF, EEOP_AGG_PLAIN_TRANS_BYVAL, EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYREF, EEOP_AGG_PLAIN_TRANS_INIT_STRICT_BYVAL, EEOP_AGG_PLAIN_TRANS_STRICT_BYREF, EEOP_AGG_PLAIN_TRANS_STRICT_BYVAL, ExprEvalPushStep(), FunctionCallInfoBaseData::flinfo, FmgrInfo::fn_strict, AggState::hashcontext, AggStatePerTransData::initValueIsNull, ExprEvalStep::jumpnull, AggStatePerTransData::numInputs, ExprEvalStep::opcode, ExprEvalStep::pertrans, ExprEvalStep::setno, ExprEvalStep::setoff, ExprEvalStep::transno, 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 4454 of file execExpr.c.

4461{
4463 ExprEvalStep scratch = {0};
4464 int maxatt = -1;
4465 List *adjust_jumps = NIL;
4466 ListCell *lc;
4467
4468 /*
4469 * When no columns are actually compared, the result's always true. See
4470 * special case in ExecQual().
4471 */
4472 if (numCols == 0)
4473 return NULL;
4474
4475 state->expr = NULL;
4476 state->flags = EEO_FLAG_IS_QUAL;
4477 state->parent = parent;
4478
4479 scratch.resvalue = &state->resvalue;
4480 scratch.resnull = &state->resnull;
4481
4482 /* compute max needed attribute */
4483 for (int natt = 0; natt < numCols; natt++)
4484 {
4485 int attno = keyColIdx[natt];
4486
4487 if (attno > maxatt)
4488 maxatt = attno;
4489 }
4490 Assert(maxatt >= 0);
4491
4492 /* push deform steps */
4493 scratch.opcode = EEOP_INNER_FETCHSOME;
4494 scratch.d.fetch.last_var = maxatt;
4495 scratch.d.fetch.fixed = false;
4496 scratch.d.fetch.known_desc = ldesc;
4497 scratch.d.fetch.kind = lops;
4498 if (ExecComputeSlotInfo(state, &scratch))
4499 ExprEvalPushStep(state, &scratch);
4500
4501 scratch.opcode = EEOP_OUTER_FETCHSOME;
4502 scratch.d.fetch.last_var = maxatt;
4503 scratch.d.fetch.fixed = false;
4504 scratch.d.fetch.known_desc = rdesc;
4505 scratch.d.fetch.kind = rops;
4506 if (ExecComputeSlotInfo(state, &scratch))
4507 ExprEvalPushStep(state, &scratch);
4508
4509 /*
4510 * Start comparing at the last field (least significant sort key). That's
4511 * the most likely to be different if we are dealing with sorted input.
4512 */
4513 for (int natt = numCols; --natt >= 0;)
4514 {
4515 int attno = keyColIdx[natt];
4516 Form_pg_attribute latt = TupleDescAttr(ldesc, attno - 1);
4517 Form_pg_attribute ratt = TupleDescAttr(rdesc, attno - 1);
4518 Oid foid = eqfunctions[natt];
4519 Oid collid = collations[natt];
4520 FmgrInfo *finfo;
4521 FunctionCallInfo fcinfo;
4522 AclResult aclresult;
4523
4524 /* Check permission to call function */
4525 aclresult = object_aclcheck(ProcedureRelationId, foid, GetUserId(), ACL_EXECUTE);
4526 if (aclresult != ACLCHECK_OK)
4527 aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(foid));
4528
4530
4531 /* Set up the primary fmgr lookup information */
4532 finfo = palloc0(sizeof(FmgrInfo));
4533 fcinfo = palloc0(SizeForFunctionCallInfo(2));
4534 fmgr_info(foid, finfo);
4535 fmgr_info_set_expr(NULL, finfo);
4536 InitFunctionCallInfoData(*fcinfo, finfo, 2,
4537 collid, NULL, NULL);
4538
4539 /* left arg */
4540 scratch.opcode = EEOP_INNER_VAR;
4541 scratch.d.var.attnum = attno - 1;
4542 scratch.d.var.vartype = latt->atttypid;
4544 scratch.resvalue = &fcinfo->args[0].value;
4545 scratch.resnull = &fcinfo->args[0].isnull;
4546 ExprEvalPushStep(state, &scratch);
4547
4548 /* right arg */
4549 scratch.opcode = EEOP_OUTER_VAR;
4550 scratch.d.var.attnum = attno - 1;
4551 scratch.d.var.vartype = ratt->atttypid;
4553 scratch.resvalue = &fcinfo->args[1].value;
4554 scratch.resnull = &fcinfo->args[1].isnull;
4555 ExprEvalPushStep(state, &scratch);
4556
4557 /* evaluate distinctness */
4558 scratch.opcode = EEOP_NOT_DISTINCT;
4559 scratch.d.func.finfo = finfo;
4560 scratch.d.func.fcinfo_data = fcinfo;
4561 scratch.d.func.fn_addr = finfo->fn_addr;
4562 scratch.d.func.nargs = 2;
4563 scratch.resvalue = &state->resvalue;
4564 scratch.resnull = &state->resnull;
4565 ExprEvalPushStep(state, &scratch);
4566
4567 /* then emit EEOP_QUAL to detect if result is false (or null) */
4568 scratch.opcode = EEOP_QUAL;
4569 scratch.d.qualexpr.jumpdone = -1;
4570 scratch.resvalue = &state->resvalue;
4571 scratch.resnull = &state->resnull;
4572 ExprEvalPushStep(state, &scratch);
4573 adjust_jumps = lappend_int(adjust_jumps,
4574 state->steps_len - 1);
4575 }
4576
4577 /* adjust jump targets */
4578 foreach(lc, adjust_jumps)
4579 {
4580 ExprEvalStep *as = &state->steps[lfirst_int(lc)];
4581
4582 Assert(as->opcode == EEOP_QUAL);
4583 Assert(as->d.qualexpr.jumpdone == -1);
4584 as->d.qualexpr.jumpdone = state->steps_len;
4585 }
4586
4587 scratch.resvalue = NULL;
4588 scratch.resnull = NULL;
4589 scratch.opcode = EEOP_DONE;
4590 ExprEvalPushStep(state, &scratch);
4591
4593
4594 return state;
4595}
AclResult
Definition: acl.h:182
@ ACLCHECK_OK
Definition: acl.h:183
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:2622
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition: aclchk.c:3804
Oid collid
static bool ExecComputeSlotInfo(ExprState *state, ExprEvalStep *op)
Definition: execExpr.c:3054
@ EEOP_NOT_DISTINCT
Definition: execExpr.h:185
@ EEOP_INNER_VAR
Definition: execExpr.h:79
@ EEOP_QUAL
Definition: execExpr.h:143
@ EEOP_INNER_FETCHSOME
Definition: execExpr.h:72
@ EEOP_OUTER_FETCHSOME
Definition: execExpr.h:73
@ EEOP_OUTER_VAR
Definition: execExpr.h:80
#define EEO_FLAG_IS_QUAL
Definition: execnodes.h:77
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition: fmgr.c:127
#define SizeForFunctionCallInfo(nargs)
Definition: fmgr.h:102
#define InitFunctionCallInfoData(Fcinfo, Flinfo, Nargs, Collation, Context, Resultinfo)
Definition: fmgr.h:150
#define fmgr_info_set_expr(expr, finfo)
Definition: fmgr.h:135
char * get_func_name(Oid funcid)
Definition: lsyscache.c:1635
void * palloc0(Size size)
Definition: mcxt.c:1347
Oid GetUserId(void)
Definition: miscinit.c:517
#define InvokeFunctionExecuteHook(objectId)
Definition: objectaccess.h:213
@ OBJECT_FUNCTION
Definition: parsenodes.h:2331
#define ACL_EXECUTE
Definition: parsenodes.h:83
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:200
unsigned int Oid
Definition: postgres_ext.h:32
@ VAR_RETURNING_DEFAULT
Definition: primnodes.h:256
int last_var
Definition: execExpr.h:319
struct ExprEvalStep::@55::@57 var
VarReturningType varreturningtype
Definition: execExpr.h:335
PGFunction fn_addr
Definition: execExpr.h:385
TupleDesc known_desc
Definition: execExpr.h:323
const TupleTableSlotOps * kind
Definition: execExpr.h:325
bool fixed
Definition: execExpr.h:321
struct ExprEvalStep::@55::@65 qualexpr
struct ExprEvalStep::@55::@63 func
FmgrInfo * finfo
Definition: execExpr.h:382
struct ExprEvalStep::@55::@56 fetch
Definition: fmgr.h:57
PGFunction fn_addr
Definition: fmgr.h:58
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition: tupdesc.h:154

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

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,
bool  keep_nulls 
)

Definition at line 4289 of file execExpr.c.

4293{
4295 ExprEvalStep scratch = {0};
4296 NullableDatum *iresult = NULL;
4297 List *adjust_jumps = NIL;
4298 ListCell *lc;
4299 ListCell *lc2;
4300 intptr_t strict_opcode;
4301 intptr_t opcode;
4302 int num_exprs = list_length(hash_exprs);
4303
4304 Assert(num_exprs == list_length(collations));
4305
4306 state->parent = parent;
4307
4308 /* Insert setup steps as needed. */
4309 ExecCreateExprSetupSteps(state, (Node *) hash_exprs);
4310
4311 /*
4312 * Make a place to store intermediate hash values between subsequent
4313 * hashing of individual expressions. We only need this if there is more
4314 * than one expression to hash or an initial value plus one expression.
4315 */
4316 if ((int64) num_exprs + (init_value != 0) > 1)
4317 iresult = palloc(sizeof(NullableDatum));
4318
4319 if (init_value == 0)
4320 {
4321 /*
4322 * No initial value, so we can assign the result of the hash function
4323 * for the first hash_expr without having to concern ourselves with
4324 * combining the result with any initial value.
4325 */
4326 strict_opcode = EEOP_HASHDATUM_FIRST_STRICT;
4327 opcode = EEOP_HASHDATUM_FIRST;
4328 }
4329 else
4330 {
4331 /*
4332 * Set up operation to set the initial value. Normally we store this
4333 * in the intermediate hash value location, but if there are no exprs
4334 * to hash, store it in the ExprState's result field.
4335 */
4337 scratch.d.hashdatum_initvalue.init_value = UInt32GetDatum(init_value);
4338 scratch.resvalue = num_exprs > 0 ? &iresult->value : &state->resvalue;
4339 scratch.resnull = num_exprs > 0 ? &iresult->isnull : &state->resnull;
4340
4341 ExprEvalPushStep(state, &scratch);
4342
4343 /*
4344 * When using an initial value use the NEXT32/NEXT32_STRICT ops as the
4345 * FIRST/FIRST_STRICT ops would overwrite the stored initial value.
4346 */
4347 strict_opcode = EEOP_HASHDATUM_NEXT32_STRICT;
4348 opcode = EEOP_HASHDATUM_NEXT32;
4349 }
4350
4351 forboth(lc, hash_exprs, lc2, collations)
4352 {
4353 Expr *expr = (Expr *) lfirst(lc);
4354 FmgrInfo *finfo;
4355 FunctionCallInfo fcinfo;
4356 int i = foreach_current_index(lc);
4357 Oid funcid;
4358 Oid inputcollid = lfirst_oid(lc2);
4359
4360 funcid = hashfunc_oids[i];
4361
4362 /* Allocate hash function lookup data. */
4363 finfo = palloc0(sizeof(FmgrInfo));
4364 fcinfo = palloc0(SizeForFunctionCallInfo(1));
4365
4366 fmgr_info(funcid, finfo);
4367
4368 /*
4369 * Build the steps to evaluate the hash function's argument have it so
4370 * the value of that is stored in the 0th argument of the hash func.
4371 */
4372 ExecInitExprRec(expr,
4373 state,
4374 &fcinfo->args[0].value,
4375 &fcinfo->args[0].isnull);
4376
4377 if (i == num_exprs - 1)
4378 {
4379 /* the result for hashing the final expr is stored in the state */
4380 scratch.resvalue = &state->resvalue;
4381 scratch.resnull = &state->resnull;
4382 }
4383 else
4384 {
4385 Assert(iresult != NULL);
4386
4387 /* intermediate values are stored in an intermediate result */
4388 scratch.resvalue = &iresult->value;
4389 scratch.resnull = &iresult->isnull;
4390 }
4391
4392 /*
4393 * NEXT32 opcodes need to look at the intermediate result. We might
4394 * as well just set this for all ops. FIRSTs won't look at it.
4395 */
4396 scratch.d.hashdatum.iresult = iresult;
4397
4398 /* Initialize function call parameter structure too */
4399 InitFunctionCallInfoData(*fcinfo, finfo, 1, inputcollid, NULL, NULL);
4400
4401 scratch.d.hashdatum.finfo = finfo;
4402 scratch.d.hashdatum.fcinfo_data = fcinfo;
4403 scratch.d.hashdatum.fn_addr = finfo->fn_addr;
4404
4405 scratch.opcode = opstrict[i] && !keep_nulls ? strict_opcode : opcode;
4406 scratch.d.hashdatum.jumpdone = -1;
4407
4408 ExprEvalPushStep(state, &scratch);
4409 adjust_jumps = lappend_int(adjust_jumps, state->steps_len - 1);
4410
4411 /*
4412 * For subsequent keys we must combine the hash value with the
4413 * previous hashes.
4414 */
4415 strict_opcode = EEOP_HASHDATUM_NEXT32_STRICT;
4416 opcode = EEOP_HASHDATUM_NEXT32;
4417 }
4418
4419 /* adjust jump targets */
4420 foreach(lc, adjust_jumps)
4421 {
4422 ExprEvalStep *as = &state->steps[lfirst_int(lc)];
4423
4428 Assert(as->d.hashdatum.jumpdone == -1);
4429 as->d.hashdatum.jumpdone = state->steps_len;
4430 }
4431
4432 scratch.resvalue = NULL;
4433 scratch.resnull = NULL;
4434 scratch.opcode = EEOP_DONE;
4435 ExprEvalPushStep(state, &scratch);
4436
4438
4439 return state;
4440}
int64_t int64
Definition: c.h:485
static void ExecCreateExprSetupSteps(ExprState *state, Node *node)
Definition: execExpr.c:2873
@ EEOP_HASHDATUM_NEXT32_STRICT
Definition: execExpr.h:254
@ EEOP_HASHDATUM_FIRST_STRICT
Definition: execExpr.h:252
@ EEOP_HASHDATUM_NEXT32
Definition: execExpr.h:253
@ EEOP_HASHDATUM_FIRST
Definition: execExpr.h:251
@ EEOP_HASHDATUM_SET_INITVAL
Definition: execExpr.h:250
int i
Definition: isn.c:72
void * palloc(Size size)
Definition: mcxt.c:1317
#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:237
NullableDatum * iresult
Definition: execExpr.h:604
struct ExprEvalStep::@55::@86 hashdatum_initvalue
struct ExprEvalStep::@55::@87 hashdatum
Datum init_value
Definition: execExpr.h:592

References FunctionCallInfoBaseData::args, Assert, ExprEvalStep::d, EEOP_DONE, EEOP_HASHDATUM_FIRST, EEOP_HASHDATUM_FIRST_STRICT, EEOP_HASHDATUM_NEXT32, EEOP_HASHDATUM_NEXT32_STRICT, EEOP_HASHDATUM_SET_INITVAL, ExecCreateExprSetupSteps(), ExecInitExprRec(), ExecReadyExpr(), ExprEvalPushStep(), ExprEvalStep::fcinfo_data, ExprEvalStep::finfo, fmgr_info(), ExprEvalStep::fn_addr, FmgrInfo::fn_addr, forboth, foreach_current_index, ExprEvalStep::hashdatum, ExprEvalStep::hashdatum_initvalue, i, ExprEvalStep::init_value, InitFunctionCallInfoData, ExprEvalStep::iresult, NullableDatum::isnull, ExprEvalStep::jumpdone, lappend_int(), lfirst, lfirst_int, lfirst_oid, list_length(), makeNode, NIL, ExprEvalStep::opcode, palloc(), palloc0(), ExprEvalStep::resnull, ExprEvalStep::resvalue, 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 4130 of file execExpr.c.

4134{
4136 ExprEvalStep scratch = {0};
4137 NullableDatum *iresult = NULL;
4138 intptr_t opcode;
4139 AttrNumber last_attnum = 0;
4140
4141 Assert(numCols >= 0);
4142
4143 state->parent = parent;
4144
4145 /*
4146 * Make a place to store intermediate hash values between subsequent
4147 * hashing of individual columns. We only need this if there is more than
4148 * one column to hash or an initial value plus one column.
4149 */
4150 if ((int64) numCols + (init_value != 0) > 1)
4151 iresult = palloc(sizeof(NullableDatum));
4152
4153 /* find the highest attnum so we deform the tuple to that point */
4154 for (int i = 0; i < numCols; i++)
4155 last_attnum = Max(last_attnum, keyColIdx[i]);
4156
4157 scratch.opcode = EEOP_INNER_FETCHSOME;
4158 scratch.d.fetch.last_var = last_attnum;
4159 scratch.d.fetch.fixed = false;
4160 scratch.d.fetch.kind = ops;
4161 scratch.d.fetch.known_desc = desc;
4162 if (ExecComputeSlotInfo(state, &scratch))
4163 ExprEvalPushStep(state, &scratch);
4164
4165 if (init_value == 0)
4166 {
4167 /*
4168 * No initial value, so we can assign the result of the hash function
4169 * for the first attribute without having to concern ourselves with
4170 * combining the result with any initial value.
4171 */
4172 opcode = EEOP_HASHDATUM_FIRST;
4173 }
4174 else
4175 {
4176 /*
4177 * Set up operation to set the initial value. Normally we store this
4178 * in the intermediate hash value location, but if there are no
4179 * columns to hash, store it in the ExprState's result field.
4180 */
4182 scratch.d.hashdatum_initvalue.init_value = UInt32GetDatum(init_value);
4183 scratch.resvalue = numCols > 0 ? &iresult->value : &state->resvalue;
4184 scratch.resnull = numCols > 0 ? &iresult->isnull : &state->resnull;
4185
4186 ExprEvalPushStep(state, &scratch);
4187
4188 /*
4189 * When using an initial value use the NEXT32 ops as the FIRST ops
4190 * would overwrite the stored initial value.
4191 */
4192 opcode = EEOP_HASHDATUM_NEXT32;
4193 }
4194
4195 for (int i = 0; i < numCols; i++)
4196 {
4197 FmgrInfo *finfo;
4198 FunctionCallInfo fcinfo;
4199 Oid inputcollid = collations[i];
4200 AttrNumber attnum = keyColIdx[i] - 1;
4201
4202 finfo = &hashfunctions[i];
4203 fcinfo = palloc0(SizeForFunctionCallInfo(1));
4204
4205 /* Initialize function call parameter structure too */
4206 InitFunctionCallInfoData(*fcinfo, finfo, 1, inputcollid, NULL, NULL);
4207
4208 /*
4209 * Fetch inner Var for this attnum and store it in the 1st arg of the
4210 * hash func.
4211 */
4212 scratch.opcode = EEOP_INNER_VAR;
4213 scratch.resvalue = &fcinfo->args[0].value;
4214 scratch.resnull = &fcinfo->args[0].isnull;
4215 scratch.d.var.attnum = attnum;
4216 scratch.d.var.vartype = TupleDescAttr(desc, attnum)->atttypid;
4218
4219 ExprEvalPushStep(state, &scratch);
4220
4221 /* Call the hash function */
4222 scratch.opcode = opcode;
4223
4224 if (i == numCols - 1)
4225 {
4226 /*
4227 * The result for hashing the final column is stored in the
4228 * ExprState.
4229 */
4230 scratch.resvalue = &state->resvalue;
4231 scratch.resnull = &state->resnull;
4232 }
4233 else
4234 {
4235 Assert(iresult != NULL);
4236
4237 /* intermediate values are stored in an intermediate result */
4238 scratch.resvalue = &iresult->value;
4239 scratch.resnull = &iresult->isnull;
4240 }
4241
4242 /*
4243 * NEXT32 opcodes need to look at the intermediate result. We might
4244 * as well just set this for all ops. FIRSTs won't look at it.
4245 */
4246 scratch.d.hashdatum.iresult = iresult;
4247
4248 scratch.d.hashdatum.finfo = finfo;
4249 scratch.d.hashdatum.fcinfo_data = fcinfo;
4250 scratch.d.hashdatum.fn_addr = finfo->fn_addr;
4251 scratch.d.hashdatum.jumpdone = -1;
4252
4253 ExprEvalPushStep(state, &scratch);
4254
4255 /* subsequent attnums must be combined with the previous */
4256 opcode = EEOP_HASHDATUM_NEXT32;
4257 }
4258
4259 scratch.resvalue = NULL;
4260 scratch.resnull = NULL;
4261 scratch.opcode = EEOP_DONE;
4262 ExprEvalPushStep(state, &scratch);
4263
4265
4266 return state;
4267}
int16 AttrNumber
Definition: attnum.h:21
int16 attnum
Definition: pg_attribute.h:74

References FunctionCallInfoBaseData::args, Assert, attnum, ExprEvalStep::attnum, ExprEvalStep::d, EEOP_DONE, EEOP_HASHDATUM_FIRST, EEOP_HASHDATUM_NEXT32, EEOP_HASHDATUM_SET_INITVAL, EEOP_INNER_FETCHSOME, EEOP_INNER_VAR, ExecComputeSlotInfo(), ExecReadyExpr(), ExprEvalPushStep(), ExprEvalStep::fcinfo_data, ExprEvalStep::fetch, ExprEvalStep::finfo, ExprEvalStep::fixed, ExprEvalStep::fn_addr, FmgrInfo::fn_addr, ExprEvalStep::hashdatum, ExprEvalStep::hashdatum_initvalue, i, ExprEvalStep::init_value, InitFunctionCallInfoData, ExprEvalStep::iresult, NullableDatum::isnull, ExprEvalStep::jumpdone, ExprEvalStep::kind, ExprEvalStep::known_desc, ExprEvalStep::last_var, makeNode, Max, ExprEvalStep::opcode, palloc(), palloc0(), ExprEvalStep::resnull, ExprEvalStep::resvalue, SizeForFunctionCallInfo, TupleDescAttr(), UInt32GetDatum(), NullableDatum::value, ExprEvalStep::var, VAR_RETURNING_DEFAULT, ExprEvalStep::varreturningtype, and ExprEvalStep::vartype.

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

4620{
4622 ExprEvalStep scratch = {0};
4623 int maxatt = list_length(param_exprs);
4624 List *adjust_jumps = NIL;
4625 ListCell *lc;
4626
4627 state->expr = NULL;
4628 state->flags = EEO_FLAG_IS_QUAL;
4629 state->parent = parent;
4630
4631 scratch.resvalue = &state->resvalue;
4632 scratch.resnull = &state->resnull;
4633
4634 /* push deform steps */
4635 scratch.opcode = EEOP_INNER_FETCHSOME;
4636 scratch.d.fetch.last_var = maxatt;
4637 scratch.d.fetch.fixed = false;
4638 scratch.d.fetch.known_desc = desc;
4639 scratch.d.fetch.kind = lops;
4640 if (ExecComputeSlotInfo(state, &scratch))
4641 ExprEvalPushStep(state, &scratch);
4642
4643 scratch.opcode = EEOP_OUTER_FETCHSOME;
4644 scratch.d.fetch.last_var = maxatt;
4645 scratch.d.fetch.fixed = false;
4646 scratch.d.fetch.known_desc = desc;
4647 scratch.d.fetch.kind = rops;
4648 if (ExecComputeSlotInfo(state, &scratch))
4649 ExprEvalPushStep(state, &scratch);
4650
4651 for (int attno = 0; attno < maxatt; attno++)
4652 {
4653 Form_pg_attribute att = TupleDescAttr(desc, attno);
4654 Oid foid = eqfunctions[attno];
4655 Oid collid = collations[attno];
4656 FmgrInfo *finfo;
4657 FunctionCallInfo fcinfo;
4658 AclResult aclresult;
4659
4660 /* Check permission to call function */
4661 aclresult = object_aclcheck(ProcedureRelationId, foid, GetUserId(), ACL_EXECUTE);
4662 if (aclresult != ACLCHECK_OK)
4663 aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(foid));
4664
4666
4667 /* Set up the primary fmgr lookup information */
4668 finfo = palloc0(sizeof(FmgrInfo));
4669 fcinfo = palloc0(SizeForFunctionCallInfo(2));
4670 fmgr_info(foid, finfo);
4671 fmgr_info_set_expr(NULL, finfo);
4672 InitFunctionCallInfoData(*fcinfo, finfo, 2,
4673 collid, NULL, NULL);
4674
4675 /* left arg */
4676 scratch.opcode = EEOP_INNER_VAR;
4677 scratch.d.var.attnum = attno;
4678 scratch.d.var.vartype = att->atttypid;
4680 scratch.resvalue = &fcinfo->args[0].value;
4681 scratch.resnull = &fcinfo->args[0].isnull;
4682 ExprEvalPushStep(state, &scratch);
4683
4684 /* right arg */
4685 scratch.opcode = EEOP_OUTER_VAR;
4686 scratch.d.var.attnum = attno;
4687 scratch.d.var.vartype = att->atttypid;
4689 scratch.resvalue = &fcinfo->args[1].value;
4690 scratch.resnull = &fcinfo->args[1].isnull;
4691 ExprEvalPushStep(state, &scratch);
4692
4693 /* evaluate distinctness */
4694 scratch.opcode = EEOP_NOT_DISTINCT;
4695 scratch.d.func.finfo = finfo;
4696 scratch.d.func.fcinfo_data = fcinfo;
4697 scratch.d.func.fn_addr = finfo->fn_addr;
4698 scratch.d.func.nargs = 2;
4699 scratch.resvalue = &state->resvalue;
4700 scratch.resnull = &state->resnull;
4701 ExprEvalPushStep(state, &scratch);
4702
4703 /* then emit EEOP_QUAL to detect if result is false (or null) */
4704 scratch.opcode = EEOP_QUAL;
4705 scratch.d.qualexpr.jumpdone = -1;
4706 scratch.resvalue = &state->resvalue;
4707 scratch.resnull = &state->resnull;
4708 ExprEvalPushStep(state, &scratch);
4709 adjust_jumps = lappend_int(adjust_jumps,
4710 state->steps_len - 1);
4711 }
4712
4713 /* adjust jump targets */
4714 foreach(lc, adjust_jumps)
4715 {
4716 ExprEvalStep *as = &state->steps[lfirst_int(lc)];
4717
4718 Assert(as->opcode == EEOP_QUAL);
4719 Assert(as->d.qualexpr.jumpdone == -1);
4720 as->d.qualexpr.jumpdone = state->steps_len;
4721 }
4722
4723 scratch.resvalue = NULL;
4724 scratch.resnull = NULL;
4725 scratch.opcode = EEOP_DONE;
4726 ExprEvalPushStep(state, &scratch);
4727
4729
4730 return state;
4731}

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

Referenced by ExecInitMemoize().

◆ ExecBuildProjectionInfo()

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

Definition at line 370 of file execExpr.c.

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

References ExprEvalStep::assign_tmp, ExprEvalStep::assign_var, attnum, ExprEvalStep::attnum, ExprEvalStep::d, 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, ExecCreateExprSetupSteps(), ExecInitExprRec(), ExecReadyExpr(), TargetEntry::expr, ExprEvalPushStep(), exprType(), get_typlen(), if(), INNER_VAR, IsA, lfirst_node, makeNode, ExprEvalStep::opcode, OUTER_VAR, ProjectionInfo::pi_exprContext, ProjectionInfo::pi_state, TargetEntry::resno, ExprEvalStep::resultnum, TupleDescAttr(), ExprState::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 547 of file execExpr.c.

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

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

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

◆ ExecCheck()

bool ExecCheck ( ExprState state,
ExprContext econtext 
)

Definition at line 872 of file execExpr.c.

873{
874 Datum ret;
875 bool isnull;
876
877 /* short-circuit (here and in ExecInitCheck) for empty restriction list */
878 if (state == NULL)
879 return true;
880
881 /* verify that expression was not compiled using ExecInitQual */
882 Assert(!(state->flags & EEO_FLAG_IS_QUAL));
883
884 ret = ExecEvalExprSwitchContext(state, econtext, &isnull);
885
886 if (isnull)
887 return true;
888
889 return DatumGetBool(ret);
890}
static Datum ExecEvalExprSwitchContext(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:389
static bool DatumGetBool(Datum X)
Definition: postgres.h:95

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

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

◆ ExecComputeSlotInfo()

static bool ExecComputeSlotInfo ( ExprState state,
ExprEvalStep op 
)
static

Definition at line 3054 of file execExpr.c.

3055{
3056 PlanState *parent = state->parent;
3057 TupleDesc desc = NULL;
3058 const TupleTableSlotOps *tts_ops = NULL;
3059 bool isfixed = false;
3060 ExprEvalOp opcode = op->opcode;
3061
3062 Assert(opcode == EEOP_INNER_FETCHSOME ||
3063 opcode == EEOP_OUTER_FETCHSOME ||
3064 opcode == EEOP_SCAN_FETCHSOME ||
3065 opcode == EEOP_OLD_FETCHSOME ||
3066 opcode == EEOP_NEW_FETCHSOME);
3067
3068 if (op->d.fetch.known_desc != NULL)
3069 {
3070 desc = op->d.fetch.known_desc;
3071 tts_ops = op->d.fetch.kind;
3072 isfixed = op->d.fetch.kind != NULL;
3073 }
3074 else if (!parent)
3075 {
3076 isfixed = false;
3077 }
3078 else if (opcode == EEOP_INNER_FETCHSOME)
3079 {
3080 PlanState *is = innerPlanState(parent);
3081
3082 if (parent->inneropsset && !parent->inneropsfixed)
3083 {
3084 isfixed = false;
3085 }
3086 else if (parent->inneropsset && parent->innerops)
3087 {
3088 isfixed = true;
3089 tts_ops = parent->innerops;
3090 desc = ExecGetResultType(is);
3091 }
3092 else if (is)
3093 {
3094 tts_ops = ExecGetResultSlotOps(is, &isfixed);
3095 desc = ExecGetResultType(is);
3096 }
3097 }
3098 else if (opcode == EEOP_OUTER_FETCHSOME)
3099 {
3100 PlanState *os = outerPlanState(parent);
3101
3102 if (parent->outeropsset && !parent->outeropsfixed)
3103 {
3104 isfixed = false;
3105 }
3106 else if (parent->outeropsset && parent->outerops)
3107 {
3108 isfixed = true;
3109 tts_ops = parent->outerops;
3110 desc = ExecGetResultType(os);
3111 }
3112 else if (os)
3113 {
3114 tts_ops = ExecGetResultSlotOps(os, &isfixed);
3115 desc = ExecGetResultType(os);
3116 }
3117 }
3118 else if (opcode == EEOP_SCAN_FETCHSOME ||
3119 opcode == EEOP_OLD_FETCHSOME ||
3120 opcode == EEOP_NEW_FETCHSOME)
3121 {
3122 desc = parent->scandesc;
3123
3124 if (parent->scanops)
3125 tts_ops = parent->scanops;
3126
3127 if (parent->scanopsset)
3128 isfixed = parent->scanopsfixed;
3129 }
3130
3131 if (isfixed && desc != NULL && tts_ops != NULL)
3132 {
3133 op->d.fetch.fixed = true;
3134 op->d.fetch.kind = tts_ops;
3135 op->d.fetch.known_desc = desc;
3136 }
3137 else
3138 {
3139 op->d.fetch.fixed = false;
3140 op->d.fetch.kind = NULL;
3141 op->d.fetch.known_desc = NULL;
3142 }
3143
3144 /* if the slot is known to always virtual we never need to deform */
3145 if (op->d.fetch.fixed && op->d.fetch.kind == &TTSOpsVirtual)
3146 return false;
3147
3148 return true;
3149}
ExprEvalOp
Definition: execExpr.h:67
@ EEOP_NEW_FETCHSOME
Definition: execExpr.h:76
@ EEOP_OLD_FETCHSOME
Definition: execExpr.h:75
@ EEOP_SCAN_FETCHSOME
Definition: execExpr.h:74
const TupleTableSlotOps TTSOpsVirtual
Definition: execTuples.c:84
TupleDesc ExecGetResultType(PlanState *planstate)
Definition: execUtils.c:497
const TupleTableSlotOps * ExecGetResultSlotOps(PlanState *planstate, bool *isfixed)
Definition: execUtils.c:506
#define outerPlanState(node)
Definition: execnodes.h:1249
#define innerPlanState(node)
Definition: execnodes.h:1248
bool inneropsset
Definition: execnodes.h:1237
bool outeropsset
Definition: execnodes.h:1236
const TupleTableSlotOps * outerops
Definition: execnodes.h:1228
const TupleTableSlotOps * innerops
Definition: execnodes.h:1229
const TupleTableSlotOps * scanops
Definition: execnodes.h:1227
bool outeropsfixed
Definition: execnodes.h:1232
bool scanopsset
Definition: execnodes.h:1235
TupleDesc scandesc
Definition: execnodes.h:1202
bool scanopsfixed
Definition: execnodes.h:1231
bool inneropsfixed
Definition: execnodes.h:1233

References Assert, ExprEvalStep::d, EEOP_INNER_FETCHSOME, EEOP_NEW_FETCHSOME, EEOP_OLD_FETCHSOME, EEOP_OUTER_FETCHSOME, EEOP_SCAN_FETCHSOME, ExecGetResultSlotOps(), ExecGetResultType(), 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 2873 of file execExpr.c.

2874{
2875 ExprSetupInfo info = {0, 0, 0, 0, 0, NIL};
2876
2877 /* Prescan to find out what we need. */
2878 expr_setup_walker(node, &info);
2879
2880 /* And generate those steps. */
2882}

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

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

◆ ExecInitCheck()

ExprState * ExecInitCheck ( List qual,
PlanState parent 
)

Definition at line 315 of file execExpr.c.

316{
317 /* short-circuit (here and in ExecCheck) for empty restriction list */
318 if (qual == NIL)
319 return NULL;
320
321 Assert(IsA(qual, List));
322
323 /*
324 * Just convert the implicit-AND list to an explicit AND (if there's more
325 * than one entry), and compile normally. Unlike ExecQual, we can't
326 * short-circuit on NULL results, so the regular AND behavior is needed.
327 */
328 return ExecInitExpr(make_ands_explicit(qual), parent);
329}
ExprState * ExecInitExpr(Expr *node, PlanState *parent)
Definition: execExpr.c:143
Expr * make_ands_explicit(List *andclauses)
Definition: makefuncs.c:752

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

Referenced by ExecPrepareCheck().

◆ ExecInitCoerceToDomain()

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

Definition at line 3514 of file execExpr.c.

3516{
3517 DomainConstraintRef *constraint_ref;
3518 Datum *domainval = NULL;
3519 bool *domainnull = NULL;
3520 ListCell *l;
3521
3522 scratch->d.domaincheck.resulttype = ctest->resulttype;
3523 /* we'll allocate workspace only if needed */
3524 scratch->d.domaincheck.checkvalue = NULL;
3525 scratch->d.domaincheck.checknull = NULL;
3526 scratch->d.domaincheck.escontext = state->escontext;
3527
3528 /*
3529 * Evaluate argument - it's fine to directly store it into resv/resnull,
3530 * if there's constraint failures there'll be errors, otherwise it's what
3531 * needs to be returned.
3532 */
3533 ExecInitExprRec(ctest->arg, state, resv, resnull);
3534
3535 /*
3536 * Note: if the argument is of varlena type, it could be a R/W expanded
3537 * object. We want to return the R/W pointer as the final result, but we
3538 * have to pass a R/O pointer as the value to be tested by any functions
3539 * in check expressions. We don't bother to emit a MAKE_READONLY step
3540 * unless there's actually at least one check expression, though. Until
3541 * we've tested that, domainval/domainnull are NULL.
3542 */
3543
3544 /*
3545 * Collect the constraints associated with the domain.
3546 *
3547 * Note: before PG v10 we'd recheck the set of constraints during each
3548 * evaluation of the expression. Now we bake them into the ExprState
3549 * during executor initialization. That means we don't need typcache.c to
3550 * provide compiled exprs.
3551 */
3552 constraint_ref = (DomainConstraintRef *)
3553 palloc(sizeof(DomainConstraintRef));
3555 constraint_ref,
3557 false);
3558
3559 /*
3560 * Compile code to check each domain constraint. NOTNULL constraints can
3561 * just be applied on the resv/resnull value, but for CHECK constraints we
3562 * need more pushups.
3563 */
3564 foreach(l, constraint_ref->constraints)
3565 {
3567 Datum *save_innermost_domainval;
3568 bool *save_innermost_domainnull;
3569
3570 scratch->d.domaincheck.constraintname = con->name;
3571
3572 switch (con->constrainttype)
3573 {
3575 scratch->opcode = EEOP_DOMAIN_NOTNULL;
3576 ExprEvalPushStep(state, scratch);
3577 break;
3579 /* Allocate workspace for CHECK output if we didn't yet */
3580 if (scratch->d.domaincheck.checkvalue == NULL)
3581 {
3582 scratch->d.domaincheck.checkvalue =
3583 (Datum *) palloc(sizeof(Datum));
3584 scratch->d.domaincheck.checknull =
3585 (bool *) palloc(sizeof(bool));
3586 }
3587
3588 /*
3589 * If first time through, determine where CoerceToDomainValue
3590 * nodes should read from.
3591 */
3592 if (domainval == NULL)
3593 {
3594 /*
3595 * Since value might be read multiple times, force to R/O
3596 * - but only if it could be an expanded datum.
3597 */
3598 if (get_typlen(ctest->resulttype) == -1)
3599 {
3600 ExprEvalStep scratch2 = {0};
3601
3602 /* Yes, so make output workspace for MAKE_READONLY */
3603 domainval = (Datum *) palloc(sizeof(Datum));
3604 domainnull = (bool *) palloc(sizeof(bool));
3605
3606 /* Emit MAKE_READONLY */
3607 scratch2.opcode = EEOP_MAKE_READONLY;
3608 scratch2.resvalue = domainval;
3609 scratch2.resnull = domainnull;
3610 scratch2.d.make_readonly.value = resv;
3611 scratch2.d.make_readonly.isnull = resnull;
3612 ExprEvalPushStep(state, &scratch2);
3613 }
3614 else
3615 {
3616 /* No, so it's fine to read from resv/resnull */
3617 domainval = resv;
3618 domainnull = resnull;
3619 }
3620 }
3621
3622 /*
3623 * Set up value to be returned by CoerceToDomainValue nodes.
3624 * We must save and restore innermost_domainval/null fields,
3625 * in case this node is itself within a check expression for
3626 * another domain.
3627 */
3628 save_innermost_domainval = state->innermost_domainval;
3629 save_innermost_domainnull = state->innermost_domainnull;
3630 state->innermost_domainval = domainval;
3631 state->innermost_domainnull = domainnull;
3632
3633 /* evaluate check expression value */
3635 scratch->d.domaincheck.checkvalue,
3636 scratch->d.domaincheck.checknull);
3637
3638 state->innermost_domainval = save_innermost_domainval;
3639 state->innermost_domainnull = save_innermost_domainnull;
3640
3641 /* now test result */
3642 scratch->opcode = EEOP_DOMAIN_CHECK;
3643 ExprEvalPushStep(state, scratch);
3644
3645 break;
3646 default:
3647 elog(ERROR, "unrecognized constraint type: %d",
3648 (int) con->constrainttype);
3649 break;
3650 }
3651 }
3652}
@ EEOP_DOMAIN_CHECK
Definition: execExpr.h:247
@ EEOP_DOMAIN_NOTNULL
Definition: execExpr.h:244
@ EEOP_MAKE_READONLY
Definition: execExpr.h:179
@ DOM_CONSTRAINT_CHECK
Definition: execnodes.h:1038
@ DOM_CONSTRAINT_NOTNULL
Definition: execnodes.h:1037
MemoryContext CurrentMemoryContext
Definition: mcxt.c:143
DomainConstraintType constrainttype
Definition: execnodes.h:1044
struct ExprEvalStep::@55::@71 make_readonly
bool * checknull
Definition: execExpr.h:583
struct ExprEvalStep::@55::@85 domaincheck
Oid resulttype
Definition: execExpr.h:538
Datum * checkvalue
Definition: execExpr.h:582
ErrorSaveContext * escontext
Definition: execExpr.h:586
char * constraintname
Definition: execExpr.h:580
void InitDomainConstraintRef(Oid type_id, DomainConstraintRef *ref, MemoryContext refctx, bool need_exprstate)
Definition: typcache.c:1400

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

Referenced by ExecInitExprRec().

◆ ExecInitExpr()

ExprState * ExecInitExpr ( Expr node,
PlanState parent 
)

Definition at line 143 of file execExpr.c.

144{
146 ExprEvalStep scratch = {0};
147
148 /* Special case: NULL expression produces a NULL ExprState pointer */
149 if (node == NULL)
150 return NULL;
151
152 /* Initialize ExprState with empty step list */
154 state->expr = node;
155 state->parent = parent;
156 state->ext_params = NULL;
157
158 /* Insert setup steps as needed */
160
161 /* Compile the expression proper */
162 ExecInitExprRec(node, state, &state->resvalue, &state->resnull);
163
164 /* Finally, append a DONE step */
165 scratch.opcode = EEOP_DONE;
166 ExprEvalPushStep(state, &scratch);
167
169
170 return state;
171}

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

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

◆ ExecInitExprList()

List * ExecInitExprList ( List nodes,
PlanState parent 
)

Definition at line 335 of file execExpr.c.

336{
337 List *result = NIL;
338 ListCell *lc;
339
340 foreach(lc, nodes)
341 {
342 Expr *e = lfirst(lc);
343
344 result = lappend(result, ExecInitExpr(e, parent));
345 }
346
347 return result;
348}
List * lappend(List *list, void *datum)
Definition: list.c:339
e
Definition: preproc-init.c:82

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

Referenced by ExecInitAgg(), ExecInitExprRec(), ExecInitFunctionResultSet(), 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 919 of file execExpr.c.

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

References ACL_EXECUTE, aclcheck_error(), ACLCHECK_OK, WindowFuncExprState::aggfilter, WindowFunc::aggfilter, ExprEvalStep::aggno, ExprEvalStep::aggref, AggState::aggs, ExprEvalStep::amstate, AND_EXPR, ExprEvalStep::anynull, arg, FieldSelect::arg, FieldStore::arg, RelabelType::arg, CoerceViaIO::arg, ArrayCoerceExpr::arg, CaseExpr::arg, NullTest::arg, BooleanTest::arg, JsonConstructorExprState::arg_nulls, JsonConstructorExprState::arg_type_cache, JsonConstructorExprState::arg_types, JsonConstructorExprState::arg_values, ExprEvalStep::argnull, generate_unaccent_rules::args, FunctionCallInfoBaseData::args, WindowFuncExprState::args, WindowFunc::args, FuncExpr::args, OpExpr::args, ScalarArrayOpExpr::args, BoolExpr::args, CaseExpr::args, RowExpr::args, CoalesceExpr::args, MinMaxExpr::args, XmlExpr::args, JsonConstructorExpr::args, ExprEvalStep::argvalue, ExprEvalStep::arraycoerce, ExprEvalStep::arrayexpr, Assert, ExprEvalStep::attnum, BlessTupleDesc(), ExprEvalStep::boolexpr, BoolExpr::boolop, BooleanTest::booltesttype, BTORDER_PROC, ExprEvalRowtypeCache::cacheptr, ExprEvalStep::casetest, castNode, JsonConstructorExprState::category, check_stack_depth(), ExprEvalStep::clauses, CMD_MERGE, TypeCacheEntry::cmp_proc, ExprEvalStep::cmptype, RowCompareExpr::cmptype, JsonConstructorExpr::coercion, JsonConstructorExprState::constructor, ExprEvalStep::constval, FunctionCallInfoBaseData::context, convert(), ExprEvalStep::convert_rowtype, ExprEvalStep::d, CaseExpr::defresult, 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, 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, ExprEvalStep::elemalign, ExprEvalStep::elembyval, ExprEvalStep::element_type, ArrayExpr::elements, ArrayCoerceExpr::elemexpr, ExprEvalStep::elemexprstate, ExprEvalStep::elemlength, ExprEvalStep::elemnulls, ExprEvalStep::elemtype, ExprEvalStep::elemvalues, elog, ereport, errcode(), errmsg(), ERROR, ExecInitCoerceToDomain(), ExecInitExpr(), ExecInitExprList(), ExecInitExprRec(), ExecInitFunc(), ExecInitJsonExpr(), ExecInitSubPlanExpr(), ExecInitSubscriptingRef(), ExecInitWholeRowVar(), ExecReadyExpr(), ExecTypeFromExprList(), ExecTypeSetColNames(), ExprState::expr, JsonIsPredicate::expr, ExprEvalPushStep(), exprType(), ExprState::ext_params, ExprEvalStep::fcinfo_data, ExprEvalStep::fcinfo_data_in, ExprEvalStep::fcinfo_data_out, ExprEvalStep::fieldnum, FieldSelect::fieldnum, ExprEvalStep::fieldselect, ExprEvalStep::fieldstore, ExprEvalStep::finfo, ExprEvalStep::finfo_in, ExprEvalStep::finfo_out, fmgr_info(), fmgr_info_set_expr, ExprEvalStep::fn_addr, FmgrInfo::fn_addr, forboth, forfive, JsonReturning::format, JsonFormat::format_type, format_type_be(), JsonValueExpr::formatted_expr, JsonExpr::formatted_expr, ExprEvalStep::fstore, ExprEvalStep::func, JsonConstructorExpr::func, FuncExpr::funcid, WindowAggState::funcs, get_element_type(), get_func_name(), get_op_opfamily_properties(), get_opfamily_proc(), get_typlen(), get_typlenbyvalalign(), getTypeInputInfo(), getTypeOutputInfo(), GetUserId(), ExprEvalStep::grouping_func, Agg::groupingSets, ExprEvalStep::hashedscalararrayop, i, ExprEvalStep::incache, ExprEvalStep::inclause, InitFunctionCallInfoData, INNER_VAR, ExprState::innermost_casenull, ExprState::innermost_caseval, ExprEvalStep::inputtype, Int32GetDatum(), InvalidAttrNumber, InvalidOid, InvokeFunctionExecuteHook, ExprEvalStep::iocoerce, IS_FALSE, ExprEvalStep::is_json, IS_NOT_FALSE, IS_NOT_NULL, IS_NOT_TRUE, IS_NOT_UNKNOWN, IS_NULL, IS_TRUE, IS_UNKNOWN, IsA, ExprEvalStep::isnull, NullableDatum::isnull, ExprEvalStep::jcstate, JS_FORMAT_JSONB, JSCTOR_JSON_PARSE, JSCTOR_JSON_SCALAR, JSCTOR_JSON_SERIALIZE, json_categorize_type(), ExprEvalStep::json_constructor, JSON_TABLE_OP, ExprEvalStep::jump, ExprEvalStep::jumpdone, ExprEvalStep::jumpnull, lappend(), lappend_int(), RowCompareExpr::largs, lfirst, lfirst_int, lfirst_oid, linitial, list_length(), lookup_rowtype_tupdesc(), lookup_rowtype_tupdesc_copy(), lookup_type_cache(), lsecond, ExprEvalStep::make_readonly, ExprEvalStep::make_ro, makeNode, makeNullConst(), ExprEvalStep::map, Max, ExprEvalStep::minmax, ExprEvalStep::multidims, MULTIEXPR_SUBLINK, ExprEvalStep::named_argnull, XmlExpr::named_args, ExprEvalStep::named_argvalue, JsonConstructorExprState::nargs, TupleDescData::natts, ExprEvalStep::ncolumns, ExprEvalStep::nelems, FieldStore::newvals, ExprEvalStep::nextvalueexpr, NIL, nodeTag, NOT_EXPR, ExprEvalStep::nullflag, ExprEvalStep::nulls, ExprEvalStep::nulltest_row, NullTest::nulltesttype, WindowAggState::numaggs, WindowAggState::numfuncs, object_aclcheck(), OBJECT_FUNCTION, ObjectIdGetDatum(), OidIsValid, ExprEvalStep::op, MinMaxExpr::op, JsonExpr::op, ExprEvalStep::opcode, OR_EXPR, ExprEvalStep::outcache, OUTER_VAR, JsonConstructorExprState::outfuncid, ExprEvalStep::outputtype, palloc(), palloc0(), ExprEvalStep::param, PARAM_EXEC, PARAM_EXTERN, ParamListInfoData::paramCompile, ExprEvalStep::paramid, Param::paramid, Param::paramkind, ExprEvalStep::paramtype, Param::paramtype, ExprState::parent, ExprEvalStep::pred, RowCompareExpr::rargs, JsonValueExpr::raw_expr, ReleaseTupleDesc, ExprEvalStep::resnull, ExprState::resnull, ExprEvalStep::resultelemtype, ExprEvalStep::resulttype, CoerceViaIO::resulttype, ArrayCoerceExpr::resulttype, ExprEvalStep::resvalue, ExprState::resvalue, ReturningExpr::retexpr, ReturningExpr::retold, JsonConstructorExpr::returning, ExprEvalStep::returningexpr, ExprEvalStep::row, ExprEvalStep::rowcache, ExprEvalStep::rowcompare_final, ExprEvalStep::rowcompare_step, ExprEvalStep::saop, ExprEvalStep::scalararrayop, ExprEvalStep::seqid, NextValueExpr::seqid, ExprEvalStep::seqtypid, SizeForFunctionCallInfo, ExprEvalStep::sqlvaluefunction, ExprState::steps, ExprState::steps_len, SubPlan::subLinkType, ExprEvalStep::svf, ExprEvalStep::tupdesc, TupleDescAttr(), JsonConstructorExpr::type, TYPECACHE_CMP_PROC, NextValueExpr::typeId, JsonConstructorExpr::unique, ExprEvalStep::useOr, ScalarArrayOpExpr::useOr, ExprEvalStep::value, NullableDatum::value, values, ExprEvalStep::values, ExprEvalStep::var, VAR_RETURNING_DEFAULT, VAR_RETURNING_NEW, VAR_RETURNING_OLD, ExprEvalStep::varreturningtype, ExprEvalStep::vartype, ExprEvalStep::wfstate, WindowFuncExprState::wfunc, ExprEvalStep::window_func, ExprEvalStep::xexpr, and ExprEvalStep::xmlexpr.

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

◆ ExecInitExprWithParams()

ExprState * ExecInitExprWithParams ( Expr node,
ParamListInfo  ext_params 
)

Definition at line 180 of file execExpr.c.

181{
183 ExprEvalStep scratch = {0};
184
185 /* Special case: NULL expression produces a NULL ExprState pointer */
186 if (node == NULL)
187 return NULL;
188
189 /* Initialize ExprState with empty step list */
191 state->expr = node;
192 state->parent = NULL;
193 state->ext_params = ext_params;
194
195 /* Insert setup steps as needed */
197
198 /* Compile the expression proper */
199 ExecInitExprRec(node, state, &state->resvalue, &state->resnull);
200
201 /* Finally, append a DONE step */
202 scratch.opcode = EEOP_DONE;
203 ExprEvalPushStep(state, &scratch);
204
206
207 return state;
208}

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

Referenced by exec_eval_simple_expr(), and InitPartitionPruneContext().

◆ ExecInitFunc()

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

Definition at line 2704 of file execExpr.c.

2706{
2707 int nargs = list_length(args);
2708 AclResult aclresult;
2709 FmgrInfo *flinfo;
2710 FunctionCallInfo fcinfo;
2711 int argno;
2712 ListCell *lc;
2713
2714 /* Check permission to call function */
2715 aclresult = object_aclcheck(ProcedureRelationId, funcid, GetUserId(), ACL_EXECUTE);
2716 if (aclresult != ACLCHECK_OK)
2717 aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(funcid));
2719
2720 /*
2721 * Safety check on nargs. Under normal circumstances this should never
2722 * fail, as parser should check sooner. But possibly it might fail if
2723 * server has been compiled with FUNC_MAX_ARGS smaller than some functions
2724 * declared in pg_proc?
2725 */
2726 if (nargs > FUNC_MAX_ARGS)
2727 ereport(ERROR,
2728 (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
2729 errmsg_plural("cannot pass more than %d argument to a function",
2730 "cannot pass more than %d arguments to a function",
2732 FUNC_MAX_ARGS)));
2733
2734 /* Allocate function lookup data and parameter workspace for this call */
2735 scratch->d.func.finfo = palloc0(sizeof(FmgrInfo));
2737 flinfo = scratch->d.func.finfo;
2738 fcinfo = scratch->d.func.fcinfo_data;
2739
2740 /* Set up the primary fmgr lookup information */
2741 fmgr_info(funcid, flinfo);
2742 fmgr_info_set_expr((Node *) node, flinfo);
2743
2744 /* Initialize function call parameter structure too */
2745 InitFunctionCallInfoData(*fcinfo, flinfo,
2746 nargs, inputcollid, NULL, NULL);
2747
2748 /* Keep extra copies of this info to save an indirection at runtime */
2749 scratch->d.func.fn_addr = flinfo->fn_addr;
2750 scratch->d.func.nargs = nargs;
2751
2752 /* We only support non-set functions here */
2753 if (flinfo->fn_retset)
2754 ereport(ERROR,
2755 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2756 errmsg("set-valued function called in context that cannot accept a set"),
2757 state->parent ?
2758 executor_errposition(state->parent->state,
2759 exprLocation((Node *) node)) : 0));
2760
2761 /* Build code to evaluate arguments directly into the fcinfo struct */
2762 argno = 0;
2763 foreach(lc, args)
2764 {
2765 Expr *arg = (Expr *) lfirst(lc);
2766
2767 if (IsA(arg, Const))
2768 {
2769 /*
2770 * Don't evaluate const arguments every round; especially
2771 * interesting for constants in comparisons.
2772 */
2773 Const *con = (Const *) arg;
2774
2775 fcinfo->args[argno].value = con->constvalue;
2776 fcinfo->args[argno].isnull = con->constisnull;
2777 }
2778 else
2779 {
2781 &fcinfo->args[argno].value,
2782 &fcinfo->args[argno].isnull);
2783 }
2784 argno++;
2785 }
2786
2787 /* Insert appropriate opcode depending on strictness and stats level */
2788 if (pgstat_track_functions <= flinfo->fn_stats)
2789 {
2790 if (flinfo->fn_strict && nargs > 0)
2791 scratch->opcode = EEOP_FUNCEXPR_STRICT;
2792 else
2793 scratch->opcode = EEOP_FUNCEXPR;
2794 }
2795 else
2796 {
2797 if (flinfo->fn_strict && nargs > 0)
2799 else
2800 scratch->opcode = EEOP_FUNCEXPR_FUSAGE;
2801 }
2802}
int errmsg_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition: elog.c:1180
@ EEOP_FUNCEXPR_STRICT_FUSAGE
Definition: execExpr.h:122
@ EEOP_FUNCEXPR_STRICT
Definition: execExpr.h:120
@ EEOP_FUNCEXPR
Definition: execExpr.h:119
@ EEOP_FUNCEXPR_FUSAGE
Definition: execExpr.h:121
int executor_errposition(EState *estate, int location)
Definition: execUtils.c:934
int exprLocation(const Node *expr)
Definition: nodeFuncs.c:1388
#define FUNC_MAX_ARGS
bool fn_retset
Definition: fmgr.h:62

References ACL_EXECUTE, aclcheck_error(), ACLCHECK_OK, arg, generate_unaccent_rules::args, FunctionCallInfoBaseData::args, ExprEvalStep::d, EEOP_FUNCEXPR, EEOP_FUNCEXPR_FUSAGE, EEOP_FUNCEXPR_STRICT, EEOP_FUNCEXPR_STRICT_FUSAGE, ereport, errcode(), errmsg(), errmsg_plural(), ERROR, ExecInitExprRec(), executor_errposition(), exprLocation(), ExprEvalStep::fcinfo_data, ExprEvalStep::finfo, fmgr_info(), fmgr_info_set_expr, ExprEvalStep::fn_addr, FmgrInfo::fn_addr, FmgrInfo::fn_retset, FmgrInfo::fn_strict, ExprEvalStep::func, FUNC_MAX_ARGS, get_func_name(), GetUserId(), InitFunctionCallInfoData, InvokeFunctionExecuteHook, IsA, NullableDatum::isnull, lfirst, list_length(), ExprEvalStep::nargs, object_aclcheck(), OBJECT_FUNCTION, ExprEvalStep::opcode, palloc0(), 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 5039 of file execExpr.c.

5043{
5044 ExprEvalStep scratch = {0};
5045
5046 /* For json_populate_type() */
5048 scratch.resvalue = resv;
5049 scratch.resnull = resnull;
5050 scratch.d.jsonexpr_coercion.targettype = returning->typid;
5051 scratch.d.jsonexpr_coercion.targettypmod = returning->typmod;
5053 scratch.d.jsonexpr_coercion.escontext = escontext;
5054 scratch.d.jsonexpr_coercion.omit_quotes = omit_quotes;
5055 scratch.d.jsonexpr_coercion.exists_coerce = exists_coerce;
5056 scratch.d.jsonexpr_coercion.exists_cast_to_int = exists_coerce &&
5057 getBaseType(returning->typid) == INT4OID;
5058 scratch.d.jsonexpr_coercion.exists_check_domain = exists_coerce &&
5059 DomainHasConstraints(returning->typid);
5060 ExprEvalPushStep(state, &scratch);
5061}
@ EEOP_JSONEXPR_COERCION
Definition: execExpr.h:264
Oid getBaseType(Oid typid)
Definition: lsyscache.c:2548
void * json_coercion_cache
Definition: execExpr.h:763
bool exists_coerce
Definition: execExpr.h:760
bool exists_cast_to_int
Definition: execExpr.h:761
struct ExprEvalStep::@55::@104 jsonexpr_coercion
bool exists_check_domain
Definition: execExpr.h:762
int32 targettypmod
Definition: execExpr.h:757
Oid targettype
Definition: execExpr.h:756
bool omit_quotes
Definition: execExpr.h:758
bool DomainHasConstraints(Oid type_id)
Definition: typcache.c:1487

References ExprEvalStep::d, DomainHasConstraints(), EEOP_JSONEXPR_COERCION, ExprEvalStep::escontext, ExprEvalStep::exists_cast_to_int, ExprEvalStep::exists_check_domain, ExprEvalStep::exists_coerce, ExprEvalPushStep(), getBaseType(), ExprEvalStep::json_coercion_cache, ExprEvalStep::jsonexpr_coercion, ExprEvalStep::omit_quotes, ExprEvalStep::opcode, ExprEvalStep::resnull, ExprEvalStep::resvalue, ExprEvalStep::targettype, ExprEvalStep::targettypmod, 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 4737 of file execExpr.c.

4740{
4741 JsonExprState *jsestate = palloc0(sizeof(JsonExprState));
4742 ListCell *argexprlc;
4743 ListCell *argnamelc;
4744 List *jumps_return_null = NIL;
4745 List *jumps_to_end = NIL;
4746 ListCell *lc;
4747 ErrorSaveContext *escontext;
4748 bool returning_domain =
4749 get_typtype(jsexpr->returning->typid) == TYPTYPE_DOMAIN;
4750
4751 Assert(jsexpr->on_error != NULL);
4752
4753 jsestate->jsexpr = jsexpr;
4754
4755 /*
4756 * Evaluate formatted_expr storing the result into
4757 * jsestate->formatted_expr.
4758 */
4760 &jsestate->formatted_expr.value,
4761 &jsestate->formatted_expr.isnull);
4762
4763 /* JUMP to return NULL if formatted_expr evaluates to NULL */
4764 jumps_return_null = lappend_int(jumps_return_null, state->steps_len);
4765 scratch->opcode = EEOP_JUMP_IF_NULL;
4766 scratch->resnull = &jsestate->formatted_expr.isnull;
4767 scratch->d.jump.jumpdone = -1; /* set below */
4768 ExprEvalPushStep(state, scratch);
4769
4770 /*
4771 * Evaluate pathspec expression storing the result into
4772 * jsestate->pathspec.
4773 */
4774 ExecInitExprRec((Expr *) jsexpr->path_spec, state,
4775 &jsestate->pathspec.value,
4776 &jsestate->pathspec.isnull);
4777
4778 /* JUMP to return NULL if path_spec evaluates to NULL */
4779 jumps_return_null = lappend_int(jumps_return_null, state->steps_len);
4780 scratch->opcode = EEOP_JUMP_IF_NULL;
4781 scratch->resnull = &jsestate->pathspec.isnull;
4782 scratch->d.jump.jumpdone = -1; /* set below */
4783 ExprEvalPushStep(state, scratch);
4784
4785 /* Steps to compute PASSING args. */
4786 jsestate->args = NIL;
4787 forboth(argexprlc, jsexpr->passing_values,
4788 argnamelc, jsexpr->passing_names)
4789 {
4790 Expr *argexpr = (Expr *) lfirst(argexprlc);
4791 String *argname = lfirst_node(String, argnamelc);
4792 JsonPathVariable *var = palloc(sizeof(*var));
4793
4794 var->name = argname->sval;
4795 var->namelen = strlen(var->name);
4796 var->typid = exprType((Node *) argexpr);
4797 var->typmod = exprTypmod((Node *) argexpr);
4798
4799 ExecInitExprRec((Expr *) argexpr, state, &var->value, &var->isnull);
4800
4801 jsestate->args = lappend(jsestate->args, var);
4802 }
4803
4804 /* Step for jsonpath evaluation; see ExecEvalJsonExprPath(). */
4805 scratch->opcode = EEOP_JSONEXPR_PATH;
4806 scratch->resvalue = resv;
4807 scratch->resnull = resnull;
4808 scratch->d.jsonexpr.jsestate = jsestate;
4809 ExprEvalPushStep(state, scratch);
4810
4811 /*
4812 * Step to return NULL after jumping to skip the EEOP_JSONEXPR_PATH step
4813 * when either formatted_expr or pathspec is NULL. Adjust jump target
4814 * addresses of JUMPs that we added above.
4815 */
4816 foreach(lc, jumps_return_null)
4817 {
4818 ExprEvalStep *as = &state->steps[lfirst_int(lc)];
4819
4820 as->d.jump.jumpdone = state->steps_len;
4821 }
4822 scratch->opcode = EEOP_CONST;
4823 scratch->resvalue = resv;
4824 scratch->resnull = resnull;
4825 scratch->d.constval.value = (Datum) 0;
4826 scratch->d.constval.isnull = true;
4827 ExprEvalPushStep(state, scratch);
4828
4829 escontext = jsexpr->on_error->btype != JSON_BEHAVIOR_ERROR ?
4830 &jsestate->escontext : NULL;
4831
4832 /*
4833 * To handle coercion errors softly, use the following ErrorSaveContext to
4834 * pass to ExecInitExprRec() when initializing the coercion expressions
4835 * and in the EEOP_JSONEXPR_COERCION step.
4836 */
4837 jsestate->escontext.type = T_ErrorSaveContext;
4838
4839 /*
4840 * Steps to coerce the result value computed by EEOP_JSONEXPR_PATH or the
4841 * NULL returned on NULL input as described above.
4842 */
4843 jsestate->jump_eval_coercion = -1;
4844 if (jsexpr->use_json_coercion)
4845 {
4846 jsestate->jump_eval_coercion = state->steps_len;
4847
4848 ExecInitJsonCoercion(state, jsexpr->returning, escontext,
4849 jsexpr->omit_quotes,
4850 jsexpr->op == JSON_EXISTS_OP,
4851 resv, resnull);
4852 }
4853 else if (jsexpr->use_io_coercion)
4854 {
4855 /*
4856 * Here we only need to initialize the FunctionCallInfo for the target
4857 * type's input function, which is called by ExecEvalJsonExprPath()
4858 * itself, so no additional step is necessary.
4859 */
4860 Oid typinput;
4861 Oid typioparam;
4862 FmgrInfo *finfo;
4863 FunctionCallInfo fcinfo;
4864
4865 getTypeInputInfo(jsexpr->returning->typid, &typinput, &typioparam);
4866 finfo = palloc0(sizeof(FmgrInfo));
4867 fcinfo = palloc0(SizeForFunctionCallInfo(3));
4868 fmgr_info(typinput, finfo);
4869 fmgr_info_set_expr((Node *) jsexpr->returning, finfo);
4870 InitFunctionCallInfoData(*fcinfo, finfo, 3, InvalidOid, NULL, NULL);
4871
4872 /*
4873 * We can preload the second and third arguments for the input
4874 * function, since they're constants.
4875 */
4876 fcinfo->args[1].value = ObjectIdGetDatum(typioparam);
4877 fcinfo->args[1].isnull = false;
4878 fcinfo->args[2].value = Int32GetDatum(jsexpr->returning->typmod);
4879 fcinfo->args[2].isnull = false;
4880 fcinfo->context = (Node *) escontext;
4881
4882 jsestate->input_fcinfo = fcinfo;
4883 }
4884
4885 /*
4886 * Add a special step, if needed, to check if the coercion evaluation ran
4887 * into an error but was not thrown because the ON ERROR behavior is not
4888 * ERROR. It will set jsestate->error if an error did occur.
4889 */
4890 if (jsestate->jump_eval_coercion >= 0 && escontext != NULL)
4891 {
4893 scratch->d.jsonexpr.jsestate = jsestate;
4894 ExprEvalPushStep(state, scratch);
4895 }
4896
4897 jsestate->jump_empty = jsestate->jump_error = -1;
4898
4899 /*
4900 * Step to check jsestate->error and return the ON ERROR expression if
4901 * there is one. This handles both the errors that occur during jsonpath
4902 * evaluation in EEOP_JSONEXPR_PATH and subsequent coercion evaluation.
4903 *
4904 * Speed up common cases by avoiding extra steps for a NULL-valued ON
4905 * ERROR expression unless RETURNING a domain type, where constraints must
4906 * be checked. ExecEvalJsonExprPath() already returns NULL on error,
4907 * making additional steps unnecessary in typical scenarios. Note that the
4908 * default ON ERROR behavior for JSON_VALUE() and JSON_QUERY() is to
4909 * return NULL.
4910 */
4911 if (jsexpr->on_error->btype != JSON_BEHAVIOR_ERROR &&
4912 (!(IsA(jsexpr->on_error->expr, Const) &&
4913 ((Const *) jsexpr->on_error->expr)->constisnull) ||
4914 returning_domain))
4915 {
4916 ErrorSaveContext *saved_escontext;
4917
4918 jsestate->jump_error = state->steps_len;
4919
4920 /* JUMP to end if false, that is, skip the ON ERROR expression. */
4921 jumps_to_end = lappend_int(jumps_to_end, state->steps_len);
4922 scratch->opcode = EEOP_JUMP_IF_NOT_TRUE;
4923 scratch->resvalue = &jsestate->error.value;
4924 scratch->resnull = &jsestate->error.isnull;
4925 scratch->d.jump.jumpdone = -1; /* set below */
4926 ExprEvalPushStep(state, scratch);
4927
4928 /*
4929 * Steps to evaluate the ON ERROR expression; handle errors softly to
4930 * rethrow them in COERCION_FINISH step that will be added later.
4931 */
4932 saved_escontext = state->escontext;
4933 state->escontext = escontext;
4934 ExecInitExprRec((Expr *) jsexpr->on_error->expr,
4935 state, resv, resnull);
4936 state->escontext = saved_escontext;
4937
4938 /* Step to coerce the ON ERROR expression if needed */
4939 if (jsexpr->on_error->coerce)
4940 ExecInitJsonCoercion(state, jsexpr->returning, escontext,
4941 jsexpr->omit_quotes, false,
4942 resv, resnull);
4943
4944 /*
4945 * Add a COERCION_FINISH step to check for errors that may occur when
4946 * coercing and rethrow them.
4947 */
4948 if (jsexpr->on_error->coerce ||
4949 IsA(jsexpr->on_error->expr, CoerceViaIO) ||
4950 IsA(jsexpr->on_error->expr, CoerceToDomain))
4951 {
4953 scratch->resvalue = resv;
4954 scratch->resnull = resnull;
4955 scratch->d.jsonexpr.jsestate = jsestate;
4956 ExprEvalPushStep(state, scratch);
4957 }
4958
4959 /* JUMP to end to skip the ON EMPTY steps added below. */
4960 jumps_to_end = lappend_int(jumps_to_end, state->steps_len);
4961 scratch->opcode = EEOP_JUMP;
4962 scratch->d.jump.jumpdone = -1;
4963 ExprEvalPushStep(state, scratch);
4964 }
4965
4966 /*
4967 * Step to check jsestate->empty and return the ON EMPTY expression if
4968 * there is one.
4969 *
4970 * See the comment above for details on the optimization for NULL-valued
4971 * expressions.
4972 */
4973 if (jsexpr->on_empty != NULL &&
4974 jsexpr->on_empty->btype != JSON_BEHAVIOR_ERROR &&
4975 (!(IsA(jsexpr->on_empty->expr, Const) &&
4976 ((Const *) jsexpr->on_empty->expr)->constisnull) ||
4977 returning_domain))
4978 {
4979 ErrorSaveContext *saved_escontext;
4980
4981 jsestate->jump_empty = state->steps_len;
4982
4983 /* JUMP to end if false, that is, skip the ON EMPTY expression. */
4984 jumps_to_end = lappend_int(jumps_to_end, state->steps_len);
4985 scratch->opcode = EEOP_JUMP_IF_NOT_TRUE;
4986 scratch->resvalue = &jsestate->empty.value;
4987 scratch->resnull = &jsestate->empty.isnull;
4988 scratch->d.jump.jumpdone = -1; /* set below */
4989 ExprEvalPushStep(state, scratch);
4990
4991 /*
4992 * Steps to evaluate the ON EMPTY expression; handle errors softly to
4993 * rethrow them in COERCION_FINISH step that will be added later.
4994 */
4995 saved_escontext = state->escontext;
4996 state->escontext = escontext;
4997 ExecInitExprRec((Expr *) jsexpr->on_empty->expr,
4998 state, resv, resnull);
4999 state->escontext = saved_escontext;
5000
5001 /* Step to coerce the ON EMPTY expression if needed */
5002 if (jsexpr->on_empty->coerce)
5003 ExecInitJsonCoercion(state, jsexpr->returning, escontext,
5004 jsexpr->omit_quotes, false,
5005 resv, resnull);
5006
5007 /*
5008 * Add a COERCION_FINISH step to check for errors that may occur when
5009 * coercing and rethrow them.
5010 */
5011 if (jsexpr->on_empty->coerce ||
5012 IsA(jsexpr->on_empty->expr, CoerceViaIO) ||
5013 IsA(jsexpr->on_empty->expr, CoerceToDomain))
5014 {
5015
5017 scratch->resvalue = resv;
5018 scratch->resnull = resnull;
5019 scratch->d.jsonexpr.jsestate = jsestate;
5020 ExprEvalPushStep(state, scratch);
5021 }
5022 }
5023
5024 foreach(lc, jumps_to_end)
5025 {
5026 ExprEvalStep *as = &state->steps[lfirst_int(lc)];
5027
5028 as->d.jump.jumpdone = state->steps_len;
5029 }
5030
5031 jsestate->jump_end = state->steps_len;
5032}
static void ExecInitJsonCoercion(ExprState *state, JsonReturning *returning, ErrorSaveContext *escontext, bool omit_quotes, bool exists_coerce, Datum *resv, bool *resnull)
Definition: execExpr.c:5039
@ EEOP_JSONEXPR_PATH
Definition: execExpr.h:263
@ EEOP_JSONEXPR_COERCION_FINISH
Definition: execExpr.h:265
@ EEOP_JUMP_IF_NULL
Definition: execExpr.h:149
char get_typtype(Oid typid)
Definition: lsyscache.c:2656
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:301
@ JSON_BEHAVIOR_ERROR
Definition: primnodes.h:1771
@ JSON_EXISTS_OP
Definition: primnodes.h:1807
NodeTag type
Definition: miscnodes.h:46
struct JsonExprState * jsestate
Definition: execExpr.h:750
struct ExprEvalStep::@55::@103 jsonexpr
Node * expr
Definition: primnodes.h:1796
JsonBehaviorType btype
Definition: primnodes.h:1795
int jump_eval_coercion
Definition: execnodes.h:1095
NullableDatum empty
Definition: execnodes.h:1081
FunctionCallInfo input_fcinfo
Definition: execnodes.h:1109
JsonExpr * jsexpr
Definition: execnodes.h:1059
NullableDatum error
Definition: execnodes.h:1078
NullableDatum pathspec
Definition: execnodes.h:1065
ErrorSaveContext escontext
Definition: execnodes.h:1118
NullableDatum formatted_expr
Definition: execnodes.h:1062
List * passing_values
Definition: primnodes.h:1841
JsonBehavior * on_empty
Definition: primnodes.h:1844
List * passing_names
Definition: primnodes.h:1840
Node * path_spec
Definition: primnodes.h:1834
bool use_io_coercion
Definition: primnodes.h:1851
JsonReturning * returning
Definition: primnodes.h:1837
bool use_json_coercion
Definition: primnodes.h:1852
JsonBehavior * on_error
Definition: primnodes.h:1845
bool omit_quotes
Definition: primnodes.h:1858
Definition: value.h:64
char * sval
Definition: value.h:68

References FunctionCallInfoBaseData::args, JsonExprState::args, Assert, JsonBehavior::btype, JsonBehavior::coerce, ExprEvalStep::constval, FunctionCallInfoBaseData::context, ExprEvalStep::d, 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(), fmgr_info(), fmgr_info_set_expr, forboth, JsonExprState::formatted_expr, JsonExpr::formatted_expr, get_typtype(), getTypeInputInfo(), InitFunctionCallInfoData, JsonExprState::input_fcinfo, Int32GetDatum(), InvalidOid, IsA, ExprEvalStep::isnull, NullableDatum::isnull, JsonPathVariable::isnull, ExprEvalStep::jsestate, JsonExprState::jsexpr, JSON_BEHAVIOR_ERROR, JSON_EXISTS_OP, ExprEvalStep::jsonexpr, ExprEvalStep::jump, JsonExprState::jump_empty, JsonExprState::jump_end, JsonExprState::jump_error, JsonExprState::jump_eval_coercion, ExprEvalStep::jumpdone, 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, ExprEvalStep::opcode, palloc(), palloc0(), JsonExpr::passing_names, JsonExpr::passing_values, JsonExpr::path_spec, JsonExprState::pathspec, ExprEvalStep::resnull, ExprEvalStep::resvalue, JsonExpr::returning, SizeForFunctionCallInfo, String::sval, ErrorSaveContext::type, JsonReturning::typid, JsonPathVariable::typid, JsonReturning::typmod, JsonPathVariable::typmod, JsonExpr::use_io_coercion, JsonExpr::use_json_coercion, ExprEvalStep::value, NullableDatum::value, and JsonPathVariable::value.

Referenced by ExecInitExprRec().

◆ ExecInitQual()

ExprState * ExecInitQual ( List qual,
PlanState parent 
)

Definition at line 229 of file execExpr.c.

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

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

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

◆ ExecInitSubPlanExpr()

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

Definition at line 2813 of file execExpr.c.

2816{
2817 ExprEvalStep scratch = {0};
2818 SubPlanState *sstate;
2819 ListCell *pvar;
2820 ListCell *l;
2821
2822 if (!state->parent)
2823 elog(ERROR, "SubPlan found with no parent plan");
2824
2825 /*
2826 * Generate steps to evaluate input arguments for the subplan.
2827 *
2828 * We evaluate the argument expressions into ExprState's resvalue/resnull,
2829 * and then use PARAM_SET to update the parameter. We do that, instead of
2830 * evaluating directly into the param, to avoid depending on the pointer
2831 * value remaining stable / being included in the generated expression. No
2832 * danger of conflicts with other uses of resvalue/resnull as storing and
2833 * using the value always is in subsequent steps.
2834 *
2835 * Any calculation we have to do can be done in the parent econtext, since
2836 * the Param values don't need to have per-query lifetime.
2837 */
2838 Assert(list_length(subplan->parParam) == list_length(subplan->args));
2839 forboth(l, subplan->parParam, pvar, subplan->args)
2840 {
2841 int paramid = lfirst_int(l);
2842 Expr *arg = (Expr *) lfirst(pvar);
2843
2845 &state->resvalue, &state->resnull);
2846
2847 scratch.opcode = EEOP_PARAM_SET;
2848 scratch.d.param.paramid = paramid;
2849 /* paramtype's not actually used, but we might as well fill it */
2850 scratch.d.param.paramtype = exprType((Node *) arg);
2851 ExprEvalPushStep(state, &scratch);
2852 }
2853
2854 sstate = ExecInitSubPlan(subplan, state->parent);
2855
2856 /* add SubPlanState nodes to state->parent->subPlan */
2857 state->parent->subPlan = lappend(state->parent->subPlan,
2858 sstate);
2859
2860 scratch.opcode = EEOP_SUBPLAN;
2861 scratch.resvalue = resv;
2862 scratch.resnull = resnull;
2863 scratch.d.subplan.sstate = sstate;
2864
2865 ExprEvalPushStep(state, &scratch);
2866}
@ EEOP_SUBPLAN
Definition: execExpr.h:270
@ EEOP_PARAM_SET
Definition: execExpr.h:172
SubPlanState * ExecInitSubPlan(SubPlan *subplan, PlanState *parent)
Definition: nodeSubplan.c:826
SubPlanState * sstate
Definition: execExpr.h:685
struct ExprEvalStep::@55::@96 subplan
List * args
Definition: primnodes.h:1108
List * parParam
Definition: primnodes.h:1107

References arg, SubPlan::args, Assert, ExprEvalStep::d, EEOP_PARAM_SET, EEOP_SUBPLAN, elog, ERROR, ExecInitExprRec(), ExecInitSubPlan(), ExprEvalPushStep(), exprType(), forboth, lappend(), lfirst, lfirst_int, list_length(), ExprEvalStep::opcode, ExprEvalStep::param, ExprEvalStep::paramid, ExprEvalStep::paramtype, SubPlan::parParam, ExprEvalStep::resnull, ExprEvalStep::resvalue, ExprEvalStep::sstate, and ExprEvalStep::subplan.

Referenced by ExecInitExprRec(), and ExecPushExprSetupSteps().

◆ ExecInitSubscriptingRef()

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

Definition at line 3235 of file execExpr.c.

3237{
3238 bool isAssignment = (sbsref->refassgnexpr != NULL);
3239 int nupper = list_length(sbsref->refupperindexpr);
3240 int nlower = list_length(sbsref->reflowerindexpr);
3241 const SubscriptRoutines *sbsroutines;
3242 SubscriptingRefState *sbsrefstate;
3243 SubscriptExecSteps methods;
3244 char *ptr;
3245 List *adjust_jumps = NIL;
3246 ListCell *lc;
3247 int i;
3248
3249 /* Look up the subscripting support methods */
3250 sbsroutines = getSubscriptingRoutines(sbsref->refcontainertype, NULL);
3251 if (!sbsroutines)
3252 ereport(ERROR,
3253 (errcode(ERRCODE_DATATYPE_MISMATCH),
3254 errmsg("cannot subscript type %s because it does not support subscripting",
3255 format_type_be(sbsref->refcontainertype)),
3256 state->parent ?
3257 executor_errposition(state->parent->state,
3258 exprLocation((Node *) sbsref)) : 0));
3259
3260 /* Allocate sbsrefstate, with enough space for per-subscript arrays too */
3261 sbsrefstate = palloc0(MAXALIGN(sizeof(SubscriptingRefState)) +
3262 (nupper + nlower) * (sizeof(Datum) +
3263 2 * sizeof(bool)));
3264
3265 /* Fill constant fields of SubscriptingRefState */
3266 sbsrefstate->isassignment = isAssignment;
3267 sbsrefstate->numupper = nupper;
3268 sbsrefstate->numlower = nlower;
3269 /* Set up per-subscript arrays */
3270 ptr = ((char *) sbsrefstate) + MAXALIGN(sizeof(SubscriptingRefState));
3271 sbsrefstate->upperindex = (Datum *) ptr;
3272 ptr += nupper * sizeof(Datum);
3273 sbsrefstate->lowerindex = (Datum *) ptr;
3274 ptr += nlower * sizeof(Datum);
3275 sbsrefstate->upperprovided = (bool *) ptr;
3276 ptr += nupper * sizeof(bool);
3277 sbsrefstate->lowerprovided = (bool *) ptr;
3278 ptr += nlower * sizeof(bool);
3279 sbsrefstate->upperindexnull = (bool *) ptr;
3280 ptr += nupper * sizeof(bool);
3281 sbsrefstate->lowerindexnull = (bool *) ptr;
3282 /* ptr += nlower * sizeof(bool); */
3283
3284 /*
3285 * Let the container-type-specific code have a chance. It must fill the
3286 * "methods" struct with function pointers for us to possibly use in
3287 * execution steps below; and it can optionally set up some data pointed
3288 * to by the workspace field.
3289 */
3290 memset(&methods, 0, sizeof(methods));
3291 sbsroutines->exec_setup(sbsref, sbsrefstate, &methods);
3292
3293 /*
3294 * Evaluate array input. It's safe to do so into resv/resnull, because we
3295 * won't use that as target for any of the other subexpressions, and it'll
3296 * be overwritten by the final EEOP_SBSREF_FETCH/ASSIGN step, which is
3297 * pushed last.
3298 */
3299 ExecInitExprRec(sbsref->refexpr, state, resv, resnull);
3300
3301 /*
3302 * If refexpr yields NULL, and the operation should be strict, then result
3303 * is NULL. We can implement this with just JUMP_IF_NULL, since we
3304 * evaluated the array into the desired target location.
3305 */
3306 if (!isAssignment && sbsroutines->fetch_strict)
3307 {
3308 scratch->opcode = EEOP_JUMP_IF_NULL;
3309 scratch->d.jump.jumpdone = -1; /* adjust later */
3310 ExprEvalPushStep(state, scratch);
3311 adjust_jumps = lappend_int(adjust_jumps,
3312 state->steps_len - 1);
3313 }
3314
3315 /* Evaluate upper subscripts */
3316 i = 0;
3317 foreach(lc, sbsref->refupperindexpr)
3318 {
3319 Expr *e = (Expr *) lfirst(lc);
3320
3321 /* When slicing, individual subscript bounds can be omitted */
3322 if (!e)
3323 {
3324 sbsrefstate->upperprovided[i] = false;
3325 sbsrefstate->upperindexnull[i] = true;
3326 }
3327 else
3328 {
3329 sbsrefstate->upperprovided[i] = true;
3330 /* Each subscript is evaluated into appropriate array entry */
3332 &sbsrefstate->upperindex[i],
3333 &sbsrefstate->upperindexnull[i]);
3334 }
3335 i++;
3336 }
3337
3338 /* Evaluate lower subscripts similarly */
3339 i = 0;
3340 foreach(lc, sbsref->reflowerindexpr)
3341 {
3342 Expr *e = (Expr *) lfirst(lc);
3343
3344 /* When slicing, individual subscript bounds can be omitted */
3345 if (!e)
3346 {
3347 sbsrefstate->lowerprovided[i] = false;
3348 sbsrefstate->lowerindexnull[i] = true;
3349 }
3350 else
3351 {
3352 sbsrefstate->lowerprovided[i] = true;
3353 /* Each subscript is evaluated into appropriate array entry */
3355 &sbsrefstate->lowerindex[i],
3356 &sbsrefstate->lowerindexnull[i]);
3357 }
3358 i++;
3359 }
3360
3361 /* SBSREF_SUBSCRIPTS checks and converts all the subscripts at once */
3362 if (methods.sbs_check_subscripts)
3363 {
3364 scratch->opcode = EEOP_SBSREF_SUBSCRIPTS;
3366 scratch->d.sbsref_subscript.state = sbsrefstate;
3367 scratch->d.sbsref_subscript.jumpdone = -1; /* adjust later */
3368 ExprEvalPushStep(state, scratch);
3369 adjust_jumps = lappend_int(adjust_jumps,
3370 state->steps_len - 1);
3371 }
3372
3373 if (isAssignment)
3374 {
3375 Datum *save_innermost_caseval;
3376 bool *save_innermost_casenull;
3377
3378 /* Check for unimplemented methods */
3379 if (!methods.sbs_assign)
3380 ereport(ERROR,
3381 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3382 errmsg("type %s does not support subscripted assignment",
3383 format_type_be(sbsref->refcontainertype))));
3384
3385 /*
3386 * We might have a nested-assignment situation, in which the
3387 * refassgnexpr is itself a FieldStore or SubscriptingRef that needs
3388 * to obtain and modify the previous value of the array element or
3389 * slice being replaced. If so, we have to extract that value from
3390 * the array and pass it down via the CaseTestExpr mechanism. It's
3391 * safe to reuse the CASE mechanism because there cannot be a CASE
3392 * between here and where the value would be needed, and an array
3393 * assignment can't be within a CASE either. (So saving and restoring
3394 * innermost_caseval is just paranoia, but let's do it anyway.)
3395 *
3396 * Since fetching the old element might be a nontrivial expense, do it
3397 * only if the argument actually needs it.
3398 */
3400 {
3401 if (!methods.sbs_fetch_old)
3402 ereport(ERROR,
3403 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3404 errmsg("type %s does not support subscripted assignment",
3405 format_type_be(sbsref->refcontainertype))));
3406 scratch->opcode = EEOP_SBSREF_OLD;
3407 scratch->d.sbsref.subscriptfunc = methods.sbs_fetch_old;
3408 scratch->d.sbsref.state = sbsrefstate;
3409 ExprEvalPushStep(state, scratch);
3410 }
3411
3412 /* SBSREF_OLD puts extracted value into prevvalue/prevnull */
3413 save_innermost_caseval = state->innermost_caseval;
3414 save_innermost_casenull = state->innermost_casenull;
3415 state->innermost_caseval = &sbsrefstate->prevvalue;
3416 state->innermost_casenull = &sbsrefstate->prevnull;
3417
3418 /* evaluate replacement value into replacevalue/replacenull */
3420 &sbsrefstate->replacevalue, &sbsrefstate->replacenull);
3421
3422 state->innermost_caseval = save_innermost_caseval;
3423 state->innermost_casenull = save_innermost_casenull;
3424
3425 /* and perform the assignment */
3426 scratch->opcode = EEOP_SBSREF_ASSIGN;
3427 scratch->d.sbsref.subscriptfunc = methods.sbs_assign;
3428 scratch->d.sbsref.state = sbsrefstate;
3429 ExprEvalPushStep(state, scratch);
3430 }
3431 else
3432 {
3433 /* array fetch is much simpler */
3434 scratch->opcode = EEOP_SBSREF_FETCH;
3435 scratch->d.sbsref.subscriptfunc = methods.sbs_fetch;
3436 scratch->d.sbsref.state = sbsrefstate;
3437 ExprEvalPushStep(state, scratch);
3438 }
3439
3440 /* adjust jump targets */
3441 foreach(lc, adjust_jumps)
3442 {
3443 ExprEvalStep *as = &state->steps[lfirst_int(lc)];
3444
3445 if (as->opcode == EEOP_SBSREF_SUBSCRIPTS)
3446 {
3447 Assert(as->d.sbsref_subscript.jumpdone == -1);
3448 as->d.sbsref_subscript.jumpdone = state->steps_len;
3449 }
3450 else
3451 {
3453 Assert(as->d.jump.jumpdone == -1);
3454 as->d.jump.jumpdone = state->steps_len;
3455 }
3456 }
3457}
#define MAXALIGN(LEN)
Definition: c.h:768
static bool isAssignmentIndirectionExpr(Expr *expr)
Definition: execExpr.c:3477
@ EEOP_SBSREF_SUBSCRIPTS
Definition: execExpr.h:224
@ EEOP_SBSREF_FETCH
Definition: execExpr.h:237
@ EEOP_SBSREF_ASSIGN
Definition: execExpr.h:234
@ EEOP_SBSREF_OLD
Definition: execExpr.h:231
const struct SubscriptRoutines * getSubscriptingRoutines(Oid typid, Oid *typelemp)
Definition: lsyscache.c:3157
ExecEvalBoolSubroutine subscriptfunc
Definition: execExpr.h:562
struct SubscriptingRefState * state
Definition: execExpr.h:564
struct ExprEvalStep::@55::@83 sbsref_subscript
struct ExprEvalStep::@55::@84 sbsref
ExecEvalSubroutine sbs_fetch_old
Definition: execExpr.h:811
ExecEvalBoolSubroutine sbs_check_subscripts
Definition: execExpr.h:808
ExecEvalSubroutine sbs_assign
Definition: execExpr.h:810
ExecEvalSubroutine sbs_fetch
Definition: execExpr.h:809
SubscriptExecSetup exec_setup
Definition: subscripting.h:161
Expr * refassgnexpr
Definition: primnodes.h:720
List * refupperindexpr
Definition: primnodes.h:710
Expr * refexpr
Definition: primnodes.h:718
List * reflowerindexpr
Definition: primnodes.h:716

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

Referenced by ExecInitExprRec().

◆ ExecInitWholeRowVar()

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

Definition at line 3156 of file execExpr.c.

3157{
3158 PlanState *parent = state->parent;
3159
3160 /* fill in all but the target */
3161 scratch->opcode = EEOP_WHOLEROW;
3162 scratch->d.wholerow.var = variable;
3163 scratch->d.wholerow.first = true;
3164 scratch->d.wholerow.slow = false;
3165 scratch->d.wholerow.tupdesc = NULL; /* filled at runtime */
3166 scratch->d.wholerow.junkFilter = NULL;
3167
3168 /* update ExprState flags if Var refers to OLD/NEW */
3169 if (variable->varreturningtype == VAR_RETURNING_OLD)
3170 state->flags |= EEO_FLAG_HAS_OLD;
3171 else if (variable->varreturningtype == VAR_RETURNING_NEW)
3172 state->flags |= EEO_FLAG_HAS_NEW;
3173
3174 /*
3175 * If the input tuple came from a subquery, it might contain "resjunk"
3176 * columns (such as GROUP BY or ORDER BY columns), which we don't want to
3177 * keep in the whole-row result. We can get rid of such columns by
3178 * passing the tuple through a JunkFilter --- but to make one, we have to
3179 * lay our hands on the subquery's targetlist. Fortunately, there are not
3180 * very many cases where this can happen, and we can identify all of them
3181 * by examining our parent PlanState. We assume this is not an issue in
3182 * standalone expressions that don't have parent plans. (Whole-row Vars
3183 * can occur in such expressions, but they will always be referencing
3184 * table rows.)
3185 */
3186 if (parent)
3187 {
3188 PlanState *subplan = NULL;
3189
3190 switch (nodeTag(parent))
3191 {
3192 case T_SubqueryScanState:
3193 subplan = ((SubqueryScanState *) parent)->subplan;
3194 break;
3195 case T_CteScanState:
3196 subplan = ((CteScanState *) parent)->cteplanstate;
3197 break;
3198 default:
3199 break;
3200 }
3201
3202 if (subplan)
3203 {
3204 bool junk_filter_needed = false;
3205 ListCell *tlist;
3206
3207 /* Detect whether subplan tlist actually has any junk columns */
3208 foreach(tlist, subplan->plan->targetlist)
3209 {
3210 TargetEntry *tle = (TargetEntry *) lfirst(tlist);
3211
3212 if (tle->resjunk)
3213 {
3214 junk_filter_needed = true;
3215 break;
3216 }
3217 }
3218
3219 /* If so, build the junkfilter now */
3220 if (junk_filter_needed)
3221 {
3222 scratch->d.wholerow.junkFilter =
3224 ExecInitExtraTupleSlot(parent->state, NULL,
3225 &TTSOpsVirtual));
3226 }
3227 }
3228 }
3229}
@ EEOP_WHOLEROW
Definition: execExpr.h:93
JunkFilter * ExecInitJunkFilter(List *targetList, TupleTableSlot *slot)
Definition: execJunk.c:60
TupleTableSlot * ExecInitExtraTupleSlot(EState *estate, TupleDesc tupledesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:2018
JunkFilter * junkFilter
Definition: execExpr.h:345
struct ExprEvalStep::@55::@58 wholerow
bool first
Definition: execExpr.h:342
Plan * plan
Definition: execnodes.h:1153
EState * state
Definition: execnodes.h:1155
List * targetlist
Definition: plannodes.h:199

References ExprEvalStep::d, EEO_FLAG_HAS_NEW, EEO_FLAG_HAS_OLD, EEOP_WHOLEROW, ExecInitExtraTupleSlot(), ExecInitJunkFilter(), ExprEvalStep::first, ExprEvalStep::junkFilter, lfirst, nodeTag, ExprEvalStep::opcode, PlanState::plan, ExprEvalStep::slow, PlanState::state, Plan::targetlist, TTSOpsVirtual, ExprEvalStep::tupdesc, ExprEvalStep::var, VAR_RETURNING_NEW, VAR_RETURNING_OLD, and ExprEvalStep::wholerow.

Referenced by ExecInitExprRec().

◆ ExecPrepareCheck()

ExprState * ExecPrepareCheck ( List qual,
EState estate 
)

Definition at line 816 of file execExpr.c.

817{
818 ExprState *result;
819 MemoryContext oldcontext;
820
821 oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
822
823 qual = (List *) expression_planner((Expr *) qual);
824
825 result = ExecInitCheck(qual, NULL);
826
827 MemoryContextSwitchTo(oldcontext);
828
829 return result;
830}
ExprState * ExecInitCheck(List *qual, PlanState *parent)
Definition: execExpr.c:315
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
Expr * expression_planner(Expr *expr)
Definition: planner.c:6581
MemoryContext es_query_cxt
Definition: execnodes.h:702

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

Referenced by ExecPartitionCheck().

◆ ExecPrepareExpr()

ExprState * ExecPrepareExpr ( Expr node,
EState estate 
)

◆ ExecPrepareExprList()

List * ExecPrepareExprList ( List nodes,
EState estate 
)

Definition at line 839 of file execExpr.c.

840{
841 List *result = NIL;
842 MemoryContext oldcontext;
843 ListCell *lc;
844
845 /* Ensure that the list cell nodes are in the right context too */
846 oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
847
848 foreach(lc, nodes)
849 {
850 Expr *e = (Expr *) lfirst(lc);
851
852 result = lappend(result, ExecPrepareExpr(e, estate));
853 }
854
855 MemoryContextSwitchTo(oldcontext);
856
857 return result;
858}
ExprState * ExecPrepareExpr(Expr *node, EState *estate)
Definition: execExpr.c:765

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

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

◆ ExecPrepareQual()

ExprState * ExecPrepareQual ( List qual,
EState estate 
)

Definition at line 793 of file execExpr.c.

794{
795 ExprState *result;
796 MemoryContext oldcontext;
797
798 oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
799
800 qual = (List *) expression_planner((Expr *) qual);
801
802 result = ExecInitQual(qual, NULL);
803
804 MemoryContextSwitchTo(oldcontext);
805
806 return result;
807}
ExprState * ExecInitQual(List *qual, PlanState *parent)
Definition: execExpr.c:229

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

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

◆ ExecPushExprSetupSteps()

static void ExecPushExprSetupSteps ( ExprState state,
ExprSetupInfo info 
)
static

Definition at line 2889 of file execExpr.c.

2890{
2891 ExprEvalStep scratch = {0};
2892 ListCell *lc;
2893
2894 scratch.resvalue = NULL;
2895 scratch.resnull = NULL;
2896
2897 /*
2898 * Add steps deforming the ExprState's inner/outer/scan/old/new slots as
2899 * much as required by any Vars appearing in the expression.
2900 */
2901 if (info->last_inner > 0)
2902 {
2903 scratch.opcode = EEOP_INNER_FETCHSOME;
2904 scratch.d.fetch.last_var = info->last_inner;
2905 scratch.d.fetch.fixed = false;
2906 scratch.d.fetch.kind = NULL;
2907 scratch.d.fetch.known_desc = NULL;
2908 if (ExecComputeSlotInfo(state, &scratch))
2909 ExprEvalPushStep(state, &scratch);
2910 }
2911 if (info->last_outer > 0)
2912 {
2913 scratch.opcode = EEOP_OUTER_FETCHSOME;
2914 scratch.d.fetch.last_var = info->last_outer;
2915 scratch.d.fetch.fixed = false;
2916 scratch.d.fetch.kind = NULL;
2917 scratch.d.fetch.known_desc = NULL;
2918 if (ExecComputeSlotInfo(state, &scratch))
2919 ExprEvalPushStep(state, &scratch);
2920 }
2921 if (info->last_scan > 0)
2922 {
2923 scratch.opcode = EEOP_SCAN_FETCHSOME;
2924 scratch.d.fetch.last_var = info->last_scan;
2925 scratch.d.fetch.fixed = false;
2926 scratch.d.fetch.kind = NULL;
2927 scratch.d.fetch.known_desc = NULL;
2928 if (ExecComputeSlotInfo(state, &scratch))
2929 ExprEvalPushStep(state, &scratch);
2930 }
2931 if (info->last_old > 0)
2932 {
2933 scratch.opcode = EEOP_OLD_FETCHSOME;
2934 scratch.d.fetch.last_var = info->last_old;
2935 scratch.d.fetch.fixed = false;
2936 scratch.d.fetch.kind = NULL;
2937 scratch.d.fetch.known_desc = NULL;
2938 if (ExecComputeSlotInfo(state, &scratch))
2939 ExprEvalPushStep(state, &scratch);
2940 }
2941 if (info->last_new > 0)
2942 {
2943 scratch.opcode = EEOP_NEW_FETCHSOME;
2944 scratch.d.fetch.last_var = info->last_new;
2945 scratch.d.fetch.fixed = false;
2946 scratch.d.fetch.kind = NULL;
2947 scratch.d.fetch.known_desc = NULL;
2948 if (ExecComputeSlotInfo(state, &scratch))
2949 ExprEvalPushStep(state, &scratch);
2950 }
2951
2952 /*
2953 * Add steps to execute any MULTIEXPR SubPlans appearing in the
2954 * expression. We need to evaluate these before any of the Params
2955 * referencing their outputs are used, but after we've prepared for any
2956 * Var references they may contain. (There cannot be cross-references
2957 * between MULTIEXPR SubPlans, so we needn't worry about their order.)
2958 */
2959 foreach(lc, info->multiexpr_subplans)
2960 {
2961 SubPlan *subplan = (SubPlan *) lfirst(lc);
2962
2964
2965 /* The result can be ignored, but we better put it somewhere */
2966 ExecInitSubPlanExpr(subplan, state,
2967 &state->resvalue, &state->resnull);
2968 }
2969}
AttrNumber last_inner
Definition: execExpr.c:62
AttrNumber last_new
Definition: execExpr.c:66
List * multiexpr_subplans
Definition: execExpr.c:68
AttrNumber last_old
Definition: execExpr.c:65

References Assert, ExprEvalStep::d, EEOP_INNER_FETCHSOME, EEOP_NEW_FETCHSOME, EEOP_OLD_FETCHSOME, EEOP_OUTER_FETCHSOME, EEOP_SCAN_FETCHSOME, ExecComputeSlotInfo(), ExecInitSubPlanExpr(), ExprEvalPushStep(), ExprEvalStep::fetch, ExprEvalStep::fixed, ExprEvalStep::kind, ExprEvalStep::known_desc, ExprSetupInfo::last_inner, ExprSetupInfo::last_new, ExprSetupInfo::last_old, ExprSetupInfo::last_outer, ExprSetupInfo::last_scan, ExprEvalStep::last_var, lfirst, MULTIEXPR_SUBLINK, ExprSetupInfo::multiexpr_subplans, ExprEvalStep::opcode, ExprEvalStep::resnull, ExprEvalStep::resvalue, and SubPlan::subLinkType.

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

◆ ExecReadyExpr()

static void ExecReadyExpr ( ExprState state)
static

◆ expr_setup_walker()

static bool expr_setup_walker ( Node node,
ExprSetupInfo info 
)
static

Definition at line 2975 of file execExpr.c.

2976{
2977 if (node == NULL)
2978 return false;
2979 if (IsA(node, Var))
2980 {
2981 Var *variable = (Var *) node;
2982 AttrNumber attnum = variable->varattno;
2983
2984 switch (variable->varno)
2985 {
2986 case INNER_VAR:
2987 info->last_inner = Max(info->last_inner, attnum);
2988 break;
2989
2990 case OUTER_VAR:
2991 info->last_outer = Max(info->last_outer, attnum);
2992 break;
2993
2994 /* INDEX_VAR is handled by default case */
2995
2996 default:
2997 switch (variable->varreturningtype)
2998 {
3000 info->last_scan = Max(info->last_scan, attnum);
3001 break;
3002 case VAR_RETURNING_OLD:
3003 info->last_old = Max(info->last_old, attnum);
3004 break;
3005 case VAR_RETURNING_NEW:
3006 info->last_new = Max(info->last_new, attnum);
3007 break;
3008 }
3009 break;
3010 }
3011 return false;
3012 }
3013
3014 /* Collect all MULTIEXPR SubPlans, too */
3015 if (IsA(node, SubPlan))
3016 {
3017 SubPlan *subplan = (SubPlan *) node;
3018
3019 if (subplan->subLinkType == MULTIEXPR_SUBLINK)
3021 subplan);
3022 }
3023
3024 /*
3025 * Don't examine the arguments or filters of Aggrefs or WindowFuncs,
3026 * because those do not represent expressions to be evaluated within the
3027 * calling expression's econtext. GroupingFunc arguments are never
3028 * evaluated at all.
3029 */
3030 if (IsA(node, Aggref))
3031 return false;
3032 if (IsA(node, WindowFunc))
3033 return false;
3034 if (IsA(node, GroupingFunc))
3035 return false;
3036 return expression_tree_walker(node, expr_setup_walker, info);
3037}
#define expression_tree_walker(n, w, c)
Definition: nodeFuncs.h:153

References attnum, expr_setup_walker(), expression_tree_walker, 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 3477 of file execExpr.c.

3478{
3479 if (expr == NULL)
3480 return false; /* just paranoia */
3481 if (IsA(expr, FieldStore))
3482 {
3483 FieldStore *fstore = (FieldStore *) expr;
3484
3485 if (fstore->arg && IsA(fstore->arg, CaseTestExpr))
3486 return true;
3487 }
3488 else if (IsA(expr, SubscriptingRef))
3489 {
3490 SubscriptingRef *sbsRef = (SubscriptingRef *) expr;
3491
3492 if (sbsRef->refexpr && IsA(sbsRef->refexpr, CaseTestExpr))
3493 return true;
3494 }
3495 else if (IsA(expr, CoerceToDomain))
3496 {
3497 CoerceToDomain *cd = (CoerceToDomain *) expr;
3498
3499 return isAssignmentIndirectionExpr(cd->arg);
3500 }
3501 else if (IsA(expr, RelabelType))
3502 {
3503 RelabelType *r = (RelabelType *) expr;
3504
3506 }
3507 return false;
3508}

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

Referenced by ExecInitSubscriptingRef(), and isAssignmentIndirectionExpr().