|
45 | 45 | #include "utils/acl.h"
|
46 | 46 | #include "utils/builtins.h"
|
47 | 47 | #include "utils/datum.h"
|
| 48 | +#include "utils/fmgroids.h" |
48 | 49 | #include "utils/lsyscache.h"
|
49 | 50 | #include "utils/memutils.h"
|
50 | 51 | #include "utils/syscache.h"
|
@@ -94,6 +95,7 @@ static bool expression_returns_set_rows_walker(Node *node, double *count);
|
94 | 95 | static bool contain_subplans_walker(Node *node, void *context);
|
95 | 96 | static bool contain_mutable_functions_walker(Node *node, void *context);
|
96 | 97 | static bool contain_volatile_functions_walker(Node *node, void *context);
|
| 98 | +static bool contain_volatile_functions_not_nextval_walker(Node *node, void *context); |
97 | 99 | static bool contain_nonstrict_functions_walker(Node *node, void *context);
|
98 | 100 | static bool contain_leaky_functions_walker(Node *node, void *context);
|
99 | 101 | static Relids find_nonnullable_rels_walker(Node *node, bool top_level);
|
@@ -971,6 +973,19 @@ contain_volatile_functions(Node *clause)
|
971 | 973 | return contain_volatile_functions_walker(clause, NULL);
|
972 | 974 | }
|
973 | 975 |
|
| 976 | +bool |
| 977 | +contain_volatile_functions_not_nextval(Node *clause) |
| 978 | +{ |
| 979 | + return contain_volatile_functions_not_nextval_walker(clause, NULL); |
| 980 | +} |
| 981 | + |
| 982 | +/* |
| 983 | + * General purpose code for checking expression volatility. |
| 984 | + * |
| 985 | + * Special purpose code for use in COPY is almost identical to this, |
| 986 | + * so any changes here may also be needed in other contain_volatile... |
| 987 | + * functions. |
| 988 | + */ |
974 | 989 | static bool
|
975 | 990 | contain_volatile_functions_walker(Node *node, void *context)
|
976 | 991 | {
|
@@ -1072,6 +1087,107 @@ contain_volatile_functions_walker(Node *node, void *context)
|
1072 | 1087 | context);
|
1073 | 1088 | }
|
1074 | 1089 |
|
| 1090 | +/* |
| 1091 | + * Special purpose version of contain_volatile_functions for use in COPY |
| 1092 | + */ |
| 1093 | +static bool |
| 1094 | +contain_volatile_functions_not_nextval_walker(Node *node, void *context) |
| 1095 | +{ |
| 1096 | + if (node == NULL) |
| 1097 | + return false; |
| 1098 | + if (IsA(node, FuncExpr)) |
| 1099 | + { |
| 1100 | + FuncExpr *expr = (FuncExpr *) node; |
| 1101 | + |
| 1102 | + /* |
| 1103 | + * For this case only, we want to ignore the volatility of the |
| 1104 | + * nextval() function, since some callers want this. |
| 1105 | + */ |
| 1106 | + if (expr->funcid != F_NEXTVAL_OID && |
| 1107 | + func_volatile(expr->funcid) == PROVOLATILE_VOLATILE) |
| 1108 | + return true; |
| 1109 | + /* else fall through to check args */ |
| 1110 | + } |
| 1111 | + else if (IsA(node, OpExpr)) |
| 1112 | + { |
| 1113 | + OpExpr *expr = (OpExpr *) node; |
| 1114 | + |
| 1115 | + set_opfuncid(expr); |
| 1116 | + if (func_volatile(expr->opfuncid) == PROVOLATILE_VOLATILE) |
| 1117 | + return true; |
| 1118 | + /* else fall through to check args */ |
| 1119 | + } |
| 1120 | + else if (IsA(node, DistinctExpr)) |
| 1121 | + { |
| 1122 | + DistinctExpr *expr = (DistinctExpr *) node; |
| 1123 | + |
| 1124 | + set_opfuncid((OpExpr *) expr); /* rely on struct equivalence */ |
| 1125 | + if (func_volatile(expr->opfuncid) == PROVOLATILE_VOLATILE) |
| 1126 | + return true; |
| 1127 | + /* else fall through to check args */ |
| 1128 | + } |
| 1129 | + else if (IsA(node, NullIfExpr)) |
| 1130 | + { |
| 1131 | + NullIfExpr *expr = (NullIfExpr *) node; |
| 1132 | + |
| 1133 | + set_opfuncid((OpExpr *) expr); /* rely on struct equivalence */ |
| 1134 | + if (func_volatile(expr->opfuncid) == PROVOLATILE_VOLATILE) |
| 1135 | + return true; |
| 1136 | + /* else fall through to check args */ |
| 1137 | + } |
| 1138 | + else if (IsA(node, ScalarArrayOpExpr)) |
| 1139 | + { |
| 1140 | + ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) node; |
| 1141 | + |
| 1142 | + set_sa_opfuncid(expr); |
| 1143 | + if (func_volatile(expr->opfuncid) == PROVOLATILE_VOLATILE) |
| 1144 | + return true; |
| 1145 | + /* else fall through to check args */ |
| 1146 | + } |
| 1147 | + else if (IsA(node, CoerceViaIO)) |
| 1148 | + { |
| 1149 | + CoerceViaIO *expr = (CoerceViaIO *) node; |
| 1150 | + Oid iofunc; |
| 1151 | + Oid typioparam; |
| 1152 | + bool typisvarlena; |
| 1153 | + |
| 1154 | + /* check the result type's input function */ |
| 1155 | + getTypeInputInfo(expr->resulttype, |
| 1156 | + &iofunc, &typioparam); |
| 1157 | + if (func_volatile(iofunc) == PROVOLATILE_VOLATILE) |
| 1158 | + return true; |
| 1159 | + /* check the input type's output function */ |
| 1160 | + getTypeOutputInfo(exprType((Node *) expr->arg), |
| 1161 | + &iofunc, &typisvarlena); |
| 1162 | + if (func_volatile(iofunc) == PROVOLATILE_VOLATILE) |
| 1163 | + return true; |
| 1164 | + /* else fall through to check args */ |
| 1165 | + } |
| 1166 | + else if (IsA(node, ArrayCoerceExpr)) |
| 1167 | + { |
| 1168 | + ArrayCoerceExpr *expr = (ArrayCoerceExpr *) node; |
| 1169 | + |
| 1170 | + if (OidIsValid(expr->elemfuncid) && |
| 1171 | + func_volatile(expr->elemfuncid) == PROVOLATILE_VOLATILE) |
| 1172 | + return true; |
| 1173 | + /* else fall through to check args */ |
| 1174 | + } |
| 1175 | + else if (IsA(node, RowCompareExpr)) |
| 1176 | + { |
| 1177 | + /* RowCompare probably can't have volatile ops, but check anyway */ |
| 1178 | + RowCompareExpr *rcexpr = (RowCompareExpr *) node; |
| 1179 | + ListCell *opid; |
| 1180 | + |
| 1181 | + foreach(opid, rcexpr->opnos) |
| 1182 | + { |
| 1183 | + if (op_volatile(lfirst_oid(opid)) == PROVOLATILE_VOLATILE) |
| 1184 | + return true; |
| 1185 | + } |
| 1186 | + /* else fall through to check args */ |
| 1187 | + } |
| 1188 | + return expression_tree_walker(node, contain_volatile_functions_not_nextval_walker, |
| 1189 | + context); |
| 1190 | +} |
1075 | 1191 |
|
1076 | 1192 | /*****************************************************************************
|
1077 | 1193 | * Check clauses for nonstrict functions
|
|
0 commit comments