Pre-fix the foreign table with the schema - postgres_pwd - postgresql

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.

Related

How to create an (FDW) foreign table and map it to a different schema?

This is how I defined the foreign table:
CREATE FOREIGN TABLE ftbl_employee (
id UUID,
name VARCHAR,
)
SERVER company_registry_dbserver
OPTIONS (schema_name 'company', table_name 'company_employee');
It created the foreign table successfully. However, when I list the foreign table, It has defaulted to public schema. See foreign_table_schema column:
> select * from information_schema.foreign_tables;
foreign_table_catalog
foreign_table_schema
foreign_table_name
foreign_server_catalog
foreign_server_name
sandbox
public
ftbl_employee
sandbox
company_registry_dbserver
I would like to map it into the company schema in our sandbox database server instead of the public schema.
The column information_schema.foreign_tables holds the schema where the foreign table is stored locally, not the schema of the table in the target database. So, there is no way you can create this foreign table in the schema company if it does not exist locally! You need to either locally run ..
CREATE SCHEMA company;
.. or live with the foreign table in the public schema. Keep in mind that a foreign table is nothing more than a "gateway" to a table that resides in a different database / server. If you wanna know more details on the foreign table, e.g. name or schema, check the view pg_foreign_table:
SELECT relname, ftoptions
FROM pg_foreign_table
JOIN pg_class ON ftrelid = oid;

Postgres: Oracle_fdw: Import foreign schema does not support if not exists

When we use import foreign schema in oracle_fdw, there is no option for IF NOT EXISTS.
Due to which if we re-execute the import foreign schema command to import the newly added tables/view we get the error that relation already exists.
As we are not aware of the table/view which were not added in the previous execution it becomes difficult to specify them in LIMIT/EXCEPT clause
Is there any work around available to achieve the IF NOT EXISTS functionality
There is no direct way to do that, but you can first find the foreign tables that already exist in the target schema and list them in the EXCEPT clause of IMPORT FOREIGN SCHEMA.
To find all foreign tables in a schema:
SELECT relname
FROM pg_class
WHERE relkind = 'f'
AND relnamespace = 'schemaname'::regnamespace;
Then
IMPORT FOREIGN SCHEMA "XYZ"
EXCEPT (/* list from above */)
FROM SERVER oraserver
INTO schemaname;

cross-database references are not implemented:

I am trying to convert SQL inner join query into PostgreSQL inner join query. In this inner join query which tables are using that all tables are not present in one database. we separated tables into two databases i.e. application db and security db
users and permission table are present in security db
userrolemapping and department are present in application db
I tried like below but I am getting following error
Error
ERROR: cross-database references are not implemented: "Rockefeller_ApplicationDb.public.userrolemapping"
LINE 4: INNER JOIN "Rockefeller_ApplicationDb".public.userro..
SQL Stored Function
SELECT Department.nDeptID
FROM Users INNER JOIN Permission
ON Users.nUserID = Permission.nUserID INNER JOIN UserRoleMapping
ON Users.nUserID = UserRoleMapping.nUserID INNER JOIN Department
ON Permission.nDeptInst = Department.nInstID
AND Department.nInstID = 60
WHERE
Users.nUserID = 3;
PostgreSQL Stored Function
SELECT dep.ndept_id
FROM "Rockefeller_SecurityDb".public.users as u
INNER JOIN "Rockefeller_SecurityDb".public.permissions p ON u.nuser_id = p.nuser_id
INNER JOIN "Rockefeller_ApplicationDb".public.userrolemapping as urm ON u.nuser_id = urm.nuser_id
INNER JOIN "Rockefeller_ApplicationDb".public.department dep ON p.ndept_inst = dep.ninst_id
AND dep.ninst_id = 60
WHERE
u.nuser_id = 3;
You cannot join tables from different databases.
Databases are logically separated in PostgreSQL by design.
If you want to join the tables, you should put them into different schemas in one database rather than into different databases.
Note that what is called “database” in MySQL is called a “schema” in standard SQL.
If you really need to join tables from different databases, you need to use a foreign data wrapper.
For future searchs, you can to use dblink to connect to other database.
Follow commands:
create extension dblink;
SELECT dblink_connect('otherdb','host=localhost port=5432 dbname=otherdb user=postgres password=???? options=-csearch_path=');
SELECT * FROM dblink('otherdb', 'select field1, field2 from public.tablex')
AS t(field1 text, field2 text);
New to postrgreSQL and I had the same requirement. FOREIGN DATA WRAPPER did the job.
IMPORT FOREIGN SCHEMA — import table definitions from a foreign server
But first I had to:
enable the fdw extension
define the foreign server (which was the locahost in this case!)
create a mapping between the local user and the foreign user.
CREATE EXTENSION postgres_fdw;
CREATE SERVER localsrv
FOREIGN DATA WRAPPER postgres_fdw
OPTIONS (host 'localhost', dbname 'otherdb', port '5432');
CREATE USER MAPPING FOR <local_user>
SERVER localsrv
OPTIONS (user 'ohterdb_user', password 'ohterdb_user_password');
IMPORT FOREIGN SCHEMA public
FROM SERVER localsrv
INTO public;
After that I could use the foreign tables as if they were local. I did not notice any performance cost.
In my case, I changed my query from:
SELECT * FROM myDB.public.person
to this:
SELECT * FROM "myDB".public.cats
and it worked.
You can read more at mathworks.com.

Does ALTER COLUMN TYPE varchar(N) rewrite the table in Postgres 9.6?

In the past
The way we handled this with Postgres 8.4 was to manually update the pg_attribute table:
LOCK TABLE pg_attribute IN EXCLUSIVE MODE;
UPDATE pg_attribute SET atttypmod = 104
WHERE attrelid = 'table_name'::regclass AND
attname = 'column_name';
column_name was a varchar(50) and we wanted a varchar(100), but the table was too enormous (tens of millions of rows) and too heavily used to rewrite.
Nowadays
The content and answers around this topic were sparse and outdated for such a (at least anecdotally) common problem.
But, after seeing hints that this might be the case on at least 3 discussions, I've come to think that with newer versions of Postgres (we're on 9.6), you are now able to run the following:
ALTER TABLE 'table_name' ALTER COLUMN 'column_name' TYPE varchar(100);
...without rewriting the table.
Is this correct?
If so, do you know where some definitive info on the topic exists in the Postgres docs?
That ALTER TABLE will not require a rewrite.
The documentation says:
Adding a column with a DEFAULT clause or changing the type of an existing column will require the entire table and its indexes to be rewritten.
It is very simple to test:
Try with an empty table and see if the relfilenode column in the pg_class row for the table changes:
SELECT relfilenode FROM pg_class
WHERE relname = 'table_name';
Reading on in the documentation, you see:
As an exception, when changing the type of an existing column, if the USING clause does not change the column contents and the old type is either binary coercible to the new type or an unconstrained domain over the new type, a table rewrite is not needed; but any indexes on the affected columns must still be rebuilt.
Since varchar(50) is clearly binary coercible to varchar(100), your case will not require a table rewrite, as the above test should confirm.
According to What's new in PostgreSQL 9.2 the above answer is at least strange to me the accepted answer was edited to align with the below:
Reduce ALTER TABLE rewrites
A table won't get rewritten anymore during
an ALTER TABLE when changing the type of a column in the following
cases:
varchar(x) to varchar(y) when y>=x. It works too if going from
varchar(x) to varchar or text (no size limitation)
I tested with postgres 10.4 and the relfilenode remained the same after running alter table ... alter column ... type varchar(50)
create table aaa (field varchar(10));
insert into aaa select f from generate_series(1,1e6) f;
commit;
SELECT oid, relfilenode FROM pg_class WHERE relname = 'aaa';
alter table aaa alter column field type varchar(50);
commit;
SELECT oid, relfilenode FROM pg_class WHERE relname = 'aaa';
I'm not sure why you got a different relfilenode in 9.6 (or I'm missing something...).

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.