src/backend/executor/execExpr.c - Coverage Report

← Back to Overview

# src/backend/executor/execExpr.c

Coverage: 37/37 lines (100.0%)
Total Lines
37
modified
Covered
37
100.0%
Uncovered
0
0.0%
Keyboard navigation
ExecInitExprRec() lines 919-2754
Modified Lines Coverage: 37/37 lines (100.0%)

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 | - | } | -