@@ -1203,9 +1203,11 @@ replace_rte_variables_mutator(Node *node,
12031203 * appear in the expression.
12041204 *
12051205 * If the expression tree contains a whole-row Var for the target RTE,
1206- * *found_whole_row is returned as TRUE. In addition, if to_rowtype is
1207- * not InvalidOid, we modify the Var's vartype and insert a ConvertRowTypeExpr
1208- * to map back to the orignal rowtype. Callers that don't provide to_rowtype
1206+ * *found_whole_row is set to TRUE. In addition, if to_rowtype is
1207+ * not InvalidOid, we replace the Var with a Var of that vartype, inserting
1208+ * a ConvertRowTypeExpr to map back to the rowtype expected by the expression.
1209+ * (Therefore, to_rowtype had better be a child rowtype of the rowtype of the
1210+ * RTE we're changing references to.) Callers that don't provide to_rowtype
12091211 * should report an error if *found_row_type is true; we don't do that here
12101212 * because we don't know exactly what wording for the error message would
12111213 * be most appropriate. The caller will be aware of the context.
@@ -1221,10 +1223,8 @@ typedef struct
12211223int sublevels_up ;/* (current) nesting depth */
12221224const AttrNumber * attno_map ;/* map array for user attnos */
12231225int map_length ;/* number of entries in attno_map[] */
1224- /* Target type when converting whole-row vars */
1225- Oid to_rowtype ;
1226+ Oid to_rowtype ;/* change whole-row Vars to this type */
12261227bool * found_whole_row ;/* output flag */
1227- bool coerced_var ;/* var is under ConvertRowTypeExpr */
12281228}map_variable_attnos_context ;
12291229
12301230static Node *
@@ -1244,7 +1244,8 @@ map_variable_attnos_mutator(Node *node,
12441244Var * newvar = (Var * )palloc (sizeof (Var ));
12451245int attno = var -> varattno ;
12461246
1247- * newvar = * var ;
1247+ * newvar = * var ;/* initially copy all fields of the Var */
1248+
12481249if (attno > 0 )
12491250{
12501251/* user-defined column, replace attno */
@@ -1259,39 +1260,29 @@ map_variable_attnos_mutator(Node *node,
12591260/* whole-row variable, warn caller */
12601261* (context -> found_whole_row )= true;
12611262
1262- /* If the callers expects us to convert the same, do so. */
1263- if (OidIsValid (context -> to_rowtype ))
1263+ /* If the caller expects us to convert the Var, do so. */
1264+ if (OidIsValid (context -> to_rowtype )&&
1265+ context -> to_rowtype != var -> vartype )
12641266{
1265- /* No support for RECORDOID. */
1267+ ConvertRowtypeExpr * r ;
1268+
1269+ /* This certainly won't work for a RECORD variable. */
12661270Assert (var -> vartype != RECORDOID );
12671271
1268- /* Don't convert unless necessary. */
1269- if (context -> to_rowtype != var -> vartype )
1270- {
1271- /* Var itself is converted to the requested type. */
1272- newvar -> vartype = context -> to_rowtype ;
1273-
1274- /*
1275- * If this var is already under a ConvertRowtypeExpr,
1276- * we don't have to add another one.
1277- */
1278- if (!context -> coerced_var )
1279- {
1280- ConvertRowtypeExpr * r ;
1281-
1282- /*
1283- * And a conversion node on top to convert back to
1284- * the original type.
1285- */
1286- r = makeNode (ConvertRowtypeExpr );
1287- r -> arg = (Expr * )newvar ;
1288- r -> resulttype = var -> vartype ;
1289- r -> convertformat = COERCE_IMPLICIT_CAST ;
1290- r -> location = -1 ;
1291-
1292- return (Node * )r ;
1293- }
1294- }
1272+ /* Var itself is changed to the requested type. */
1273+ newvar -> vartype = context -> to_rowtype ;
1274+
1275+ /*
1276+ * Add a conversion node on top to convert back to the
1277+ * original type expected by the expression.
1278+ */
1279+ r = makeNode (ConvertRowtypeExpr );
1280+ r -> arg = (Expr * )newvar ;
1281+ r -> resulttype = var -> vartype ;
1282+ r -> convertformat = COERCE_IMPLICIT_CAST ;
1283+ r -> location = -1 ;
1284+
1285+ return (Node * )r ;
12951286}
12961287}
12971288return (Node * )newvar ;
@@ -1301,24 +1292,43 @@ map_variable_attnos_mutator(Node *node,
13011292else if (IsA (node ,ConvertRowtypeExpr ))
13021293{
13031294ConvertRowtypeExpr * r = (ConvertRowtypeExpr * )node ;
1295+ Var * var = (Var * )r -> arg ;
13041296
13051297/*
1306- * If this is coercing a var (which is typical), convert only the var,
1307- * as against adding another ConvertRowtypeExpr over it.
1298+ * If this is coercing a whole-row Var that we need to convert, then
1299+ * just convert the Var without adding an extra ConvertRowtypeExpr.
1300+ * Effectively we're simplifying var::parenttype::grandparenttype into
1301+ * just var::grandparenttype. This avoids building stacks of CREs if
1302+ * this function is applied repeatedly.
13081303 */
1309- if (IsA (r -> arg ,Var ))
1304+ if (IsA (var ,Var )&&
1305+ var -> varno == context -> target_varno &&
1306+ var -> varlevelsup == context -> sublevels_up &&
1307+ var -> varattno == 0 &&
1308+ OidIsValid (context -> to_rowtype )&&
1309+ context -> to_rowtype != var -> vartype )
13101310{
13111311ConvertRowtypeExpr * newnode ;
1312+ Var * newvar = (Var * )palloc (sizeof (Var ));
1313+
1314+ /* whole-row variable, warn caller */
1315+ * (context -> found_whole_row )= true;
1316+
1317+ * newvar = * var ;/* initially copy all fields of the Var */
1318+
1319+ /* This certainly won't work for a RECORD variable. */
1320+ Assert (var -> vartype != RECORDOID );
1321+
1322+ /* Var itself is changed to the requested type. */
1323+ newvar -> vartype = context -> to_rowtype ;
13121324
13131325newnode = (ConvertRowtypeExpr * )palloc (sizeof (ConvertRowtypeExpr ));
1314- * newnode = * r ;
1315- context -> coerced_var = true;
1316- newnode -> arg = (Expr * )map_variable_attnos_mutator ((Node * )r -> arg ,context );
1317- context -> coerced_var = false;
1326+ * newnode = * r ;/* initially copy all fields of the CRE */
1327+ newnode -> arg = (Expr * )newvar ;
13181328
13191329return (Node * )newnode ;
13201330}
1321- /*Else fall through the expressiontree mutator */
1331+ /*otherwise fall throughto process the expressionnormally */
13221332}
13231333else if (IsA (node ,Query ))
13241334{
@@ -1351,7 +1361,6 @@ map_variable_attnos(Node *node,
13511361context .map_length = map_length ;
13521362context .to_rowtype = to_rowtype ;
13531363context .found_whole_row = found_whole_row ;
1354- context .coerced_var = false;
13551364
13561365* found_whole_row = false;
13571366