@@ -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
12211223 int sublevels_up ; /* (current) nesting depth */
12221224 const AttrNumber * attno_map ; /* map array for user attnos */
12231225 int 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 */
12261227 bool * 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,
12441244 Var * newvar = (Var * ) palloc (sizeof (Var ));
12451245 int attno = var -> varattno ;
12461246
1247- * newvar = * var ;
1247+ * newvar = * var ; /* initially copy all fields of the Var */
1248+
12481249 if (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. */
12661270 Assert (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 }
12971288 return (Node * ) newvar ;
@@ -1301,24 +1292,43 @@ map_variable_attnos_mutator(Node *node,
13011292 else if (IsA (node , ConvertRowtypeExpr ))
13021293 {
13031294 ConvertRowtypeExpr * 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 {
13111311 ConvertRowtypeExpr * 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
13131325 newnode = (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
13191329 return (Node * ) newnode ;
13201330 }
1321- /* Else fall through the expression tree mutator */
1331+ /* otherwise fall through to process the expression normally */
13221332 }
13231333 else if (IsA (node , Query ))
13241334 {
@@ -1351,7 +1361,6 @@ map_variable_attnos(Node *node,
13511361 context .map_length = map_length ;
13521362 context .to_rowtype = to_rowtype ;
13531363 context .found_whole_row = found_whole_row ;
1354- context .coerced_var = false;
13551364
13561365 * found_whole_row = false;
13571366
0 commit comments