Skip to content
Open

pg15 #11

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
PostgreSQL License

Copyright (c) 2024, ClickHouse

Permission to use, copy, modify, and distribute this software and its
documentation for any purpose, without fee, and without a written agreement is
hereby granted, provided that the above copyright notice and this paragraph
and the following two paragraphs appear in all copies.

IN NO EVENT SHALL ClickHouse BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF ClickHouse
HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

ClickHouse SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS,
AND ClickHouse HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
ENHANCEMENTS, OR MODIFICATIONS.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ PG_CPPFLAGS = -I$(libpq_srcdir)
SHLIB_LINK_INTERNAL = $(libpq)

EXTENSION = postgres_fdw
DATA = postgres_fdw--1.0.sql postgres_fdw--1.0--1.1.sql postgres_fdw--1.1--1.2.sql
DATA = postgres_fdw--1.0.sql postgres_fdw--1.0--1.1.sql postgres_fdw--1.1--1.2.sql postgres_fdw--1.2--1.3.sql

REGRESS = postgres_fdw

Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
`peerdb_fdw` is a copy of postgres_fdw with a couple adjustments to improve usability with PeerDB's query layer.

First, some cost adjustments were made to encourage pushing down everything. Second, a UDF `peerdb_exec` using code from dblink was put together so that users can explicitly craft queries if postgres planner isn't playing along or they have specific syntax for PeerDB
8 changes: 5 additions & 3 deletions connection.c
Original file line number Diff line number Diff line change
Expand Up @@ -543,10 +543,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
Expand Down
25 changes: 21 additions & 4 deletions deparse.c
Original file line number Diff line number Diff line change
Expand Up @@ -3344,13 +3344,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);
Expand Down Expand Up @@ -3383,6 +3382,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
Expand All @@ -3397,7 +3416,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);

/*
Expand All @@ -3407,7 +3425,6 @@ appendOrderByClause(List *pathkeys, bool has_final_sort,
appendOrderBySuffix(oprid, exprType((Node *) em_expr),
pathkey->pk_nulls_first, context);

delim = ", ";
}
reset_transmission_modes(nestlevel);
}
Expand Down
199 changes: 158 additions & 41 deletions expected/postgres_fdw.out
Original file line number Diff line number Diff line change
Expand Up @@ -631,6 +631,17 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft_empty ORDER BY c1;
Remote SQL: SELECT c1, c2 FROM public.loct_empty ORDER BY c1 ASC NULLS LAST
(3 rows)

-- test restriction on non-system foreign tables.
SET restrict_nonsystem_relation_kind TO 'foreign-table';
SELECT * from ft1 where c1 < 1; -- ERROR
ERROR: access to non-system foreign table is restricted
INSERT INTO ft1 (c1) VALUES (1); -- ERROR
ERROR: access to non-system foreign table is restricted
DELETE FROM ft1 WHERE c1 = 1; -- ERROR
ERROR: access to non-system foreign table is restricted
TRUNCATE ft1; -- ERROR
ERROR: access to non-system foreign table is restricted
RESET restrict_nonsystem_relation_kind;
-- ===================================================================
-- WHERE with remotely-executable conditions
-- ===================================================================
Expand Down Expand Up @@ -738,10 +749,10 @@ EXPLAIN (VERBOSE, COSTS OFF)
Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (($1::integer = "C 1"))
(8 rows)

SELECT * FROM ft2 a, ft2 b WHERE a.c1 = 47 AND b.c1 = a.c2;
c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8 | c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8
----+----+-------+------------------------------+--------------------------+----+------------+-----+----+----+-------+------------------------------+--------------------------+----+------------+-----
47 | 7 | 00047 | Tue Feb 17 00:00:00 1970 PST | Tue Feb 17 00:00:00 1970 | 7 | 7 | foo | 7 | 7 | 00007 | Thu Jan 08 00:00:00 1970 PST | Thu Jan 08 00:00:00 1970 | 7 | 7 | foo
SELECT * FROM "S 1"."T 1" a, ft2 b WHERE a."C 1" = 47 AND b.c1 = a.c2;
C 1 | c2 | c3 | c4 | c5 | c6 | c7 | c8 | c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8
-----+----+-------+------------------------------+--------------------------+----+------------+-----+----+----+-------+------------------------------+--------------------------+----+------------+-----
47 | 7 | 00047 | Tue Feb 17 00:00:00 1970 PST | Tue Feb 17 00:00:00 1970 | 7 | 7 | foo | 7 | 7 | 00007 | Thu Jan 08 00:00:00 1970 PST | Thu Jan 08 00:00:00 1970 | 7 | 7 | foo
(1 row)

-- check both safe and unsafe join conditions
Expand Down Expand Up @@ -887,32 +898,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
Expand Down Expand Up @@ -1067,6 +1052,27 @@ SELECT * FROM ft1 t1 WHERE t1.c1 === t1.c2 order by t1.c2 limit 1;
1 | 1 | 00001 | Fri Jan 02 00:00:00 1970 PST | Fri Jan 02 00:00:00 1970 | 1 | 1 | foo
(1 row)

-- Ensure we don't ship FETCH FIRST .. WITH TIES
EXPLAIN (VERBOSE, COSTS OFF)
SELECT t1.c2 FROM ft1 t1 WHERE t1.c1 > 960 ORDER BY t1.c2 FETCH FIRST 2 ROWS WITH TIES;
QUERY PLAN
-------------------------------------------------------------------------------------------------
Limit
Output: c2
-> Foreign Scan on public.ft1 t1
Output: c2
Remote SQL: SELECT c2 FROM "S 1"."T 1" WHERE (("C 1" > 960)) ORDER BY c2 ASC NULLS LAST
(5 rows)

SELECT t1.c2 FROM ft1 t1 WHERE t1.c1 > 960 ORDER BY t1.c2 FETCH FIRST 2 ROWS WITH TIES;
c2
----
0
0
0
0
(4 rows)

-- check schema-qualification of regconfig constant
CREATE TEXT SEARCH CONFIGURATION public.custom_search
(COPY = pg_catalog.english);
Expand All @@ -1087,6 +1093,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
-- ===================================================================
Expand Down Expand Up @@ -2197,6 +2270,32 @@ SELECT t1."C 1" FROM "S 1"."T 1" t1, LATERAL (SELECT DISTINCT t2.c1, t3.c1 FROM
1
(10 rows)

-- join with pseudoconstant quals, not pushed down.
EXPLAIN (VERBOSE, COSTS OFF)
SELECT t1.c1, t2.c1 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = t2.c1 AND CURRENT_USER = SESSION_USER) ORDER BY t1.c3, t1.c1 OFFSET 100 LIMIT 10;
QUERY PLAN
-------------------------------------------------------------------------------
Limit
Output: t1.c1, t2.c1, t1.c3
-> Sort
Output: t1.c1, t2.c1, t1.c3
Sort Key: t1.c3, t1.c1
-> Result
Output: t1.c1, t2.c1, t1.c3
One-Time Filter: (CURRENT_USER = SESSION_USER)
-> Hash Join
Output: t1.c1, t1.c3, t2.c1
Hash Cond: (t2.c1 = t1.c1)
-> Foreign Scan on public.ft2 t2
Output: t2.c1
Remote SQL: SELECT "C 1" FROM "S 1"."T 1"
-> Hash
Output: t1.c1, t1.c3
-> Foreign Scan on public.ft1 t1
Output: t1.c1, t1.c3
Remote SQL: SELECT "C 1", c3 FROM "S 1"."T 1"
(19 rows)

-- non-Var items in targetlist of the nullable rel of a join preventing
-- push-down in some cases
-- unable to push {ft1, ft2}
Expand Down Expand Up @@ -6724,6 +6823,28 @@ select * from grem1;
(2 rows)

delete from grem1;
-- batch insert with foreign partitions.
-- This schema uses two partitions, one local and one remote with a modulo
-- to loop across all of them in batches.
create table tab_batch_local (id int, data text);
insert into tab_batch_local select i, 'test'|| i from generate_series(1, 45) i;
create table tab_batch_sharded (id int, data text) partition by hash(id);
create table tab_batch_sharded_p0 partition of tab_batch_sharded
for values with (modulus 2, remainder 0);
create table tab_batch_sharded_p1_remote (id int, data text);
create foreign table tab_batch_sharded_p1 partition of tab_batch_sharded
for values with (modulus 2, remainder 1)
server loopback options (table_name 'tab_batch_sharded_p1_remote');
insert into tab_batch_sharded select * from tab_batch_local;
select count(*) from tab_batch_sharded;
count
-------
45
(1 row)

drop table tab_batch_local;
drop table tab_batch_sharded;
drop table tab_batch_sharded_p1_remote;
alter server loopback options (drop batch_size);
-- ===================================================================
-- test local triggers
Expand Down Expand Up @@ -9969,17 +10090,6 @@ SELECT COUNT(*) FROM ftable;
34
(1 row)

TRUNCATE batch_table;
DROP FOREIGN TABLE ftable;
-- try if large batches exceed max number of bind parameters
CREATE FOREIGN TABLE ftable ( x int ) SERVER loopback OPTIONS ( table_name 'batch_table', batch_size '100000' );
INSERT INTO ftable SELECT * FROM generate_series(1, 70000) i;
SELECT COUNT(*) FROM ftable;
count
-------
70000
(1 row)

TRUNCATE batch_table;
DROP FOREIGN TABLE ftable;
-- Disable batch insert
Expand Down Expand Up @@ -10366,6 +10476,13 @@ SELECT * FROM result_tbl ORDER BY a;
(2 rows)

DELETE FROM result_tbl;
-- Test error handling, if accessing one of the foreign partitions errors out
CREATE FOREIGN TABLE async_p_broken PARTITION OF async_pt FOR VALUES FROM (10000) TO (10001)
SERVER loopback OPTIONS (table_name 'non_existent_table');
SELECT * FROM async_pt;
ERROR: relation "public.non_existent_table" does not exist
CONTEXT: remote SQL command: SELECT a, b, c FROM public.non_existent_table
DROP FOREIGN TABLE async_p_broken;
-- Check case where multiple partitions use the same connection
CREATE TABLE base_tbl3 (a int, b int, c text);
CREATE FOREIGN TABLE async_p3 PARTITION OF async_pt FOR VALUES FROM (3000) TO (4000)
Expand Down
7 changes: 7 additions & 0 deletions postgres_fdw--1.2--1.3.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
-- complain if script is sourced in psql, rather than via ALTER EXTENSION
\echo Use "ALTER EXTENSION postgres_fdw UPDATE TO '1.3'" to load this file. \quit

CREATE FUNCTION peerdb_exec (text, text)
RETURNS setof record
AS 'MODULE_PATHNAME','peerdb_exec'
LANGUAGE C STRICT PARALLEL RESTRICTED;
Loading