diff --git a/scripts-available/CDB_FederatedServerListRemote.sql b/scripts-available/CDB_FederatedServerListRemote.sql index 84b4f81..7cc3fb4 100644 --- a/scripts-available/CDB_FederatedServerListRemote.sql +++ b/scripts-available/CDB_FederatedServerListRemote.sql @@ -86,7 +86,7 @@ LANGUAGE PLPGSQL VOLATILE PARALLEL UNSAFE; -- List the columns from a remote PG table -- CREATE OR REPLACE FUNCTION @extschema@.__CDB_FS_List_Foreign_Columns_PG(server_internal name, remote_schema name, remote_table name) -RETURNS TABLE(column_name name) +RETURNS TABLE(column_name name, column_type text) AS $func$ DECLARE -- Import `columns` from the information schema @@ -100,7 +100,6 @@ DECLARE inf_schema name := 'information_schema'; remote_col_table name := 'columns'; local_schema name := @extschema@.__CDB_FS_Create_Schema(server_internal, inf_schema); - sql_q text; BEGIN -- Import the foreign `columns` if not done IF NOT EXISTS ( @@ -114,14 +113,69 @@ BEGIN -- Return the result we're interested in -- Note: in this context, remote schema and remote table names are not to be quoted RETURN QUERY EXECUTE format($q$ - SELECT column_name::name FROM %I.%I + SELECT + a.column_name::name, COALESCE(b.column_type, a.data_type)::TEXT as column_type + FROM %I.%I a + LEFT JOIN @extschema@.__CDB_FS_List_Foreign_Geometry_Columns_PG('%s', '%s', '%s') b ON a.column_name = b.column_name WHERE table_schema = '%s' AND table_name = '%s' ORDER BY column_name$q$, - local_schema, remote_col_table, remote_schema, remote_table); + local_schema, remote_col_table, + server_internal, remote_schema, remote_table, + remote_schema, remote_table); END $func$ LANGUAGE PLPGSQL VOLATILE PARALLEL UNSAFE; +-- +-- List the columns from a remote PG table +-- +CREATE OR REPLACE FUNCTION @extschema@.__CDB_FS_List_Foreign_Geometry_Columns_PG(server_internal name, remote_schema name, remote_table name, postgis_schema name DEFAULT 'public') +RETURNS TABLE(column_name name, column_type text) +AS $func$ +DECLARE + -- Import `geometry_columns` and geography_columns from the postgis schema + -- We assume that postgis is installed in the public schema + + -- Create local target schema if it does not exists + remote_geometry_view name := 'geometry_columns'; + remote_geography_view name := 'geography_columns'; + local_schema name := @extschema@.__CDB_FS_Create_Schema(server_internal, postgis_schema); +BEGIN + -- Import the foreign `geometry_columns` and `geography_columns` if not done + IF NOT EXISTS ( + SELECT * FROM pg_class + WHERE relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = local_schema) + AND relname = remote_geometry_view + ) THEN + EXECUTE format('IMPORT FOREIGN SCHEMA %I LIMIT TO (%I, %I) FROM SERVER %I INTO %I', + postgis_schema, remote_geometry_view, remote_geography_view, server_internal, local_schema); + END IF; + + BEGIN + -- Note: We return both the type and srid as the type + RETURN QUERY EXECUTE format($q$ + SELECT f_geometry_column::NAME as column_name, + type::TEXT || ',' || srid::TEXT as column_type + FROM + ( + SELECT * FROM %I.%I UNION ALL SELECT * FROM %I.%I + ) _geo_views + WHERE + f_table_schema = '%s' AND + f_table_name = '%s' + $q$, + local_schema, remote_geometry_view, + local_schema, remote_geography_view, + remote_schema, remote_table); + EXCEPTION WHEN OTHERS THEN + RAISE NOTICE 'Could not find Postgis installation in the remote "%" schema', postgis_schema; + RETURN; + END; +END +$func$ +LANGUAGE PLPGSQL VOLATILE PARALLEL UNSAFE; + + -------------------------------------------------------------------------------- -- Public functions -------------------------------------------------------------------------------- @@ -170,7 +224,7 @@ CREATE OR REPLACE FUNCTION @extschema@.CDB_Federated_Server_List_Remote_Columns( server TEXT, remote_schema TEXT, remote_table TEXT) -RETURNS TABLE(column_name name) +RETURNS TABLE(column_name name, column_type text) AS $$ DECLARE server_internal name := @extschema@.__CDB_FS_Generate_Server_Name(input_name := server, check_existence := true); @@ -178,7 +232,7 @@ DECLARE BEGIN CASE server_type WHEN 'postgres_fdw' THEN - RETURN QUERY SELECT @extschema@.__CDB_FS_List_Foreign_Columns_PG(server_internal, remote_schema, remote_table); + RETURN QUERY SELECT * FROM @extschema@.__CDB_FS_List_Foreign_Columns_PG(server_internal, remote_schema, remote_table); ELSE RAISE EXCEPTION 'Not implemented server type % for remote server %', server_type, remote_server; END CASE; diff --git a/test/CDB_FederatedServerListRemote.sql b/test/CDB_FederatedServerListRemote.sql index 07b0344..d9d263a 100644 --- a/test/CDB_FederatedServerListRemote.sql +++ b/test/CDB_FederatedServerListRemote.sql @@ -32,7 +32,7 @@ SELECT 'C2', cartodb.CDB_Federated_Server_Register_PG(server := 'loopback2'::tex }'::jsonb); -- =================================================================== --- create objects used through FDW loopback server +-- Setup 1 -- =================================================================== \c cdb_fs_tester cdb_fs_tester @@ -92,7 +92,7 @@ SELECT * FROM cartodb.CDB_Federated_Server_List_Remote_Tables(server => 'loopbac SELECT * FROM cartodb.CDB_Federated_Server_List_Remote_Columns(server => 'loopback', remote_schema => 'S 1', remote_table => 'T 1'); -- =================================================================== --- Cleanup +-- Cleanup 1 -- =================================================================== \set QUIET on @@ -105,6 +105,51 @@ DROP TABLE "S 1". "T 4"; DROP SCHEMA "S 1"; DROP TYPE user_enum; + +-- =================================================================== +-- Setup 2: Using Postgis too +-- =================================================================== + +\c cdb_fs_tester postgres + +CREATE EXTENSION postgis; + +\c cdb_fs_tester cdb_fs_tester + +CREATE SCHEMA "S 1"; +CREATE TABLE "S 1"."T 5" ( + geom geometry(Geometry,4326), + geom_wm geometry(GeometryZ,3857), + geo_nosrid geometry, + geog geography +); + +\c contrib_regression postgres +SET client_min_messages TO notice; +\set VERBOSITY terse +\set QUIET off + + +-- =================================================================== +-- Test the listing functions +-- =================================================================== + +\echo 'Test listing of remote geometry columns (sunny day)' +SELECT * FROM cartodb.CDB_Federated_Server_List_Remote_Columns(server => 'loopback', remote_schema => 'S 1', remote_table => 'T 5'); +\echo 'Test listing of remote geometry columns (sunny day) - Rerun' +-- Rerun should be ok +SELECT * FROM cartodb.CDB_Federated_Server_List_Remote_Columns(server => 'loopback', remote_schema => 'S 1', remote_table => 'T 5'); + +-- =================================================================== +-- Cleanup 2 +-- =================================================================== +\set QUIET on + +\c cdb_fs_tester cdb_fs_tester +DROP TABLE "S 1". "T 5"; + +DROP SCHEMA "S 1"; + \c contrib_regression postgres \set QUIET on SET client_min_messages TO error; @@ -112,6 +157,7 @@ SET client_min_messages TO error; SELECT 'D1', cartodb.CDB_Federated_Server_Unregister(server := 'loopback'::text); SELECT 'D2', cartodb.CDB_Federated_Server_Unregister(server := 'loopback2'::text); + DROP DATABASE cdb_fs_tester; DROP ROLE cdb_fs_tester; DROP EXTENSION postgres_fdw; diff --git a/test/CDB_FederatedServerListRemote_expect b/test/CDB_FederatedServerListRemote_expect index f36517b..4554d3f 100644 --- a/test/CDB_FederatedServerListRemote_expect +++ b/test/CDB_FederatedServerListRemote_expect @@ -10,13 +10,24 @@ T 2 T 3 T 4 Test listing of remote columns (sunny day) -C 1 -c2 -c3 -c4 -c5 -c6 -c7 -c8 +NOTICE: Could not find Postgis installation in the remote "public" schema +C 1|integer +c2|integer +c3|text +c4|timestamp with time zone +c5|timestamp without time zone +c6|character varying +c7|character +c8|USER-DEFINED +Test listing of remote geometry columns (sunny day) +geo_nosrid|GEOMETRY,0 +geog|Geometry,0 +geom|GEOMETRY,4326 +geom_wm|GEOMETRY,3857 +Test listing of remote geometry columns (sunny day) - Rerun +geo_nosrid|GEOMETRY,0 +geog|Geometry,0 +geom|GEOMETRY,4326 +geom_wm|GEOMETRY,3857 D1| D2|