SQL/MED support in PostgreSQL has produced a large ecosystem of foreign data wrappers; a GitHub search for postgres plus fdw gives a sense of the volume. Maintenance quality varies and many wrappers fall out of use, but db2_fdw remains current and does its main job well: moving data from DB2 into PostgreSQL.
Prerequisites and environment checks
The setup described here uses PostgreSQL 12.2 on Ubuntu 18.04.4. Before the extension itself can be built, the IBM Data Server Client Packages have to be installed and configured. Two checks cover the essentials.
Environment variables:
|
1 2 3 4 5 |
# env |grep DB2 DB2_HOME=/home/user/sqllib DB2LIB=/home/user/sqllib/lib DB2INSTANCE=instance_name |
Connecting to the DB2 instance with the db2 tool:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# db2 connect to testdb user db2inst1 using my_password Database Connection Information Database server = DB2/LINUXX8664 11.5.0.0 SQL authorization ID = DB2INST1 Local database alias = TESTDB # db2 => SELECT EMPLOYEE_ID, DATE_OF_BIRTH FROM EMPLOYEES LIMIT 5; EMPLOYEE_ID DATE_OF_BIRTH ----------- ------------- 1. 08/19/1971 2. 06/15/1978 3. 12/23/1979 4. 11/14/1979 5. 02/08/1977 5 record(s) selected. |
If the DB2 instance lives on another host, its address must also be listed in pg_hba.conf.
Building and installing the extension
Installation follows the usual steps for building an extension from source:
|
1 2 3 |
# git clone https://github.com/wolfgangbrandl/db2_fdw.git # make # sudo make install |
The extension is then created inside PostgreSQL and verified:
|
1 2 3 4 5 6 7 8 9 10 |
pgdb=# create extension db2_fdw; pgdb=# dx List of installed extensions Name | Version | Schema | Description ---------+---------+------------+------------------------------------- db2_fdw | 1.0 | public | foreign data wrapper for DB2 access plpgsql | 1.0 | pg_catalog | PL/pgSQL procedural language (2 rows) |
Mapping DB2 objects into PostgreSQL
Once the client packages and the extension are working, wrapping DB2 inside PostgreSQL requires a foreign server, a user mapping, and an import of the relevant table or schema definitions.
Foreign server and user mapping
|
1 |
pgdb=# CREATE SERVER testdb FOREIGN DATA WRAPPER db2_fdw OPTIONS (dbserver 'testdb'); |
|
1 |
pgdb=# CREATE USER MAPPING FOR PUBLIC SERVER testdb OPTIONS (user 'db2inst1', password 'my_password'); |
Here db2inst1 and my_password are the DB2 server's username and password, and the corresponding schema name is DB2INST1 — all defaults produced by the DB2 setup wizard. They will differ on other installations.
Importing definitions and querying data
Table or schema definitions are imported from the foreign server into the public schema:
|
1 |
pgdb=# IMPORT FOREIGN SCHEMA 'DB2INST1' FROM SERVER testdb INTO public; |
Read access can then be tested directly from PostgreSQL:
|
1 2 3 4 5 6 7 8 9 |
pgdb=# SELECT EMPLOYEE_ID, DATE_OF_BIRTH FROM EMPLOYEES LIMIT 5; employee_id | date_of_birth -------------+--------------- 1 | 1971-08-19 2 | 1978-06-15 3 | 1979-12-23 4 | 1979-11-14 5 | 1977-02-08 (5 rows) |
A foreign table looks like this in the PostgreSQL catalog:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
pgdb=# d public.employees Foreign table 'public.employees' Column | Type | Collation | Nullable | Default | FDW options ---------------+-------------------------+-----------+----------+---------+-------------- employee_id | numeric | | not null | | (key 'true') first_name | character varying(1000) | | not null | | (key 'true') last_name | character varying(1000) | | not null | | (key 'true') date_of_birth | date | | not null | | (key 'true') phone_number | character varying(1000) | | not null | | (key 'true') junk | character(254) | | not null | | (key 'true') t | text | | | | Server: testdb FDW options: (schema 'DB2INST1', 'table' 'EMPLOYEES') |
The FDW options on the table definition are the marker that the relation is not stored locally, while remaining fully usable.
CRUD operations and EXPLAIN
Foreign tables accept CRUD operations, and explain returns details about how a query will be executed. In this case it invokes db2expln, exposing the cost and the access path chosen inside the DB2 engine.
|
1 2 3 4 5 6 7 8 9 |
pgdb=# EXPLAIN SELECT EMPLOYEE_ID, DATE_OF_BIRTH FROM EMPLOYEES LIMIT 5; QUERY PLAN --------------------------------------------------------------------------------------------------- Limit (cost=10000.00..10050.00 rows=5 width=36) -> Foreign Scan on employees (cost=10000.00..20000.00 rows=1000 width=36) DB2 query: SELECT /*30a9058135496929abaa9e871e651ec4*/ r1.'EMPLOYEE_ID', r1.'DATE_OF_BIRTH' FROM 'DB2INST1'.'EMPLOYEES' r1 DB2 plan: Estimated Cost = 70.485092 DB2 plan: Estimated Cardinality = 1000.000000 (5rows) |
Wrap-up
db2_fdw is a mature, straightforward and dependable extension for migrating data out of DB2 and into PostgreSQL, and the steps above show the full path from client-package configuration to querying imported tables.



