@@ -131,6 +131,10 @@ static void deparseRelabelType(RelabelType *node, deparse_expr_cxt *context);
131
131
static void deparseBoolExpr (BoolExpr * node , deparse_expr_cxt * context );
132
132
static void deparseNullTest (NullTest * node , deparse_expr_cxt * context );
133
133
static void deparseArrayExpr (ArrayExpr * node , deparse_expr_cxt * context );
134
+ static void printRemoteParam (int paramindex , Oid paramtype , int32 paramtypmod ,
135
+ deparse_expr_cxt * context );
136
+ static void printRemotePlaceholder (Oid paramtype , int32 paramtypmod ,
137
+ deparse_expr_cxt * context );
134
138
135
139
136
140
/*
@@ -1272,16 +1276,11 @@ deparseVar(Var *node, deparse_expr_cxt *context)
1272
1276
* context -> params_list = lappend (* context -> params_list , node );
1273
1277
}
1274
1278
1275
- appendStringInfo (buf , "$%d" , pindex );
1276
- appendStringInfo (buf , "::%s" ,
1277
- format_type_with_typemod (node -> vartype ,
1278
- node -> vartypmod ));
1279
+ printRemoteParam (pindex , node -> vartype , node -> vartypmod , context );
1279
1280
}
1280
1281
else
1281
1282
{
1282
- appendStringInfo (buf , "(SELECT null::%s)" ,
1283
- format_type_with_typemod (node -> vartype ,
1284
- node -> vartypmod ));
1283
+ printRemotePlaceholder (node -> vartype , node -> vartypmod , context );
1285
1284
}
1286
1285
}
1287
1286
}
@@ -1388,26 +1387,12 @@ deparseConst(Const *node, deparse_expr_cxt *context)
1388
1387
*
1389
1388
* If we're generating the query "for real", add the Param to
1390
1389
* context->params_list if it's not already present, and then use its index
1391
- * in that list as the remote parameter number.
1392
- *
1393
- * If we're just generating the query for EXPLAIN, replace the Param with
1394
- * a dummy expression "(SELECT null::<type>)". In all extant versions of
1395
- * Postgres, the planner will see that as an unknown constant value, which is
1396
- * what we want. (If we sent a Param, recent versions might try to use the
1397
- * value supplied for the Param as an estimated or even constant value, which
1398
- * we don't want.) This might need adjustment if we ever make the planner
1399
- * flatten scalar subqueries.
1400
- *
1401
- * Note: we label the Param's type explicitly rather than relying on
1402
- * transmitting a numeric type OID in PQexecParams(). This allows us to
1403
- * avoid assuming that types have the same OIDs on the remote side as they
1404
- * do locally --- they need only have the same names.
1390
+ * in that list as the remote parameter number. During EXPLAIN, there's
1391
+ * no need to identify a parameter number.
1405
1392
*/
1406
1393
static void
1407
1394
deparseParam (Param * node , deparse_expr_cxt * context )
1408
1395
{
1409
- StringInfo buf = context -> buf ;
1410
-
1411
1396
if (context -> params_list )
1412
1397
{
1413
1398
int pindex = 0 ;
@@ -1427,16 +1412,11 @@ deparseParam(Param *node, deparse_expr_cxt *context)
1427
1412
* context -> params_list = lappend (* context -> params_list , node );
1428
1413
}
1429
1414
1430
- appendStringInfo (buf , "$%d" , pindex );
1431
- appendStringInfo (buf , "::%s" ,
1432
- format_type_with_typemod (node -> paramtype ,
1433
- node -> paramtypmod ));
1415
+ printRemoteParam (pindex , node -> paramtype , node -> paramtypmod , context );
1434
1416
}
1435
1417
else
1436
1418
{
1437
- appendStringInfo (buf , "(SELECT null::%s)" ,
1438
- format_type_with_typemod (node -> paramtype ,
1439
- node -> paramtypmod ));
1419
+ printRemotePlaceholder (node -> paramtype , node -> paramtypmod , context );
1440
1420
}
1441
1421
}
1442
1422
@@ -1813,3 +1793,47 @@ deparseArrayExpr(ArrayExpr *node, deparse_expr_cxt *context)
1813
1793
appendStringInfo (buf , "::%s" ,
1814
1794
format_type_with_typemod (node -> array_typeid , -1 ));
1815
1795
}
1796
+
1797
+ /*
1798
+ * Print the representation of a parameter to be sent to the remote side.
1799
+ *
1800
+ * Note: we always label the Param's type explicitly rather than relying on
1801
+ * transmitting a numeric type OID in PQexecParams(). This allows us to
1802
+ * avoid assuming that types have the same OIDs on the remote side as they
1803
+ * do locally --- they need only have the same names.
1804
+ */
1805
+ static void
1806
+ printRemoteParam (int paramindex , Oid paramtype , int32 paramtypmod ,
1807
+ deparse_expr_cxt * context )
1808
+ {
1809
+ StringInfo buf = context -> buf ;
1810
+ char * ptypename = format_type_with_typemod (paramtype , paramtypmod );
1811
+
1812
+ appendStringInfo (buf , "$%d::%s" , paramindex , ptypename );
1813
+ }
1814
+
1815
+ /*
1816
+ * Print the representation of a placeholder for a parameter that will be
1817
+ * sent to the remote side at execution time.
1818
+ *
1819
+ * This is used when we're just trying to EXPLAIN the remote query.
1820
+ * We don't have the actual value of the runtime parameter yet, and we don't
1821
+ * want the remote planner to generate a plan that depends on such a value
1822
+ * anyway. Thus, we can't do something simple like "$1::paramtype".
1823
+ * Instead, we emit "((SELECT null::paramtype)::paramtype)".
1824
+ * In all extant versions of Postgres, the planner will see that as an unknown
1825
+ * constant value, which is what we want. This might need adjustment if we
1826
+ * ever make the planner flatten scalar subqueries. Note: the reason for the
1827
+ * apparently useless outer cast is to ensure that the representation as a
1828
+ * whole will be parsed as an a_expr and not a select_with_parens; the latter
1829
+ * would do the wrong thing in the context "x = ANY(...)".
1830
+ */
1831
+ static void
1832
+ printRemotePlaceholder (Oid paramtype , int32 paramtypmod ,
1833
+ deparse_expr_cxt * context )
1834
+ {
1835
+ StringInfo buf = context -> buf ;
1836
+ char * ptypename = format_type_with_typemod (paramtype , paramtypmod );
1837
+
1838
+ appendStringInfo (buf , "((SELECT null::%s)::%s)" , ptypename , ptypename );
1839
+ }
0 commit comments