PostgreSQL foreign data wrapper with postgres_fdw

Published on May. 10, 2018 by Gabriel Bordeaux

Foreign data wrapper

Setting up postgres_fdw

Using postgres_fdw requires 4 steps:

  • Creating the extension
  • Creating the server
  • Creating a user mapping
  • Importing the tables

Before setting up the foreign data wrapper connection, you should test the connection to the remote server from the server used for the foreign data wrapper:

$ psql -h remote-server.com -U remote_user my_database
Password for user remote_user: 
psql (10.3 (Debian 10.3-1.pgdg90+1))

my_database=> 

Once you have ensured that the connection is working correctly, you can create the extension, the server and the user mapping:

-- Create extension
CREATE EXTENSION postgres_fdw;

-- Create server
CREATE SERVER fdw_server
  FOREIGN DATA WRAPPER postgres_fdw
  OPTIONS (host 'remote-server.com', dbname 'my_database');

-- Create user mapping
CREATE USER MAPPING FOR postgres -- or another user!
  SERVER fdw_server
  OPTIONS (user 'remote_user', password 'my_password');

Creating a test table

Now, let's create a test table on our remote server:

-- Create table
CREATE TABLE remote_table (
    id serial primary key,
    num int,
    date timestamp with time zone
);

-- Add indexes
CREATE INDEX ON remote_table (num);
CREATE INDEX ON remote_table (date);

-- Populate with some data
INSERT INTO remote_table (num, date)
SELECT floor(random() * 10 + 1)::int, generate_series(NOW() - INTERVAL '1000 days', NOW(), '1 day'::interval);

-- Grant SELECT privileges to "remote_user"
GRANT SELECT ON ALL TABLES IN SCHEMA public TO remote_user;

Creating foreign tables

Automatic import

To import all tables from the remote server:

-- Create new schema
CREATE SCHEMA fdw;

-- Import the schema
IMPORT FOREIGN SCHEMA public
  FROM SERVER fdw_server
  INTO fdw;

-- Test query
SELECT * FROM fdw.remote_table LIMIT 2;
 id | num |             date              
----+-----+-------------------------------
  1 |   5 | 2015-08-13 18:32:15.549739+04
  2 |  10 | 2015-08-14 18:32:15.549739+04
(2 rows)

You can also limit the import to specific tables:

IMPORT FOREIGN SCHEMA public LIMIT TO (remote_table, remote_table_2)
  FROM SERVER fdw_server
  INTO fdw;

Creating the schema manually

If you don't want to automate the schema import, you can re-declare the table schema:

-- Create new schema
CREATE SCHEMA fdw;

-- Create foreign table
CREATE FOREIGN TABLE fdw.remote_table (
    id serial, -- no "primary key" here!
    num int,
    date timestamp with time zone
)
SERVER fdw_server
OPTIONS (schema_name 'public', table_name 'remote_table');

-- Test query
SELECT * FROM fdw.remote_table LIMIT 2;
 id | num |             date              
----+-----+-------------------------------
  1 |   5 | 2015-08-13 18:32:15.549739+04
  2 |  10 | 2015-08-14 18:32:15.549739+04
(2 rows)