Use PXF Iceberg connector to read and write Iceberg-format data between Greengage DB and Hive Metastore and REST catalogs
Apache Iceberg is an open-source data format designed for large analytic tables. It supports SQL commands and enables concurrent read/write operations from multiple query engines including Spark, Trino, Flink, Presto, Hive, and Impala.
PXF Iceberg connector supports the following features:
-
Reading and writing data in Hive Metastore and REST catalogs.
-
Reading data in Parquet, ORC, and Avro formats.
-
Writing data in Parquet format.
-
Reading and writing data to dedicated Iceberg branches and tags.
-
Column projection.
-
Predicate pushdown.
For foreign tables, the master commit protocol is supported, which allows for exchanging metadata between executors and the master.
Metadata is aggregated from all segments and the write transaction is then finalized via a single HTTP request to the PXF server.
To enable the protocol, add the ext_protocol_version option with value v1 to the foreign data wrapper definition.
This topic describes how to configure and use the PXF Iceberg connector for reading and writing Iceberg data stored in the Hive Metastore and REST catalogs by using external and foreign tables and provides practical examples.
Compatibility notes
For correct operation, the PXF Iceberg connector requires Greengage DB 6.31.0 or later and PXF 6.16.0 or later.
For earlier Greengage DB, PXF, and the pxf_fdw extension versions, a compatibility layer is provided, under which working with Iceberg data is possible with several limitations.
| PXF version | pxf_fdw version | Greengage DB version | Runtime error when working with Iceberg | Iceberg support |
|---|---|---|---|---|
Required |
Required |
Required |
No |
Yes |
Earlier |
Earlier |
Earlier |
No |
No |
Required |
Earlier |
Earlier |
No |
No |
Required |
Required |
Earlier |
No |
Creating, selecting from, and inserting into Iceberg foreign tables is supported. Master commit protocol is not supported: multiple snapshots are created for different PXF instances |
Earlier |
Required |
Earlier |
Yes |
Only creating Iceberg foreign tables is supported; selecting from or inserting into foreign tables is not supported.
No |
Earlier |
Required |
Required |
Yes |
Only creating Iceberg foreign tables is supported; selecting from or inserting into foreign tables is not supported.
No |
Earlier |
Earlier |
Required |
No |
No |
Configure PXF Iceberg connector
To be able to use the PXF Iceberg connector with external tables, you need to create a server configuration as described in Configure a PXF server in PXF documentation and then synchronize it to the Greengage DB cluster:
-
Log in to the Greengage DB master host as
gpadmin. -
Go to the $PXF_BASE/servers directory and create a server configuration directory (for example, named iceberg):
$ mkdir $PXF_BASE/servers/iceberg $ cd $PXF_BASE/servers/iceberg -
In the server configuration directory, create an iceberg-site.xml configuration and provide the required configuration depending on the data store used.
<?xml version="1.0" encoding="UTF-8"?> <configuration> <property> <name>iceberg.param.s3.endpoint</name> <value>http://minio:9000</value> <description>S3 endpoint</description> </property> <property> <name>iceberg.param.s3.path-style-access</name> <value>true</value> <description>S3 path style access</description> </property> <property> <name>iceberg.param.s3.access-key-id</name> <value>admin</value> <description>S3 access key id</description> </property> <property> <name>iceberg.param.s3.secret-access-key</name> <value>minioadmin</value> <description>S3 secret access key</description> </property> <property> <name>iceberg.param.client.region</name> <value>us-east-1</value> <description>AWS region</description> </property> <property> <name>iceberg.param.uri</name> <value>http://iceberg-rest:8181</value> <description>Catalog uri</description> </property> <property> <name>iceberg.config.catalog.name</name> <value>iceberg_rest_s3</value> <description>Catalog name</description> </property> <property> <name>iceberg.config.catalog.type</name> <value>REST</value> <description>Catalog type</description> </property> </configuration><?xml version="1.0" encoding="UTF-8"?> <configuration> <property> <name>iceberg.param.uri</name> <value>thrift://hive-metastore:9083</value> <description>Catalog uri</description> </property> <property> <name>iceberg.config.catalog.name</name> <value>iceberg_hive</value> <description>Catalog name</description> </property> <property> <name>iceberg.config.catalog.type</name> <value>HIVE_METASTORE</value> <description>Catalog type</description> </property> </configuration> -
Synchronize the server configuration to the Greengage DB cluster hosts:
$ pxf cluster sync
Server configuration properties
| Option | Server configuration property | Description |
|---|---|---|
uri |
iceberg.param.uri |
Iceberg catalog URI |
catalog_type |
iceberg.config.catalog.type |
Iceberg catalog type ( |
catalog_name |
iceberg.config.catalog.name |
Iceberg catalog name |
ref |
— |
The name of an Iceberg branch or tag. When reading data, the name of an existing tag or branch must be provided |
fragmentSize |
— |
The target size of a fragment in bytes |
s3_endpoint |
iceberg.param.s3.endpoint |
S3 endpoint (for S3 storage) |
s3_path_style_access |
iceberg.param.s3.path-style-access |
S3 path style access (for S3 storage) |
s3_access_key_id |
iceberg.param.s3.access-key-id |
S3 access key id (for S3 storage) |
s3_secret_access_key |
iceberg.param.s3.secret-access-key |
S3 secret access key (for S3 storage) |
aws_region |
iceberg.param.client.region |
AWS region (for S3 storage) |
Create an Iceberg foreign data wrapper
To work with Iceberg data using foreign tables, you need to create a foreign data wrapper.
-
On the Greengage DB master host, list the extensions available for installation:
SELECT * FROM pg_available_extensions WHERE name LIKE '%pxf_fdw%';The output should list
pxf_fdw:name | default_version | installed_version | comment --------------+-----------------+-------------------+----------------------------------------- pxf_fdw | 1.0 | | PXF Foreign Data Wrapper for Greengage (1 row)
-
Create an extension to register the
pxf_fdwforeign data wrapper in the database where you plan to use it:CREATE EXTENSION pxf_fdw;Then, make sure the
iceberg_pxf_fdwforeign data wrapper is available:SELECT * FROM pg_catalog.pg_foreign_data_wrapper;The output should look as follows:
fdwname | fdwowner | fdwhandler | fdwvalidator | fdwacl | fdwoptions -----------------+----------+------------+--------------+--------+----------------------------------------------- jdbc_pxf_fdw | 10 | 24609 | 24610 | | {protocol=jdbc,"mpp_execute=all segments"} hdfs_pxf_fdw | 10 | 24609 | 24610 | | {protocol=hdfs,"mpp_execute=all segments"} hive_pxf_fdw | 10 | 24609 | 24610 | | {protocol=hive,"mpp_execute=all segments"} hbase_pxf_fdw | 10 | 24609 | 24610 | | {protocol=hbase,"mpp_execute=all segments"} s3_pxf_fdw | 10 | 24609 | 24610 | | {protocol=s3,"mpp_execute=all segments"} gs_pxf_fdw | 10 | 24609 | 24610 | | {protocol=gs,"mpp_execute=all segments"} adl_pxf_fdw | 10 | 24609 | 24610 | | {protocol=adl,"mpp_execute=all segments"} wasbs_pxf_fdw | 10 | 24609 | 24610 | | {protocol=wasbs,"mpp_execute=all segments"} file_pxf_fdw | 10 | 24609 | 24610 | | {protocol=file,"mpp_execute=all segments"} iceberg_pxf_fdw | 10 | 24609 | 24610 | | {protocol=iceberg,"mpp_execute=all segments"} (10 rows)
Examples
These examples demonstrate how to configure and use the PXF Iceberg connector for reading and writing Iceberg data in the REST and Hive Metastore catalogs by using external and foreign tables.
Use REST catalog
Create source data
-
Connect to the Iceberg REST catalog and create a test database:
CREATE DATABASE IF NOT EXISTS customers; -
Create a source data table:
CREATE TABLE customers.data ( id INT, first_name VARCHAR(20), last_name VARCHAR(20) ); -
Populate the created table with sample data:
INSERT INTO customers.data VALUES (1, 'John', 'Doe'), (2, 'Jane', 'Doe'); -
Query the created table:
SELECT * FROM customers.data;The output should look as follows:
1 John Doe 2 Jane Doe Time taken: 0.26 seconds, Fetched 2 row(s)
Create a readable external table
-
On the Greengage DB master host, create a readable PXF external table that references the earlier created
customers.dataIceberg table. In theLOCATIONclause, specify the PXFicebergprofile and the server configuration. In theFORMATclause, specifypxfwritable_import, which is the built-in custom formatter function for read operations:CREATE EXTERNAL TABLE customers_r_rest ( id INT, first_name TEXT, last_name TEXT ) LOCATION ('pxf://customers.data?PROFILE=iceberg&SERVER=iceberg') FORMAT 'CUSTOM' (FORMATTER='pxfwritable_import'); -
Query the created external table:
SELECT * FROM customers_r_rest;The output should look as follows:
id | first_name | last_name ----+------------+----------- 1 | John | Doe 2 | Jane | Doe (2 rows)
Create a writable external table
-
On the Greengage DB master host, create a writable PXF external table that references the earlier created
customers.dataIceberg table. In theLOCATIONclause, specify the PXFicebergprofile and the server configuration. In theFORMATclause, specifypxfwritable_export, which is the built-in custom formatter function for write operations:CREATE WRITABLE EXTERNAL TABLE customers_w_rest ( id INT, first_name TEXT, last_name TEXT ) LOCATION ('pxf://customers.data?PROFILE=iceberg&SERVER=iceberg') FORMAT 'CUSTOM' (FORMATTER='pxfwritable_export'); -
Insert some data into the created external table:
INSERT INTO customers_w_rest ( id, first_name, last_name ) VALUES (3, 'Bob', 'Brown'), (4, 'Jane', 'Smith'); -
Connect to the Iceberg REST catalog and query the source
customers.datatable:SELECT * FROM customers.data;The output should look as follows:
1 John Doe 2 Jane Doe 3 Bob Brown 4 Jane Smith Time taken: 0.168 seconds, Fetched 4 row(s)
Then delete the newly inserted rows to revert the table to its initial state:
DELETE FROM customers.data WHERE id IN (3,4);
Create a foreign table
-
On the Greengage DB master host, create a foreign server that uses the
iceberg_pxf_fdwforeign data wrapper and points to the REST catalog:CREATE SERVER iceberg_rest_server FOREIGN DATA WRAPPER iceberg_pxf_fdw OPTIONS (uri 'http://iceberg-rest:8181'); -
Create a user mapping that will handle authentication on the Iceberg REST server. In the
SERVERclause, specify the earlier creatediceberg_rest_serverserver; in theOPTIONSclause, provide the authentication parameters (s3_access_key_idands3_secret_access_key):CREATE USER MAPPING FOR CURRENT_USER SERVER iceberg_rest_server OPTIONS (s3_access_key_id 'admin', s3_secret_access_key 'password'); -
Create the foreign table whose structure matches the one of the
customers.datatable initially created in the REST catalog. In theSERVERclause, specify the earlier creatediceberg_rest_serverserver; in theOPTIONSclause, provide the name of the earlier createdcustomers.datatable:CREATE FOREIGN TABLE customers_f_rest ( id INT, first_name TEXT, last_name TEXT ) SERVER iceberg_rest_server OPTIONS (resource 'customers.data'); -
Query the created foreign table:
SELECT * FROM customers_f_rest;The output should look as follows:
id | first_name | last_name ----+------------+----------- 1 | John | Doe 2 | Jane | Doe (2 rows)
-
Insert some data into the created foreign table:
INSERT INTO customers_f_rest ( id, first_name, last_name ) VALUES (3, 'Bob', 'Brown'), (4, 'Jane', 'Smith'); -
Query the foreign table again:
SELECT * FROM customers_f_rest;The output should look as follows:
id | first_name | last_name ----+------------+----------- 1 | John | Doe 2 | Jane | Doe 3 | Bob | Brown 4 | Jane | Smith (4 rows)
-
Connect to the Iceberg REST catalog and query the source
customers.datatable:SELECT * FROM customers.data;The output should look as follows:
1 John Doe 2 Jane Doe 3 Bob Brown 4 Jane Smith Time taken: 0.194 seconds, Fetched 4 row(s)
Then delete the newly inserted rows to revert the table to its initial state:
DELETE FROM customers.data WHERE id IN (3,4);
Use Hive Metastore catalog
Create source data
-
On the HiveClient host, launch the Hive command line:
$ hive -
Create the
customersHive table in thedefaultdatabase to store the sample dataset. TheSTORED BY ICEBERGclause instructs Hive to create the table in the Iceberg format:CREATE TABLE customers ( id INT, first_name STRING, last_name STRING ) STORED BY ICEBERG; -
Populate the created table with sample data:
INSERT INTO customers ( id, first_name, last_name ) VALUES (1, 'John', 'Doe'), (2, 'Jane', 'Doe'); -
Query the
customersHive table to verify that the data was loaded correctly:SELECT * FROM customers;The output should look as follows:
+---------------+-----------------------+----------------------+ | customers.id | customers.first_name | customers.last_name | +---------------+-----------------------+----------------------+ | 1 | John | Doe | | 2 | Jane | Doe | +---------------+-----------------------+----------------------+ 2 rows selected (0.171 seconds)
Create a readable external table
-
On the Greengage DB master host, create a readable PXF external table that references the earlier created
default.customersIceberg table. In theLOCATIONclause, specify the PXFicebergprofile and the server configuration. In theFORMATclause, specifypxfwritable_import, which is the built-in custom formatter function for read operations:CREATE EXTERNAL TABLE customers_r_hive ( id INT, first_name TEXT, last_name TEXT ) LOCATION ('pxf://default.customers?PROFILE=iceberg&SERVER=iceberg') FORMAT 'CUSTOM' (FORMATTER='pxfwritable_import'); -
Query the created external table:
SELECT * FROM customers_r_hive;The output should look as follows:
id | first_name | last_name ----+------------+----------- 1 | John | Doe 2 | Jane | Doe (2 rows)
Create a writable external table
-
On the Greengage DB master host, create a writable PXF external table that references the earlier created
default.customersIceberg table. In theLOCATIONclause, specify the PXFicebergprofile and the server configuration. In theFORMATclause, specifypxfwritable_export, which is the built-in custom formatter function for write operations:CREATE WRITABLE EXTERNAL TABLE customers_w_hive ( id INT, first_name TEXT, last_name TEXT ) LOCATION ('pxf://default.customers?PROFILE=iceberg&SERVER=iceberg') FORMAT 'CUSTOM' (FORMATTER='pxfwritable_export'); -
Populate the created table with sample data:
INSERT INTO customers_w_hive ( id, first_name, last_name ) VALUES (3, 'Bob', 'Brown'), (4, 'Jane', 'Smith'); -
On the HiveClient host, query the
customersIceberg table:SELECT * FROM customers;The output should look as follows:
+---------------+-----------------------+----------------------+ | customers.id | customers.first_name | customers.last_name | +---------------+-----------------------+----------------------+ | 1 | John | Doe | | 2 | Jane | Doe | | 3 | Bob | Brown | | 4 | Jane | Smith | +---------------+-----------------------+----------------------+ 4 rows selected (0.371 seconds)
Then delete the newly inserted rows to revert the table to its initial state:
DELETE FROM customers WHERE id IN (3,4);
Create a foreign table
-
On the Greengage DB master host, create a foreign server that uses the
iceberg_pxf_fdwforeign data wrapper and points to the Hive Metastore catalog. In theOPTIONSclause, set thecatalog_typetoHIVE_METASTOREand provide the URI of the Hive Metastore server and the name of the Iceberg Hive Metastore catalog:CREATE SERVER iceberg_hive_server FOREIGN DATA WRAPPER iceberg_pxf_fdw OPTIONS (catalog_type 'HIVE_METASTORE', uri 'thrift://hive-metastore:9083', catalog_name 'iceberg_hive'); -
Create a user mapping that will handle authentication on the Iceberg Hive Metastore server. In the
SERVERclause, specify the earlier creatediceberg_hive_serverserver:CREATE USER MAPPING FOR CURRENT_USER SERVER iceberg_hive_server; -
Create the foreign table whose structure matches the one of the
default.customerstable initially created in the Hive Metastore catalog. In theSERVERclause, specify the earlier creatediceberg_hive_serverserver; in theOPTIONSclause, provide the name of the earlier createdcustomerstable:CREATE FOREIGN TABLE customers_f_hive ( id INT, first_name TEXT, last_name TEXT ) SERVER iceberg_hive_server OPTIONS (resource 'default.customers'); -
Query the created foreign table:
SELECT * FROM customers_f_hive;The output should look as follows:
id | first_name | last_name ----+------------+----------- 1 | John | Doe 2 | Jane | Doe (2 rows)
-
Insert some data into the created foreign table:
INSERT INTO customers_f_hive ( id, first_name, last_name ) VALUES (3, 'Bob', 'Brown'), (4, 'Jane', 'Smith'); -
On the HiveClient host, query the
customerstable:SELECT * FROM customers;The output should look as follows:
+---------------+-----------------------+----------------------+ | customers.id | customers.first_name | customers.last_name | +---------------+-----------------------+----------------------+ | 1 | John | Doe | | 2 | Jane | Doe | | 3 | Bob | Brown | | 4 | Jane | Smith | +---------------+-----------------------+----------------------+ 4 rows selected (0.132 seconds)
Then delete the newly inserted rows to revert the table to its initial state:
DELETE FROM customers WHERE id IN (3,4);