aboutsummaryrefslogtreecommitdiff
path: root/src/backend/rewrite/rewriteManip.c
diff options
context:
space:
mode:
authorRobert Haas <rhaas@postgresql.org>2017-08-03 11:21:29 -0400
committerRobert Haas <rhaas@postgresql.org>2017-08-03 11:21:29 -0400
commit610e8ebb0fadd7a738c2ad07fef6c5ea86b11f8d (patch)
tree703e9cd198a275278767d7e1756907305e580429 /src/backend/rewrite/rewriteManip.c
parent5ff3d73813ebcc3ff80be77c30b458d728951036 (diff)
downloadpostgresql-610e8ebb0fadd7a738c2ad07fef6c5ea86b11f8d.tar.gz
postgresql-610e8ebb0fadd7a738c2ad07fef6c5ea86b11f8d.zip
Teach map_partition_varattnos to handle whole-row expressions.
Otherwise, partitioned tables with RETURNING expressions or subject to a WITH CHECK OPTION do not work properly. Amit Langote, reviewed by Amit Khandekar and Etsuro Fujita. A few comment changes by me. Discussion: http://postgr.es/m/9a39df80-871e-6212-0684-f93c83be4097@lab.ntt.co.jp
Diffstat (limited to 'src/backend/rewrite/rewriteManip.c')
-rw-r--r--src/backend/rewrite/rewriteManip.c47
1 files changed, 38 insertions, 9 deletions
diff --git a/src/backend/rewrite/rewriteManip.c b/src/backend/rewrite/rewriteManip.c
index b89b435da02..ba706b25b40 100644
--- a/src/backend/rewrite/rewriteManip.c
+++ b/src/backend/rewrite/rewriteManip.c
@@ -1203,14 +1203,12 @@ replace_rte_variables_mutator(Node *node,
* appear in the expression.
*
* If the expression tree contains a whole-row Var for the target RTE,
- * the Var is not changed but *found_whole_row is returned as TRUE.
- * For most callers this is an error condition, but we leave it to the caller
- * to report the error so that useful context can be provided. (In some
- * usages it would be appropriate to modify the Var's vartype and insert a
- * ConvertRowtypeExpr node to map back to the original vartype. We might
- * someday extend this function's API to support that. For now, the only
- * concession to that future need is that this function is a tree mutator
- * not just a walker.)
+ * *found_whole_row is returned as TRUE. In addition, if to_rowtype is
+ * not InvalidOid, we modify the Var's vartype and insert a ConvertRowTypeExpr
+ * to map back to the orignal rowtype. Callers that don't provide to_rowtype
+ * should report an error if *found_row_type is true; we don't do that here
+ * because we don't know exactly what wording for the error message would
+ * be most appropriate. The caller will be aware of the context.
*
* This could be built using replace_rte_variables and a callback function,
* but since we don't ever need to insert sublinks, replace_rte_variables is
@@ -1223,6 +1221,8 @@ typedef struct
int sublevels_up; /* (current) nesting depth */
const AttrNumber *attno_map; /* map array for user attnos */
int map_length; /* number of entries in attno_map[] */
+ /* Target type when converting whole-row vars */
+ Oid to_rowtype;
bool *found_whole_row; /* output flag */
} map_variable_attnos_context;
@@ -1257,6 +1257,34 @@ map_variable_attnos_mutator(Node *node,
{
/* whole-row variable, warn caller */
*(context->found_whole_row) = true;
+
+ /* If the callers expects us to convert the same, do so. */
+ if (OidIsValid(context->to_rowtype))
+ {
+ /* No support for RECORDOID. */
+ Assert(var->vartype != RECORDOID);
+
+ /* Don't convert unless necessary. */
+ if (context->to_rowtype != var->vartype)
+ {
+ ConvertRowtypeExpr *r;
+
+ /* Var itself is converted to the requested type. */
+ newvar->vartype = context->to_rowtype;
+
+ /*
+ * And a conversion node on top to convert back to the
+ * original type.
+ */
+ r = makeNode(ConvertRowtypeExpr);
+ r->arg = (Expr *) newvar;
+ r->resulttype = var->vartype;
+ r->convertformat = COERCE_IMPLICIT_CAST;
+ r->location = -1;
+
+ return (Node *) r;
+ }
+ }
}
return (Node *) newvar;
}
@@ -1283,7 +1311,7 @@ Node *
map_variable_attnos(Node *node,
int target_varno, int sublevels_up,
const AttrNumber *attno_map, int map_length,
- bool *found_whole_row)
+ Oid to_rowtype, bool *found_whole_row)
{
map_variable_attnos_context context;
@@ -1291,6 +1319,7 @@ map_variable_attnos(Node *node,
context.sublevels_up = sublevels_up;
context.attno_map = attno_map;
context.map_length = map_length;
+ context.to_rowtype = to_rowtype;
context.found_whole_row = found_whole_row;
*found_whole_row = false;