Why is postgres_fdw double-qualifying schemas? - postgresql

Using postgres_fdw, I need to create the foreign tables in a specified schema to prevent name collisions. To isolate the issue I've been having, I set up two test postgres databases on the same cluster, import_test and export_test. Export_test has a table, foreign_schema.aa. On the server import_test, after doing the other FDW prerequisites, I ran:
CREATE FOREIGN TABLE local_schema.aa(
id serial NOT NULL,
dat text
) SERVER export_server OPTIONS (table_name 'foreign_schema.aa');
Then:
SELECT * FROM local_schema.aa;
When I do this, I get:
ERROR: relation "local_schema.foreign_schema.aa" does not exist
CONTEXT: Remote SQL command: SELECT id, dat FROM local_schema."foreign_schema.aa"
If I don't do any schema qualification, as in:
CREATE FOREIGN TABLE aa(
id serial NOT NULL,
dat text
) SERVER export_server OPTIONS (table_name 'aa');
And move the aa table to the public schema, the select works just fine.
If the command "SELECT id, dat FROM local_schema."foreign_schema.aa" is literally being run on the remote server, it's obvious why it doesn't work: local_schema."foreign_schema.aa" really doesn't exist on the remote server. For some reason, the postgres_fdw appears to be prepending the name given for table_name with the schema of the foreign table.
I need to specify the schema in the select query, because if I don't it doesn't see the foreign table. Achieving the schema qualification by preceding the select with setting the search path doesn't help either.
Is there anything I am doing wrong? If not, is there a workaround that will let me schema-qualify the foreign table?
EDIT: Per #Craig Ringer's suggestions, here's the self-contained psql input:
CREATE USER test_user SUPERUSER PASSWORD 'password';
SET ROLE test_user;
CREATE DATABASE import;
CREATE DATABASE export;
\c export test_user
CREATE SCHEMA export_schema;
CREATE TABLE export_schema.aa (
id serial PRIMARY KEY,
dat text
);
\c import test_user
CREATE EXTENSION postgres_fdw;
CREATE SERVER export_server
FOREIGN DATA WRAPPER postgres_fdw
OPTIONS (host 'localhost', dbname 'export', port '5432');
CREATE USER MAPPING FOR test_user
SERVER export_server
OPTIONS (user 'test_user', password 'password');
CREATE SCHEMA import_schema;
CREATE FOREIGN TABLE import_schema.aa(
id serial NOT NULL,
dat text
) SERVER export_server OPTIONS (table_name 'export_schema.aa');
SELECT * FROM import_schema.aa;
Which yields this output:
ERROR: relation "import_schema.export_schema.aa" does not exist
CONTEXT: Remote SQL command: SELECT id, dat FROM import_schema."export_schema.aa"

Forgot to come back with resolution. Turns out sometime around the time I posted my bug report, the docs on postgres_fdw were updated. See the section "F.31.1.2. Object Name Options" and the schema_name option on this page: http://www.postgresql.org/docs/current/static/postgres-fdw.html.
I quote the mailing list reply:
"Use: OPTIONS (schema_name 'export_schema', table_name 'aa'); above.
Thanks,
Stephen"
So to resolve, just specify the foreign schema name in the schema_name option parameter.

Related

Query tables from multiple servers with postgreSQL

I have several databases on the different PostgreSQL servers with the tables with the same columns in it
(installs_1, installs_2 and installs_3)
installs(country varchar, date datetime,paid boolean, installs int)
I want to write a function that a user could use to query across all these databases at once, how can I do it?
my query is:select country,count(*) from t1,t2
A PostgreSQL extension that offer this feature is the postgres_fdw. Here is an example of how to set it up:
First you create the extension:
CREATE EXTENSION postgres_fdw
After that you create a server pointing to the foreign postgres server
CREATE SERVER remote_postgres
FOREIGN DATA WRAPPER postgres_fdw
OPTIONS (dbname 'mydb', host 'remoteserver', port '5432');
Then an user mapping, so that an user in your current database may access the foreign database:
CREATE USER MAPPING FOR local_user
SERVER remote_postgres
OPTIONS (user 'foreign_user', password 'secret');
And finally you create a foreign table to link both tables
CREATE FOREIGN TABLE foreign_table_test
(id INT, description TEXT)
SERVER remote_postgres
OPTIONS (schema_name 'public', table_name 'table_test');
Once your table is created you can query it like you'd query a normal/local table:
SELECT * FROM foreign_table_test
Further reading:
A closer look into postgres_fdw
postgres_fdw documentation examples

Logging records in a postgresql database

I am having trouble thinking of a way to copy three fields out of a database into and append them to another table along with the current date. Basically what I want to do is:
DB-A: ID (N9), Name (C69), Phone (N15) {and a list of other fields I dont care about}
DB-B: Date (Todays date/time), Nane, Address, Phone (as above)
Would be great is this was a trigger in the DB on add or update of DB-A.
Greg
Quick and dirty using postgres_fdw
CREATE EXTENSION IF NOT EXISTS postgres_fdw ;
CREATE SERVER extern_server FOREIGN DATA WRAPPER postgres_fdw OPTIONS (host 'foreignserver.co.uk', port '5432', dbname 'mydb');
CREATE USER MAPPING FOR myuser SERVER extern_server OPTIONS (user 'anotheruser');
-- Creating a foreign table based on table t1 at the server described above
CREATE FOREIGN TABLE foreign_t1 (
dba INT,
name VARCHAR(9),
phone VARCHAR(15)
)
SERVER extern_server OPTIONS (schema_name 'public', table_name 't1');
--Inserting data to a new table + date
INSERT INTO t2 SELECT dba,name,phone,CURRENT_DATE FROM foreign_t1;
-- Or just retrieving what you need placing the current date as a column
SELECT dba,name,phone,CURRENT_DATE FROM foreign_t1;

postgresql permission denied to foreign table pg_redis_fdw

I am working with pg_rdeis_fdw from postgres.
When I try to insert a record to the existing schema from the postgres account, it all works fine.
However, when I try to do the same from another user, I get "permission denied for relation", though i gave the user the following privileges:
grant all on FOREIGN DATA WRAPPER redis_fdw to ami;
grant all on FOREIGN SERVER redis_server to ami;
grant all on ALL TABLES IN SCHEMA public to ami;
GRANT ALL PRIVILEGES ON TABLE user_redis_hash to ami;
The definition is as following (and as I was saying, works just fine from user postgres):
CREATE EXTENSION redis_fdw;
CREATE SERVER redis_server
FOREIGN DATA WRAPPER redis_fdw
OPTIONS (address '127.0.0.1', port '6379');
CREATE USER MAPPING FOR PUBLIC
SERVER redis_server
OPTIONS (password 'secret');
create foreign table user_redis_hash(key text, val text[])
server redis_server
options (database '0', tabletype 'hash', tablekeyset 'user:');
thanks,
Ami
In my case I had to change the owner of the foreign table to the right role. So you might try something like this (from the postgres account):
ALTER FOREIGN TABLE public.user_redis_hash OWNER TO ami;
If you have other foreign tables (as I did) and need to change them all, the following SQL will produce a series of SQL lines you can copy into psql prompt to update each foreign table.
SELECT 'ALTER FOREIGN TABLE '|| foreign_table_schema || '.' || foreign_table_name ||' OWNER TO ami;' FROM information_schema.foreign_tables WHERE NOT foreign_table_schema IN ('pg_catalog', 'information_schema') ORDER BY foreign_table_schema, foreign_table_name;
If you have other foreign tables for other servers or data wrappers that you do not want to change ownership on you can limit the above by adding AND foreign_server_name = 'redis_server' to the WHERE clause.

Problems while Using postgres_fdw

I m getting some problem while using postgres_fdw.
CREATE SERVER foreign_server
FOREIGN DATA WRAPPER postgres_fdw
OPTIONS (host '192.162.0.1', port '5432', dbname 'Test');
CREATE USER MAPPING FOR postgres
SERVER foreign_server
OPTIONS (user 'foreign_user', password 'password');
CREATE FOREIGN TABLE foreign_table (
id serial NOT NULL,
data text)SERVER foreign_server
OPTIONS (schema_name 'public', table_name 'employee');
select * from employee where user ='foreign_user'
Now I can see entries are made to pg_foreign_data_wrapper, pg_foreign_server and pg_foreign_table tables.
But how do I access employee table of remote system.
I mean select * from employee where user ='foreign_user' doesn't give any result. Though it has data in Employee table of remote system.
Any idea please?
But How do I access employee table of remote system.
You just need to access the foreign table, say "SELECT * FROM foreign_table;".
The procedure seems fine, but your foreign table doesn't have a column named "user", so your query must cause an error.
It would be better to show what has happened actually. Showing actual query and error messages helps us understand where the problem is.

Create a foreign table pointing to a view in Postgres

Is it possible to create a foreign table, using Postgres Foreign Data Wrapper, that points to a view instead of a table?
Yes, it is possible!
The following query worked perfectly:
CREATE FOREIGN TABLE facts(name character varying(255))
SERVER my_server
OPTIONS (table_name 'facts');
Where facts is a view in my_server instead of a table.
Recently I had to do the same thing and here are the steps that worked for me. All these commands are run on the local postgreSQL DB.
CREATE EXTENSION postgres_fdw;
CREATE SERVER remote_server_name
FOREIGN DATA WRAPPER postgres_fdw
OPTIONS (host '10.10.10.10', port '5432', dbname 'remote_db_name');
CREATE USER MAPPING FOR local_user_name
SERVER remote_server_name
OPTIONS (user 'remote_user', password 'remote_password');
CREATE FOREIGN TABLE local_table_name (
id NUMERIC NOT NULL,
row TEXT,
another_row INTEGER,
whatever_row TEXT
)
SERVER remote_server_name
OPTIONS (schema_name 'public', table_name 'remote_table_name');
I have the same question.
In pgadmin4 for postgresql-11, if use GUI Command: Create -> Foreign Table...
on table, it works; but on view, it does't works, you will get a empty table.
for view, i use this code, it works:
IMPORT FOREIGN SCHEMA remote_schema_name
LIMIT TO (remote_view_name)
FROM SERVER remote_host_map_name INTO local_shema_name;
The reason is, for table, pgadmin4 can create columns same as remote table in constract SQL statement, but for view, it create no columns in constract SQL statement.