aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/ruleutils.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2017-07-12 18:00:04 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2017-07-12 18:00:04 -0400
commitbc2d716ad09fceeb391c755f78c256ddac9d3b9f (patch)
treeae0a40ddfbc1da7d4b58e2fdd2584a7db3f6f910 /src/backend/utils/adt/ruleutils.c
parentda11977de9c685ef808d3a293727f9ce26753ec4 (diff)
downloadpostgresql-bc2d716ad09fceeb391c755f78c256ddac9d3b9f.tar.gz
postgresql-bc2d716ad09fceeb391c755f78c256ddac9d3b9f.zip
Fix ruleutils.c for domain-over-array cases, too.
Further investigation shows that ruleutils isn't quite up to speed either for cases where we have a domain-over-array: it needs to be prepared to look past a CoerceToDomain at the top level of field and element assignments, else it decompiles them incorrectly. Potentially this would result in failure to dump/reload a rule, if it looked like the one in the new test case. (I also added a test for EXPLAIN; that output isn't broken, but clearly we need more test coverage here.) Like commit b1cb32fb6, this bug is reachable in cases we already support, so back-patch all the way.
Diffstat (limited to 'src/backend/utils/adt/ruleutils.c')
-rw-r--r--src/backend/utils/adt/ruleutils.c41
1 files changed, 37 insertions, 4 deletions
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 18d9e27d1ed..5a4adbdc52e 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -6206,8 +6206,11 @@ get_update_query_targetlist_def(Query *query, List *targetList,
/*
* We must dig down into the expr to see if it's a PARAM_MULTIEXPR
* Param. That could be buried under FieldStores and ArrayRefs
- * (cf processIndirection()), and underneath those there could be
- * an implicit type coercion.
+ * and CoerceToDomains (cf processIndirection()), and underneath
+ * those there could be an implicit type coercion. Because we
+ * would ignore implicit type coercions anyway, we don't need to
+ * be as careful as processIndirection() is about descending past
+ * implicit CoerceToDomains.
*/
expr = (Node *) tle->expr;
while (expr)
@@ -6226,6 +6229,14 @@ get_update_query_targetlist_def(Query *query, List *targetList,
break;
expr = (Node *) aref->refassgnexpr;
}
+ else if (IsA(expr, CoerceToDomain))
+ {
+ CoerceToDomain *cdomain = (CoerceToDomain *) expr;
+
+ if (cdomain->coercionformat != COERCE_IMPLICIT_CAST)
+ break;
+ expr = (Node *) cdomain->arg;
+ }
else
break;
}
@@ -10185,13 +10196,17 @@ get_opclass_name(Oid opclass, Oid actual_datatype,
*
* We strip any top-level FieldStore or assignment ArrayRef nodes that
* appear in the input, printing them as decoration for the base column
- * name (which we assume the caller just printed). Return the subexpression
- * that's to be assigned.
+ * name (which we assume the caller just printed). We might also need to
+ * strip CoerceToDomain nodes, but only ones that appear above assignment
+ * nodes.
+ *
+ * Returns the subexpression that's to be assigned.
*/
static Node *
processIndirection(Node *node, deparse_context *context)
{
StringInfo buf = context->buf;
+ CoerceToDomain *cdomain = NULL;
for (;;)
{
@@ -10239,10 +10254,28 @@ processIndirection(Node *node, deparse_context *context)
*/
node = (Node *) aref->refassgnexpr;
}
+ else if (IsA(node, CoerceToDomain))
+ {
+ cdomain = (CoerceToDomain *) node;
+ /* If it's an explicit domain coercion, we're done */
+ if (cdomain->coercionformat != COERCE_IMPLICIT_CAST)
+ break;
+ /* Tentatively descend past the CoerceToDomain */
+ node = (Node *) cdomain->arg;
+ }
else
break;
}
+ /*
+ * If we descended past a CoerceToDomain whose argument turned out not to
+ * be a FieldStore or array assignment, back up to the CoerceToDomain.
+ * (This is not enough to be fully correct if there are nested implicit
+ * CoerceToDomains, but such cases shouldn't ever occur.)
+ */
+ if (cdomain && node == (Node *) cdomain->arg)
+ node = (Node *) cdomain;
+
return node;
}