| Line | Hits | Source | Commit |
| 919 |
- |
ExecInitExprRec(Expr *node, ExprState *state, |
- |
| 920 |
- |
Datum *resv, bool *resnull) |
- |
| 921 |
- |
{ |
- |
| 922 |
- |
ExprEvalStep scratch = {0}; |
- |
| 923 |
- |
|
- |
| 924 |
- |
/* Guard against stack overflow due to overly complex expressions */ |
- |
| 925 |
- |
check_stack_depth(); |
- |
| 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 */ |
- |
| 942 |
- |
ExecInitWholeRowVar(&scratch, variable, state); |
- |
| 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 |
- |
{ |
- |
| 964 |
- |
case VAR_RETURNING_DEFAULT: |
- |
| 965 |
- |
scratch.opcode = EEOP_SCAN_SYSVAR; |
- |
| 966 |
- |
break; |
- |
| 967 |
- |
case VAR_RETURNING_OLD: |
- |
| 968 |
- |
scratch.opcode = EEOP_OLD_SYSVAR; |
- |
| 969 |
- |
state->flags |= EEO_FLAG_HAS_OLD; |
- |
| 970 |
- |
break; |
- |
| 971 |
- |
case VAR_RETURNING_NEW: |
- |
| 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 |
- |
{ |
- |
| 999 |
- |
case VAR_RETURNING_DEFAULT: |
- |
| 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; |
- |
| 1128 |
- |
WindowFuncExprState *wfstate = makeNode(WindowFuncExprState); |
- |
| 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 |
- |
|
- |
| 1179 |
- |
scratch.opcode = EEOP_MERGE_SUPPORT_FUNC; |
- |
| 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 |
1028 |
case T_RPRNavExpr: |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1193 |
- |
{ |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1194 |
- |
/* |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1195 |
- |
* RPR navigation functions (PREV/NEXT/FIRST/LAST) are |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1196 |
- |
* compiled into EEOP_RPR_NAV_SET / EEOP_RPR_NAV_RESTORE |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1197 |
- |
* opcodes instead of a normal function call. The SET opcode |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1198 |
- |
* swaps ecxt_outertuple to the target row, the argument |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1199 |
- |
* expression is compiled normally (reads from the swapped |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1200 |
- |
* slot), and the RESTORE opcode restores the original slot. |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1201 |
- |
* |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1202 |
- |
* Default offset when offset_arg is NULL: PREV/NEXT: 1 |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1203 |
- |
* (physical offset from currentpos) FIRST/LAST: 0 (logical |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1204 |
- |
* offset from match boundary) |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1205 |
- |
*/ |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1206 |
1028 |
RPRNavExpr *nav = (RPRNavExpr *) node; |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1207 |
1028 |
WindowAggState *winstate; |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1208 |
- |
|
24cfb8dRow pattern recognition patch (executor and commands). |
| 1209 |
1028 |
Assert(state->parent && IsA(state->parent, WindowAggState)); |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1210 |
1028 |
winstate = (WindowAggState *) state->parent; |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1211 |
- |
|
24cfb8dRow pattern recognition patch (executor and commands). |
| 1212 |
- |
/* Emit SET opcode: swap slot to target row */ |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1213 |
1028 |
scratch.opcode = EEOP_RPR_NAV_SET; |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1214 |
1028 |
scratch.d.rpr_nav.winstate = winstate; |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1215 |
1028 |
scratch.d.rpr_nav.kind = nav->kind; |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1216 |
- |
|
24cfb8dRow pattern recognition patch (executor and commands). |
| 1217 |
1028 |
if (nav->kind >= RPR_NAV_PREV_FIRST) |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1218 |
- |
{ |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1219 |
- |
/* |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1220 |
- |
* Compound navigation: allocate array of 2 for inner [0] |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1221 |
- |
* and outer [1] offsets. |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1222 |
- |
*/ |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1223 |
136 |
Datum *offset_values = palloc_array(Datum, 2); |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1224 |
136 |
bool *offset_isnulls = palloc_array(bool, 2); |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1225 |
- |
|
24cfb8dRow pattern recognition patch (executor and commands). |
| 1226 |
- |
/* Inner offset (default 0 for FIRST/LAST) */ |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1227 |
136 |
if (nav->offset_arg != NULL) |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1228 |
64 |
ExecInitExprRec(nav->offset_arg, state, |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1229 |
- |
&offset_values[0], &offset_isnulls[0]); |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1230 |
- |
else |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1231 |
- |
{ |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1232 |
72 |
offset_values[0] = Int64GetDatum(0); |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1233 |
72 |
offset_isnulls[0] = false; |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1234 |
- |
} |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1235 |
- |
|
24cfb8dRow pattern recognition patch (executor and commands). |
| 1236 |
- |
/* Outer offset (default 1 for PREV/NEXT) */ |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1237 |
136 |
if (nav->compound_offset_arg != NULL) |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1238 |
128 |
ExecInitExprRec(nav->compound_offset_arg, state, |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1239 |
- |
&offset_values[1], &offset_isnulls[1]); |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1240 |
- |
else |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1241 |
- |
{ |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1242 |
8 |
offset_values[1] = Int64GetDatum(1); |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1243 |
8 |
offset_isnulls[1] = false; |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1244 |
- |
} |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1245 |
- |
|
24cfb8dRow pattern recognition patch (executor and commands). |
| 1246 |
136 |
scratch.d.rpr_nav.offset_value = offset_values; |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1247 |
136 |
scratch.d.rpr_nav.offset_isnull = offset_isnulls; |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1248 |
- |
} |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1249 |
892 |
else if (nav->offset_arg != NULL) |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1250 |
- |
{ |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1251 |
- |
/* Simple navigation with explicit offset */ |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1252 |
192 |
Datum *offset_value = palloc_object(Datum); |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1253 |
192 |
bool *offset_isnull = palloc_object(bool); |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1254 |
- |
|
24cfb8dRow pattern recognition patch (executor and commands). |
| 1255 |
192 |
ExecInitExprRec(nav->offset_arg, state, |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1256 |
- |
offset_value, offset_isnull); |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1257 |
192 |
scratch.d.rpr_nav.offset_value = offset_value; |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1258 |
192 |
scratch.d.rpr_nav.offset_isnull = offset_isnull; |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1259 |
- |
} |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1260 |
- |
else |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1261 |
- |
{ |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1262 |
- |
/* Simple navigation with default offset */ |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1263 |
700 |
scratch.d.rpr_nav.offset_value = NULL; |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1264 |
700 |
scratch.d.rpr_nav.offset_isnull = NULL; |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1265 |
- |
} |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1266 |
- |
|
24cfb8dRow pattern recognition patch (executor and commands). |
| 1267 |
1028 |
ExprEvalPushStep(state, &scratch); |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1268 |
- |
|
24cfb8dRow pattern recognition patch (executor and commands). |
| 1269 |
- |
/* Compile the argument expression normally */ |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1270 |
1028 |
ExecInitExprRec(nav->arg, state, resv, resnull); |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1271 |
- |
|
24cfb8dRow pattern recognition patch (executor and commands). |
| 1272 |
- |
/* Emit RESTORE opcode: restore original slot */ |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1273 |
1028 |
scratch.opcode = EEOP_RPR_NAV_RESTORE; |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1274 |
1028 |
scratch.resvalue = resv; |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1275 |
1028 |
scratch.resnull = resnull; |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1276 |
1028 |
scratch.d.rpr_nav.winstate = winstate; |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1277 |
1028 |
get_typlenbyval(nav->resulttype, |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1278 |
- |
&scratch.d.rpr_nav.resulttyplen, |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1279 |
- |
&scratch.d.rpr_nav.resulttypbyval); |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1280 |
1028 |
ExprEvalPushStep(state, &scratch); |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1281 |
- |
break; |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1282 |
- |
} |
24cfb8dRow pattern recognition patch (executor and commands). |
| 1283 |
- |
|
24cfb8dRow pattern recognition patch (executor and commands). |
| 1284 |
- |
case T_FuncExpr: |
- |
| 1285 |
- |
{ |
- |
| 1286 |
- |
FuncExpr *func = (FuncExpr *) node; |
- |
| 1287 |
- |
|
- |
| 1288 |
- |
ExecInitFunc(&scratch, node, |
- |
| 1289 |
- |
func->args, func->funcid, func->inputcollid, |
- |
| 1290 |
- |
state); |
- |
| 1291 |
- |
ExprEvalPushStep(state, &scratch); |
- |
| 1292 |
- |
break; |
- |
| 1293 |
- |
} |
- |
| 1294 |
- |
|
- |
| 1295 |
- |
case T_OpExpr: |
- |
| 1296 |
- |
{ |
- |
| 1297 |
- |
OpExpr *op = (OpExpr *) node; |
- |
| 1298 |
- |
|
- |
| 1299 |
- |
ExecInitFunc(&scratch, node, |
- |
| 1300 |
- |
op->args, op->opfuncid, op->inputcollid, |
- |
| 1301 |
- |
state); |
- |
| 1302 |
- |
ExprEvalPushStep(state, &scratch); |
- |
| 1303 |
- |
break; |
- |
| 1304 |
- |
} |
- |
| 1305 |
- |
|
- |
| 1306 |
- |
case T_DistinctExpr: |
- |
| 1307 |
- |
{ |
- |
| 1308 |
- |
DistinctExpr *op = (DistinctExpr *) node; |
- |
| 1309 |
- |
|
- |
| 1310 |
- |
ExecInitFunc(&scratch, node, |
- |
| 1311 |
- |
op->args, op->opfuncid, op->inputcollid, |
- |
| 1312 |
- |
state); |
- |
| 1313 |
- |
|
- |
| 1314 |
- |
/* |
- |
| 1315 |
- |
* Change opcode of call instruction to EEOP_DISTINCT. |
- |
| 1316 |
- |
* |
- |
| 1317 |
- |
* XXX: historically we've not called the function usage |
- |
| 1318 |
- |
* pgstat infrastructure - that seems inconsistent given that |
- |
| 1319 |
- |
* we do so for normal function *and* operator evaluation. If |
- |
| 1320 |
- |
* we decided to do that here, we'd probably want separate |
- |
| 1321 |
- |
* opcodes for FUSAGE or not. |
- |
| 1322 |
- |
*/ |
- |
| 1323 |
- |
scratch.opcode = EEOP_DISTINCT; |
- |
| 1324 |
- |
ExprEvalPushStep(state, &scratch); |
- |
| 1325 |
- |
break; |
- |
| 1326 |
- |
} |
- |
| 1327 |
- |
|
- |
| 1328 |
- |
case T_NullIfExpr: |
- |
| 1329 |
- |
{ |
- |
| 1330 |
- |
NullIfExpr *op = (NullIfExpr *) node; |
- |
| 1331 |
- |
|
- |
| 1332 |
- |
ExecInitFunc(&scratch, node, |
- |
| 1333 |
- |
op->args, op->opfuncid, op->inputcollid, |
- |
| 1334 |
- |
state); |
- |
| 1335 |
- |
|
- |
| 1336 |
- |
/* |
- |
| 1337 |
- |
* If first argument is of varlena type, we'll need to ensure |
- |
| 1338 |
- |
* that the value passed to the comparison function is a |
- |
| 1339 |
- |
* read-only pointer. |
- |
| 1340 |
- |
*/ |
- |
| 1341 |
- |
scratch.d.func.make_ro = |
- |
| 1342 |
- |
(get_typlen(exprType((Node *) linitial(op->args))) == -1); |
- |
| 1343 |
- |
|
- |
| 1344 |
- |
/* |
- |
| 1345 |
- |
* Change opcode of call instruction to EEOP_NULLIF. |
- |
| 1346 |
- |
* |
- |
| 1347 |
- |
* XXX: historically we've not called the function usage |
- |
| 1348 |
- |
* pgstat infrastructure - that seems inconsistent given that |
- |
| 1349 |
- |
* we do so for normal function *and* operator evaluation. If |
- |
| 1350 |
- |
* we decided to do that here, we'd probably want separate |
- |
| 1351 |
- |
* opcodes for FUSAGE or not. |
- |
| 1352 |
- |
*/ |
- |
| 1353 |
- |
scratch.opcode = EEOP_NULLIF; |
- |
| 1354 |
- |
ExprEvalPushStep(state, &scratch); |
- |
| 1355 |
- |
break; |
- |
| 1356 |
- |
} |
- |
| 1357 |
- |
|
- |
| 1358 |
- |
case T_ScalarArrayOpExpr: |
- |
| 1359 |
- |
{ |
- |
| 1360 |
- |
ScalarArrayOpExpr *opexpr = (ScalarArrayOpExpr *) node; |
- |
| 1361 |
- |
Expr *scalararg; |
- |
| 1362 |
- |
Expr *arrayarg; |
- |
| 1363 |
- |
FmgrInfo *finfo; |
- |
| 1364 |
- |
FunctionCallInfo fcinfo; |
- |
| 1365 |
- |
AclResult aclresult; |
- |
| 1366 |
- |
Oid cmpfuncid; |
- |
| 1367 |
- |
|
- |
| 1368 |
- |
/* |
- |
| 1369 |
- |
* Select the correct comparison function. When we do hashed |
- |
| 1370 |
- |
* NOT IN clauses, the opfuncid will be the inequality |
- |
| 1371 |
- |
* comparison function and negfuncid will be set to equality. |
- |
| 1372 |
- |
* We need to use the equality function for hash probes. |
- |
| 1373 |
- |
*/ |
- |
| 1374 |
- |
if (OidIsValid(opexpr->negfuncid)) |
- |
| 1375 |
- |
{ |
- |
| 1376 |
- |
Assert(OidIsValid(opexpr->hashfuncid)); |
- |
| 1377 |
- |
cmpfuncid = opexpr->negfuncid; |
- |
| 1378 |
- |
} |
- |
| 1379 |
- |
else |
- |
| 1380 |
- |
cmpfuncid = opexpr->opfuncid; |
- |
| 1381 |
- |
|
- |
| 1382 |
- |
Assert(list_length(opexpr->args) == 2); |
- |
| 1383 |
- |
scalararg = (Expr *) linitial(opexpr->args); |
- |
| 1384 |
- |
arrayarg = (Expr *) lsecond(opexpr->args); |
- |
| 1385 |
- |
|
- |
| 1386 |
- |
/* Check permission to call function */ |
- |
| 1387 |
- |
aclresult = object_aclcheck(ProcedureRelationId, cmpfuncid, |
- |
| 1388 |
- |
GetUserId(), |
- |
| 1389 |
- |
ACL_EXECUTE); |
- |
| 1390 |
- |
if (aclresult != ACLCHECK_OK) |
- |
| 1391 |
- |
aclcheck_error(aclresult, OBJECT_FUNCTION, |
- |
| 1392 |
- |
get_func_name(cmpfuncid)); |
- |
| 1393 |
- |
InvokeFunctionExecuteHook(cmpfuncid); |
- |
| 1394 |
- |
|
- |
| 1395 |
- |
if (OidIsValid(opexpr->hashfuncid)) |
- |
| 1396 |
- |
{ |
- |
| 1397 |
- |
aclresult = object_aclcheck(ProcedureRelationId, opexpr->hashfuncid, |
- |
| 1398 |
- |
GetUserId(), |
- |
| 1399 |
- |
ACL_EXECUTE); |
- |
| 1400 |
- |
if (aclresult != ACLCHECK_OK) |
- |
| 1401 |
- |
aclcheck_error(aclresult, OBJECT_FUNCTION, |
- |
| 1402 |
- |
get_func_name(opexpr->hashfuncid)); |
- |
| 1403 |
- |
InvokeFunctionExecuteHook(opexpr->hashfuncid); |
- |
| 1404 |
- |
} |
- |
| 1405 |
- |
|
- |
| 1406 |
- |
/* Set up the primary fmgr lookup information */ |
- |
| 1407 |
- |
finfo = palloc0_object(FmgrInfo); |
- |
| 1408 |
- |
fcinfo = palloc0(SizeForFunctionCallInfo(2)); |
- |
| 1409 |
- |
fmgr_info(cmpfuncid, finfo); |
- |
| 1410 |
- |
fmgr_info_set_expr((Node *) node, finfo); |
- |
| 1411 |
- |
InitFunctionCallInfoData(*fcinfo, finfo, 2, |
- |
| 1412 |
- |
opexpr->inputcollid, NULL, NULL); |
- |
| 1413 |
- |
|
- |
| 1414 |
- |
/* |
- |
| 1415 |
- |
* If hashfuncid is set, we create a EEOP_HASHED_SCALARARRAYOP |
- |
| 1416 |
- |
* step instead of a EEOP_SCALARARRAYOP. This provides much |
- |
| 1417 |
- |
* faster lookup performance than the normal linear search |
- |
| 1418 |
- |
* when the number of items in the array is anything but very |
- |
| 1419 |
- |
* small. |
- |
| 1420 |
- |
*/ |
- |
| 1421 |
- |
if (OidIsValid(opexpr->hashfuncid)) |
- |
| 1422 |
- |
{ |
- |
| 1423 |
- |
/* Evaluate scalar directly into left function argument */ |
- |
| 1424 |
- |
ExecInitExprRec(scalararg, state, |
- |
| 1425 |
- |
&fcinfo->args[0].value, &fcinfo->args[0].isnull); |
- |
| 1426 |
- |
|
- |
| 1427 |
- |
/* |
- |
| 1428 |
- |
* Evaluate array argument into our return value. There's |
- |
| 1429 |
- |
* no danger in that, because the return value is |
- |
| 1430 |
- |
* guaranteed to be overwritten by |
- |
| 1431 |
- |
* EEOP_HASHED_SCALARARRAYOP, and will not be passed to |
- |
| 1432 |
- |
* any other expression. |
- |
| 1433 |
- |
*/ |
- |
| 1434 |
- |
ExecInitExprRec(arrayarg, state, resv, resnull); |
- |
| 1435 |
- |
|
- |
| 1436 |
- |
/* And perform the operation */ |
- |
| 1437 |
- |
scratch.opcode = EEOP_HASHED_SCALARARRAYOP; |
- |
| 1438 |
- |
scratch.d.hashedscalararrayop.inclause = opexpr->useOr; |
- |
| 1439 |
- |
scratch.d.hashedscalararrayop.finfo = finfo; |
- |
| 1440 |
- |
scratch.d.hashedscalararrayop.fcinfo_data = fcinfo; |
- |
| 1441 |
- |
scratch.d.hashedscalararrayop.saop = opexpr; |
- |
| 1442 |
- |
|
- |
| 1443 |
- |
|
- |
| 1444 |
- |
ExprEvalPushStep(state, &scratch); |
- |
| 1445 |
- |
} |
- |
| 1446 |
- |
else |
- |
| 1447 |
- |
{ |
- |
| 1448 |
- |
/* Evaluate scalar directly into left function argument */ |
- |
| 1449 |
- |
ExecInitExprRec(scalararg, state, |
- |
| 1450 |
- |
&fcinfo->args[0].value, |
- |
| 1451 |
- |
&fcinfo->args[0].isnull); |
- |
| 1452 |
- |
|
- |
| 1453 |
- |
/* |
- |
| 1454 |
- |
* Evaluate array argument into our return value. There's |
- |
| 1455 |
- |
* no danger in that, because the return value is |
- |
| 1456 |
- |
* guaranteed to be overwritten by EEOP_SCALARARRAYOP, and |
- |
| 1457 |
- |
* will not be passed to any other expression. |
- |
| 1458 |
- |
*/ |
- |
| 1459 |
- |
ExecInitExprRec(arrayarg, state, resv, resnull); |
- |
| 1460 |
- |
|
- |
| 1461 |
- |
/* And perform the operation */ |
- |
| 1462 |
- |
scratch.opcode = EEOP_SCALARARRAYOP; |
- |
| 1463 |
- |
scratch.d.scalararrayop.element_type = InvalidOid; |
- |
| 1464 |
- |
scratch.d.scalararrayop.useOr = opexpr->useOr; |
- |
| 1465 |
- |
scratch.d.scalararrayop.finfo = finfo; |
- |
| 1466 |
- |
scratch.d.scalararrayop.fcinfo_data = fcinfo; |
- |
| 1467 |
- |
scratch.d.scalararrayop.fn_addr = finfo->fn_addr; |
- |
| 1468 |
- |
ExprEvalPushStep(state, &scratch); |
- |
| 1469 |
- |
} |
- |
| 1470 |
- |
break; |
- |
| 1471 |
- |
} |
- |
| 1472 |
- |
|
- |
| 1473 |
- |
case T_BoolExpr: |
- |
| 1474 |
- |
{ |
- |
| 1475 |
- |
BoolExpr *boolexpr = (BoolExpr *) node; |
- |
| 1476 |
- |
int nargs = list_length(boolexpr->args); |
- |
| 1477 |
- |
List *adjust_jumps = NIL; |
- |
| 1478 |
- |
int off; |
- |
| 1479 |
- |
ListCell *lc; |
- |
| 1480 |
- |
|
- |
| 1481 |
- |
/* allocate scratch memory used by all steps of AND/OR */ |
- |
| 1482 |
- |
if (boolexpr->boolop != NOT_EXPR) |
- |
| 1483 |
- |
scratch.d.boolexpr.anynull = palloc_object(bool); |
- |
| 1484 |
- |
|
- |
| 1485 |
- |
/* |
- |
| 1486 |
- |
* For each argument evaluate the argument itself, then |
- |
| 1487 |
- |
* perform the bool operation's appropriate handling. |
- |
| 1488 |
- |
* |
- |
| 1489 |
- |
* We can evaluate each argument into our result area, since |
- |
| 1490 |
- |
* the short-circuiting logic means we only need to remember |
- |
| 1491 |
- |
* previous NULL values. |
- |
| 1492 |
- |
* |
- |
| 1493 |
- |
* AND/OR is split into separate STEP_FIRST (one) / STEP (zero |
- |
| 1494 |
- |
* or more) / STEP_LAST (one) steps, as each of those has to |
- |
| 1495 |
- |
* perform different work. The FIRST/LAST split is valid |
- |
| 1496 |
- |
* because AND/OR have at least two arguments. |
- |
| 1497 |
- |
*/ |
- |
| 1498 |
- |
off = 0; |
- |
| 1499 |
- |
foreach(lc, boolexpr->args) |
- |
| 1500 |
- |
{ |
- |
| 1501 |
- |
Expr *arg = (Expr *) lfirst(lc); |
- |
| 1502 |
- |
|
- |
| 1503 |
- |
/* Evaluate argument into our output variable */ |
- |
| 1504 |
- |
ExecInitExprRec(arg, state, resv, resnull); |
- |
| 1505 |
- |
|
- |
| 1506 |
- |
/* Perform the appropriate step type */ |
- |
| 1507 |
- |
switch (boolexpr->boolop) |
- |
| 1508 |
- |
{ |
- |
| 1509 |
- |
case AND_EXPR: |
- |
| 1510 |
- |
Assert(nargs >= 2); |
- |
| 1511 |
- |
|
- |
| 1512 |
- |
if (off == 0) |
- |
| 1513 |
- |
scratch.opcode = EEOP_BOOL_AND_STEP_FIRST; |
- |
| 1514 |
- |
else if (off + 1 == nargs) |
- |
| 1515 |
- |
scratch.opcode = EEOP_BOOL_AND_STEP_LAST; |
- |
| 1516 |
- |
else |
- |
| 1517 |
- |
scratch.opcode = EEOP_BOOL_AND_STEP; |
- |
| 1518 |
- |
break; |
- |
| 1519 |
- |
case OR_EXPR: |
- |
| 1520 |
- |
Assert(nargs >= 2); |
- |
| 1521 |
- |
|
- |
| 1522 |
- |
if (off == 0) |
- |
| 1523 |
- |
scratch.opcode = EEOP_BOOL_OR_STEP_FIRST; |
- |
| 1524 |
- |
else if (off + 1 == nargs) |
- |
| 1525 |
- |
scratch.opcode = EEOP_BOOL_OR_STEP_LAST; |
- |
| 1526 |
- |
else |
- |
| 1527 |
- |
scratch.opcode = EEOP_BOOL_OR_STEP; |
- |
| 1528 |
- |
break; |
- |
| 1529 |
- |
case NOT_EXPR: |
- |
| 1530 |
- |
Assert(nargs == 1); |
- |
| 1531 |
- |
|
- |
| 1532 |
- |
scratch.opcode = EEOP_BOOL_NOT_STEP; |
- |
| 1533 |
- |
break; |
- |
| 1534 |
- |
default: |
- |
| 1535 |
- |
elog(ERROR, "unrecognized boolop: %d", |
- |
| 1536 |
- |
(int) boolexpr->boolop); |
- |
| 1537 |
- |
break; |
- |
| 1538 |
- |
} |
- |
| 1539 |
- |
|
- |
| 1540 |
- |
scratch.d.boolexpr.jumpdone = -1; |
- |
| 1541 |
- |
ExprEvalPushStep(state, &scratch); |
- |
| 1542 |
- |
adjust_jumps = lappend_int(adjust_jumps, |
- |
| 1543 |
- |
state->steps_len - 1); |
- |
| 1544 |
- |
off++; |
- |
| 1545 |
- |
} |
- |
| 1546 |
- |
|
- |
| 1547 |
- |
/* adjust jump targets */ |
- |
| 1548 |
- |
foreach(lc, adjust_jumps) |
- |
| 1549 |
- |
{ |
- |
| 1550 |
- |
ExprEvalStep *as = &state->steps[lfirst_int(lc)]; |
- |
| 1551 |
- |
|
- |
| 1552 |
- |
Assert(as->d.boolexpr.jumpdone == -1); |
- |
| 1553 |
- |
as->d.boolexpr.jumpdone = state->steps_len; |
- |
| 1554 |
- |
} |
- |
| 1555 |
- |
|
- |
| 1556 |
- |
break; |
- |
| 1557 |
- |
} |
- |
| 1558 |
- |
|
- |
| 1559 |
- |
case T_SubPlan: |
- |
| 1560 |
- |
{ |
- |
| 1561 |
- |
SubPlan *subplan = (SubPlan *) node; |
- |
| 1562 |
- |
|
- |
| 1563 |
- |
/* |
- |
| 1564 |
- |
* Real execution of a MULTIEXPR SubPlan has already been |
- |
| 1565 |
- |
* done. What we have to do here is return a dummy NULL record |
- |
| 1566 |
- |
* value in case this targetlist element is assigned |
- |
| 1567 |
- |
* someplace. |
- |
| 1568 |
- |
*/ |
- |
| 1569 |
- |
if (subplan->subLinkType == MULTIEXPR_SUBLINK) |
- |
| 1570 |
- |
{ |
- |
| 1571 |
- |
scratch.opcode = EEOP_CONST; |
- |
| 1572 |
- |
scratch.d.constval.value = (Datum) 0; |
- |
| 1573 |
- |
scratch.d.constval.isnull = true; |
- |
| 1574 |
- |
ExprEvalPushStep(state, &scratch); |
- |
| 1575 |
- |
break; |
- |
| 1576 |
- |
} |
- |
| 1577 |
- |
|
- |
| 1578 |
- |
ExecInitSubPlanExpr(subplan, state, resv, resnull); |
- |
| 1579 |
- |
break; |
- |
| 1580 |
- |
} |
- |
| 1581 |
- |
|
- |
| 1582 |
- |
case T_FieldSelect: |
- |
| 1583 |
- |
{ |
- |
| 1584 |
- |
FieldSelect *fselect = (FieldSelect *) node; |
- |
| 1585 |
- |
|
- |
| 1586 |
- |
/* evaluate row/record argument into result area */ |
- |
| 1587 |
- |
ExecInitExprRec(fselect->arg, state, resv, resnull); |
- |
| 1588 |
- |
|
- |
| 1589 |
- |
/* and extract field */ |
- |
| 1590 |
- |
scratch.opcode = EEOP_FIELDSELECT; |
- |
| 1591 |
- |
scratch.d.fieldselect.fieldnum = fselect->fieldnum; |
- |
| 1592 |
- |
scratch.d.fieldselect.resulttype = fselect->resulttype; |
- |
| 1593 |
- |
scratch.d.fieldselect.rowcache.cacheptr = NULL; |
- |
| 1594 |
- |
|
- |
| 1595 |
- |
ExprEvalPushStep(state, &scratch); |
- |
| 1596 |
- |
break; |
- |
| 1597 |
- |
} |
- |
| 1598 |
- |
|
- |
| 1599 |
- |
case T_FieldStore: |
- |
| 1600 |
- |
{ |
- |
| 1601 |
- |
FieldStore *fstore = (FieldStore *) node; |
- |
| 1602 |
- |
TupleDesc tupDesc; |
- |
| 1603 |
- |
ExprEvalRowtypeCache *rowcachep; |
- |
| 1604 |
- |
Datum *values; |
- |
| 1605 |
- |
bool *nulls; |
- |
| 1606 |
- |
int ncolumns; |
- |
| 1607 |
- |
ListCell *l1, |
- |
| 1608 |
- |
*l2; |
- |
| 1609 |
- |
|
- |
| 1610 |
- |
/* find out the number of columns in the composite type */ |
- |
| 1611 |
- |
tupDesc = lookup_rowtype_tupdesc(fstore->resulttype, -1); |
- |
| 1612 |
- |
ncolumns = tupDesc->natts; |
- |
| 1613 |
- |
ReleaseTupleDesc(tupDesc); |
- |
| 1614 |
- |
|
- |
| 1615 |
- |
/* create workspace for column values */ |
- |
| 1616 |
- |
values = palloc_array(Datum, ncolumns); |
- |
| 1617 |
- |
nulls = palloc_array(bool, ncolumns); |
- |
| 1618 |
- |
|
- |
| 1619 |
- |
/* create shared composite-type-lookup cache struct */ |
- |
| 1620 |
- |
rowcachep = palloc_object(ExprEvalRowtypeCache); |
- |
| 1621 |
- |
rowcachep->cacheptr = NULL; |
- |
| 1622 |
- |
|
- |
| 1623 |
- |
/* emit code to evaluate the composite input value */ |
- |
| 1624 |
- |
ExecInitExprRec(fstore->arg, state, resv, resnull); |
- |
| 1625 |
- |
|
- |
| 1626 |
- |
/* next, deform the input tuple into our workspace */ |
- |
| 1627 |
- |
scratch.opcode = EEOP_FIELDSTORE_DEFORM; |
- |
| 1628 |
- |
scratch.d.fieldstore.fstore = fstore; |
- |
| 1629 |
- |
scratch.d.fieldstore.rowcache = rowcachep; |
- |
| 1630 |
- |
scratch.d.fieldstore.values = values; |
- |
| 1631 |
- |
scratch.d.fieldstore.nulls = nulls; |
- |
| 1632 |
- |
scratch.d.fieldstore.ncolumns = ncolumns; |
- |
| 1633 |
- |
ExprEvalPushStep(state, &scratch); |
- |
| 1634 |
- |
|
- |
| 1635 |
- |
/* evaluate new field values, store in workspace columns */ |
- |
| 1636 |
- |
forboth(l1, fstore->newvals, l2, fstore->fieldnums) |
- |
| 1637 |
- |
{ |
- |
| 1638 |
- |
Expr *e = (Expr *) lfirst(l1); |
- |
| 1639 |
- |
AttrNumber fieldnum = lfirst_int(l2); |
- |
| 1640 |
- |
Datum *save_innermost_caseval; |
- |
| 1641 |
- |
bool *save_innermost_casenull; |
- |
| 1642 |
- |
|
- |
| 1643 |
- |
if (fieldnum <= 0 || fieldnum > ncolumns) |
- |
| 1644 |
- |
elog(ERROR, "field number %d is out of range in FieldStore", |
- |
| 1645 |
- |
fieldnum); |
- |
| 1646 |
- |
|
- |
| 1647 |
- |
/* |
- |
| 1648 |
- |
* Use the CaseTestExpr mechanism to pass down the old |
- |
| 1649 |
- |
* value of the field being replaced; this is needed in |
- |
| 1650 |
- |
* case the newval is itself a FieldStore or |
- |
| 1651 |
- |
* SubscriptingRef that has to obtain and modify the old |
- |
| 1652 |
- |
* value. It's safe to reuse the CASE mechanism because |
- |
| 1653 |
- |
* there cannot be a CASE between here and where the value |
- |
| 1654 |
- |
* would be needed, and a field assignment can't be within |
- |
| 1655 |
- |
* a CASE either. (So saving and restoring |
- |
| 1656 |
- |
* innermost_caseval is just paranoia, but let's do it |
- |
| 1657 |
- |
* anyway.) |
- |
| 1658 |
- |
* |
- |
| 1659 |
- |
* Another non-obvious point is that it's safe to use the |
- |
| 1660 |
- |
* field's values[]/nulls[] entries as both the caseval |
- |
| 1661 |
- |
* source and the result address for this subexpression. |
- |
| 1662 |
- |
* That's okay only because (1) both FieldStore and |
- |
| 1663 |
- |
* SubscriptingRef evaluate their arg or refexpr inputs |
- |
| 1664 |
- |
* first, and (2) any such CaseTestExpr is directly the |
- |
| 1665 |
- |
* arg or refexpr input. So any read of the caseval will |
- |
| 1666 |
- |
* occur before there's a chance to overwrite it. Also, |
- |
| 1667 |
- |
* if multiple entries in the newvals/fieldnums lists |
- |
| 1668 |
- |
* target the same field, they'll effectively be applied |
- |
| 1669 |
- |
* left-to-right which is what we want. |
- |
| 1670 |
- |
*/ |
- |
| 1671 |
- |
save_innermost_caseval = state->innermost_caseval; |
- |
| 1672 |
- |
save_innermost_casenull = state->innermost_casenull; |
- |
| 1673 |
- |
state->innermost_caseval = &values[fieldnum - 1]; |
- |
| 1674 |
- |
state->innermost_casenull = &nulls[fieldnum - 1]; |
- |
| 1675 |
- |
|
- |
| 1676 |
- |
ExecInitExprRec(e, state, |
- |
| 1677 |
- |
&values[fieldnum - 1], |
- |
| 1678 |
- |
&nulls[fieldnum - 1]); |
- |
| 1679 |
- |
|
- |
| 1680 |
- |
state->innermost_caseval = save_innermost_caseval; |
- |
| 1681 |
- |
state->innermost_casenull = save_innermost_casenull; |
- |
| 1682 |
- |
} |
- |
| 1683 |
- |
|
- |
| 1684 |
- |
/* finally, form result tuple */ |
- |
| 1685 |
- |
scratch.opcode = EEOP_FIELDSTORE_FORM; |
- |
| 1686 |
- |
scratch.d.fieldstore.fstore = fstore; |
- |
| 1687 |
- |
scratch.d.fieldstore.rowcache = rowcachep; |
- |
| 1688 |
- |
scratch.d.fieldstore.values = values; |
- |
| 1689 |
- |
scratch.d.fieldstore.nulls = nulls; |
- |
| 1690 |
- |
scratch.d.fieldstore.ncolumns = ncolumns; |
- |
| 1691 |
- |
ExprEvalPushStep(state, &scratch); |
- |
| 1692 |
- |
break; |
- |
| 1693 |
- |
} |
- |
| 1694 |
- |
|
- |
| 1695 |
- |
case T_RelabelType: |
- |
| 1696 |
- |
{ |
- |
| 1697 |
- |
/* relabel doesn't need to do anything at runtime */ |
- |
| 1698 |
- |
RelabelType *relabel = (RelabelType *) node; |
- |
| 1699 |
- |
|
- |
| 1700 |
- |
ExecInitExprRec(relabel->arg, state, resv, resnull); |
- |
| 1701 |
- |
break; |
- |
| 1702 |
- |
} |
- |
| 1703 |
- |
|
- |
| 1704 |
- |
case T_CoerceViaIO: |
- |
| 1705 |
- |
{ |
- |
| 1706 |
- |
CoerceViaIO *iocoerce = (CoerceViaIO *) node; |
- |
| 1707 |
- |
Oid iofunc; |
- |
| 1708 |
- |
bool typisvarlena; |
- |
| 1709 |
- |
Oid typioparam; |
- |
| 1710 |
- |
FunctionCallInfo fcinfo_in; |
- |
| 1711 |
- |
|
- |
| 1712 |
- |
/* evaluate argument into step's result area */ |
- |
| 1713 |
- |
ExecInitExprRec(iocoerce->arg, state, resv, resnull); |
- |
| 1714 |
- |
|
- |
| 1715 |
- |
/* |
- |
| 1716 |
- |
* Prepare both output and input function calls, to be |
- |
| 1717 |
- |
* evaluated inside a single evaluation step for speed - this |
- |
| 1718 |
- |
* can be a very common operation. |
- |
| 1719 |
- |
* |
- |
| 1720 |
- |
* We don't check permissions here as a type's input/output |
- |
| 1721 |
- |
* function are assumed to be executable by everyone. |
- |
| 1722 |
- |
*/ |
- |
| 1723 |
- |
if (state->escontext == NULL) |
- |
| 1724 |
- |
scratch.opcode = EEOP_IOCOERCE; |
- |
| 1725 |
- |
else |
- |
| 1726 |
- |
scratch.opcode = EEOP_IOCOERCE_SAFE; |
- |
| 1727 |
- |
|
- |
| 1728 |
- |
/* lookup the source type's output function */ |
- |
| 1729 |
- |
scratch.d.iocoerce.finfo_out = palloc0_object(FmgrInfo); |
- |
| 1730 |
- |
scratch.d.iocoerce.fcinfo_data_out = palloc0(SizeForFunctionCallInfo(1)); |
- |
| 1731 |
- |
|
- |
| 1732 |
- |
getTypeOutputInfo(exprType((Node *) iocoerce->arg), |
- |
| 1733 |
- |
&iofunc, &typisvarlena); |
- |
| 1734 |
- |
fmgr_info(iofunc, scratch.d.iocoerce.finfo_out); |
- |
| 1735 |
- |
fmgr_info_set_expr((Node *) node, scratch.d.iocoerce.finfo_out); |
- |
| 1736 |
- |
InitFunctionCallInfoData(*scratch.d.iocoerce.fcinfo_data_out, |
- |
| 1737 |
- |
scratch.d.iocoerce.finfo_out, |
- |
| 1738 |
- |
1, InvalidOid, NULL, NULL); |
- |
| 1739 |
- |
|
- |
| 1740 |
- |
/* lookup the result type's input function */ |
- |
| 1741 |
- |
scratch.d.iocoerce.finfo_in = palloc0_object(FmgrInfo); |
- |
| 1742 |
- |
scratch.d.iocoerce.fcinfo_data_in = palloc0(SizeForFunctionCallInfo(3)); |
- |
| 1743 |
- |
|
- |
| 1744 |
- |
getTypeInputInfo(iocoerce->resulttype, |
- |
| 1745 |
- |
&iofunc, &typioparam); |
- |
| 1746 |
- |
fmgr_info(iofunc, scratch.d.iocoerce.finfo_in); |
- |
| 1747 |
- |
fmgr_info_set_expr((Node *) node, scratch.d.iocoerce.finfo_in); |
- |
| 1748 |
- |
InitFunctionCallInfoData(*scratch.d.iocoerce.fcinfo_data_in, |
- |
| 1749 |
- |
scratch.d.iocoerce.finfo_in, |
- |
| 1750 |
- |
3, InvalidOid, NULL, NULL); |
- |
| 1751 |
- |
|
- |
| 1752 |
- |
/* |
- |
| 1753 |
- |
* We can preload the second and third arguments for the input |
- |
| 1754 |
- |
* function, since they're constants. |
- |
| 1755 |
- |
*/ |
- |
| 1756 |
- |
fcinfo_in = scratch.d.iocoerce.fcinfo_data_in; |
- |
| 1757 |
- |
fcinfo_in->args[1].value = ObjectIdGetDatum(typioparam); |
- |
| 1758 |
- |
fcinfo_in->args[1].isnull = false; |
- |
| 1759 |
- |
fcinfo_in->args[2].value = Int32GetDatum(-1); |
- |
| 1760 |
- |
fcinfo_in->args[2].isnull = false; |
- |
| 1761 |
- |
|
- |
| 1762 |
- |
fcinfo_in->context = (Node *) state->escontext; |
- |
| 1763 |
- |
|
- |
| 1764 |
- |
ExprEvalPushStep(state, &scratch); |
- |
| 1765 |
- |
break; |
- |
| 1766 |
- |
} |
- |
| 1767 |
- |
|
- |
| 1768 |
- |
case T_ArrayCoerceExpr: |
- |
| 1769 |
- |
{ |
- |
| 1770 |
- |
ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node; |
- |
| 1771 |
- |
Oid resultelemtype; |
- |
| 1772 |
- |
ExprState *elemstate; |
- |
| 1773 |
- |
|
- |
| 1774 |
- |
/* evaluate argument into step's result area */ |
- |
| 1775 |
- |
ExecInitExprRec(acoerce->arg, state, resv, resnull); |
- |
| 1776 |
- |
|
- |
| 1777 |
- |
resultelemtype = get_element_type(acoerce->resulttype); |
- |
| 1778 |
- |
if (!OidIsValid(resultelemtype)) |
- |
| 1779 |
- |
ereport(ERROR, |
- |
| 1780 |
- |
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
- |
| 1781 |
- |
errmsg("target type is not an array"))); |
- |
| 1782 |
- |
|
- |
| 1783 |
- |
/* |
- |
| 1784 |
- |
* Construct a sub-expression for the per-element expression; |
- |
| 1785 |
- |
* but don't ready it until after we check it for triviality. |
- |
| 1786 |
- |
* We assume it hasn't any Var references, but does have a |
- |
| 1787 |
- |
* CaseTestExpr representing the source array element values. |
- |
| 1788 |
- |
*/ |
- |
| 1789 |
- |
elemstate = makeNode(ExprState); |
- |
| 1790 |
- |
elemstate->expr = acoerce->elemexpr; |
- |
| 1791 |
- |
elemstate->parent = state->parent; |
- |
| 1792 |
- |
elemstate->ext_params = state->ext_params; |
- |
| 1793 |
- |
|
- |
| 1794 |
- |
elemstate->innermost_caseval = palloc_object(Datum); |
- |
| 1795 |
- |
elemstate->innermost_casenull = palloc_object(bool); |
- |
| 1796 |
- |
|
- |
| 1797 |
- |
ExecInitExprRec(acoerce->elemexpr, elemstate, |
- |
| 1798 |
- |
&elemstate->resvalue, &elemstate->resnull); |
- |
| 1799 |
- |
|
- |
| 1800 |
- |
if (elemstate->steps_len == 1 && |
- |
| 1801 |
- |
elemstate->steps[0].opcode == EEOP_CASE_TESTVAL) |
- |
| 1802 |
- |
{ |
- |
| 1803 |
- |
/* Trivial, so we need no per-element work at runtime */ |
- |
| 1804 |
- |
elemstate = NULL; |
- |
| 1805 |
- |
} |
- |
| 1806 |
- |
else |
- |
| 1807 |
- |
{ |
- |
| 1808 |
- |
/* Not trivial, so append a DONE step */ |
- |
| 1809 |
- |
scratch.opcode = EEOP_DONE_RETURN; |
- |
| 1810 |
- |
ExprEvalPushStep(elemstate, &scratch); |
- |
| 1811 |
- |
/* and ready the subexpression */ |
- |
| 1812 |
- |
ExecReadyExpr(elemstate); |
- |
| 1813 |
- |
} |
- |
| 1814 |
- |
|
- |
| 1815 |
- |
scratch.opcode = EEOP_ARRAYCOERCE; |
- |
| 1816 |
- |
scratch.d.arraycoerce.elemexprstate = elemstate; |
- |
| 1817 |
- |
scratch.d.arraycoerce.resultelemtype = resultelemtype; |
- |
| 1818 |
- |
|
- |
| 1819 |
- |
if (elemstate) |
- |
| 1820 |
- |
{ |
- |
| 1821 |
- |
/* Set up workspace for array_map */ |
- |
| 1822 |
- |
scratch.d.arraycoerce.amstate = palloc0_object(ArrayMapState); |
- |
| 1823 |
- |
} |
- |
| 1824 |
- |
else |
- |
| 1825 |
- |
{ |
- |
| 1826 |
- |
/* Don't need workspace if there's no subexpression */ |
- |
| 1827 |
- |
scratch.d.arraycoerce.amstate = NULL; |
- |
| 1828 |
- |
} |
- |
| 1829 |
- |
|
- |
| 1830 |
- |
ExprEvalPushStep(state, &scratch); |
- |
| 1831 |
- |
break; |
- |
| 1832 |
- |
} |
- |
| 1833 |
- |
|
- |
| 1834 |
- |
case T_ConvertRowtypeExpr: |
- |
| 1835 |
- |
{ |
- |
| 1836 |
- |
ConvertRowtypeExpr *convert = (ConvertRowtypeExpr *) node; |
- |
| 1837 |
- |
ExprEvalRowtypeCache *rowcachep; |
- |
| 1838 |
- |
|
- |
| 1839 |
- |
/* cache structs must be out-of-line for space reasons */ |
- |
| 1840 |
- |
rowcachep = palloc(2 * sizeof(ExprEvalRowtypeCache)); |
- |
| 1841 |
- |
rowcachep[0].cacheptr = NULL; |
- |
| 1842 |
- |
rowcachep[1].cacheptr = NULL; |
- |
| 1843 |
- |
|
- |
| 1844 |
- |
/* evaluate argument into step's result area */ |
- |
| 1845 |
- |
ExecInitExprRec(convert->arg, state, resv, resnull); |
- |
| 1846 |
- |
|
- |
| 1847 |
- |
/* and push conversion step */ |
- |
| 1848 |
- |
scratch.opcode = EEOP_CONVERT_ROWTYPE; |
- |
| 1849 |
- |
scratch.d.convert_rowtype.inputtype = |
- |
| 1850 |
- |
exprType((Node *) convert->arg); |
- |
| 1851 |
- |
scratch.d.convert_rowtype.outputtype = convert->resulttype; |
- |
| 1852 |
- |
scratch.d.convert_rowtype.incache = &rowcachep[0]; |
- |
| 1853 |
- |
scratch.d.convert_rowtype.outcache = &rowcachep[1]; |
- |
| 1854 |
- |
scratch.d.convert_rowtype.map = NULL; |
- |
| 1855 |
- |
|
- |
| 1856 |
- |
ExprEvalPushStep(state, &scratch); |
- |
| 1857 |
- |
break; |
- |
| 1858 |
- |
} |
- |
| 1859 |
- |
|
- |
| 1860 |
- |
/* note that CaseWhen expressions are handled within this block */ |
- |
| 1861 |
- |
case T_CaseExpr: |
- |
| 1862 |
- |
{ |
- |
| 1863 |
- |
CaseExpr *caseExpr = (CaseExpr *) node; |
- |
| 1864 |
- |
List *adjust_jumps = NIL; |
- |
| 1865 |
- |
Datum *caseval = NULL; |
- |
| 1866 |
- |
bool *casenull = NULL; |
- |
| 1867 |
- |
ListCell *lc; |
- |
| 1868 |
- |
|
- |
| 1869 |
- |
/* |
- |
| 1870 |
- |
* If there's a test expression, we have to evaluate it and |
- |
| 1871 |
- |
* save the value where the CaseTestExpr placeholders can find |
- |
| 1872 |
- |
* it. |
- |
| 1873 |
- |
*/ |
- |
| 1874 |
- |
if (caseExpr->arg != NULL) |
- |
| 1875 |
- |
{ |
- |
| 1876 |
- |
/* Evaluate testexpr into caseval/casenull workspace */ |
- |
| 1877 |
- |
caseval = palloc_object(Datum); |
- |
| 1878 |
- |
casenull = palloc_object(bool); |
- |
| 1879 |
- |
|
- |
| 1880 |
- |
ExecInitExprRec(caseExpr->arg, state, |
- |
| 1881 |
- |
caseval, casenull); |
- |
| 1882 |
- |
|
- |
| 1883 |
- |
/* |
- |
| 1884 |
- |
* Since value might be read multiple times, force to R/O |
- |
| 1885 |
- |
* - but only if it could be an expanded datum. |
- |
| 1886 |
- |
*/ |
- |
| 1887 |
- |
if (get_typlen(exprType((Node *) caseExpr->arg)) == -1) |
- |
| 1888 |
- |
{ |
- |
| 1889 |
- |
/* change caseval in-place */ |
- |
| 1890 |
- |
scratch.opcode = EEOP_MAKE_READONLY; |
- |
| 1891 |
- |
scratch.resvalue = caseval; |
- |
| 1892 |
- |
scratch.resnull = casenull; |
- |
| 1893 |
- |
scratch.d.make_readonly.value = caseval; |
- |
| 1894 |
- |
scratch.d.make_readonly.isnull = casenull; |
- |
| 1895 |
- |
ExprEvalPushStep(state, &scratch); |
- |
| 1896 |
- |
/* restore normal settings of scratch fields */ |
- |
| 1897 |
- |
scratch.resvalue = resv; |
- |
| 1898 |
- |
scratch.resnull = resnull; |
- |
| 1899 |
- |
} |
- |
| 1900 |
- |
} |
- |
| 1901 |
- |
|
- |
| 1902 |
- |
/* |
- |
| 1903 |
- |
* Prepare to evaluate each of the WHEN clauses in turn; as |
- |
| 1904 |
- |
* soon as one is true we return the value of the |
- |
| 1905 |
- |
* corresponding THEN clause. If none are true then we return |
- |
| 1906 |
- |
* the value of the ELSE clause, or NULL if there is none. |
- |
| 1907 |
- |
*/ |
- |
| 1908 |
- |
foreach(lc, caseExpr->args) |
- |
| 1909 |
- |
{ |
- |
| 1910 |
- |
CaseWhen *when = (CaseWhen *) lfirst(lc); |
- |
| 1911 |
- |
Datum *save_innermost_caseval; |
- |
| 1912 |
- |
bool *save_innermost_casenull; |
- |
| 1913 |
- |
int whenstep; |
- |
| 1914 |
- |
|
- |
| 1915 |
- |
/* |
- |
| 1916 |
- |
* Make testexpr result available to CaseTestExpr nodes |
- |
| 1917 |
- |
* within the condition. We must save and restore prior |
- |
| 1918 |
- |
* setting of innermost_caseval fields, in case this node |
- |
| 1919 |
- |
* is itself within a larger CASE. |
- |
| 1920 |
- |
* |
- |
| 1921 |
- |
* If there's no test expression, we don't actually need |
- |
| 1922 |
- |
* to save and restore these fields; but it's less code to |
- |
| 1923 |
- |
* just do so unconditionally. |
- |
| 1924 |
- |
*/ |
- |
| 1925 |
- |
save_innermost_caseval = state->innermost_caseval; |
- |
| 1926 |
- |
save_innermost_casenull = state->innermost_casenull; |
- |
| 1927 |
- |
state->innermost_caseval = caseval; |
- |
| 1928 |
- |
state->innermost_casenull = casenull; |
- |
| 1929 |
- |
|
- |
| 1930 |
- |
/* evaluate condition into CASE's result variables */ |
- |
| 1931 |
- |
ExecInitExprRec(when->expr, state, resv, resnull); |
- |
| 1932 |
- |
|
- |
| 1933 |
- |
state->innermost_caseval = save_innermost_caseval; |
- |
| 1934 |
- |
state->innermost_casenull = save_innermost_casenull; |
- |
| 1935 |
- |
|
- |
| 1936 |
- |
/* If WHEN result isn't true, jump to next CASE arm */ |
- |
| 1937 |
- |
scratch.opcode = EEOP_JUMP_IF_NOT_TRUE; |
- |
| 1938 |
- |
scratch.d.jump.jumpdone = -1; /* computed later */ |
- |
| 1939 |
- |
ExprEvalPushStep(state, &scratch); |
- |
| 1940 |
- |
whenstep = state->steps_len - 1; |
- |
| 1941 |
- |
|
- |
| 1942 |
- |
/* |
- |
| 1943 |
- |
* If WHEN result is true, evaluate THEN result, storing |
- |
| 1944 |
- |
* it into the CASE's result variables. |
- |
| 1945 |
- |
*/ |
- |
| 1946 |
- |
ExecInitExprRec(when->result, state, resv, resnull); |
- |
| 1947 |
- |
|
- |
| 1948 |
- |
/* Emit JUMP step to jump to end of CASE's code */ |
- |
| 1949 |
- |
scratch.opcode = EEOP_JUMP; |
- |
| 1950 |
- |
scratch.d.jump.jumpdone = -1; /* computed later */ |
- |
| 1951 |
- |
ExprEvalPushStep(state, &scratch); |
- |
| 1952 |
- |
|
- |
| 1953 |
- |
/* |
- |
| 1954 |
- |
* Don't know address for that jump yet, compute once the |
- |
| 1955 |
- |
* whole CASE expression is built. |
- |
| 1956 |
- |
*/ |
- |
| 1957 |
- |
adjust_jumps = lappend_int(adjust_jumps, |
- |
| 1958 |
- |
state->steps_len - 1); |
- |
| 1959 |
- |
|
- |
| 1960 |
- |
/* |
- |
| 1961 |
- |
* But we can set WHEN test's jump target now, to make it |
- |
| 1962 |
- |
* jump to the next WHEN subexpression or the ELSE. |
- |
| 1963 |
- |
*/ |
- |
| 1964 |
- |
state->steps[whenstep].d.jump.jumpdone = state->steps_len; |
- |
| 1965 |
- |
} |
- |
| 1966 |
- |
|
- |
| 1967 |
- |
/* transformCaseExpr always adds a default */ |
- |
| 1968 |
- |
Assert(caseExpr->defresult); |
- |
| 1969 |
- |
|
- |
| 1970 |
- |
/* evaluate ELSE expr into CASE's result variables */ |
- |
| 1971 |
- |
ExecInitExprRec(caseExpr->defresult, state, |
- |
| 1972 |
- |
resv, resnull); |
- |
| 1973 |
- |
|
- |
| 1974 |
- |
/* adjust jump targets */ |
- |
| 1975 |
- |
foreach(lc, adjust_jumps) |
- |
| 1976 |
- |
{ |
- |
| 1977 |
- |
ExprEvalStep *as = &state->steps[lfirst_int(lc)]; |
- |
| 1978 |
- |
|
- |
| 1979 |
- |
Assert(as->opcode == EEOP_JUMP); |
- |
| 1980 |
- |
Assert(as->d.jump.jumpdone == -1); |
- |
| 1981 |
- |
as->d.jump.jumpdone = state->steps_len; |
- |
| 1982 |
- |
} |
- |
| 1983 |
- |
|
- |
| 1984 |
- |
break; |
- |
| 1985 |
- |
} |
- |
| 1986 |
- |
|
- |
| 1987 |
- |
case T_CaseTestExpr: |
- |
| 1988 |
- |
{ |
- |
| 1989 |
- |
/* |
- |
| 1990 |
- |
* Read from location identified by innermost_caseval. Note |
- |
| 1991 |
- |
* that innermost_caseval could be NULL, if this node isn't |
- |
| 1992 |
- |
* actually within a CaseExpr, ArrayCoerceExpr, etc structure. |
- |
| 1993 |
- |
* That can happen because some parts of the system abuse |
- |
| 1994 |
- |
* CaseTestExpr to cause a read of a value externally supplied |
- |
| 1995 |
- |
* in econtext->caseValue_datum. We'll take care of that by |
- |
| 1996 |
- |
* generating a specialized operation. |
- |
| 1997 |
- |
*/ |
- |
| 1998 |
- |
if (state->innermost_caseval == NULL) |
- |
| 1999 |
- |
scratch.opcode = EEOP_CASE_TESTVAL_EXT; |
- |
| 2000 |
- |
else |
- |
| 2001 |
- |
{ |
- |
| 2002 |
- |
scratch.opcode = EEOP_CASE_TESTVAL; |
- |
| 2003 |
- |
scratch.d.casetest.value = state->innermost_caseval; |
- |
| 2004 |
- |
scratch.d.casetest.isnull = state->innermost_casenull; |
- |
| 2005 |
- |
} |
- |
| 2006 |
- |
ExprEvalPushStep(state, &scratch); |
- |
| 2007 |
- |
break; |
- |
| 2008 |
- |
} |
- |
| 2009 |
- |
|
- |
| 2010 |
- |
case T_ArrayExpr: |
- |
| 2011 |
- |
{ |
- |
| 2012 |
- |
ArrayExpr *arrayexpr = (ArrayExpr *) node; |
- |
| 2013 |
- |
int nelems = list_length(arrayexpr->elements); |
- |
| 2014 |
- |
ListCell *lc; |
- |
| 2015 |
- |
int elemoff; |
- |
| 2016 |
- |
|
- |
| 2017 |
- |
/* |
- |
| 2018 |
- |
* Evaluate by computing each element, and then forming the |
- |
| 2019 |
- |
* array. Elements are computed into scratch arrays |
- |
| 2020 |
- |
* associated with the ARRAYEXPR step. |
- |
| 2021 |
- |
*/ |
- |
| 2022 |
- |
scratch.opcode = EEOP_ARRAYEXPR; |
- |
| 2023 |
- |
scratch.d.arrayexpr.elemvalues = |
- |
| 2024 |
- |
palloc_array(Datum, nelems); |
- |
| 2025 |
- |
scratch.d.arrayexpr.elemnulls = |
- |
| 2026 |
- |
palloc_array(bool, nelems); |
- |
| 2027 |
- |
scratch.d.arrayexpr.nelems = nelems; |
- |
| 2028 |
- |
|
- |
| 2029 |
- |
/* fill remaining fields of step */ |
- |
| 2030 |
- |
scratch.d.arrayexpr.multidims = arrayexpr->multidims; |
- |
| 2031 |
- |
scratch.d.arrayexpr.elemtype = arrayexpr->element_typeid; |
- |
| 2032 |
- |
|
- |
| 2033 |
- |
/* do one-time catalog lookup for type info */ |
- |
| 2034 |
- |
get_typlenbyvalalign(arrayexpr->element_typeid, |
- |
| 2035 |
- |
&scratch.d.arrayexpr.elemlength, |
- |
| 2036 |
- |
&scratch.d.arrayexpr.elembyval, |
- |
| 2037 |
- |
&scratch.d.arrayexpr.elemalign); |
- |
| 2038 |
- |
|
- |
| 2039 |
- |
/* prepare to evaluate all arguments */ |
- |
| 2040 |
- |
elemoff = 0; |
- |
| 2041 |
- |
foreach(lc, arrayexpr->elements) |
- |
| 2042 |
- |
{ |
- |
| 2043 |
- |
Expr *e = (Expr *) lfirst(lc); |
- |
| 2044 |
- |
|
- |
| 2045 |
- |
ExecInitExprRec(e, state, |
- |
| 2046 |
- |
&scratch.d.arrayexpr.elemvalues[elemoff], |
- |
| 2047 |
- |
&scratch.d.arrayexpr.elemnulls[elemoff]); |
- |
| 2048 |
- |
elemoff++; |
- |
| 2049 |
- |
} |
- |
| 2050 |
- |
|
- |
| 2051 |
- |
/* and then collect all into an array */ |
- |
| 2052 |
- |
ExprEvalPushStep(state, &scratch); |
- |
| 2053 |
- |
break; |
- |
| 2054 |
- |
} |
- |
| 2055 |
- |
|
- |
| 2056 |
- |
case T_RowExpr: |
- |
| 2057 |
- |
{ |
- |
| 2058 |
- |
RowExpr *rowexpr = (RowExpr *) node; |
- |
| 2059 |
- |
int nelems = list_length(rowexpr->args); |
- |
| 2060 |
- |
TupleDesc tupdesc; |
- |
| 2061 |
- |
int i; |
- |
| 2062 |
- |
ListCell *l; |
- |
| 2063 |
- |
|
- |
| 2064 |
- |
/* Build tupdesc to describe result tuples */ |
- |
| 2065 |
- |
if (rowexpr->row_typeid == RECORDOID) |
- |
| 2066 |
- |
{ |
- |
| 2067 |
- |
/* generic record, use types of given expressions */ |
- |
| 2068 |
- |
tupdesc = ExecTypeFromExprList(rowexpr->args); |
- |
| 2069 |
- |
/* ... but adopt RowExpr's column aliases */ |
- |
| 2070 |
- |
ExecTypeSetColNames(tupdesc, rowexpr->colnames); |
- |
| 2071 |
- |
/* Bless the tupdesc so it can be looked up later */ |
- |
| 2072 |
- |
BlessTupleDesc(tupdesc); |
- |
| 2073 |
- |
} |
- |
| 2074 |
- |
else |
- |
| 2075 |
- |
{ |
- |
| 2076 |
- |
/* it's been cast to a named type, use that */ |
- |
| 2077 |
- |
tupdesc = lookup_rowtype_tupdesc_copy(rowexpr->row_typeid, -1); |
- |
| 2078 |
- |
} |
- |
| 2079 |
- |
|
- |
| 2080 |
- |
/* |
- |
| 2081 |
- |
* In the named-type case, the tupdesc could have more columns |
- |
| 2082 |
- |
* than are in the args list, since the type might have had |
- |
| 2083 |
- |
* columns added since the ROW() was parsed. We want those |
- |
| 2084 |
- |
* extra columns to go to nulls, so we make sure that the |
- |
| 2085 |
- |
* workspace arrays are large enough and then initialize any |
- |
| 2086 |
- |
* extra columns to read as NULLs. |
- |
| 2087 |
- |
*/ |
- |
| 2088 |
- |
Assert(nelems <= tupdesc->natts); |
- |
| 2089 |
- |
nelems = Max(nelems, tupdesc->natts); |
- |
| 2090 |
- |
|
- |
| 2091 |
- |
/* |
- |
| 2092 |
- |
* Evaluate by first building datums for each field, and then |
- |
| 2093 |
- |
* a final step forming the composite datum. |
- |
| 2094 |
- |
*/ |
- |
| 2095 |
- |
scratch.opcode = EEOP_ROW; |
- |
| 2096 |
- |
scratch.d.row.tupdesc = tupdesc; |
- |
| 2097 |
- |
|
- |
| 2098 |
- |
/* space for the individual field datums */ |
- |
| 2099 |
- |
scratch.d.row.elemvalues = |
- |
| 2100 |
- |
palloc_array(Datum, nelems); |
- |
| 2101 |
- |
scratch.d.row.elemnulls = |
- |
| 2102 |
- |
palloc_array(bool, nelems); |
- |
| 2103 |
- |
/* as explained above, make sure any extra columns are null */ |
- |
| 2104 |
- |
memset(scratch.d.row.elemnulls, true, sizeof(bool) * nelems); |
- |
| 2105 |
- |
|
- |
| 2106 |
- |
/* Set up evaluation, skipping any deleted columns */ |
- |
| 2107 |
- |
i = 0; |
- |
| 2108 |
- |
foreach(l, rowexpr->args) |
- |
| 2109 |
- |
{ |
- |
| 2110 |
- |
Form_pg_attribute att = TupleDescAttr(tupdesc, i); |
- |
| 2111 |
- |
Expr *e = (Expr *) lfirst(l); |
- |
| 2112 |
- |
|
- |
| 2113 |
- |
if (!att->attisdropped) |
- |
| 2114 |
- |
{ |
- |
| 2115 |
- |
/* |
- |
| 2116 |
- |
* Guard against ALTER COLUMN TYPE on rowtype since |
- |
| 2117 |
- |
* the RowExpr was created. XXX should we check |
- |
| 2118 |
- |
* typmod too? Not sure we can be sure it'll be the |
- |
| 2119 |
- |
* same. |
- |
| 2120 |
- |
*/ |
- |
| 2121 |
- |
if (exprType((Node *) e) != att->atttypid) |
- |
| 2122 |
- |
ereport(ERROR, |
- |
| 2123 |
- |
(errcode(ERRCODE_DATATYPE_MISMATCH), |
- |
| 2124 |
- |
errmsg("ROW() column has type %s instead of type %s", |
- |
| 2125 |
- |
format_type_be(exprType((Node *) e)), |
- |
| 2126 |
- |
format_type_be(att->atttypid)))); |
- |
| 2127 |
- |
} |
- |
| 2128 |
- |
else |
- |
| 2129 |
- |
{ |
- |
| 2130 |
- |
/* |
- |
| 2131 |
- |
* Ignore original expression and insert a NULL. We |
- |
| 2132 |
- |
* don't really care what type of NULL it is, so |
- |
| 2133 |
- |
* always make an int4 NULL. |
- |
| 2134 |
- |
*/ |
- |
| 2135 |
- |
e = (Expr *) makeNullConst(INT4OID, -1, InvalidOid); |
- |
| 2136 |
- |
} |
- |
| 2137 |
- |
|
- |
| 2138 |
- |
/* Evaluate column expr into appropriate workspace slot */ |
- |
| 2139 |
- |
ExecInitExprRec(e, state, |
- |
| 2140 |
- |
&scratch.d.row.elemvalues[i], |
- |
| 2141 |
- |
&scratch.d.row.elemnulls[i]); |
- |
| 2142 |
- |
i++; |
- |
| 2143 |
- |
} |
- |
| 2144 |
- |
|
- |
| 2145 |
- |
/* And finally build the row value */ |
- |
| 2146 |
- |
ExprEvalPushStep(state, &scratch); |
- |
| 2147 |
- |
break; |
- |
| 2148 |
- |
} |
- |
| 2149 |
- |
|
- |
| 2150 |
- |
case T_RowCompareExpr: |
- |
| 2151 |
- |
{ |
- |
| 2152 |
- |
RowCompareExpr *rcexpr = (RowCompareExpr *) node; |
- |
| 2153 |
- |
int nopers = list_length(rcexpr->opnos); |
- |
| 2154 |
- |
List *adjust_jumps = NIL; |
- |
| 2155 |
- |
ListCell *l_left_expr, |
- |
| 2156 |
- |
*l_right_expr, |
- |
| 2157 |
- |
*l_opno, |
- |
| 2158 |
- |
*l_opfamily, |
- |
| 2159 |
- |
*l_inputcollid; |
- |
| 2160 |
- |
ListCell *lc; |
- |
| 2161 |
- |
|
- |
| 2162 |
- |
/* |
- |
| 2163 |
- |
* Iterate over each field, prepare comparisons. To handle |
- |
| 2164 |
- |
* NULL results, prepare jumps to after the expression. If a |
- |
| 2165 |
- |
* comparison yields a != 0 result, jump to the final step. |
- |
| 2166 |
- |
*/ |
- |
| 2167 |
- |
Assert(list_length(rcexpr->largs) == nopers); |
- |
| 2168 |
- |
Assert(list_length(rcexpr->rargs) == nopers); |
- |
| 2169 |
- |
Assert(list_length(rcexpr->opfamilies) == nopers); |
- |
| 2170 |
- |
Assert(list_length(rcexpr->inputcollids) == nopers); |
- |
| 2171 |
- |
|
- |
| 2172 |
- |
forfive(l_left_expr, rcexpr->largs, |
- |
| 2173 |
- |
l_right_expr, rcexpr->rargs, |
- |
| 2174 |
- |
l_opno, rcexpr->opnos, |
- |
| 2175 |
- |
l_opfamily, rcexpr->opfamilies, |
- |
| 2176 |
- |
l_inputcollid, rcexpr->inputcollids) |
- |
| 2177 |
- |
{ |
- |
| 2178 |
- |
Expr *left_expr = (Expr *) lfirst(l_left_expr); |
- |
| 2179 |
- |
Expr *right_expr = (Expr *) lfirst(l_right_expr); |
- |
| 2180 |
- |
Oid opno = lfirst_oid(l_opno); |
- |
| 2181 |
- |
Oid opfamily = lfirst_oid(l_opfamily); |
- |
| 2182 |
- |
Oid inputcollid = lfirst_oid(l_inputcollid); |
- |
| 2183 |
- |
int strategy; |
- |
| 2184 |
- |
Oid lefttype; |
- |
| 2185 |
- |
Oid righttype; |
- |
| 2186 |
- |
Oid proc; |
- |
| 2187 |
- |
FmgrInfo *finfo; |
- |
| 2188 |
- |
FunctionCallInfo fcinfo; |
- |
| 2189 |
- |
|
- |
| 2190 |
- |
get_op_opfamily_properties(opno, opfamily, false, |
- |
| 2191 |
- |
&strategy, |
- |
| 2192 |
- |
&lefttype, |
- |
| 2193 |
- |
&righttype); |
- |
| 2194 |
- |
proc = get_opfamily_proc(opfamily, |
- |
| 2195 |
- |
lefttype, |
- |
| 2196 |
- |
righttype, |
- |
| 2197 |
- |
BTORDER_PROC); |
- |
| 2198 |
- |
if (!OidIsValid(proc)) |
- |
| 2199 |
- |
elog(ERROR, "missing support function %d(%u,%u) in opfamily %u", |
- |
| 2200 |
- |
BTORDER_PROC, lefttype, righttype, opfamily); |
- |
| 2201 |
- |
|
- |
| 2202 |
- |
/* Set up the primary fmgr lookup information */ |
- |
| 2203 |
- |
finfo = palloc0_object(FmgrInfo); |
- |
| 2204 |
- |
fcinfo = palloc0(SizeForFunctionCallInfo(2)); |
- |
| 2205 |
- |
fmgr_info(proc, finfo); |
- |
| 2206 |
- |
fmgr_info_set_expr((Node *) node, finfo); |
- |
| 2207 |
- |
InitFunctionCallInfoData(*fcinfo, finfo, 2, |
- |
| 2208 |
- |
inputcollid, NULL, NULL); |
- |
| 2209 |
- |
|
- |
| 2210 |
- |
/* |
- |
| 2211 |
- |
* If we enforced permissions checks on index support |
- |
| 2212 |
- |
* functions, we'd need to make a check here. But the |
- |
| 2213 |
- |
* index support machinery doesn't do that, and thus |
- |
| 2214 |
- |
* neither does this code. |
- |
| 2215 |
- |
*/ |
- |
| 2216 |
- |
|
- |
| 2217 |
- |
/* evaluate left and right args directly into fcinfo */ |
- |
| 2218 |
- |
ExecInitExprRec(left_expr, state, |
- |
| 2219 |
- |
&fcinfo->args[0].value, &fcinfo->args[0].isnull); |
- |
| 2220 |
- |
ExecInitExprRec(right_expr, state, |
- |
| 2221 |
- |
&fcinfo->args[1].value, &fcinfo->args[1].isnull); |
- |
| 2222 |
- |
|
- |
| 2223 |
- |
scratch.opcode = EEOP_ROWCOMPARE_STEP; |
- |
| 2224 |
- |
scratch.d.rowcompare_step.finfo = finfo; |
- |
| 2225 |
- |
scratch.d.rowcompare_step.fcinfo_data = fcinfo; |
- |
| 2226 |
- |
scratch.d.rowcompare_step.fn_addr = finfo->fn_addr; |
- |
| 2227 |
- |
/* jump targets filled below */ |
- |
| 2228 |
- |
scratch.d.rowcompare_step.jumpnull = -1; |
- |
| 2229 |
- |
scratch.d.rowcompare_step.jumpdone = -1; |
- |
| 2230 |
- |
|
- |
| 2231 |
- |
ExprEvalPushStep(state, &scratch); |
- |
| 2232 |
- |
adjust_jumps = lappend_int(adjust_jumps, |
- |
| 2233 |
- |
state->steps_len - 1); |
- |
| 2234 |
- |
} |
- |
| 2235 |
- |
|
- |
| 2236 |
- |
/* |
- |
| 2237 |
- |
* We could have a zero-column rowtype, in which case the rows |
- |
| 2238 |
- |
* necessarily compare equal. |
- |
| 2239 |
- |
*/ |
- |
| 2240 |
- |
if (nopers == 0) |
- |
| 2241 |
- |
{ |
- |
| 2242 |
- |
scratch.opcode = EEOP_CONST; |
- |
| 2243 |
- |
scratch.d.constval.value = Int32GetDatum(0); |
- |
| 2244 |
- |
scratch.d.constval.isnull = false; |
- |
| 2245 |
- |
ExprEvalPushStep(state, &scratch); |
- |
| 2246 |
- |
} |
- |
| 2247 |
- |
|
- |
| 2248 |
- |
/* Finally, examine the last comparison result */ |
- |
| 2249 |
- |
scratch.opcode = EEOP_ROWCOMPARE_FINAL; |
- |
| 2250 |
- |
scratch.d.rowcompare_final.cmptype = rcexpr->cmptype; |
- |
| 2251 |
- |
ExprEvalPushStep(state, &scratch); |
- |
| 2252 |
- |
|
- |
| 2253 |
- |
/* adjust jump targets */ |
- |
| 2254 |
- |
foreach(lc, adjust_jumps) |
- |
| 2255 |
- |
{ |
- |
| 2256 |
- |
ExprEvalStep *as = &state->steps[lfirst_int(lc)]; |
- |
| 2257 |
- |
|
- |
| 2258 |
- |
Assert(as->opcode == EEOP_ROWCOMPARE_STEP); |
- |
| 2259 |
- |
Assert(as->d.rowcompare_step.jumpdone == -1); |
- |
| 2260 |
- |
Assert(as->d.rowcompare_step.jumpnull == -1); |
- |
| 2261 |
- |
|
- |
| 2262 |
- |
/* jump to comparison evaluation */ |
- |
| 2263 |
- |
as->d.rowcompare_step.jumpdone = state->steps_len - 1; |
- |
| 2264 |
- |
/* jump to the following expression */ |
- |
| 2265 |
- |
as->d.rowcompare_step.jumpnull = state->steps_len; |
- |
| 2266 |
- |
} |
- |
| 2267 |
- |
|
- |
| 2268 |
- |
break; |
- |
| 2269 |
- |
} |
- |
| 2270 |
- |
|
- |
| 2271 |
- |
case T_CoalesceExpr: |
- |
| 2272 |
- |
{ |
- |
| 2273 |
- |
CoalesceExpr *coalesce = (CoalesceExpr *) node; |
- |
| 2274 |
- |
List *adjust_jumps = NIL; |
- |
| 2275 |
- |
ListCell *lc; |
- |
| 2276 |
- |
|
- |
| 2277 |
- |
/* We assume there's at least one arg */ |
- |
| 2278 |
- |
Assert(coalesce->args != NIL); |
- |
| 2279 |
- |
|
- |
| 2280 |
- |
/* |
- |
| 2281 |
- |
* Prepare evaluation of all coalesced arguments, after each |
- |
| 2282 |
- |
* one push a step that short-circuits if not null. |
- |
| 2283 |
- |
*/ |
- |
| 2284 |
- |
foreach(lc, coalesce->args) |
- |
| 2285 |
- |
{ |
- |
| 2286 |
- |
Expr *e = (Expr *) lfirst(lc); |
- |
| 2287 |
- |
|
- |
| 2288 |
- |
/* evaluate argument, directly into result datum */ |
- |
| 2289 |
- |
ExecInitExprRec(e, state, resv, resnull); |
- |
| 2290 |
- |
|
- |
| 2291 |
- |
/* if it's not null, skip to end of COALESCE expr */ |
- |
| 2292 |
- |
scratch.opcode = EEOP_JUMP_IF_NOT_NULL; |
- |
| 2293 |
- |
scratch.d.jump.jumpdone = -1; /* adjust later */ |
- |
| 2294 |
- |
ExprEvalPushStep(state, &scratch); |
- |
| 2295 |
- |
|
- |
| 2296 |
- |
adjust_jumps = lappend_int(adjust_jumps, |
- |
| 2297 |
- |
state->steps_len - 1); |
- |
| 2298 |
- |
} |
- |
| 2299 |
- |
|
- |
| 2300 |
- |
/* |
- |
| 2301 |
- |
* No need to add a constant NULL return - we only can get to |
- |
| 2302 |
- |
* the end of the expression if a NULL already is being |
- |
| 2303 |
- |
* returned. |
- |
| 2304 |
- |
*/ |
- |
| 2305 |
- |
|
- |
| 2306 |
- |
/* adjust jump targets */ |
- |
| 2307 |
- |
foreach(lc, adjust_jumps) |
- |
| 2308 |
- |
{ |
- |
| 2309 |
- |
ExprEvalStep *as = &state->steps[lfirst_int(lc)]; |
- |
| 2310 |
- |
|
- |
| 2311 |
- |
Assert(as->opcode == EEOP_JUMP_IF_NOT_NULL); |
- |
| 2312 |
- |
Assert(as->d.jump.jumpdone == -1); |
- |
| 2313 |
- |
as->d.jump.jumpdone = state->steps_len; |
- |
| 2314 |
- |
} |
- |
| 2315 |
- |
|
- |
| 2316 |
- |
break; |
- |
| 2317 |
- |
} |
- |
| 2318 |
- |
|
- |
| 2319 |
- |
case T_MinMaxExpr: |
- |
| 2320 |
- |
{ |
- |
| 2321 |
- |
MinMaxExpr *minmaxexpr = (MinMaxExpr *) node; |
- |
| 2322 |
- |
int nelems = list_length(minmaxexpr->args); |
- |
| 2323 |
- |
TypeCacheEntry *typentry; |
- |
| 2324 |
- |
FmgrInfo *finfo; |
- |
| 2325 |
- |
FunctionCallInfo fcinfo; |
- |
| 2326 |
- |
ListCell *lc; |
- |
| 2327 |
- |
int off; |
- |
| 2328 |
- |
|
- |
| 2329 |
- |
/* Look up the btree comparison function for the datatype */ |
- |
| 2330 |
- |
typentry = lookup_type_cache(minmaxexpr->minmaxtype, |
- |
| 2331 |
- |
TYPECACHE_CMP_PROC); |
- |
| 2332 |
- |
if (!OidIsValid(typentry->cmp_proc)) |
- |
| 2333 |
- |
ereport(ERROR, |
- |
| 2334 |
- |
(errcode(ERRCODE_UNDEFINED_FUNCTION), |
- |
| 2335 |
- |
errmsg("could not identify a comparison function for type %s", |
- |
| 2336 |
- |
format_type_be(minmaxexpr->minmaxtype)))); |
- |
| 2337 |
- |
|
- |
| 2338 |
- |
/* |
- |
| 2339 |
- |
* If we enforced permissions checks on index support |
- |
| 2340 |
- |
* functions, we'd need to make a check here. But the index |
- |
| 2341 |
- |
* support machinery doesn't do that, and thus neither does |
- |
| 2342 |
- |
* this code. |
- |
| 2343 |
- |
*/ |
- |
| 2344 |
- |
|
- |
| 2345 |
- |
/* Perform function lookup */ |
- |
| 2346 |
- |
finfo = palloc0_object(FmgrInfo); |
- |
| 2347 |
- |
fcinfo = palloc0(SizeForFunctionCallInfo(2)); |
- |
| 2348 |
- |
fmgr_info(typentry->cmp_proc, finfo); |
- |
| 2349 |
- |
fmgr_info_set_expr((Node *) node, finfo); |
- |
| 2350 |
- |
InitFunctionCallInfoData(*fcinfo, finfo, 2, |
- |
| 2351 |
- |
minmaxexpr->inputcollid, NULL, NULL); |
- |
| 2352 |
- |
|
- |
| 2353 |
- |
scratch.opcode = EEOP_MINMAX; |
- |
| 2354 |
- |
/* allocate space to store arguments */ |
- |
| 2355 |
- |
scratch.d.minmax.values = palloc_array(Datum, nelems); |
- |
| 2356 |
- |
scratch.d.minmax.nulls = palloc_array(bool, nelems); |
- |
| 2357 |
- |
scratch.d.minmax.nelems = nelems; |
- |
| 2358 |
- |
|
- |
| 2359 |
- |
scratch.d.minmax.op = minmaxexpr->op; |
- |
| 2360 |
- |
scratch.d.minmax.finfo = finfo; |
- |
| 2361 |
- |
scratch.d.minmax.fcinfo_data = fcinfo; |
- |
| 2362 |
- |
|
- |
| 2363 |
- |
/* evaluate expressions into minmax->values/nulls */ |
- |
| 2364 |
- |
off = 0; |
- |
| 2365 |
- |
foreach(lc, minmaxexpr->args) |
- |
| 2366 |
- |
{ |
- |
| 2367 |
- |
Expr *e = (Expr *) lfirst(lc); |
- |
| 2368 |
- |
|
- |
| 2369 |
- |
ExecInitExprRec(e, state, |
- |
| 2370 |
- |
&scratch.d.minmax.values[off], |
- |
| 2371 |
- |
&scratch.d.minmax.nulls[off]); |
- |
| 2372 |
- |
off++; |
- |
| 2373 |
- |
} |
- |
| 2374 |
- |
|
- |
| 2375 |
- |
/* and push the final comparison */ |
- |
| 2376 |
- |
ExprEvalPushStep(state, &scratch); |
- |
| 2377 |
- |
break; |
- |
| 2378 |
- |
} |
- |
| 2379 |
- |
|
- |
| 2380 |
- |
case T_SQLValueFunction: |
- |
| 2381 |
- |
{ |
- |
| 2382 |
- |
SQLValueFunction *svf = (SQLValueFunction *) node; |
- |
| 2383 |
- |
|
- |
| 2384 |
- |
scratch.opcode = EEOP_SQLVALUEFUNCTION; |
- |
| 2385 |
- |
scratch.d.sqlvaluefunction.svf = svf; |
- |
| 2386 |
- |
|
- |
| 2387 |
- |
ExprEvalPushStep(state, &scratch); |
- |
| 2388 |
- |
break; |
- |
| 2389 |
- |
} |
- |
| 2390 |
- |
|
- |
| 2391 |
- |
case T_XmlExpr: |
- |
| 2392 |
- |
{ |
- |
| 2393 |
- |
XmlExpr *xexpr = (XmlExpr *) node; |
- |
| 2394 |
- |
int nnamed = list_length(xexpr->named_args); |
- |
| 2395 |
- |
int nargs = list_length(xexpr->args); |
- |
| 2396 |
- |
int off; |
- |
| 2397 |
- |
ListCell *arg; |
- |
| 2398 |
- |
|
- |
| 2399 |
- |
scratch.opcode = EEOP_XMLEXPR; |
- |
| 2400 |
- |
scratch.d.xmlexpr.xexpr = xexpr; |
- |
| 2401 |
- |
|
- |
| 2402 |
- |
/* allocate space for storing all the arguments */ |
- |
| 2403 |
- |
if (nnamed) |
- |
| 2404 |
- |
{ |
- |
| 2405 |
- |
scratch.d.xmlexpr.named_argvalue = palloc_array(Datum, nnamed); |
- |
| 2406 |
- |
scratch.d.xmlexpr.named_argnull = palloc_array(bool, nnamed); |
- |
| 2407 |
- |
} |
- |
| 2408 |
- |
else |
- |
| 2409 |
- |
{ |
- |
| 2410 |
- |
scratch.d.xmlexpr.named_argvalue = NULL; |
- |
| 2411 |
- |
scratch.d.xmlexpr.named_argnull = NULL; |
- |
| 2412 |
- |
} |
- |
| 2413 |
- |
|
- |
| 2414 |
- |
if (nargs) |
- |
| 2415 |
- |
{ |
- |
| 2416 |
- |
scratch.d.xmlexpr.argvalue = palloc_array(Datum, nargs); |
- |
| 2417 |
- |
scratch.d.xmlexpr.argnull = palloc_array(bool, nargs); |
- |
| 2418 |
- |
} |
- |
| 2419 |
- |
else |
- |
| 2420 |
- |
{ |
- |
| 2421 |
- |
scratch.d.xmlexpr.argvalue = NULL; |
- |
| 2422 |
- |
scratch.d.xmlexpr.argnull = NULL; |
- |
| 2423 |
- |
} |
- |
| 2424 |
- |
|
- |
| 2425 |
- |
/* prepare argument execution */ |
- |
| 2426 |
- |
off = 0; |
- |
| 2427 |
- |
foreach(arg, xexpr->named_args) |
- |
| 2428 |
- |
{ |
- |
| 2429 |
- |
Expr *e = (Expr *) lfirst(arg); |
- |
| 2430 |
- |
|
- |
| 2431 |
- |
ExecInitExprRec(e, state, |
- |
| 2432 |
- |
&scratch.d.xmlexpr.named_argvalue[off], |
- |
| 2433 |
- |
&scratch.d.xmlexpr.named_argnull[off]); |
- |
| 2434 |
- |
off++; |
- |
| 2435 |
- |
} |
- |
| 2436 |
- |
|
- |
| 2437 |
- |
off = 0; |
- |
| 2438 |
- |
foreach(arg, xexpr->args) |
- |
| 2439 |
- |
{ |
- |
| 2440 |
- |
Expr *e = (Expr *) lfirst(arg); |
- |
| 2441 |
- |
|
- |
| 2442 |
- |
ExecInitExprRec(e, state, |
- |
| 2443 |
- |
&scratch.d.xmlexpr.argvalue[off], |
- |
| 2444 |
- |
&scratch.d.xmlexpr.argnull[off]); |
- |
| 2445 |
- |
off++; |
- |
| 2446 |
- |
} |
- |
| 2447 |
- |
|
- |
| 2448 |
- |
/* and evaluate the actual XML expression */ |
- |
| 2449 |
- |
ExprEvalPushStep(state, &scratch); |
- |
| 2450 |
- |
break; |
- |
| 2451 |
- |
} |
- |
| 2452 |
- |
|
- |
| 2453 |
- |
case T_JsonValueExpr: |
- |
| 2454 |
- |
{ |
- |
| 2455 |
- |
JsonValueExpr *jve = (JsonValueExpr *) node; |
- |
| 2456 |
- |
|
- |
| 2457 |
- |
Assert(jve->raw_expr != NULL); |
- |
| 2458 |
- |
ExecInitExprRec(jve->raw_expr, state, resv, resnull); |
- |
| 2459 |
- |
Assert(jve->formatted_expr != NULL); |
- |
| 2460 |
- |
ExecInitExprRec(jve->formatted_expr, state, resv, resnull); |
- |
| 2461 |
- |
break; |
- |
| 2462 |
- |
} |
- |
| 2463 |
- |
|
- |
| 2464 |
- |
case T_JsonConstructorExpr: |
- |
| 2465 |
- |
{ |
- |
| 2466 |
- |
JsonConstructorExpr *ctor = (JsonConstructorExpr *) node; |
- |
| 2467 |
- |
List *args = ctor->args; |
- |
| 2468 |
- |
ListCell *lc; |
- |
| 2469 |
- |
int nargs = list_length(args); |
- |
| 2470 |
- |
int argno = 0; |
- |
| 2471 |
- |
|
- |
| 2472 |
- |
if (ctor->func) |
- |
| 2473 |
- |
{ |
- |
| 2474 |
- |
ExecInitExprRec(ctor->func, state, resv, resnull); |
- |
| 2475 |
- |
} |
- |
| 2476 |
- |
else if ((ctor->type == JSCTOR_JSON_PARSE && !ctor->unique) || |
- |
| 2477 |
- |
ctor->type == JSCTOR_JSON_SERIALIZE) |
- |
| 2478 |
- |
{ |
- |
| 2479 |
- |
/* Use the value of the first argument as result */ |
- |
| 2480 |
- |
ExecInitExprRec(linitial(args), state, resv, resnull); |
- |
| 2481 |
- |
} |
- |
| 2482 |
- |
else |
- |
| 2483 |
- |
{ |
- |
| 2484 |
- |
JsonConstructorExprState *jcstate; |
- |
| 2485 |
- |
|
- |
| 2486 |
- |
jcstate = palloc0_object(JsonConstructorExprState); |
- |
| 2487 |
- |
|
- |
| 2488 |
- |
scratch.opcode = EEOP_JSON_CONSTRUCTOR; |
- |
| 2489 |
- |
scratch.d.json_constructor.jcstate = jcstate; |
- |
| 2490 |
- |
|
- |
| 2491 |
- |
jcstate->constructor = ctor; |
- |
| 2492 |
- |
jcstate->arg_values = palloc_array(Datum, nargs); |
- |
| 2493 |
- |
jcstate->arg_nulls = palloc_array(bool, nargs); |
- |
| 2494 |
- |
jcstate->arg_types = palloc_array(Oid, nargs); |
- |
| 2495 |
- |
jcstate->nargs = nargs; |
- |
| 2496 |
- |
|
- |
| 2497 |
- |
foreach(lc, args) |
- |
| 2498 |
- |
{ |
- |
| 2499 |
- |
Expr *arg = (Expr *) lfirst(lc); |
- |
| 2500 |
- |
|
- |
| 2501 |
- |
jcstate->arg_types[argno] = exprType((Node *) arg); |
- |
| 2502 |
- |
|
- |
| 2503 |
- |
if (IsA(arg, Const)) |
- |
| 2504 |
- |
{ |
- |
| 2505 |
- |
/* Don't evaluate const arguments every round */ |
- |
| 2506 |
- |
Const *con = (Const *) arg; |
- |
| 2507 |
- |
|
- |
| 2508 |
- |
jcstate->arg_values[argno] = con->constvalue; |
- |
| 2509 |
- |
jcstate->arg_nulls[argno] = con->constisnull; |
- |
| 2510 |
- |
} |
- |
| 2511 |
- |
else |
- |
| 2512 |
- |
{ |
- |
| 2513 |
- |
ExecInitExprRec(arg, state, |
- |
| 2514 |
- |
&jcstate->arg_values[argno], |
- |
| 2515 |
- |
&jcstate->arg_nulls[argno]); |
- |
| 2516 |
- |
} |
- |
| 2517 |
- |
argno++; |
- |
| 2518 |
- |
} |
- |
| 2519 |
- |
|
- |
| 2520 |
- |
/* prepare type cache for datum_to_json[b]() */ |
- |
| 2521 |
- |
if (ctor->type == JSCTOR_JSON_SCALAR) |
- |
| 2522 |
- |
{ |
- |
| 2523 |
- |
bool is_jsonb = |
- |
| 2524 |
- |
ctor->returning->format->format_type == JS_FORMAT_JSONB; |
- |
| 2525 |
- |
|
- |
| 2526 |
- |
jcstate->arg_type_cache = |
- |
| 2527 |
- |
palloc(sizeof(*jcstate->arg_type_cache) * nargs); |
- |
| 2528 |
- |
|
- |
| 2529 |
- |
for (int i = 0; i < nargs; i++) |
- |
| 2530 |
- |
{ |
- |
| 2531 |
- |
JsonTypeCategory category; |
- |
| 2532 |
- |
Oid outfuncid; |
- |
| 2533 |
- |
Oid typid = jcstate->arg_types[i]; |
- |
| 2534 |
- |
|
- |
| 2535 |
- |
json_categorize_type(typid, is_jsonb, |
- |
| 2536 |
- |
&category, &outfuncid); |
- |
| 2537 |
- |
|
- |
| 2538 |
- |
jcstate->arg_type_cache[i].outfuncid = outfuncid; |
- |
| 2539 |
- |
jcstate->arg_type_cache[i].category = (int) category; |
- |
| 2540 |
- |
} |
- |
| 2541 |
- |
} |
- |
| 2542 |
- |
|
- |
| 2543 |
- |
ExprEvalPushStep(state, &scratch); |
- |
| 2544 |
- |
} |
- |
| 2545 |
- |
|
- |
| 2546 |
- |
if (ctor->coercion) |
- |
| 2547 |
- |
{ |
- |
| 2548 |
- |
Datum *innermost_caseval = state->innermost_caseval; |
- |
| 2549 |
- |
bool *innermost_isnull = state->innermost_casenull; |
- |
| 2550 |
- |
|
- |
| 2551 |
- |
state->innermost_caseval = resv; |
- |
| 2552 |
- |
state->innermost_casenull = resnull; |
- |
| 2553 |
- |
|
- |
| 2554 |
- |
ExecInitExprRec(ctor->coercion, state, resv, resnull); |
- |
| 2555 |
- |
|
- |
| 2556 |
- |
state->innermost_caseval = innermost_caseval; |
- |
| 2557 |
- |
state->innermost_casenull = innermost_isnull; |
- |
| 2558 |
- |
} |
- |
| 2559 |
- |
} |
- |
| 2560 |
- |
break; |
- |
| 2561 |
- |
|
- |
| 2562 |
- |
case T_JsonIsPredicate: |
- |
| 2563 |
- |
{ |
- |
| 2564 |
- |
JsonIsPredicate *pred = (JsonIsPredicate *) node; |
- |
| 2565 |
- |
|
- |
| 2566 |
- |
ExecInitExprRec((Expr *) pred->expr, state, resv, resnull); |
- |
| 2567 |
- |
|
- |
| 2568 |
- |
scratch.opcode = EEOP_IS_JSON; |
- |
| 2569 |
- |
scratch.d.is_json.pred = pred; |
- |
| 2570 |
- |
|
- |
| 2571 |
- |
ExprEvalPushStep(state, &scratch); |
- |
| 2572 |
- |
break; |
- |
| 2573 |
- |
} |
- |
| 2574 |
- |
|
- |
| 2575 |
- |
case T_JsonExpr: |
- |
| 2576 |
- |
{ |
- |
| 2577 |
- |
JsonExpr *jsexpr = castNode(JsonExpr, node); |
- |
| 2578 |
- |
|
- |
| 2579 |
- |
/* |
- |
| 2580 |
- |
* No need to initialize a full JsonExprState For |
- |
| 2581 |
- |
* JSON_TABLE(), because the upstream caller tfuncFetchRows() |
- |
| 2582 |
- |
* is only interested in the value of formatted_expr. |
- |
| 2583 |
- |
*/ |
- |
| 2584 |
- |
if (jsexpr->op == JSON_TABLE_OP) |
- |
| 2585 |
- |
ExecInitExprRec((Expr *) jsexpr->formatted_expr, state, |
- |
| 2586 |
- |
resv, resnull); |
- |
| 2587 |
- |
else |
- |
| 2588 |
- |
ExecInitJsonExpr(jsexpr, state, resv, resnull, &scratch); |
- |
| 2589 |
- |
break; |
- |
| 2590 |
- |
} |
- |
| 2591 |
- |
|
- |
| 2592 |
- |
case T_NullTest: |
- |
| 2593 |
- |
{ |
- |
| 2594 |
- |
NullTest *ntest = (NullTest *) node; |
- |
| 2595 |
- |
|
- |
| 2596 |
- |
if (ntest->nulltesttype == IS_NULL) |
- |
| 2597 |
- |
{ |
- |
| 2598 |
- |
if (ntest->argisrow) |
- |
| 2599 |
- |
scratch.opcode = EEOP_NULLTEST_ROWISNULL; |
- |
| 2600 |
- |
else |
- |
| 2601 |
- |
scratch.opcode = EEOP_NULLTEST_ISNULL; |
- |
| 2602 |
- |
} |
- |
| 2603 |
- |
else if (ntest->nulltesttype == IS_NOT_NULL) |
- |
| 2604 |
- |
{ |
- |
| 2605 |
- |
if (ntest->argisrow) |
- |
| 2606 |
- |
scratch.opcode = EEOP_NULLTEST_ROWISNOTNULL; |
- |
| 2607 |
- |
else |
- |
| 2608 |
- |
scratch.opcode = EEOP_NULLTEST_ISNOTNULL; |
- |
| 2609 |
- |
} |
- |
| 2610 |
- |
else |
- |
| 2611 |
- |
{ |
- |
| 2612 |
- |
elog(ERROR, "unrecognized nulltesttype: %d", |
- |
| 2613 |
- |
(int) ntest->nulltesttype); |
- |
| 2614 |
- |
} |
- |
| 2615 |
- |
/* initialize cache in case it's a row test */ |
- |
| 2616 |
- |
scratch.d.nulltest_row.rowcache.cacheptr = NULL; |
- |
| 2617 |
- |
|
- |
| 2618 |
- |
/* first evaluate argument into result variable */ |
- |
| 2619 |
- |
ExecInitExprRec(ntest->arg, state, |
- |
| 2620 |
- |
resv, resnull); |
- |
| 2621 |
- |
|
- |
| 2622 |
- |
/* then push the test of that argument */ |
- |
| 2623 |
- |
ExprEvalPushStep(state, &scratch); |
- |
| 2624 |
- |
break; |
- |
| 2625 |
- |
} |
- |
| 2626 |
- |
|
- |
| 2627 |
- |
case T_BooleanTest: |
- |
| 2628 |
- |
{ |
- |
| 2629 |
- |
BooleanTest *btest = (BooleanTest *) node; |
- |
| 2630 |
- |
|
- |
| 2631 |
- |
/* |
- |
| 2632 |
- |
* Evaluate argument, directly into result datum. That's ok, |
- |
| 2633 |
- |
* because resv/resnull is definitely not used anywhere else, |
- |
| 2634 |
- |
* and will get overwritten by the below EEOP_BOOLTEST_IS_* |
- |
| 2635 |
- |
* step. |
- |
| 2636 |
- |
*/ |
- |
| 2637 |
- |
ExecInitExprRec(btest->arg, state, resv, resnull); |
- |
| 2638 |
- |
|
- |
| 2639 |
- |
switch (btest->booltesttype) |
- |
| 2640 |
- |
{ |
- |
| 2641 |
- |
case IS_TRUE: |
- |
| 2642 |
- |
scratch.opcode = EEOP_BOOLTEST_IS_TRUE; |
- |
| 2643 |
- |
break; |
- |
| 2644 |
- |
case IS_NOT_TRUE: |
- |
| 2645 |
- |
scratch.opcode = EEOP_BOOLTEST_IS_NOT_TRUE; |
- |
| 2646 |
- |
break; |
- |
| 2647 |
- |
case IS_FALSE: |
- |
| 2648 |
- |
scratch.opcode = EEOP_BOOLTEST_IS_FALSE; |
- |
| 2649 |
- |
break; |
- |
| 2650 |
- |
case IS_NOT_FALSE: |
- |
| 2651 |
- |
scratch.opcode = EEOP_BOOLTEST_IS_NOT_FALSE; |
- |
| 2652 |
- |
break; |
- |
| 2653 |
- |
case IS_UNKNOWN: |
- |
| 2654 |
- |
/* Same as scalar IS NULL test */ |
- |
| 2655 |
- |
scratch.opcode = EEOP_NULLTEST_ISNULL; |
- |
| 2656 |
- |
break; |
- |
| 2657 |
- |
case IS_NOT_UNKNOWN: |
- |
| 2658 |
- |
/* Same as scalar IS NOT NULL test */ |
- |
| 2659 |
- |
scratch.opcode = EEOP_NULLTEST_ISNOTNULL; |
- |
| 2660 |
- |
break; |
- |
| 2661 |
- |
default: |
- |
| 2662 |
- |
elog(ERROR, "unrecognized booltesttype: %d", |
- |
| 2663 |
- |
(int) btest->booltesttype); |
- |
| 2664 |
- |
} |
- |
| 2665 |
- |
|
- |
| 2666 |
- |
ExprEvalPushStep(state, &scratch); |
- |
| 2667 |
- |
break; |
- |
| 2668 |
- |
} |
- |
| 2669 |
- |
|
- |
| 2670 |
- |
case T_CoerceToDomain: |
- |
| 2671 |
- |
{ |
- |
| 2672 |
- |
CoerceToDomain *ctest = (CoerceToDomain *) node; |
- |
| 2673 |
- |
|
- |
| 2674 |
- |
ExecInitCoerceToDomain(&scratch, ctest, state, |
- |
| 2675 |
- |
resv, resnull); |
- |
| 2676 |
- |
break; |
- |
| 2677 |
- |
} |
- |
| 2678 |
- |
|
- |
| 2679 |
- |
case T_CoerceToDomainValue: |
- |
| 2680 |
- |
{ |
- |
| 2681 |
- |
/* |
- |
| 2682 |
- |
* Read from location identified by innermost_domainval. Note |
- |
| 2683 |
- |
* that innermost_domainval could be NULL, if we're compiling |
- |
| 2684 |
- |
* a standalone domain check rather than one embedded in a |
- |
| 2685 |
- |
* larger expression. In that case we must read from |
- |
| 2686 |
- |
* econtext->domainValue_datum. We'll take care of that by |
- |
| 2687 |
- |
* generating a specialized operation. |
- |
| 2688 |
- |
*/ |
- |
| 2689 |
- |
if (state->innermost_domainval == NULL) |
- |
| 2690 |
- |
scratch.opcode = EEOP_DOMAIN_TESTVAL_EXT; |
- |
| 2691 |
- |
else |
- |
| 2692 |
- |
{ |
- |
| 2693 |
- |
scratch.opcode = EEOP_DOMAIN_TESTVAL; |
- |
| 2694 |
- |
/* we share instruction union variant with case testval */ |
- |
| 2695 |
- |
scratch.d.casetest.value = state->innermost_domainval; |
- |
| 2696 |
- |
scratch.d.casetest.isnull = state->innermost_domainnull; |
- |
| 2697 |
- |
} |
- |
| 2698 |
- |
ExprEvalPushStep(state, &scratch); |
- |
| 2699 |
- |
break; |
- |
| 2700 |
- |
} |
- |
| 2701 |
- |
|
- |
| 2702 |
- |
case T_CurrentOfExpr: |
- |
| 2703 |
- |
{ |
- |
| 2704 |
- |
scratch.opcode = EEOP_CURRENTOFEXPR; |
- |
| 2705 |
- |
ExprEvalPushStep(state, &scratch); |
- |
| 2706 |
- |
break; |
- |
| 2707 |
- |
} |
- |
| 2708 |
- |
|
- |
| 2709 |
- |
case T_NextValueExpr: |
- |
| 2710 |
- |
{ |
- |
| 2711 |
- |
NextValueExpr *nve = (NextValueExpr *) node; |
- |
| 2712 |
- |
|
- |
| 2713 |
- |
scratch.opcode = EEOP_NEXTVALUEEXPR; |
- |
| 2714 |
- |
scratch.d.nextvalueexpr.seqid = nve->seqid; |
- |
| 2715 |
- |
scratch.d.nextvalueexpr.seqtypid = nve->typeId; |
- |
| 2716 |
- |
|
- |
| 2717 |
- |
ExprEvalPushStep(state, &scratch); |
- |
| 2718 |
- |
break; |
- |
| 2719 |
- |
} |
- |
| 2720 |
- |
|
- |
| 2721 |
- |
case T_ReturningExpr: |
- |
| 2722 |
- |
{ |
- |
| 2723 |
- |
ReturningExpr *rexpr = (ReturningExpr *) node; |
- |
| 2724 |
- |
int retstep; |
- |
| 2725 |
- |
|
- |
| 2726 |
- |
/* Skip expression evaluation if OLD/NEW row doesn't exist */ |
- |
| 2727 |
- |
scratch.opcode = EEOP_RETURNINGEXPR; |
- |
| 2728 |
- |
scratch.d.returningexpr.nullflag = rexpr->retold ? |
- |
| 2729 |
- |
EEO_FLAG_OLD_IS_NULL : EEO_FLAG_NEW_IS_NULL; |
- |
| 2730 |
- |
scratch.d.returningexpr.jumpdone = -1; /* set below */ |
- |
| 2731 |
- |
ExprEvalPushStep(state, &scratch); |
- |
| 2732 |
- |
retstep = state->steps_len - 1; |
- |
| 2733 |
- |
|
- |
| 2734 |
- |
/* Steps to evaluate expression to return */ |
- |
| 2735 |
- |
ExecInitExprRec(rexpr->retexpr, state, resv, resnull); |
- |
| 2736 |
- |
|
- |
| 2737 |
- |
/* Jump target used if OLD/NEW row doesn't exist */ |
- |
| 2738 |
- |
state->steps[retstep].d.returningexpr.jumpdone = state->steps_len; |
- |
| 2739 |
- |
|
- |
| 2740 |
- |
/* Update ExprState flags */ |
- |
| 2741 |
- |
if (rexpr->retold) |
- |
| 2742 |
- |
state->flags |= EEO_FLAG_HAS_OLD; |
- |
| 2743 |
- |
else |
- |
| 2744 |
- |
state->flags |= EEO_FLAG_HAS_NEW; |
- |
| 2745 |
- |
|
- |
| 2746 |
- |
break; |
- |
| 2747 |
- |
} |
- |
| 2748 |
- |
|
- |
| 2749 |
- |
default: |
- |
| 2750 |
- |
elog(ERROR, "unrecognized node type: %d", |
- |
| 2751 |
- |
(int) nodeTag(node)); |
- |
| 2752 |
- |
break; |
- |
| 2753 |
- |
} |
- |
| 2754 |
- |
} |
- |