mirror of
https://github.com/postgres/postgres.git
synced 2025-09-03 15:22:11 +03:00
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
This commit is contained in:
@@ -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;
|
||||
|
Reference in New Issue
Block a user