@@ -1203,9 +1203,11 @@ replace_rte_variables_mutator(Node *node,
1203
1203
* appear in the expression.
1204
1204
*
1205
1205
* 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
1209
1211
* should report an error if *found_row_type is true; we don't do that here
1210
1212
* because we don't know exactly what wording for the error message would
1211
1213
* be most appropriate. The caller will be aware of the context.
@@ -1221,10 +1223,8 @@ typedef struct
1221
1223
int sublevels_up ; /* (current) nesting depth */
1222
1224
const AttrNumber * attno_map ; /* map array for user attnos */
1223
1225
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 */
1226
1227
bool * found_whole_row ; /* output flag */
1227
- bool coerced_var ; /* var is under ConvertRowTypeExpr */
1228
1228
} map_variable_attnos_context ;
1229
1229
1230
1230
static Node *
@@ -1244,7 +1244,8 @@ map_variable_attnos_mutator(Node *node,
1244
1244
Var * newvar = (Var * ) palloc (sizeof (Var ));
1245
1245
int attno = var -> varattno ;
1246
1246
1247
- * newvar = * var ;
1247
+ * newvar = * var ; /* initially copy all fields of the Var */
1248
+
1248
1249
if (attno > 0 )
1249
1250
{
1250
1251
/* user-defined column, replace attno */
@@ -1259,39 +1260,29 @@ map_variable_attnos_mutator(Node *node,
1259
1260
/* whole-row variable, warn caller */
1260
1261
* (context -> found_whole_row ) = true;
1261
1262
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 )
1264
1266
{
1265
- /* No support for RECORDOID. */
1267
+ ConvertRowtypeExpr * r ;
1268
+
1269
+ /* This certainly won't work for a RECORD variable. */
1266
1270
Assert (var -> vartype != RECORDOID );
1267
1271
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 ;
1295
1286
}
1296
1287
}
1297
1288
return (Node * ) newvar ;
@@ -1301,24 +1292,43 @@ map_variable_attnos_mutator(Node *node,
1301
1292
else if (IsA (node , ConvertRowtypeExpr ))
1302
1293
{
1303
1294
ConvertRowtypeExpr * r = (ConvertRowtypeExpr * ) node ;
1295
+ Var * var = (Var * ) r -> arg ;
1304
1296
1305
1297
/*
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.
1308
1303
*/
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 )
1310
1310
{
1311
1311
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 ;
1312
1324
1313
1325
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 ;
1318
1328
1319
1329
return (Node * ) newnode ;
1320
1330
}
1321
- /* Else fall through the expression tree mutator */
1331
+ /* otherwise fall through to process the expression normally */
1322
1332
}
1323
1333
else if (IsA (node , Query ))
1324
1334
{
@@ -1351,7 +1361,6 @@ map_variable_attnos(Node *node,
1351
1361
context .map_length = map_length ;
1352
1362
context .to_rowtype = to_rowtype ;
1353
1363
context .found_whole_row = found_whole_row ;
1354
- context .coerced_var = false;
1355
1364
1356
1365
* found_whole_row = false;
1357
1366
0 commit comments