@@ -132,6 +132,10 @@ static void deparseRelabelType(RelabelType *node, deparse_expr_cxt *context);
132132static void deparseBoolExpr (BoolExpr * node , deparse_expr_cxt * context );
133133static void deparseNullTest (NullTest * node , deparse_expr_cxt * context );
134134static void deparseArrayExpr (ArrayExpr * node , deparse_expr_cxt * context );
135+ static void printRemoteParam (int paramindex , Oid paramtype , int32 paramtypmod ,
136+ deparse_expr_cxt * context );
137+ static void printRemotePlaceholder (Oid paramtype , int32 paramtypmod ,
138+ deparse_expr_cxt * context );
135139
136140
137141/*
@@ -1283,16 +1287,11 @@ deparseVar(Var *node, deparse_expr_cxt *context)
12831287 * context -> params_list = lappend (* context -> params_list , node );
12841288 }
12851289
1286- appendStringInfo (buf , "$%d" , pindex );
1287- appendStringInfo (buf , "::%s" ,
1288- format_type_with_typemod (node -> vartype ,
1289- node -> vartypmod ));
1290+ printRemoteParam (pindex , node -> vartype , node -> vartypmod , context );
12901291 }
12911292 else
12921293 {
1293- appendStringInfo (buf , "(SELECT null::%s)" ,
1294- format_type_with_typemod (node -> vartype ,
1295- node -> vartypmod ));
1294+ printRemotePlaceholder (node -> vartype , node -> vartypmod , context );
12961295 }
12971296 }
12981297}
@@ -1399,26 +1398,12 @@ deparseConst(Const *node, deparse_expr_cxt *context)
13991398 *
14001399 * If we're generating the query "for real", add the Param to
14011400 * context->params_list if it's not already present, and then use its index
1402- * in that list as the remote parameter number.
1403- *
1404- * If we're just generating the query for EXPLAIN, replace the Param with
1405- * a dummy expression "(SELECT null::<type>)". In all extant versions of
1406- * Postgres, the planner will see that as an unknown constant value, which is
1407- * what we want. (If we sent a Param, recent versions might try to use the
1408- * value supplied for the Param as an estimated or even constant value, which
1409- * we don't want.) This might need adjustment if we ever make the planner
1410- * flatten scalar subqueries.
1411- *
1412- * Note: we label the Param's type explicitly rather than relying on
1413- * transmitting a numeric type OID in PQexecParams(). This allows us to
1414- * avoid assuming that types have the same OIDs on the remote side as they
1415- * do locally --- they need only have the same names.
1401+ * in that list as the remote parameter number. During EXPLAIN, there's
1402+ * no need to identify a parameter number.
14161403 */
14171404static void
14181405deparseParam (Param * node , deparse_expr_cxt * context )
14191406{
1420- StringInfo buf = context -> buf ;
1421-
14221407 if (context -> params_list )
14231408 {
14241409 int pindex = 0 ;
@@ -1438,16 +1423,11 @@ deparseParam(Param *node, deparse_expr_cxt *context)
14381423 * context -> params_list = lappend (* context -> params_list , node );
14391424 }
14401425
1441- appendStringInfo (buf , "$%d" , pindex );
1442- appendStringInfo (buf , "::%s" ,
1443- format_type_with_typemod (node -> paramtype ,
1444- node -> paramtypmod ));
1426+ printRemoteParam (pindex , node -> paramtype , node -> paramtypmod , context );
14451427 }
14461428 else
14471429 {
1448- appendStringInfo (buf , "(SELECT null::%s)" ,
1449- format_type_with_typemod (node -> paramtype ,
1450- node -> paramtypmod ));
1430+ printRemotePlaceholder (node -> paramtype , node -> paramtypmod , context );
14511431 }
14521432}
14531433
@@ -1816,3 +1796,47 @@ deparseArrayExpr(ArrayExpr *node, deparse_expr_cxt *context)
18161796 appendStringInfo (buf , "::%s" ,
18171797 format_type_with_typemod (node -> array_typeid , -1 ));
18181798}
1799+
1800+ /*
1801+ * Print the representation of a parameter to be sent to the remote side.
1802+ *
1803+ * Note: we always label the Param's type explicitly rather than relying on
1804+ * transmitting a numeric type OID in PQexecParams(). This allows us to
1805+ * avoid assuming that types have the same OIDs on the remote side as they
1806+ * do locally --- they need only have the same names.
1807+ */
1808+ static void
1809+ printRemoteParam (int paramindex , Oid paramtype , int32 paramtypmod ,
1810+ deparse_expr_cxt * context )
1811+ {
1812+ StringInfo buf = context -> buf ;
1813+ char * ptypename = format_type_with_typemod (paramtype , paramtypmod );
1814+
1815+ appendStringInfo (buf , "$%d::%s" , paramindex , ptypename );
1816+ }
1817+
1818+ /*
1819+ * Print the representation of a placeholder for a parameter that will be
1820+ * sent to the remote side at execution time.
1821+ *
1822+ * This is used when we're just trying to EXPLAIN the remote query.
1823+ * We don't have the actual value of the runtime parameter yet, and we don't
1824+ * want the remote planner to generate a plan that depends on such a value
1825+ * anyway. Thus, we can't do something simple like "$1::paramtype".
1826+ * Instead, we emit "((SELECT null::paramtype)::paramtype)".
1827+ * In all extant versions of Postgres, the planner will see that as an unknown
1828+ * constant value, which is what we want. This might need adjustment if we
1829+ * ever make the planner flatten scalar subqueries. Note: the reason for the
1830+ * apparently useless outer cast is to ensure that the representation as a
1831+ * whole will be parsed as an a_expr and not a select_with_parens; the latter
1832+ * would do the wrong thing in the context "x = ANY(...)".
1833+ */
1834+ static void
1835+ printRemotePlaceholder (Oid paramtype , int32 paramtypmod ,
1836+ deparse_expr_cxt * context )
1837+ {
1838+ StringInfo buf = context -> buf ;
1839+ char * ptypename = format_type_with_typemod (paramtype , paramtypmod );
1840+
1841+ appendStringInfo (buf , "((SELECT null::%s)::%s)" , ptypename , ptypename );
1842+ }
0 commit comments