Check foreign table owner on Postgres - sql

I have a foreign table on Postgres, linking to another server. I'm trying to select on this table, but I'm getting this error:
ERROR: permission denied for relation whitelist
Anyone knows how to check the ownership of a foreign table?
I've tried this, but it returns info just about local tables...
select t.table_name, t.table_type, c.relname, c.relowner, u.usename
from information_schema.tables t
join pg_catalog.pg_class c on (t.table_name = c.relname)
join pg_catalog.pg_user u on (c.relowner = u.usesysid)
where t.table_schema='schema_name';

Any admin tool should be able to tell you who owns a foreign table (or any other database object, for that matter). In pgAdmin, the owner appears in the Properties tab when you select the foreign table in the object browser, and psql will report the owner when you run \dE.
If you really need a query, this should do it:
SELECT
oid::regclass,
pg_get_userbyid(relowner)
FROM pg_class
WHERE relkind = 'f'

Related

Postgres: Get owner of all schemas

I want to find out what the owner is of my postgres database schema. I tried
select * from information_schema.schemata s order by schema_name
But when I use a visual database client for our postgres database, there appear to be more schemas than the results of the query above. How can I see owners of these 'hidden' tables? I suspect it has something to do with the owner of the schema not granting others to see the schema, but I just can't figure that out.
try:
select r.rolname as schema_owner, ns.* from pg_namespace ns join pg_roles r on ns.nspowner = r.oid

How do I SELECT all (table, column) referencing the same column as foreign key

(TL;DR at the end)
I am working on merging 2 well sized postgres databases.
As there are ID conflicts and many foreign keys I would have enjoyed that UPDATE foo SET bar_id = bar_id + 100000 CASCADE was a thing in SQL so it magically update everything accordingly. Unfortunately, it's not.
So I want to use a LOOP structure (see below) that will simply edit the references everywhere.
I want a select query the return all table_name, column_name that references the column I want.
DO
$$
DECLARE
rec record;
BEGIN
FOR rec IN
(SELECT table_name, column_name FROM /*??*/ WHERE /*??*/) -- <<< This line
LOOP
EXECUTE format('UPDATE %I SET %s = %s + 100000 ;',
rec.table_name,rec.column_name,rec.column_name);
END LOOP;
END;
$$
LANGUAGE plpgsql;
I know already how to get all tables (+column_name) having a specific column_name that I use when the foreign key column share the name with the column it references. Or even if it's a list of column_name I know:
SELECT col.table_name, col.column_name
FROM information_schema.columns col
right join
information_schema.tables tab
ON col.table_name = tab.table_name
WHERE column_name = 'foo_id'
-- IN ('FOO_ID','BAR_FOO_ID') | or : like '%foo_id' | both works well most of the time
and tab.table_type = 'BASE TABLE'
But...
I am now with a table PLACES with the place_id column being referenced on at least 60 different constraints (matching LIKE '%place_id'). Then there is columns referencing the place id named otherwise like 'foo_currentplace','foo_storageroom', 'foo_lastrecomposition_place', 'operating_theatre' and so on. In the other hand, there is columns referring 'placetype_id' from placetype table which are LIKE '%place%' and I do NOT want to change the placetype_id, so we can not guess which column is to include or not only from their name.
I know there is the information_schema.table_constraints table, but it does NOT tell the referenced column.
If we can have the definition from the constraint name, it could be possible to match :
ILIKE format('%%REFERENCES %s(%s)%%',table_name,column_name)
but the definition isn't part of the table_constraints table either.
(For those wondering, I'm working on Hospital databases related to sterilization services.)
WHAT I WANT / TL;DR
I need a SELECT query (or a function definition ) returning all column of the whole database (schema_name,table_name,column_name) or (table_name,column_name) having a foreign key constraint referencing a specified column (parameter).
OK so I have done it :-)
The following query returns every column in database referencing FOO_TABLE.foo_column as foreign key:
SELECT
fk.table_schema as schema, --optional in my case, I only use public
fk.table_name as table,
substring(fk.constraint_def, 14, position(')' in constraint_def)-14) as column
FROM
(SELECT tc.*,
pg_get_constraintdef(c.oid) as constraint_def
--,c.oid
from pg_constraint c
left join information_schema.table_constraints tc
on c.conname = tc.constraint_name
where tc.constraint_type = 'FOREIGN KEY')
as fk
WHERE constraint_def ILIKE format('%%REFERENCES %s(%s)%%',
'FOO_TABLE','foo_column')
ORDER BY table_schema,table_name,3;
Test it there
I've found information_schema.table_constraints gets most of the information from pg_constraint which includes internal reference OID, and there is a built-in function pg_get_constraintdef() returning the definition of constraint object from it's OID.
Then, some substring of the definition is enough to extract the column_name AND
filter over the referenced column with the (I)LIKE filter I've prepared in my question.
----------------- OTHER ANSWER ------------------
Another acceptable query I've built from improving #Abelisto suggestion :
SELECT table_name, column_name
FROM (SELECT table_name, SUBSTR(column_name, 2, LENGTH(column_name)-2) as column_name,
referenced_table,SUBSTR(referenced_column, 2, LENGTH(referenced_column)-2) as referenced_column
FROM(select
conrelid::regclass::text as table_name,
(select array_agg(attname) from pg_attribute where conrelid = attrelid and attnum = any(conkey))::text as column_name,
confrelid::regclass::text as referenced_table,
(select array_agg(attname) from pg_attribute where confrelid = attrelid and attnum = any(confkey))::text as referenced_column
from pg_constraint where contype = 'f'
) b ) a
WHERE (referenced_table, referenced_column) = ('FOO_TABLE','foo_column');
Test it there
I don't think performances really matters there, so one should pick regarding what are the side needs. I think my first solution have the advantage to get the constraint definition if you want to alter it (say, for exemple, add a ON UPDATE CASCADE clause), yet the second seems more "compact" for this very purpose of just returning the table.column.
This is perhaps too long for a comment.
Postgres definitely supports cascading update constraints (see here). However, this is part of the definition of the constraint, not the update statement:
ALTER TABLE foo
ADD FOREIGN KEY fk_foo_bar_id FOREIGN KEY (bar_id) REFERENCES bar(bar_id)
ON UPDATE CASCADE;
----^ this is the important part
Note: You will need to redefine all your foreign key constraints to make them cascading update constraints.
And, as an editorial comment, I generally avoid cascading update foreign key constraints (because I don't like the idea of primary keys changing values). However, this is definitely a place where they are useful.
Then if you change bar.bar_id, the change will be reflected in foo. Here is a db<>fiddle.

Programmatically get all tables of a database owned by a user

I created the following query:
select
is_tables.table_name
from information_schema.tables is_tables
join pg_tables
on is_tables.table_name=pg_tables.tablename
where
is_tables.table_catalog='<mydatabase>'
and is_tables.table_schema<>'information_schema'
and is_tables.table_schema<>'pg_catalog'
and pg_tables.tableowner='<myuser>';
I assume there is no database vendor independent way of querying this. Is this the easiest/shortest SQL query to achieve what I want in PostgreSQL?
I think you're pretty close. Object owners don't seem to appear in the information_schema views, although I might have overlooked it.
select is_tables.table_schema,
is_tables.table_name
from information_schema.tables is_tables
inner join pg_tables
on is_tables.table_name = pg_tables.tablename
and is_tables.table_schema = pg_tables.schemaname
where is_tables.table_catalog = '<mydatabase>'
and is_tables.table_schema <> 'information_schema'
and is_tables.table_schema <> 'pg_catalog'
and pg_tables.tableowner = '<myuser>';
You need to join on both the table name and the schema name. Table names are unique within a schema; they're not unique within a database.

How can I list Foreign tables in PostgreSQL?

In PostgreSQL, running \d command will list the tables along with their table type. Currently I'm trying to list out all foreign tables that I've created using foreign data wrapper. What is the query to list out those tables?
Query for listing foreign tables only:
select * from information_schema.foreign_tables
According to the manual \dE[S+] should do it.
http://www.postgresql.org/docs/current/static/app-psql.html
To see the query behind this, start psql with the -e ("echo queries") option.
Or use the information_schema.tables view: http://www.postgresql.org/docs/current/static/infoschema-tables.html
The table_type column will contain FOREIGN TABLE for those tables.
You can also use this command:
\detr
SELECT tc.table_name , ctu.table_name
FROM information_schema.table_constraints tc
inner join information_schema.constraint_table_usage ctu on ctu.constraint_name = tc.constraint_name
where constraint_type = 'FOREIGN KEY'

How to get the name of a unique constraint in postgresql?

I need to drop a unique constraint from a postgresql table, but I didn't give it a name in the schema. Does anybody know, how to get the name of such a constraint, or how to drop it?
That is something like (for single column constaint):
tableName_columnName_key
To get constaint name write (in psql):
\d tableName
or use pg_constraint system catalog:
SELECT conname
FROM pg_constraint
WHERE conrelid =
(SELECT oid
FROM pg_class
WHERE relname LIKE 'tableName');
Also you can get it from pgAdmin in objects tree.
SELECT conname
FROM pg_constraint
WHERE conrelid = 'mytable'::regclass::oid