Cross-database query lets you read data from Hologres internal tables in other instances and databases — including instances in different regions — without moving the data. It uses the PostgreSQL foreign data wrapper (FDW) mechanism. For more information about FDW, see PostgreSQL FDW documentation.
Limitations
Before you set up cross-database queries, review the following constraints:
Requires Hologres V1.1 or later on both the source and destination instances. If your instance is earlier than V1.1, see Common upgrade preparation failure errors or get online support for upgrade assistance. Cross-database queries are supported only between instances of the same major version — for example, a V1.3 instance cannot query a V1.1 instance.
Supported source objects: internal tables and partitioned parent tables only. Foreign tables, views, and partitioned child tables are not supported.
Supported data types: basic types only. Complex types such as
JSONare not supported.Supported operations on foreign tables:
SELECTonly.UPDATE,DELETE, andTRUNCATEare not supported.Hologres instance IP addresses are not fixed. Do not configure IP address whitelists when using this feature, as the connection may break if the IP address changes.
Supported data types
| Supported | Not supported |
|---|---|
INT | JSON |
BIGINT | Other complex types |
DATE |
Prerequisites
Before you begin, ensure that you have:
A Hologres instance running V1.1 or later (both local and remote)
Superuser access to the local database
An Alibaba Cloud AccessKey ID and AccessKey secret for the account that has
SELECTpermission on the source tables. Get them from the RAM console
Set up cross-database query
Setting up a cross-database query involves four configuration steps, followed by running the query.
Step 1: Create the extension
A superuser must run the following statement once per database to install the FDW extension:
CREATE EXTENSION hologres_fdw;To uninstall the extension, run DROP EXTENSION hologres_fdw;.
Step 2: Create a server
After the extension is installed, create a server object that points to the remote Hologres instance:
CREATE SERVER <server_name> FOREIGN DATA WRAPPER hologres_fdw OPTIONS (
host '<endpoint>',
port '<port>',
dbname '<dbname>'
);| Parameter | Description | Example |
|---|---|---|
server_name | A name you assign to the server. | holo_fdw_server |
host | The classic network (internal network) endpoint of the remote Hologres instance. Find it on the Instance Configuration tab in the Hologres console. | hgpostcn-cn-xxx-cn-hangzhou-internal.hologres.aliyuncs.com |
port | The port of the remote Hologres instance. Find it on the Instance Configuration tab in the Hologres console. | 80 |
dbname | The name of the remote database to query. | testdb |
You can create multiple servers in the same database.
Step 3: Create a user mapping
Create a user mapping to authenticate the cross-database connection. The mapped account must have SELECT permission on the source tables.
CREATE USER MAPPING FOR <account_uid> SERVER <server_name>
OPTIONS (
access_id '<access_id>',
access_key '<access_key>'
);| Parameter | Description |
|---|---|
account_uid | The local user to map. Use CURRENT_USER for the current session user, or a RAM user in p4_<uid> format. |
server_name | The server name from step 2. |
access_id | The AccessKey ID of the account. |
access_key | The AccessKey secret of the account. |
Examples:
-- Map the current user.
CREATE USER MAPPING FOR CURRENT_USER SERVER holo_fdw_server OPTIONS (
access_id 'yourAccessKeyId',
access_key 'yourAccessKeySecret'
);
-- Map a RAM user.
CREATE USER MAPPING FOR "p4_123xxx" SERVER holo_fdw_server OPTIONS (
access_id 'yourAccessKeyId',
access_key 'yourAccessKeySecret'
);
-- Remove a user mapping.
DROP USER MAPPING FOR CURRENT_USER SERVER holo_fdw_server;
DROP USER MAPPING FOR "p4_123xxx" SERVER holo_fdw_server;You can create multiple user mappings in the same database.
Step 4: Create a foreign table
Use one of the following two methods to create a foreign table. The IMPORT FOREIGN SCHEMA method is simpler and is recommended for most cases.
Method 1 (recommended): IMPORT FOREIGN SCHEMA
IMPORT FOREIGN SCHEMA <holo_remote_schema>
[{ LIMIT TO | EXCEPT } (<remote_table> [, ...])]
FROM SERVER <server_name>
INTO <holo_local_schema>
[OPTIONS (<option> '<value>' [, ...])];| Parameter | Description | Example |
|---|---|---|
holo_remote_schema | The schema name in the remote database where the source table resides. | remote |
remote_table | The source table name. The foreign table is created with the same name in the local schema. | lineitem |
server_name | The server name from step 2. | holo_fdw_server |
holo_local_schema | The local schema where the foreign table is created. | local |
Supported options:
| Option | Description | Default |
|---|---|---|
import_collate | Include column collation settings. | true |
import_default | Include column default values. | false |
import_not_null | Include NOT NULL constraints. | true |
Use LIMIT TO to import only the tables you need. Importing the full remote schema can be slow if it contains many tables.
Method 2: CREATE FOREIGN TABLE
CREATE FOREIGN TABLE <local_table> (
col_name type,
...
) SERVER <server_name>
OPTIONS (schema_name '<remote_schema_name>', table_name '<remote_table>');| Parameter | Description | Example |
|---|---|---|
local_table | The name of the foreign table to create locally. To place it in a custom schema, use schema.table format. | public.lineitem |
server_name | The server name from step 2. | holo_fdw_server |
remote_schema_name | The schema name in the remote database. | public |
remote_table | The source table name in the remote database. | holo_lineitem |
Step 5: Query the foreign table
After the foreign table is created, query it directly:
SELECT * FROM <holo_local_table> LIMIT 10;Step 6 (optional): Import data into a local internal table
If foreign table query performance does not meet your needs, or if you need a local copy of the data, import it into a Hologres internal table:
INSERT INTO <holo_table> SELECT * FROM <holo_local_table>;Create the target internal table before running this statement. See Manage internal tables for details.
Manage servers and user mappings
List servers
SELECT
s.srvname AS "Name",
pg_catalog.pg_get_userbyid(s.srvowner) AS "Owner",
f.fdwname AS "Foreign-data wrapper",
pg_catalog.array_to_string(s.srvacl, E'\n') AS "Access privileges",
s.srvtype AS "Type",
s.srvversion AS "Version",
CASE WHEN srvoptions IS NULL THEN
''
ELSE
'(' || pg_catalog.array_to_string(ARRAY (
SELECT
pg_catalog.quote_ident(option_name) || ' ' || pg_catalog.quote_literal(option_value)
FROM pg_catalog.pg_options_to_table(srvoptions)), ', ') || ')'
END AS "FDW options",
d.description AS "Description"
FROM
pg_catalog.pg_foreign_server s
JOIN pg_catalog.pg_foreign_data_wrapper f ON f.oid = s.srvfdw
LEFT JOIN pg_catalog.pg_description d ON d.classoid = s.tableoid
AND d.objoid = s.oid
AND d.objsubid = 0
WHERE
f.fdwname = 'hologres_fdw';List user mappings
SELECT
um.srvname AS "Server",
um.usename AS "User name",
CASE WHEN umoptions IS NULL THEN
''
ELSE
'(' || pg_catalog.array_to_string(ARRAY (
SELECT
pg_catalog.quote_ident(option_name) || ' ' || pg_catalog.quote_literal(option_value)
FROM pg_catalog.pg_options_to_table(umoptions)), ', ') || ')'
END AS "FDW options"
FROM
pg_catalog.pg_user_mappings um
WHERE
um.srvname != 'query_log_store_server';Delete a user mapping
DROP USER MAPPING FOR <account_uid> SERVER <server_name>;Delete a server
Delete all related user mappings and foreign tables before dropping a server.
DROP SERVER <server_name>;Examples
The following examples use a shared source instance and database. Run all statements in the local database — the one where you perform the cross-database query.
Source instance configuration
| Configuration | Value |
|---|---|
| Source instance ID | hgpostcn-cn-i7mxxxxxxxxx |
| Source database | remote_db |
| Source schema | remote |
| Non-partitioned table | lineitem |
| Partitioned parent table | holo_dwd_product_movie_basic_info |
DDL for the source Hologres internal table
BEGIN;
CREATE SCHEMA remote;
CREATE TABLE "remote"."lineitem" (
"l_orderkey" int8 NOT NULL,
"l_linenumber" int8 NOT NULL,
"l_suppkey" int8 NOT NULL,
"l_partkey" int8 NOT NULL,
"l_quantity" int8 NOT NULL,
"l_extendedprice" int8 NOT NULL,
"l_discount" int8 NOT NULL,
"l_tax" int8 NOT NULL,
"l_returnflag" text NOT NULL,
"l_linestatus" text NOT NULL,
"l_shipdate" timestamptz NOT NULL,
"l_commitdate" timestamptz NOT NULL,
"l_receiptdate" timestamptz NOT NULL,
"l_shipinstruct" text NOT NULL,
"l_shipmode" text NOT NULL,
"l_comment" text NOT NULL
);
COMMIT;DDL for the source Hologres partitioned table
BEGIN;
CREATE TABLE "remote"."holo_dwd_product_movie_basic_info" (
"movie_name" text,
"director" text,
"scriptwriter" text,
"area" text,
"actors" text,
"type" text,
"movie_length" text,
"movie_date" text,
"movie_language" text,
"imdb_url" text,
"ds" text
)
PARTITION BY LIST (ds);
COMMIT;
-- Create a partition for '20170122'.
CREATE TABLE IF NOT EXISTS "remote".holo_dwd_product_movie_basic_info_20170122
PARTITION OF "remote".holo_dwd_product_movie_basic_info
FOR VALUES IN ('20170122');Example 1: Query a non-partitioned table
-- Run as a superuser in the local database.
-- Step 1: Install the extension.
CREATE EXTENSION hologres_fdw;
-- Step 2: Create a server pointing to the remote instance.
CREATE SERVER holo_fdw_server FOREIGN DATA WRAPPER hologres_fdw OPTIONS (
host 'hgpostcn-cn-i7mxxxxxxxxx-cn-hangzhou-internal.hologres.aliyuncs.com',
port '80',
dbname 'remote_db'
);
-- Step 3: Create a user mapping for the current user.
CREATE USER MAPPING FOR CURRENT_USER SERVER holo_fdw_server
OPTIONS (access_id 'yourAccessKeyId', access_key 'yourAccessKeySecret');
-- Step 4: Create a local schema and import the foreign table.
CREATE SCHEMA local;
IMPORT FOREIGN SCHEMA remote
LIMIT TO (lineitem)
FROM SERVER holo_fdw_server
INTO local
OPTIONS (import_not_null 'true');
-- Step 5: Query the foreign table.
SELECT * FROM local.lineitem LIMIT 10;Example 2: Query a partitioned table
-- Run as a superuser in the local database.
CREATE EXTENSION hologres_fdw;
CREATE SERVER holo_fdw_server FOREIGN DATA WRAPPER hologres_fdw OPTIONS (
host 'hgpostcn-cn-i7mxxxxxxxxx-cn-hangzhou-internal.hologres.aliyuncs.com',
port '80',
dbname 'remote_db'
);
CREATE USER MAPPING FOR CURRENT_USER SERVER holo_fdw_server
OPTIONS (access_id 'yourAccessKeyId', access_key 'yourAccessKeySecret');
CREATE SCHEMA local;
-- Import the partitioned parent table (child tables are included automatically).
IMPORT FOREIGN SCHEMA remote
LIMIT TO (holo_dwd_product_movie_basic_info)
FROM SERVER holo_fdw_server
INTO local
OPTIONS (import_not_null 'true');
SELECT * FROM local.holo_dwd_product_movie_basic_info LIMIT 10;Example 3: Import data from a foreign table into a local internal table
-- Create a local schema.
CREATE SCHEMA local;
-- Create the target internal table.
BEGIN;
CREATE TABLE "local"."dwd_product_movie_basic_info" (
"movie_name" text,
"director" text,
"scriptwriter" text,
"area" text,
"actors" text,
"type" text,
"movie_length" text,
"movie_date" text,
"movie_language" text,
"imdb_url" text,
"ds" text
);
COMMIT;
-- Copy data from the foreign table into the internal table.
INSERT INTO local.dwd_product_movie_basic_info
SELECT * FROM local.holo_dwd_product_movie_basic_info;Troubleshooting
Error when querying a read-only replica
If you configure a read-only replica instance as the query target, you may see the following error:
internal error: Failed to get available shards for query[xxxxx], please retry later.Run the following statement in both the primary instance of the read-only replica and the local (initiating) instance:
ALTER DATABASE <database> SET hg_experimental_enable_dml_read_replica=ON;Use the primary instance as the query target whenever possible.