@@ -131,6 +131,10 @@ static void deparseRelabelType(RelabelType *node, deparse_expr_cxt *context);
131131static void deparseBoolExpr (BoolExpr * node ,deparse_expr_cxt * context );
132132static void deparseNullTest (NullTest * node ,deparse_expr_cxt * context );
133133static 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 );
134138
135139
136140/*
@@ -1272,16 +1276,11 @@ deparseVar(Var *node, deparse_expr_cxt *context)
12721276* context -> params_list = lappend (* context -> params_list ,node );
12731277}
12741278
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 );
12791280}
12801281else
12811282{
1282- appendStringInfo (buf ,"(SELECT null::%s)" ,
1283- format_type_with_typemod (node -> vartype ,
1284- node -> vartypmod ));
1283+ printRemotePlaceholder (node -> vartype ,node -> vartypmod ,context );
12851284}
12861285}
12871286}
@@ -1388,26 +1387,12 @@ deparseConst(Const *node, deparse_expr_cxt *context)
13881387 *
13891388 * If we're generating the query "for real", add the Param to
13901389 * 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.
14051392 */
14061393static void
14071394deparseParam (Param * node ,deparse_expr_cxt * context )
14081395{
1409- StringInfo buf = context -> buf ;
1410-
14111396if (context -> params_list )
14121397{
14131398int pindex = 0 ;
@@ -1427,16 +1412,11 @@ deparseParam(Param *node, deparse_expr_cxt *context)
14271412* context -> params_list = lappend (* context -> params_list ,node );
14281413}
14291414
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 );
14341416}
14351417else
14361418{
1437- appendStringInfo (buf ,"(SELECT null::%s)" ,
1438- format_type_with_typemod (node -> paramtype ,
1439- node -> paramtypmod ));
1419+ printRemotePlaceholder (node -> paramtype ,node -> paramtypmod ,context );
14401420}
14411421}
14421422
@@ -1813,3 +1793,47 @@ deparseArrayExpr(ArrayExpr *node, deparse_expr_cxt *context)
18131793appendStringInfo (buf ,"::%s" ,
18141794format_type_with_typemod (node -> array_typeid ,-1 ));
18151795}
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+ }