From e75d99818dd3940be997520e64db8c9e3b207e39 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Tue, 21 May 2024 07:05:26 +0200 Subject: Merging upstream version 15.7. Signed-off-by: Daniel Baumann --- contrib/postgres_fdw/connection.c | 8 ++- contrib/postgres_fdw/deparse.c | 25 +++++-- contrib/postgres_fdw/expected/postgres_fdw.out | 93 +++++++++++++++++++------- contrib/postgres_fdw/postgres_fdw.c | 18 ++--- contrib/postgres_fdw/sql/postgres_fdw.sql | 32 +++++++-- 5 files changed, 129 insertions(+), 47 deletions(-) (limited to 'contrib/postgres_fdw') diff --git a/contrib/postgres_fdw/connection.c b/contrib/postgres_fdw/connection.c index 5187ea8..db2a2c4 100644 --- a/contrib/postgres_fdw/connection.c +++ b/contrib/postgres_fdw/connection.c @@ -612,10 +612,12 @@ configure_remote_session(PGconn *conn) * anyway. However it makes the regression test outputs more predictable. * * We don't risk setting remote zone equal to ours, since the remote - * server might use a different timezone database. Instead, use UTC - * (quoted, because very old servers are picky about case). + * server might use a different timezone database. Instead, use GMT + * (quoted, because very old servers are picky about case). That's + * guaranteed to work regardless of the remote's timezone database, + * because pg_tzset() hard-wires it (at least in PG 9.2 and later). */ - do_sql_command(conn, "SET timezone = 'UTC'"); + do_sql_command(conn, "SET timezone = 'GMT'"); /* * Set values needed to ensure unambiguous data output from remote. (This diff --git a/contrib/postgres_fdw/deparse.c b/contrib/postgres_fdw/deparse.c index 8f4d8a5..d7235a5 100644 --- a/contrib/postgres_fdw/deparse.c +++ b/contrib/postgres_fdw/deparse.c @@ -3624,13 +3624,12 @@ appendOrderByClause(List *pathkeys, bool has_final_sort, { ListCell *lcell; int nestlevel; - const char *delim = " "; StringInfo buf = context->buf; + bool gotone = false; /* Make sure any constants in the exprs are printed portably */ nestlevel = set_transmission_modes(); - appendStringInfoString(buf, " ORDER BY"); foreach(lcell, pathkeys) { PathKey *pathkey = lfirst(lcell); @@ -3663,6 +3662,26 @@ appendOrderByClause(List *pathkeys, bool has_final_sort, em_expr = em->em_expr; + /* + * If the member is a Const expression then we needn't add it to the + * ORDER BY clause. This can happen in UNION ALL queries where the + * union child targetlist has a Const. Adding these would be + * wasteful, but also, for INT columns, an integer literal would be + * seen as an ordinal column position rather than a value to sort by. + * deparseConst() does have code to handle this, but it seems less + * effort on all accounts just to skip these for ORDER BY clauses. + */ + if (IsA(em_expr, Const)) + continue; + + if (!gotone) + { + appendStringInfoString(buf, " ORDER BY "); + gotone = true; + } + else + appendStringInfoString(buf, ", "); + /* * Lookup the operator corresponding to the strategy in the opclass. * The datatype used by the opfamily is not necessarily the same as @@ -3677,7 +3696,6 @@ appendOrderByClause(List *pathkeys, bool has_final_sort, pathkey->pk_strategy, em->em_datatype, em->em_datatype, pathkey->pk_opfamily); - appendStringInfoString(buf, delim); deparseExpr(em_expr, context); /* @@ -3687,7 +3705,6 @@ appendOrderByClause(List *pathkeys, bool has_final_sort, appendOrderBySuffix(oprid, exprType((Node *) em_expr), pathkey->pk_nulls_first, context); - delim = ", "; } reset_transmission_modes(nestlevel); } diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out index d21a3d8..d7fdc6b 100644 --- a/contrib/postgres_fdw/expected/postgres_fdw.out +++ b/contrib/postgres_fdw/expected/postgres_fdw.out @@ -893,32 +893,6 @@ SELECT * FROM ft2 WHERE c1 = ANY (ARRAY(SELECT c1 FROM ft1 WHERE c1 < 5)); 4 | 4 | 00004 | Mon Jan 05 00:00:00 1970 PST | Mon Jan 05 00:00:00 1970 | 4 | 4 | foo (4 rows) --- we should not push order by clause with volatile expressions or unsafe --- collations -EXPLAIN (VERBOSE, COSTS OFF) - SELECT * FROM ft2 ORDER BY ft2.c1, random(); - QUERY PLAN -------------------------------------------------------------------------------- - Sort - Output: c1, c2, c3, c4, c5, c6, c7, c8, (random()) - Sort Key: ft2.c1, (random()) - -> Foreign Scan on public.ft2 - Output: c1, c2, c3, c4, c5, c6, c7, c8, random() - Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" -(6 rows) - -EXPLAIN (VERBOSE, COSTS OFF) - SELECT * FROM ft2 ORDER BY ft2.c1, ft2.c3 collate "C"; - QUERY PLAN -------------------------------------------------------------------------------- - Sort - Output: c1, c2, c3, c4, c5, c6, c7, c8, ((c3)::text) - Sort Key: ft2.c1, ft2.c3 COLLATE "C" - -> Foreign Scan on public.ft2 - Output: c1, c2, c3, c4, c5, c6, c7, c8, c3 - Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" -(6 rows) - -- user-defined operator/function CREATE FUNCTION postgres_fdw_abs(int) RETURNS int AS $$ BEGIN @@ -1183,6 +1157,73 @@ WHERE c1 = 642 AND length(to_tsvector('custom_search'::regconfig, c3)) > 0; 642 | '00642':1 (1 row) +-- =================================================================== +-- ORDER BY queries +-- =================================================================== +-- we should not push order by clause with volatile expressions or unsafe +-- collations +EXPLAIN (VERBOSE, COSTS OFF) + SELECT * FROM ft2 ORDER BY ft2.c1, random(); + QUERY PLAN +------------------------------------------------------------------------------- + Sort + Output: c1, c2, c3, c4, c5, c6, c7, c8, (random()) + Sort Key: ft2.c1, (random()) + -> Foreign Scan on public.ft2 + Output: c1, c2, c3, c4, c5, c6, c7, c8, random() + Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" +(6 rows) + +EXPLAIN (VERBOSE, COSTS OFF) + SELECT * FROM ft2 ORDER BY ft2.c1, ft2.c3 collate "C"; + QUERY PLAN +------------------------------------------------------------------------------- + Sort + Output: c1, c2, c3, c4, c5, c6, c7, c8, ((c3)::text) + Sort Key: ft2.c1, ft2.c3 COLLATE "C" + -> Foreign Scan on public.ft2 + Output: c1, c2, c3, c4, c5, c6, c7, c8, c3 + Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" +(6 rows) + +-- Ensure we don't push ORDER BY expressions which are Consts at the UNION +-- child level to the foreign server. +EXPLAIN (VERBOSE, COSTS OFF) +SELECT * FROM ( + SELECT 1 AS type,c1 FROM ft1 + UNION ALL + SELECT 2 AS type,c1 FROM ft2 +) a ORDER BY type,c1; + QUERY PLAN +--------------------------------------------------------------------------------- + Merge Append + Sort Key: (1), ft1.c1 + -> Foreign Scan on public.ft1 + Output: 1, ft1.c1 + Remote SQL: SELECT "C 1" FROM "S 1"."T 1" ORDER BY "C 1" ASC NULLS LAST + -> Foreign Scan on public.ft2 + Output: 2, ft2.c1 + Remote SQL: SELECT "C 1" FROM "S 1"."T 1" ORDER BY "C 1" ASC NULLS LAST +(8 rows) + +EXPLAIN (VERBOSE, COSTS OFF) +SELECT * FROM ( + SELECT 1 AS type,c1 FROM ft1 + UNION ALL + SELECT 2 AS type,c1 FROM ft2 +) a ORDER BY type; + QUERY PLAN +--------------------------------------------------- + Merge Append + Sort Key: (1) + -> Foreign Scan on public.ft1 + Output: 1, ft1.c1 + Remote SQL: SELECT "C 1" FROM "S 1"."T 1" + -> Foreign Scan on public.ft2 + Output: 2, ft2.c1 + Remote SQL: SELECT "C 1" FROM "S 1"."T 1" +(8 rows) + -- =================================================================== -- JOIN queries -- =================================================================== diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c index b08b314..e3b9b8d 100644 --- a/contrib/postgres_fdw/postgres_fdw.c +++ b/contrib/postgres_fdw/postgres_fdw.c @@ -6968,14 +6968,16 @@ postgresForeignAsyncConfigureWait(AsyncRequest *areq) { /* * This is the case when the in-process request was made by another - * Append. Note that it might be useless to process the request, - * because the query might not need tuples from that Append anymore. - * If there are any child subplans of the same parent that are ready - * for new requests, skip the given request. Likewise, if there are - * any configured events other than the postmaster death event, skip - * it. Otherwise, process the in-process request, then begin a fetch - * to configure the event below, because we might otherwise end up - * with no configured events other than the postmaster death event. + * Append. Note that it might be useless to process the request made + * by that Append, because the query might not need tuples from that + * Append anymore; so we avoid processing it to begin a fetch for the + * given request if possible. If there are any child subplans of the + * same parent that are ready for new requests, skip the given + * request. Likewise, if there are any configured events other than + * the postmaster death event, skip it. Otherwise, process the + * in-process request, then begin a fetch to configure the event + * below, because we might otherwise end up with no configured events + * other than the postmaster death event. */ if (!bms_is_empty(requestor->as_needrequest)) return; diff --git a/contrib/postgres_fdw/sql/postgres_fdw.sql b/contrib/postgres_fdw/sql/postgres_fdw.sql index 80aa7fb..fdbbb4f 100644 --- a/contrib/postgres_fdw/sql/postgres_fdw.sql +++ b/contrib/postgres_fdw/sql/postgres_fdw.sql @@ -354,12 +354,6 @@ WHERE a.c2 = 6 AND b.c1 = a.c1 AND a.c8 = 'foo' AND b.c7 = upper(a.c7); -- bug before 9.3.5 due to sloppy handling of remote-estimate parameters SELECT * FROM ft1 WHERE c1 = ANY (ARRAY(SELECT c1 FROM ft2 WHERE c1 < 5)); SELECT * FROM ft2 WHERE c1 = ANY (ARRAY(SELECT c1 FROM ft1 WHERE c1 < 5)); --- we should not push order by clause with volatile expressions or unsafe --- collations -EXPLAIN (VERBOSE, COSTS OFF) - SELECT * FROM ft2 ORDER BY ft2.c1, random(); -EXPLAIN (VERBOSE, COSTS OFF) - SELECT * FROM ft2 ORDER BY ft2.c1, ft2.c3 collate "C"; -- user-defined operator/function CREATE FUNCTION postgres_fdw_abs(int) RETURNS int AS $$ @@ -451,6 +445,32 @@ WHERE c1 = 642 AND length(to_tsvector('custom_search'::regconfig, c3)) > 0; SELECT c1, to_tsvector('custom_search'::regconfig, c3) FROM ft1 WHERE c1 = 642 AND length(to_tsvector('custom_search'::regconfig, c3)) > 0; +-- =================================================================== +-- ORDER BY queries +-- =================================================================== +-- we should not push order by clause with volatile expressions or unsafe +-- collations +EXPLAIN (VERBOSE, COSTS OFF) + SELECT * FROM ft2 ORDER BY ft2.c1, random(); +EXPLAIN (VERBOSE, COSTS OFF) + SELECT * FROM ft2 ORDER BY ft2.c1, ft2.c3 collate "C"; + +-- Ensure we don't push ORDER BY expressions which are Consts at the UNION +-- child level to the foreign server. +EXPLAIN (VERBOSE, COSTS OFF) +SELECT * FROM ( + SELECT 1 AS type,c1 FROM ft1 + UNION ALL + SELECT 2 AS type,c1 FROM ft2 +) a ORDER BY type,c1; + +EXPLAIN (VERBOSE, COSTS OFF) +SELECT * FROM ( + SELECT 1 AS type,c1 FROM ft1 + UNION ALL + SELECT 2 AS type,c1 FROM ft2 +) a ORDER BY type; + -- =================================================================== -- JOIN queries -- =================================================================== -- cgit v1.2.3