How can I import a foreign schema with anyarray columns? - postgresql

Is it possible to query the pg_catalog schema of a remote Postgres server? I'm trying to access some simple statistics of a remote server. I've tried importing the foreign schema, but it fails on an anyarray column.
psql> IMPORT FOREIGN SCHEMA pg_catalog LIMIT TO (pg_stats) FROM SERVER myserver into myschema;
ERROR: column "most_common_vals" has pseudo-type anyarray
CONTEXT: importing foreign table "pg_stats"
I'm able to individually import tables that don't have anyarray columns.

You could define a view (on the foreign side) which casts those columns to text, then create a foreign table for that view instead of the original. Not very elegant, but it works. But you do have to have create privs on the foreign side, or have the cooperation of someone who does.
I don't know what will happen for stats over bytea columns.

Related

Foreign Table that references ALL columns of the origin table

Is it possible to create a foreign table that lists all columns of the original table, like this somehow?
CREATE FOREIGN TABLE localschema.localtable (/* list all columns of foreign_table here */)
SERVER foreignserver
OPTIONS (schema_name 'foreign_schema', table_name 'foreign_table');
Use IMPORT FOREIGN SCHEMA:
IMPORT FOREIGN SCHEMA foreign_schema LIMIT TO (foreign_table)
FROM SERVER foreignserver INTO localschema;
If you need the foreign table name to be different, rename it.

Pre-fix the foreign table with the schema - postgres_pwd

If I follow: https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Appendix.PostgreSQL.CommonDBATasks.html#postgresql-commondbatasks-fdw, how can I pre-fix the tables with the schema I am retrieving tables from, e.g.
IMPORT FOREIGN SCHEMA lands
LIMIT TO (land, land2)
FROM SERVER foreign_server INTO public;
The created tables are named land and land2. Is it possible to prefix land and land2 with 'lands', e.g. 'lands_land' and 'lands_land2'?
With psql and recent PostgreSQL versions, you could simply run (after the IMPORT FOREIGN SCHEMA):
SELECT format(
'ALTER FOREIGN TABLE public.%I RENAME TO %I;',
relname,
'lands_' || relname
)
FROM pg_class
WHERE relkind = 'f' -- foreign table
AND relnamespace = 'public'::regnamespace \gexec
The \gexec will interpret each result row as an SQL stateent and execute it.
Another option that I'd like better is to keep the original names, but use a different schema for the foreign tables:
IMPORT FOREIGN SCHEMA lands
LIMIT TO (land, land2)
FROM SERVER foreign_server INTO lands;
Then all foreign tables will be in a schema lands, and you have the same effect in a more natural fashion. You can adjust search_path to include the lands schema.

updating table with Postgresql Foreign data wrapper

I created a foreign data wrapper table named t_user into mySchema.
IMPORT FOREIGN SCHEMA public LIMIT TO (t_user)
FROM SERVER myServer INTO mySchema;
The myServer side t_user added some column, but the foreign table didn't update accordingly.
I tried to delete the foreign table t_user, but it was used by my view and materialized view t_user, so the deletion failed.
Any ideas on how to update this table?
As you have seen, the foreign table definition does not change when the underlying table changes.
If all you did is add a column, you can use ALTER FOREIGN TABLE to add a corresponding column to the foreign table. That should work even if views depend on the foreign table.
For example, if the column is of type text, you can do:
ALTER FOREIGN TABLE t_user ADD COLUMN my_column text;

Foreign table inserts don't use the remote sequence

I have a set of applications accessing two different PostgreSQL 9.6 DBs on the same server. Due to some application limitations, one application accesses a handful of tables via FDW in one DB to the other.
Something like this:
DB1.fdw_table_a -> DB2.table_a
fdw_table_a is only used for inserts of log data. This table has an id column, which is a bigint sequence. The sequence exists in DB1 (on the foreign table) and in DB2 (the "real" table). This works as it should and all is well.
Now there's a need to have another application (again with limited access capabilities) perform inserts into the "real" table, DB2.table_a. In testing, I can see some inconsistencies in the id column, but no obvious issues have appeared.
I can see in the customer-facing environments that the DB1 FDW sequence is used as expected, but when inserts start directly on the DB2 'real' table, that sequence will start at 1 (as it has never been used).
Are there other things we should be considering in this environment?
Are there some issues that could arise from overlap in these two sequences inserting into the table?
The sequence only gets used if you omit the id column in the INSERT statement. But postgres_fdw will never omit a column, as you can see from the execution plan.
One way to solve the problem is to use a foreign table that does not contain the id column. Then any insert into that foreign table will use the sequence to populate that column.
The following plan from 2014 is still valid today.
=# CREATE SEQUENCE seq;
CREATE SEQUENCE
=# CREATE VIEW seq_view AS SELECT nextval('seq') as a;
CREATE VIEW
=# CREATE EXTENSION postgres_fdw;
CREATE EXTENSION
=# CREATE SERVER postgres_server
-# FOREIGN DATA WRAPPER postgres_fdw
-# OPTIONS (host 'localhost', port '5433', dbname 'postgres');
CREATE SERVER
=# CREATE USER MAPPING FOR PUBLIC SERVER postgres_server OPTIONS (password '');
CREATE USER MAPPING
=# CREATE FOREIGN TABLE foreign_seq_table (a bigint)
-# SERVER postgres_server OPTIONS (table_name 'seq_view');
CREATE FOREIGN TABLE
=# CREATE FUNCTION foreign_seq_nextval() RETURNS bigint AS
-# 'SELECT a FROM foreign_seq_table;' LANGUAGE SQL;
CREATE FUNCTION
=# CREATE TABLE tab (a int DEFAULT foreign_seq_nextval());
CREATE TABLE
=# INSERT INTO tab VALUES (DEFAULT), (DEFAULT), (DEFAULT);
INSERT 0 3
=# SELECT * FROM tab;
a
----
9
10
11
(3 rows)
https://paquier.xyz/postgresql-2/global-sequences-with-postgres_fdw-and-postgres-core/

Query to foreign table impossible due to index on custom stored function value in host database

I have a following situation.
In database A on server I, let's call it Host DB, there is a table, that has a following sample create script:
CREATE TABLE public.some_table (
id SERIAL PRIMARY KEY,
some_field TEXT
);
CREATE INDEX public.some_field_index
ON public.some_table USING btree
(my_custom_function(some_field));
As you can see, the index is created on a result of some custom, stored in database A, function my_custom_function.
Now I want to declare some_table as foreign table on other server, in database B. After creating the server, user mappings etc. I declare foreign table as:
CREATE FOREIGN TABLE public.some_table (
id SERIAL PRIMARY KEY,
some_field TEXT
)
SERVER host_server
OPTIONS (
schema_name 'public',
table_name 'some_table'
);
The table is created nicely, however I cannot query it. Instead I am getting following error:
ERROR: function my_custom_function(text) does not exist.
No function matches the given name and argument type.
You might need to add explcit type casts.
CONTEXT: Remote SQL command: SELECT id, some_field FROM public.some_table
SQL fuction my_custom_function during inlining.
I believe the problem is related to function my_custom_function not being declared on the server B, in the "guest" database. For some reasons i don't want to create this function. Is there any solution to overcome this problem?
Thanks for all your answers in advance.