Add federated server list remotes

Includes:
- CDB_Federated_Server_List_Remote_Schemas
- CDB_Federated_Server_List_Remote_Tables
This commit is contained in:
Raul Marin
2019-10-29 18:26:36 +01:00
parent e22aaee5f5
commit 144c4e722b
5 changed files with 286 additions and 29 deletions

View File

@@ -11,20 +11,19 @@ AS $$
$$
LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
-- Produce a valid DB name for servers generated for the Federated Server
CREATE OR REPLACE FUNCTION @extschema@.__CDB_FS_Generate_Server_Name(input_name TEXT, check_existence BOOL)
RETURNS NAME
AS $$
DECLARE
object_name text := format('%s%s', @extschema@.__CDB_FS_Name_Pattern(), input_name);
internal_server_name text := format('%s%s', @extschema@.__CDB_FS_Name_Pattern(), input_name);
BEGIN
-- We discard anything that would be truncated
IF (char_length(object_name) < 64) THEN
IF (check_existence AND (NOT EXISTS (SELECT * FROM pg_foreign_server WHERE srvname = object_name))) THEN
IF (char_length(internal_server_name) < 64) THEN
IF (check_existence AND (NOT EXISTS (SELECT * FROM pg_foreign_server WHERE srvname = internal_server_name))) THEN
RAISE EXCEPTION 'Server "%" does not exist', input_name;
END IF;
RETURN object_name::name;
RETURN internal_server_name::name;
ELSE
RAISE EXCEPTION 'Server name is too long to be used as identifier';
END IF;
@@ -32,21 +31,20 @@ END
$$
LANGUAGE PLPGSQL IMMUTABLE PARALLEL SAFE;
CREATE OR REPLACE FUNCTION @extschema@.__CDB_FS_Extract_Server_Name(fdw_stored_name NAME)
CREATE OR REPLACE FUNCTION @extschema@.__CDB_FS_Extract_Server_Name(internal_server_name NAME)
RETURNS TEXT
AS $$
SELECT right(fdw_stored_name,
char_length(fdw_stored_name::TEXT) - char_length(@extschema@.__CDB_FS_Name_Pattern()))::TEXT;
SELECT right(internal_server_name,
char_length(internal_server_name::TEXT) - char_length(@extschema@.__CDB_FS_Name_Pattern()))::TEXT;
$$
LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
-- Produce a valid name for a schema generated for the Federated Server
CREATE OR REPLACE FUNCTION @extschema@.__CDB_FS_Generate_Schema_Name(server_name TEXT, schema_name TEXT)
CREATE OR REPLACE FUNCTION @extschema@.__CDB_FS_Generate_Schema_Name(internal_server_name TEXT, schema_name TEXT)
RETURNS NAME
AS $$
DECLARE
server_full_name text := @extschema@.__CDB_FS_Generate_Server_Name(server_name, check_existence := true);
hash_value text := md5(server_full_name::text || '__' || schema_name::text);
hash_value text := md5(internal_server_name::text || '__' || schema_name::text);
schema_name text := format('%s%s%s', @extschema@.__CDB_FS_Name_Pattern(), 'schema_', hash_value);
BEGIN
RETURN schema_name::name;
@@ -56,12 +54,11 @@ LANGUAGE PLPGSQL IMMUTABLE PARALLEL SAFE;
-- Produce a valid name for a role generated for the Federated Server
-- This needs to include the current database in its hash to avoid collisions in clusters with more than one database
CREATE OR REPLACE FUNCTION @extschema@.__CDB_FS_Generate_Server_Role_Name(server_name TEXT)
CREATE OR REPLACE FUNCTION @extschema@.__CDB_FS_Generate_Server_Role_Name(internal_server_name TEXT)
RETURNS NAME
AS $$
DECLARE
server_full_name text := @extschema@.__CDB_FS_Generate_Server_Name(server_name, check_existence := true);
hash_value text := md5(current_database()::text || '__' || server_full_name::text);
hash_value text := md5(current_database()::text || '__' || internal_server_name::text);
role_name text := format('%s%s%s', @extschema@.__CDB_FS_Name_Pattern(), 'role_', hash_value);
BEGIN
RETURN role_name::name;
@@ -70,22 +67,36 @@ $$
LANGUAGE PLPGSQL IMMUTABLE PARALLEL SAFE;
-- Creates (if not exist) a schema to place the objects for a remote schema
CREATE OR REPLACE FUNCTION @extschema@.__CDB_FS_Create_Schema(server_name TEXT, schema_name TEXT)
CREATE OR REPLACE FUNCTION @extschema@.__CDB_FS_Create_Schema(internal_server_name TEXT, schema_name TEXT)
RETURNS NAME
AS $$
DECLARE
schema_name text := @extschema@.__CDB_FS_Generate_Schema_Name(server_name, schema_name);
role_name text := @extschema@.__CDB_FS_Generate_Server_Role_Name(server_name);
schema_name text := @extschema@.__CDB_FS_Generate_Schema_Name(internal_server_name, schema_name);
role_name text := @extschema@.__CDB_FS_Generate_Server_Role_Name(internal_server_name);
BEGIN
BEGIN
EXECUTE 'CREATE SCHEMA IF NOT EXISTS ' || quote_ident(schema_name) || ' AUTHORIZATION ' || quote_ident(role_name);
EXCEPTION WHEN OTHERS THEN
RAISE EXCEPTION 'TODO: This needs a better error handling after reviewing permissions';
END;
IF NOT EXISTS (SELECT oid FROM pg_namespace WHERE nspname = schema_name) THEN
BEGIN
EXECUTE 'CREATE SCHEMA IF NOT EXISTS ' || quote_ident(schema_name) || ' AUTHORIZATION ' || quote_ident(role_name);
EXCEPTION WHEN OTHERS THEN
RAISE EXCEPTION 'TODO: This needs a better error handling after reviewing permissions: %', SQLERRM;
END;
END IF;
RETURN schema_name;
END
$$
LANGUAGE PLPGSQL VOLATILE PARALLEL UNSAFE;
-- Returns the type of a server by internal name
CREATE OR REPLACE FUNCTION @extschema@.__CDB_FS_server_type(remote_server name)
RETURNS name
AS $$
SELECT f.fdwname
FROM pg_foreign_server s
JOIN pg_foreign_data_wrapper f ON s.srvfdw = f.oid
WHERE s.srvname = remote_server;
$$
LANGUAGE SQL VOLATILE PARALLEL UNSAFE;
-- List registered servers
-- TODO: Decide whether we want to show extra config (extensions, fetch_size, use_remote_estimate)
@@ -109,7 +120,7 @@ BEGIN
@extschema@.__CDB_FS_Extract_Server_Name(s.srvname) AS "Name",
-- Which driver are we using (postgres_fdw, odbc_fdw...)
f.fdwname::text AS "Driver",
@extschema@.__CDB_FS_server_type(s.srvname)::text AS "Driver",
-- Read options from pg_foreign_server
(SELECT option_value FROM pg_options_to_table(s.srvoptions) WHERE option_name LIKE 'host') AS "Host",
@@ -120,7 +131,6 @@ BEGIN
-- Read username from pg_user_mappings
(SELECT option_value FROM pg_options_to_table(u.umoptions) WHERE option_name LIKE 'user') AS "Username"
FROM pg_foreign_server s
JOIN pg_foreign_data_wrapper f ON f.oid=s.srvfdw
LEFT JOIN pg_user_mappings u
ON u.srvid = s.oid
WHERE s.srvname ILIKE server_name
@@ -137,10 +147,13 @@ AS $$
DECLARE
user_mapping jsonb := json_build_object(
'user_mapping',
jsonb_build_object('user', input_config->'credentials'->'username',
'password', input_config->'credentials'->'password')
jsonb_build_object( 'user', input_config->'credentials'->'username',
'password', input_config->'credentials'->'password')
);
BEGIN
IF NOT (input_config ? 'credentials') THEN
RAISE EXCEPTION 'Credentials are mandatory';
END IF;
RETURN (input_config - 'credentials')::jsonb || user_mapping;
END
$$
@@ -174,7 +187,7 @@ AS $$
DECLARE
server_internal name := @extschema@.__CDB_FS_Generate_Server_Name(input_name := server, check_existence := false);
final_config json := @extschema@.__CDB_FS_credentials_to_user_mapping(@extschema@.__CDB_FS_add_default_options(config));
role_name name;
role_name name := @extschema@.__CDB_FS_Generate_Server_Role_Name(server_internal);
row record;
option record;
BEGIN
@@ -187,7 +200,6 @@ BEGIN
IF NOT EXISTS (SELECT * FROM pg_foreign_server WHERE srvname = server_internal) THEN
BEGIN
EXECUTE FORMAT('CREATE SERVER %I FOREIGN DATA WRAPPER postgres_fdw', server_internal);
role_name := @extschema@.__CDB_FS_Generate_Server_Role_Name(server);
EXECUTE FORMAT('CREATE ROLE %I NOLOGIN', role_name);
EXECUTE FORMAT('GRANT USAGE ON FOREIGN DATA WRAPPER postgres_fdw TO %I', role_name);
EXECUTE FORMAT('GRANT USAGE ON FOREIGN SERVER %I TO %I', server_internal, role_name);
@@ -238,7 +250,7 @@ RETURNS void
AS $$
DECLARE
server_internal text := @extschema@.__CDB_FS_Generate_Server_Name(input_name := server, check_existence := true);
role_name name := @extschema@.__CDB_FS_Generate_Server_Role_Name(server);
role_name name := @extschema@.__CDB_FS_Generate_Server_Role_Name(server_internal);
BEGIN
EXECUTE FORMAT ('DROP USER MAPPING FOR public SERVER %I', server_internal);
EXECUTE FORMAT ('DROP OWNED BY %I CASCADE', role_name);