* function or type defined in the information_schema.
*
* Our constraints for dealing with types are tighter than they are for
- * functions or operators: we want to accept only types that are in pg_catalog
- * (else format_type might incorrectly fail to schema-qualify their names),
- * and we want to be sure that the remote server will use the same OID as
- * we do (since we must transmit a numeric type OID when passing a value of
- * the type as a query parameter). Both of these are reasons to reject
- * objects created post-bootstrap.
+ * functions or operators: we want to accept only types that are in pg_catalog,
+ * else format_type might incorrectly fail to schema-qualify their names.
+ * (This could be fixed with some changes to format_type, but for now there's
+ * no need.) Thus we must exclude information_schema types.
*
* XXX there is a problem with this, which is that the set of built-in
* objects expands over time. Something that is built-in to us might not
* We don't need to renumber the parameter ID, because the executor functions
* in postgres_fdw.c preserve the numbering of PARAM_EXTERN Params.
* (This might change soon.)
+ *
+ * Note: we label the Param's type explicitly rather than relying on
+ * transmitting a numeric type OID in PQexecParams(). This allows us to
+ * avoid assuming that types have the same OIDs on the remote side as they
+ * do locally --- they need only have the same names.
*/
static void
deparseParam(StringInfo buf, Param *node, PlannerInfo *root)
{
Assert(node->paramkind == PARAM_EXTERN);
appendStringInfo(buf, "$%d", node->paramid);
+ appendStringInfo(buf, "::%s",
+ format_type_with_typemod(node->paramtype,
+ node->paramtypmod));
}
/*
-- once we try it enough times, should switch to generic plan
EXPLAIN (VERBOSE, COSTS false) EXECUTE st4(1);
- QUERY PLAN
-----------------------------------------------------------------------------------------------
+ QUERY PLAN
+-------------------------------------------------------------------------------------------------------
Foreign Scan on public.ft1 t1
Output: c1, c2, c3, c4, c5, c6, c7, c8
- Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (("C 1" = $1))
+ Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (("C 1" = $1::integer))
(3 rows)
-- value of $1 should not be sent to remote
(4 rows)
EXPLAIN (VERBOSE, COSTS false) EXECUTE st5('foo', 1);
- QUERY PLAN
-----------------------------------------------------------------------------------------------
+ QUERY PLAN
+-------------------------------------------------------------------------------------------------------
Foreign Scan on public.ft1 t1
Output: c1, c2, c3, c4, c5, c6, c7, c8
Filter: (t1.c8 = $1)
- Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (("C 1" = $2))
+ Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (("C 1" = $2::integer))
(4 rows)
EXECUTE st5('foo', 1);
if (!OidIsValid(prm->ptype) && params->paramFetch != NULL)
params->paramFetch(params, paramno);
+ /*
+ * Force the remote server to infer a type for this parameter.
+ * Since we explicitly cast every parameter (see deparse.c), the
+ * "inference" is trivial and will produce the desired result.
+ * This allows us to avoid assuming that the remote server has the
+ * same OIDs we do for the parameters' types.
+ *
+ * We'd not need to pass a type array to PQexecParams at all,
+ * except that there may be unused holes in the array, which
+ * will have to be filled with something or the remote server will
+ * complain. We arbitrarily set them to INT4OID earlier.
+ */
+ types[paramno - 1] = InvalidOid;
+
/*
* Get string representation of each parameter value by invoking
* type-specific output function, unless the value is null.
*/
- types[paramno - 1] = prm->ptype;
if (prm->isnull)
values[paramno - 1] = NULL;
else