diff --git a/contrib/postgres_fdw/connection.c b/contrib/postgres_fdw/connection.c index fe4893a8e054a..b318dfeab3379 100644 --- a/contrib/postgres_fdw/connection.c +++ b/contrib/postgres_fdw/connection.c @@ -359,8 +359,8 @@ configure_remote_session(PGconn *conn) { int remoteversion = PQserverVersion(conn); - /* Force the search path to contain only pg_catalog (see deparse.c) */ - do_sql_command(conn, "SET search_path = pg_catalog"); + /* Force the search path to contain only pg_catalog & public (see deparse.c) */ + do_sql_command(conn, "SET search_path = pg_catalog,public"); /* * Set remote timezone; this is basically just cosmetic, since all diff --git a/contrib/postgres_fdw/deparse.c b/contrib/postgres_fdw/deparse.c index e7b3cf35eca94..3ac1c4ca627eb 100644 --- a/contrib/postgres_fdw/deparse.c +++ b/contrib/postgres_fdw/deparse.c @@ -103,6 +103,7 @@ typedef struct deparse_expr_cxt * a base relation. */ StringInfo buf; /* output buffer to append to */ List **params_list; /* exprs that will become remote Params */ + RowExpr *row_expr; /* used for later generation of equivalent subquery */ } deparse_expr_cxt; #define REL_ALIAS_PREFIX "r" @@ -182,6 +183,7 @@ static void appendGroupByClause(List *tlist, deparse_expr_cxt *context); static void appendAggOrderBy(List *orderList, List *targetList, deparse_expr_cxt *context); static void appendFunctionName(Oid funcid, deparse_expr_cxt *context); +static void deparseRowExpr(RowExpr *node, deparse_expr_cxt *context); static Node *deparseSortGroupClause(Index ref, List *tlist, bool force_colno, deparse_expr_cxt *context); @@ -464,7 +466,7 @@ foreign_expr_walker(Node *node, * If function's input collation is not derived from a foreign * Var, it can't be sent to remote. */ - if (fe->inputcollid == InvalidOid) + if (fe->inputcollid == InvalidOid || inner_cxt.state == FDW_COLLATE_NONE) /* OK, inputs are all noncollatable */ ; else if (inner_cxt.state != FDW_COLLATE_SAFE || fe->inputcollid != inner_cxt.collation) @@ -512,7 +514,7 @@ foreign_expr_walker(Node *node, * If operator's input collation is not derived from a foreign * Var, it can't be sent to remote. */ - if (oe->inputcollid == InvalidOid) + if (oe->inputcollid == InvalidOid || inner_cxt.state == FDW_COLLATE_NONE) /* OK, inputs are all noncollatable */ ; else if (inner_cxt.state != FDW_COLLATE_SAFE || oe->inputcollid != inner_cxt.collation) @@ -552,7 +554,7 @@ foreign_expr_walker(Node *node, * If operator's input collation is not derived from a foreign * Var, it can't be sent to remote. */ - if (oe->inputcollid == InvalidOid) + if (oe->inputcollid == InvalidOid || inner_cxt.state == FDW_COLLATE_NONE) /* OK, inputs are all noncollatable */ ; else if (inner_cxt.state != FDW_COLLATE_SAFE || oe->inputcollid != inner_cxt.collation) @@ -751,7 +753,7 @@ foreign_expr_walker(Node *node, * If aggregate's input collation is not derived from a * foreign Var, it can't be sent to remote. */ - if (agg->inputcollid == InvalidOid) + if (agg->inputcollid == InvalidOid || inner_cxt.state == FDW_COLLATE_NONE) /* OK, inputs are all noncollatable */ ; else if (inner_cxt.state != FDW_COLLATE_SAFE || agg->inputcollid != inner_cxt.collation) @@ -775,7 +777,14 @@ foreign_expr_walker(Node *node, state = FDW_COLLATE_UNSAFE; } break; - default: + case T_RowExpr: + /* + * rtorre: this is a bold move, let's consider it true. Trying to + * cover the st_asmvt(ROW(st_asmvtgeom(...)) case. I guess the + * proper solution is to examine the row expression carefully. + */ + return true; + default: /* * If it's anything else, assume it's unsafe. This list can be @@ -998,6 +1007,7 @@ deparseSelectStmtForRel(StringInfo buf, PlannerInfo *root, RelOptInfo *rel, context.foreignrel = rel; context.scanrel = IS_UPPER_REL(rel) ? fpinfo->outerrel : rel; context.params_list = params_list; + context.row_expr = NULL; /* Construct SELECT clause */ deparseSelectSql(tlist, is_subquery, retrieved_attrs, &context); @@ -1124,6 +1134,26 @@ deparseFromExpr(List *quals, deparse_expr_cxt *context) /* Construct FROM clause */ appendStringInfoString(buf, " FROM "); + + // We have a row expression. Add the corresponding subquery + if (context->row_expr) { + bool first; + ListCell *lc; + RowExpr *node = context->row_expr; + + appendStringInfoString(buf, "(SELECT "); + first = true; + foreach(lc, node->args) + { + if (!first) + appendStringInfo(buf, ", "); + deparseExpr((Expr *) lfirst(lc), context); + first = false; + } + + appendStringInfoString(buf, " FROM "); + } + deparseFromExprForRel(buf, context->root, scanrel, (bms_num_members(scanrel->relids) > 1), (Index) 0, NULL, context->params_list); @@ -1134,6 +1164,12 @@ deparseFromExpr(List *quals, deparse_expr_cxt *context) appendStringInfoString(buf, " WHERE "); appendConditions(quals, context); } + + // Close subquery and add an alias + if (context->row_expr) { + appendStringInfoString(buf, ") myalias"); + context->row_expr = NULL; + } } /* @@ -2354,6 +2390,9 @@ deparseExpr(Expr *node, deparse_expr_cxt *context) case T_Aggref: deparseAggref((Aggref *) node, context); break; + case T_RowExpr: + deparseRowExpr((RowExpr *) node, context); + break; default: elog(ERROR, "unsupported expression type for deparse: %d", (int) nodeTag(node)); @@ -2361,6 +2400,18 @@ deparseExpr(Expr *node, deparse_expr_cxt *context) } } +static void +deparseRowExpr(RowExpr *node, deparse_expr_cxt *context) +{ + StringInfo buf = context->buf; + + // Add an arbitrary alias + appendStringInfoString(buf, "myalias"); + + // Just save the node for later generation of subquery + context->row_expr = node; +} + /* * Deparse given Var node into context->buf. * diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out index f19f982e0ac9b..a1deffe14b5be 100644 --- a/contrib/postgres_fdw/expected/postgres_fdw.out +++ b/contrib/postgres_fdw/expected/postgres_fdw.out @@ -8373,13 +8373,13 @@ DROP TYPE "Colors" CASCADE; NOTICE: drop cascades to column Col of table import_source.t5 IMPORT FOREIGN SCHEMA import_source LIMIT TO (t5) FROM SERVER loopback INTO import_dest5; -- ERROR -ERROR: type "public.Colors" does not exist -LINE 4: "Col" public."Colors" OPTIONS (column_name 'Col') +ERROR: type "Colors" does not exist +LINE 4: "Col" "Colors" OPTIONS (column_name 'Col') ^ QUERY: CREATE FOREIGN TABLE t5 ( c1 integer OPTIONS (column_name 'c1'), c2 text OPTIONS (column_name 'c2') COLLATE pg_catalog."C", - "Col" public."Colors" OPTIONS (column_name 'Col') + "Col" "Colors" OPTIONS (column_name 'Col') ) SERVER loopback OPTIONS (schema_name 'import_source', table_name 't5'); CONTEXT: importing foreign table "t5"