How to find inherited tables programatically in PostgreSQL? - postgresql

I have a PostgreSQL 8.3 database where table inheritance is being used. I would like to get a list of all tables along with its schema name which is inherited from a base table using query. Is there any way we can get this using PGSQL?

Since you're on such an old version of PostgreSQL you'll probably have to use a PL/PgSQL function to handle inheritance depths of > 1. On modern PostgreSQL (or even 8.4) you'd use a recursive common table expression (WITH RECURSIVE).
The pg_catalog.pg_inherits table is the key. Given:
create table pp( ); -- The parent we'll search for
CREATE TABLE notpp(); -- Another root for multiple inheritance
create table cc( ) inherits (pp); -- a 1st level child of pp
create table dd( ) inherits (cc,notpp); -- a 2nd level child of pp that also inherits aa
create table notshown( ) inherits (notpp); -- Table that inherits only notpp
create table ccdd () inherits (cc,dd) -- Inheritance is a graph not a tree; join node
A correct result will find cc, dd, and ccdd, but not find notpp or notshown.
A single-depth query is:
SELECT pg_namespace.nspname, pg_class.relname
FROM pg_catalog.pg_inherits
INNER JOIN pg_catalog.pg_class ON (pg_inherits.inhrelid = pg_class.oid)
INNER JOIN pg_catalog.pg_namespace ON (pg_class.relnamespace = pg_namespace.oid)
WHERE inhparent = 'pp'::regclass;
... but this will only find cc.
For multi-depth inheritance (ie tableC inherits tableB inherits tableA) you have to extend that via a recursive CTE or a loop in PL/PgSQL, using the children of the last loop as parents in the next.
Update: Here's an 8.3 compatible version that should recursively find all tables that inherit directly or indirectly from a given parent. If multiple inheritance is used, it should find any table that has the target table as one of its parents at any point along the tree.
CREATE OR REPLACE FUNCTION find_children(oid) RETURNS SETOF oid as $$
SELECT i.inhrelid FROM pg_catalog.pg_inherits i WHERE i.inhparent = $1
UNION
SELECT find_children(i.inhrelid) FROM pg_catalog.pg_inherits i WHERE i.inhparent = $1;
$$ LANGUAGE 'sql' STABLE;
CREATE OR REPLACE FUNCTION find_children_of(parentoid IN regclass, schemaname OUT name, tablename OUT name) RETURNS SETOF record AS $$
SELECT pg_namespace.nspname, pg_class.relname
FROM find_children($1) inh(inhrelid)
INNER JOIN pg_catalog.pg_class ON (inh.inhrelid = pg_class.oid)
INNER JOIN pg_catalog.pg_namespace ON (pg_class.relnamespace = pg_namespace.oid);
$$ LANGUAGE 'sql' STABLE;
Usage:
regress=# SELECT * FROM find_children_of('pp'::regclass);
schemaname | tablename
------------+-----------
public | cc
public | dd
public | ccdd
(3 rows)
Here's the recursive CTE version, which will work if you update Pg, but won't work on your current version. It's much cleaner IMO.
WITH RECURSIVE inh AS (
SELECT i.inhrelid FROM pg_catalog.pg_inherits i WHERE inhparent = 'pp'::regclass
UNION
SELECT i.inhrelid FROM inh INNER JOIN pg_catalog.pg_inherits i ON (inh.inhrelid = i.inhparent)
)
SELECT pg_namespace.nspname, pg_class.relname
FROM inh
INNER JOIN pg_catalog.pg_class ON (inh.inhrelid = pg_class.oid)
INNER JOIN pg_catalog.pg_namespace ON (pg_class.relnamespace = pg_namespace.oid);

The following statement retrieves all child tables of the table public.base_table_name:
select bt.relname as table_name, bns.nspname as table_schema
from pg_class ct
join pg_namespace cns on ct.relnamespace = cns.oid and cns.nspname = 'public'
join pg_inherits i on i.inhparent = ct.oid and ct.relname = 'base_table_name'
join pg_class bt on i.inhrelid = bt.oid
join pg_namespace bns on bt.relnamespace = bns.oid
It should work with 8.3 although I'm not 100% sure.

For those who are running a version of PostgreSQL with RECURSIVE support here's a function that finds derived tables for the specified base table.
CREATE OR REPLACE FUNCTION tables_derived_from(base_namespace name, base_table name)
RETURNS TABLE (table_schema name, table_name name, oid oid)
AS $BODY$
WITH RECURSIVE inherited_id AS
(
SELECT i.inhrelid AS oid
FROM pg_inherits i
JOIN pg_class base_t ON i.inhparent = base_t.oid
JOIN pg_namespace base_ns ON base_t.relnamespace = base_ns.oid
WHERE base_ns.nspname = base_namespace AND base_t.relname = base_table
UNION
SELECT i.inhrelid AS oid
FROM pg_inherits i
JOIN inherited_id b ON i.inhparent = b.oid
)
SELECT child_ns.nspname as table_schema, child_t.relname as table_name, child_t.oid
FROM inherited_id i
JOIN pg_class child_t ON i.oid = child_t.oid
JOIN pg_namespace child_ns ON child_t.relnamespace = child_ns.oid
ORDER BY 1, 2, 3;
$BODY$ LANGUAGE sql STABLE;

It's important to note that one table can inherit multiple tables, and none of the solutions listed really expose that; they just walk down the tree of a single parent. Consider:
CREATE TABLE a();
CREATE TABLE b();
CREATE TABLE ab_() INHERITS (a,b);
CREATE TABLE ba_() INHERITS (b,a);
CREATE TABLE ab__() INHERITS (ab_);
CREATE TABLE ba__() INHERITS (ba_);
CREATE TABLE ab_ba_() INHERITS (ab_, ba_);
CREATE TABLE ba_ab_() INHERITS (ba_, ab_);
WITH RECURSIVE inh AS (
SELECT i.inhparent::regclass, i.inhrelid::regclass, i.inhseqno FROM pg_catalog.pg_inherits i WHERE inhparent = 'a'::regclass
UNION
SELECT i.inhparent::regclass, i.inhrelid::regclass, i.inhseqno FROM inh INNER JOIN pg_catalog.pg_inherits i ON (inh.inhrelid = i.inhparent)
) SELECT * FROM inh;
inhparent | inhrelid | inhseqno
-----------+----------+----------
a | ab_ | 1
a | ba_ | 2
ab_ | ab__ | 1
ba_ | ba__ | 1
ab_ | ab_ba_ | 1
ba_ | ab_ba_ | 2
ba_ | ba_ab_ | 1
ab_ | ba_ab_ | 2
(8 rows)
Notice that b doesn't show up at all which is incorrect, as both ab_ and ba_ inherit b.
I suspect the "best" way to handle this would be a column that's text[] and contains (array[inhparent::regclass])::text for each table. That would give you something like
inhrelid path
ab_ {"{a,b}"}
ba_ {"{b,a}"}
ab_ba_ {"{a,b}","{b,a}"}
While obviously not ideal, that would at least expose the complete inheritance path and allow you to access it with enough gymnastics. Unfortunately, constructing that is not at all easy.
A somewhat simpler alternative is not to include the full inheritance path at each level, only each tables direct parents. That would give you this:
inhrelid parents
ab_ {a,b}
ba_ {b,a}
ab_ba_ {ab_,ba_}

Related

OID type in regular postgres function

I have a PL/pgSQL function, which fetch data from pg_catalog.pg_constraint table to generate restore FK statements like: ALTER TABLE table_name ADD CONSTRAINT constraint_name FOREIGN KEY (column) REFERENCES table_name (column);.
Firstly I find oid of the table, then I put that table oid into variable table_oid OID; and make some stuff with it.
My question is.. Is it OK to use OID type variable inside function or I should better use BIGINT or something?
Example:
CREATE OR REPLACE FUNCTION func()
RETURNS VOID AS
$$
DECLARE
row RECORD;
table_oid OID; --> Is it OK or I should use BIGINT?
BEGIN
...
SELECT pg_class.oid
FROM pg_catalog.pg_class
INNER JOIN pg_catalog.pg_namespace ON pg_namespace.oid = pg_class.relnamespace
WHERE pg_class.relname = row.table_name
AND pg_namespace.nspname = row.schema_name INTO table_oid;
...
SELECT nspname, relname, 'ALTER TABLE '||nspname||'.'||relname||' ADD CONSTRAINT '||conname||' '||pg_catalog.pg_get_constraintdef(pg_constraint.oid)||';'
FROM pg_catalog.pg_constraint
INNER JOIN pg_class ON conrelid = pg_class.oid
INNER JOIN pg_namespace ON pg_namespace.oid = pg_class.relnamespace
WHERE confrelid = table_oid --> I use this variable here
OR conrelid = table_oid --> ...and here
AND contype = 'f';
END;
$$ LANGUAGE plpgsql;
There is nothing wrong with using oid like any other data type.
The only thing that you should keep in mind is that the OIDs that PostgreSQL uses internally to identify objects like tables are subject to change during an upgrade or restore from a dump. So you should not use oids to permanently store references to system objects.
The same applies to the ref* types, which are OIDs under the hood.

Show only list of tables without child partitions

I would like to show only the list of top level tables without child partitioned tables in PostgreSQL. (Currently using PostgreSQL 12.)
\dt in psql gives me all tables, including partitions of tables. I see this:
postgres=# \dt
List of relations
Schema | Name | Type | Owner
--------+------------------------------+-------------------+--------
public | tablea | table | me
public | partitionedtable1 | partitioned table | me
public | partitionedtable1_part1 | table | me
public | partitionedtable1_part2 | table | me
public | partitionedtable1_part3 | table | me
public | tableb | table | me
But I want a list like this, without child partitions of the parent partitioned table:
List of relations
Schema | Name | Type | Owner
--------+------------------------------+-------------------+--------
public | tablea | table | me
public | partitionedtable1 | partitioned table | me
public | tableb | table | me
Query to get all ordinary tables, including root partitioned tables, but excluding all non-root partitioned tables:
SELECT n.nspname AS "Schema"
, c.relname AS "Name"
, CASE c.relkind
WHEN 'p' THEN 'partitioned table'
WHEN 'r' THEN 'ordinary table'
-- more types?
ELSE 'unknown table type'
END AS "Type"
, pg_catalog.pg_get_userbyid(c.relowner) AS "Owner"
FROM pg_catalog.pg_class c
JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
WHERE c.relkind = ANY ('{p,r,""}') -- add more types?
AND NOT c.relispartition -- exclude child partitions
AND n.nspname !~ ALL ('{^pg_,^information_schema$}') -- exclude system schemas
ORDER BY 1, 2;
The manual about relispartition:
... True if table or index is a partition
pg_get_userbyid() is instrumental to get the name of the owning role.
There are more types of "tables" in Postgres 12. The manual about relkind:
r = ordinary table, i = index, S = sequence, t = TOAST table,
v = view, m = materialized view, c = composite type, f =
foreign table, p = partitioned table, I = partitioned index
Postgres 12 also added the meta-command \dP to psql:
The manual:
\dP[itn+] [ pattern ]
Lists partitioned relations. If pattern is specified, only entries whose name matches the pattern are listed. The modifiers t (tables) and i (indexes) can be appended to the command, filtering the kind of relations to list. By default, partitioned tables and indexes are listed.
If the modifier n (“nested”) is used, or a pattern is specified, then non-root partitioned relations are included, and a column is shown displaying the parent of each partitioned relation.
So \dPt gets all root partitioned tables - but not ordinary tables.
Version 1
I can't test this right now, but this ought to give you only top-level tables that are partitioned
select relname
from pg_class
where oid in (select partrelid from pg_partitioned_table);
You should be able to refine/expand that to get more details.
Version 2
Here's a comically verbose solution:
with
partition_parents as (
select relnamespace::regnamespace::text as schema_name,
relname as table_name,
'partition_parent' as info,
*
from pg_class
where relkind = 'p'), -- The parent table is relkind 'p', the partitions are regular tables, relkind 'r'
unpartitioned_tables as (
select relnamespace::regnamespace::text as schema_name,
relname as table_name,
'unpartitioned_table' as info,
*
from pg_class
where relkind = 'r'
and not relispartition
) -- Regular table
select * from partition_parents where schema_name not in ('information_schema','pg_catalog','api','extensions') -- Whatever you've got for schemas
union
select * from unpartitioned_tables where schema_name not in ('information_schema','pg_catalog','api','extensions') -- Whatever you've got for schemas
order by 1,2,3
You should be able to cut the size of that way down to match what you really want. Someone here who really gets the system catalogs should likely be able to provide a more concise version. In the plus column, it's kind of nice to add in the "partition_parent" versus "unpartitioned_table" detail, as above.
If you don't have to use a \d* shortcut, this query should work (though you'll need to filter out schemas not in your search_path):
SELECT relname FROM pg_class WHERE relkind IN ('r','p') AND NOT relispartition;
--do some test in greenplum 6.14
--to find normal table ,partition table
SELECT
*
FROM
(
SELECT
t1.schemaname,
t1.tablename,
t1.tableowner,
CASE
WHEN t3.tablename IS NULL
AND t2.tablename IS NULL THEN
'r'
WHEN t3.tablename IS NOT NULL
AND t2.tablename IS NULL THEN
'p-root' ELSE'p-child'
END AS tabletype,
t4.actionname,
t4.statime
FROM
pg_tables t1
LEFT JOIN pg_partitions t2 ON t1.tablename = t2.partitiontablename
AND t1.schemaname = t2.partitionschemaname
LEFT JOIN ( SELECT DISTINCT schemaname, tablename FROM pg_partitions WHERE schemaname IN ( 'public', 'ods', 'tmp' ) ) t3 ON t1.tablename = t3.tablename
AND t1.schemaname = t3.schemaname
LEFT JOIN (
SELECT
*
FROM
(
SELECT
schemaname,
objname,
actionname,
statime,
ROW_NUMBER ( ) OVER ( PARTITION BY schemaname, objname ORDER BY statime DESC ) AS rn
FROM
pg_catalog.pg_stat_operations
WHERE
classname = 'pg_class'
AND schemaname IN ( 'public', 'ods', 'tmp' )
AND actionname IN ( 'CREATE', 'ALTER' )
) n
WHERE
n.rn = 1
) t4 ON t1.schemaname = t4.schemaname
AND t1.tablename = t4.objname
WHERE
t1.schemaname IN ( 'public', 'ods', 'tmp' )
) o
WHERE
tabletype IN ( 'r', 'p-root' )
ORDER BY
1,
2,
3,
4

Getting a column comment in PostgreSql [duplicate]

I'm running a project on a Postgres database and need to retrieve the comments on columns within the DB to be used as table headings and such. I have seen that there are a couple of built in functions (pg_description and col_description) but i haven't been able to find examples on how to use them and playing around with them has proved pretty futile.
So I was wondering if any has been able to do this before and if so, how?
select
c.table_schema,
c.table_name,
c.column_name,
pgd.description
from pg_catalog.pg_statio_all_tables as st
inner join pg_catalog.pg_description pgd on (
pgd.objoid = st.relid
)
inner join information_schema.columns c on (
pgd.objsubid = c.ordinal_position and
c.table_schema = st.schemaname and
c.table_name = st.relname
);
It all works by oid,
mat=> SELECT c.oid FROM pg_catalog.pg_class c WHERE c.relname = 'customers';
oid
-------
23208
(1 row)
Now, I have the oid for that table, so I can ask :
mat=> select pg_catalog.obj_description(23208);
obj_description
-------------------
Customers
(1 row)
Then, I can ask for the description of the fourth column :
mat=> select pg_catalog.col_description(23208,4);
col_description
-----------------------------------------
Customer codes, CHS, FACTPOST, POWER...
(1 row)
If you want to know which queries does psql run when you do \dt+ or \d+ customers, just run it with -E.
Just to be here if somebody will need it.
There are many answers here, but none of them was as simple as I would like it to be. So, based on previous answers and current postgres 9.4, I have created this query:
SELECT
obj_description(format('%s.%s',isc.table_schema,isc.table_name)::regclass::oid, 'pg_class') as table_description,
pg_catalog.col_description(format('%s.%s',isc.table_schema,isc.table_name)::regclass::oid,isc.ordinal_position) as column_description
FROM
information_schema.columns isc
It fetches table and column descriptions, without any confusing joins and ugly string concatenations.
Take care with schemas, this code considers them:
SELECT
cols.column_name, (
SELECT
pg_catalog.col_description(c.oid, cols.ordinal_position::int)
FROM
pg_catalog.pg_class c
WHERE
c.oid = (SELECT ('"' || cols.table_name || '"')::regclass::oid)
AND c.relname = cols.table_name
) AS column_comment
FROM
information_schema.columns cols
WHERE
cols.table_catalog = 'your_database'
AND cols.table_name = 'your_table'
AND cols.table_schema = 'your_schema';
References:
Postgresql Document Table and Column Description Comments on Table and Column
Determining the OID of a table in Postgres 9.1?
A slight change to one of the other answers which only gives you columns that have comments on them, this gives you all columns whether they have a comment or not.
select c.table_schema, st.relname as TableName, c.column_name,
pgd.description
from pg_catalog.pg_statio_all_tables as st
inner join information_schema.columns c
on c.table_schema = st.schemaname
and c.table_name = st.relname
left join pg_catalog.pg_description pgd
on pgd.objoid=st.relid
and pgd.objsubid=c.ordinal_position
where st.relname = 'YourTableName';
This works for me using the PostBooks 3.2.2 DB:
select cols.column_name,
(select pg_catalog.obj_description(oid) from pg_catalog.pg_class c where c.relname=cols.table_name) as table_comment
,(select pg_catalog.col_description(oid,cols.ordinal_position::int) from pg_catalog.pg_class c where c.relname=cols.table_name) as column_comment
from information_schema.columns cols
where cols.table_catalog='postbooks' and cols.table_name='apapply'
Regards,
Sylnsr
If you just need to show the comments for your columns among other data, you can also use:
\d+ my_table
Enhance for #Nick and #mat suggestions: use
SELECT obj_description('schemaName.tableName'::regclass, 'pg_class');
when you have string name (not oid).
To avoid to remember 'pg_class' parameter, and to avoid ugly concatenations at the function calls, as (tname||'.'||schema)::regclass, an useful overload for obj_description:
CREATE FUNCTION obj_description(
p_rname text, p_schema text DEFAULT NULL,
p_catalname text DEFAULT 'pg_class'
) RETURNS text AS $f$
SELECT obj_description((CASE
WHEN strpos($1, '.')>0 OR $2 IS NULL OR $2='' THEN $1
ELSE $2||'.'||$1
END)::regclass, $3);
$f$ LANGUAGE SQL IMMUTABLE;
-- USAGE: obj_description('mytable')
-- SELECT obj_description('s.t');
-- PS: obj_description('s.t', 'otherschema') is a syntax error,
-- but not generates exception: returns the same as ('s.t')
Now is easy to use, because the table name (rname parameter) is a varchar and can be expressed with a separated field for schema name, as in the main tables and queries.
See also "Getting list of table comments in PostgreSQL" or the new pg9.3 Guide
This answer is a little late, but it popped up on a google search I did to research this problem. We only needed Table descriptions, but the method would be the same for columns.
The column descriptions are in the pg_description table also, referenced by objoid.
Add this view:
CREATE OR REPLACE VIEW our_tables AS
SELECT c.oid, n.nspname AS schemaname, c.relname AS tablename, d.description,
pg_get_userbyid(c.relowner) AS tableowner, t.spcname AS "tablespace",
c.relhasindex AS hasindexes, c.relhasrules AS hasrules, c.reltriggers > 0 AS hastriggers
FROM pg_class c
LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
LEFT JOIN pg_tablespace t ON t.oid = c.reltablespace
LEFT JOIN pg_description d ON c.oid = d.objoid
WHERE c.relkind = 'r'::"char";
ALTER TABLE our_tables OWNER TO postgres;
GRANT SELECT, UPDATE, INSERT, DELETE, REFERENCES, TRIGGER ON TABLE our_tables TO postgres;
GRANT SELECT ON TABLE our_tables TO public;
Then run:
SELECT tablename, description FROM our_tables WHERE schemaname = 'public'
The view is a modified version of the pg_tables view which adds in the description column.
You could also monkey around with the view definition to make it a single query.
I accessed table comments like this:
select c.relname table_name, pg_catalog.obj_description(c.oid) as comment from pg_catalog.pg_class c where c.relname = 'table_name';
and column comments thusly:
SELECT c.column_name, pgd.description FROM pg_catalog.pg_statio_all_tables as st inner join pg_catalog.pg_description pgd on (pgd.objoid=st.relid) inner join information_schema.columns c on (pgd.objsubid=c.ordinal_position and c.table_schema=st.schemaname and c.table_name=st.relname and c.table_name = 'table_name' and c.table_schema = 'public');
I asked a similar question about Postgresql comments last month. If you dig through that, you'll come across some Perl code over on my blog that automates the process of extracting a comment.
To pull out the column names of a table, you can use something like the following:
select
a.attname as "colname"
,a.attrelid as "tableoid"
,a.attnum as "columnoid"
from
pg_catalog.pg_attribute a
inner join pg_catalog.pg_class c on a.attrelid = c.oid
where
c.relname = 'mytable' -- better to use a placeholder
and a.attnum > 0
and a.attisdropped is false
and pg_catalog.pg_table_is_visible(c.oid)
order by a.attnum
You can then use the tableoid,columnoid tuple to extract the comment of each column (see my question).
I just found this here. It will provide you with all kind of metadata on one specific table (type, default value, not null flag, length, comment, foreign key name, primary key name). It seems to work well.
SELECT pg_tables.tablename, pg_attribute.attname AS field,
format_type(pg_attribute.atttypid, NULL) AS "type",
pg_attribute.atttypmod AS len,
(SELECT col_description(pg_attribute.attrelid,
pg_attribute.attnum)) AS comment,
CASE pg_attribute.attnotnull
WHEN false THEN 1 ELSE 0
END AS "notnull",
pg_constraint.conname AS "key", pc2.conname AS ckey,
(SELECT pg_attrdef.adsrc FROM pg_attrdef
WHERE pg_attrdef.adrelid = pg_class.oid
AND pg_attrdef.adnum = pg_attribute.attnum) AS def
FROM pg_tables, pg_class
JOIN pg_attribute ON pg_class.oid = pg_attribute.attrelid
AND pg_attribute.attnum > 0
LEFT JOIN pg_constraint ON pg_constraint.contype = 'p'::"char"
AND pg_constraint.conrelid = pg_class.oid AND
(pg_attribute.attnum = ANY (pg_constraint.conkey))
LEFT JOIN pg_constraint AS pc2 ON pc2.contype = 'f'::"char"
AND pc2.conrelid = pg_class.oid
AND (pg_attribute.attnum = ANY (pc2.conkey))
WHERE pg_class.relname = pg_tables.tablename
-- AND pg_tables.tableowner = "current_user"()
AND pg_attribute.atttypid <> 0::oid
AND tablename='your_table'
ORDER BY field ASC
Source: http://golden13.blogspot.de/2012/08/how-to-get-some-information-about_7.html
Ok, so i worked it out to degree...
select col_description(table id, column number)...
ie: select col_description(36698,2);
That worked, but is there an easier way to do this maybe bringing all the comments on all the columns and using the table name instead of the oid???
To display comments from all columns of all table :
SELECT
cols.table_name,
cols.column_name, (
SELECT
pg_catalog.col_description(c.oid, cols.ordinal_position::int)
FROM
pg_catalog.pg_class c
WHERE
c.oid = (SELECT ('"' || cols.table_name || '"')::regclass::oid)
AND c.relname = cols.table_name
) AS column_comment
FROM
information_schema.columns cols
WHERE
cols.table_name IN (SELECT cols.table_name FROM information_schema.columns)
AND cols.table_catalog = 'your_database_name'
AND cols.table_schema = 'your_schema_name';
You need to execute this query outside any schema/catalog/db
This query is based on another answer in this question which display comments from one table only
To extend on the response provided by #amxy; I found that adding a schema filter can help in some environments. As I found #amxy's solution didn't work until I added by schema filters
SELECT
pg_tables.schemaname,
pg_tables.TABLENAME,
pg_attribute.attname AS field,
format_type(pg_attribute.atttypid, NULL) AS "type",
pg_attribute.atttypmod AS len,
(
SELECT col_description(pg_attribute.attrelid, pg_attribute.attnum)) AS COMMENT,
CASE pg_attribute.attnotnull
WHEN FALSE THEN 1
ELSE 0
END AS "notnull",
pg_constraint.conname AS "key", pc2.conname AS ckey,
(
SELECT pg_attrdef.adsrc
FROM pg_attrdef
WHERE pg_attrdef.adrelid = pg_class.oid
AND pg_attrdef.adnum = pg_attribute.attnum) AS def
FROM pg_tables, pg_class
JOIN pg_attribute
ON pg_class.oid = pg_attribute.attrelid
AND pg_attribute.attnum > 0
LEFT JOIN pg_constraint
ON pg_constraint.contype = 'p'::"char"
AND pg_constraint.conrelid = pg_class.oid
AND
(pg_attribute.attnum = ANY (pg_constraint.conkey))
LEFT JOIN pg_constraint AS pc2
ON pc2.contype = 'f'::"char"
AND pc2.conrelid = pg_class.oid
AND (pg_attribute.attnum = ANY (pc2.conkey))
WHERE pg_class.relname = pg_tables.TABLENAME
AND pg_tables.schemaname IN ('op', 'im', 'cs','usr','li')
-- AND pg_tables.tableowner = "current_user"()
AND pg_attribute.atttypid <> 0::oid
---AND TABLENAME='your_table'
ORDER BY pg_tables.schemaname,
pg_tables.TABLENAME ASC;
RESULTS:
SELECT
relname table_name,
obj_description(oid) table_description,
column_name,
pgd.description column_description
FROM pg_class
INNER JOIN
information_schema.columns
ON table_name = pg_class.relname
LEFT JOIN
pg_catalog.pg_description pgd
ON pgd.objsubid = ordinal_position
WHERE
relname = 'your_table_name'
SELECT sc.table_schema , sc.table_name, sc.column_name, col_description(pc."oid" , sc.ordinal_position) col_description FROM pg_class pc
INNER JOIN pg_namespace ns ON ns."oid" =pc.relnamespace
INNER JOIN information_schema.COLUMNS sc ON sc.table_name=pc.relname AND sc.table_schema=ns.nspname
WHERE 1=1
AND upper(ns.nspname) = 'TABLE_SCHEMA'
AND upper(pc.relname) = 'TABLE_NAME'
Retrieving Comments from a PostgreSQL DB

Find all partition tables "inheriting" from master table

Say I have a table, "foo", with partition tables "foo1", "foo2", and "foo3". But at the current moment all I know is there are parition tables which inherit from table "foo". How can I find that foo has 3 partitions, foo1, foo2, and foo3?
To list all your partitions (child tables) - tested with PG v9-v13:
SELECT c.relname FROM pg_inherits i JOIN pg_class p ON i.inhparent = p.oid
JOIN pg_class c ON i.inhrelid = c.oid WHERE p.relname='parentTableName';
Use pg_inherits. Example:
create table my_parent_table (id int);
create table my_child_table_no_1 (check (id < 10)) inherits (my_parent_table);
create table my_child_table_no_2 (check (id >= 10)) inherits (my_parent_table);
select relname
from pg_inherits i
join pg_class c on c.oid = inhrelid
where inhparent = 'my_parent_table'::regclass
relname
---------------------
my_child_table_no_1
my_child_table_no_2
(2 rows)
You can also select check constraints using pg_constraint:
select relname "child table", consrc "check"
from pg_inherits i
join pg_class c on c.oid = inhrelid
join pg_constraint on c.oid = conrelid
where contype = 'c'
and inhparent = 'my_parent_table'::regclass
child table | check
---------------------+------------
my_child_table_no_1 | (id < 10)
my_child_table_no_2 | (id >= 10)
(2 rows)
Starting with Postgres 12, there is a built-in function:
select *
from pg_partition_tree('the_table'::regclass)
where parentrelid is not null;
The way I dig into such catalog information is by using psql. Start psql with the -eE options:
psql -eE <your database>
And then show your table:
\d <your table>
This will list all the queries which psql generates to fetch the information from the catalog. This includes inherited tables.
Keep in mind that it is possible that the catalog changes from one major version to another - although for such basic functionality it is unlikely.

How can I get a list of all functions stored in the database of a particular schema in PostgreSQL?

I want to be able to connect to a PostgreSQL database and find all of the functions for a particular schema.
My thought was that I could make some query to pg_catalog or information_schema and get a list of all functions, but I can't figure out where the names and parameters are stored. I'm looking for a query that will give me the function name and the parameter types it takes (and what order it takes them in).
Is there a way to do this?
\df <schema>.*
in psql gives the necessary information.
To see the query that's used internally connect to a database with psql and supply an extra "-E" (or "--echo-hidden") option and then execute the above command.
After some searching, I was able to find the information_schema.routines table and the information_schema.parameters tables. Using those, one can construct a query for this purpose. LEFT JOIN, instead of JOIN, is necessary to retrieve functions without parameters.
SELECT routines.routine_name, parameters.data_type, parameters.ordinal_position
FROM information_schema.routines
LEFT JOIN information_schema.parameters ON routines.specific_name=parameters.specific_name
WHERE routines.specific_schema='my_specified_schema_name'
ORDER BY routines.routine_name, parameters.ordinal_position;
If any one is interested here is what query is executed by psql on postgres 9.1:
SELECT n.nspname as "Schema",
p.proname as "Name",
pg_catalog.pg_get_function_result(p.oid) as "Result data type",
pg_catalog.pg_get_function_arguments(p.oid) as "Argument data types",
CASE
WHEN p.proisagg THEN 'agg'
WHEN p.proiswindow THEN 'window'
WHEN p.prorettype = 'pg_catalog.trigger'::pg_catalog.regtype THEN 'trigger'
ELSE 'normal'
END as "Type"
FROM pg_catalog.pg_proc p
LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace
WHERE pg_catalog.pg_function_is_visible(p.oid)
AND n.nspname <> 'pg_catalog'
AND n.nspname <> 'information_schema'
ORDER BY 1, 2, 4;
You can get what psql runs for a backslash command by running psql with the -E flag.
There's a handy function, oidvectortypes, that makes this a lot easier.
SELECT format('%I.%I(%s)', ns.nspname, p.proname, oidvectortypes(p.proargtypes))
FROM pg_proc p INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid)
WHERE ns.nspname = 'my_namespace';
Credit to Leo Hsu and Regina Obe at Postgres Online for pointing out oidvectortypes. I wrote similar functions before, but used complex nested expressions that this function gets rid of the need for.
See related answer.
(edit in 2016)
Summarizing typical report options:
-- Compact:
SELECT format('%I.%I(%s)', ns.nspname, p.proname, oidvectortypes(p.proargtypes))
-- With result data type:
SELECT format(
'%I.%I(%s)=%s',
ns.nspname, p.proname, oidvectortypes(p.proargtypes),
pg_get_function_result(p.oid)
)
-- With complete argument description:
SELECT format('%I.%I(%s)', ns.nspname, p.proname, pg_get_function_arguments(p.oid))
-- ... and mixing it.
-- All with the same FROM clause:
FROM pg_proc p INNER JOIN pg_namespace ns ON (p.pronamespace = ns.oid)
WHERE ns.nspname = 'my_namespace';
NOTICE: use p.proname||'_'||p.oid AS specific_name to obtain unique names, or to JOIN with information_schema tables — see routines and parameters at #RuddZwolinski's answer.
The function's OID (see pg_catalog.pg_proc) and the function's specific_name (see information_schema.routines) are the main reference options to functions. Below, some useful functions in reporting and other contexts.
--- --- --- --- ---
--- Useful overloads:
CREATE FUNCTION oidvectortypes(p_oid int) RETURNS text AS $$
SELECT oidvectortypes(proargtypes) FROM pg_proc WHERE oid=$1;
$$ LANGUAGE SQL IMMUTABLE;
CREATE FUNCTION oidvectortypes(p_specific_name text) RETURNS text AS $$
-- Extract OID from specific_name and use it in oidvectortypes(oid).
SELECT oidvectortypes(proargtypes)
FROM pg_proc WHERE oid=regexp_replace($1, '^.+?([^_]+)$', '\1')::int;
$$ LANGUAGE SQL IMMUTABLE;
CREATE FUNCTION pg_get_function_arguments(p_specific_name text) RETURNS text AS $$
-- Extract OID from specific_name and use it in pg_get_function_arguments.
SELECT pg_get_function_arguments(regexp_replace($1, '^.+?([^_]+)$', '\1')::int)
$$ LANGUAGE SQL IMMUTABLE;
--- --- --- --- ---
--- User customization:
CREATE FUNCTION pg_get_function_arguments2(p_specific_name text) RETURNS text AS $$
-- Example of "special layout" version.
SELECT trim(array_agg( op||'-'||dt )::text,'{}')
FROM (
SELECT data_type::text as dt, ordinal_position as op
FROM information_schema.parameters
WHERE specific_name = p_specific_name
ORDER BY ordinal_position
) t
$$ LANGUAGE SQL IMMUTABLE;
Run below SQL query to create a view which will show all functions:
CREATE OR REPLACE VIEW show_functions AS
SELECT routine_name FROM information_schema.routines
WHERE routine_type='FUNCTION' AND specific_schema='public';
Get List of function_schema and function_name...
SELECT
n.nspname AS function_schema,
p.proname AS function_name
FROM
pg_proc p
LEFT JOIN pg_namespace n ON p.pronamespace = n.oid
WHERE
n.nspname NOT IN ('pg_catalog', 'information_schema')
ORDER BY
function_schema,
function_name;
Is a good idea named the functions with commun alias on the first words for filtre the name with LIKE
Example with public schema in Postgresql 9.4, be sure to replace with his scheme
SELECT routine_name
FROM information_schema.routines
WHERE routine_type='FUNCTION'
AND specific_schema='public'
AND routine_name LIKE 'aliasmyfunctions%';
Example:
perfdb-# \df information_schema.*;
List of functions
Schema | Name | Result data type | Argument data types | Type
information_schema | _pg_char_max_length | integer | typid oid, typmod integer | normal
information_schema | _pg_char_octet_length | integer | typid oid, typmod integer | normal
information_schema | _pg_datetime_precision| integer | typid oid, typmod integer | normal
.....
information_schema | _pg_numeric_scale | integer | typid oid, typmod integer | normal
information_schema | _pg_truetypid | oid | pg_attribute, pg_type | normal
information_schema | _pg_truetypmod | integer | pg_attribute, pg_type | normal
(11 rows)
This function returns all user defined routines in current database.
SELECT pg_get_functiondef(p.oid) FROM pg_proc p
INNER JOIN pg_namespace ns ON p.pronamespace = ns.oid
WHERE ns.nspname = 'public';
The joins in abovementioned answers returns not only input parameters, but also outputs. So it is necessary to specify also parameter_mode. This select will return list of functions with its input parametrs (if having some). Postgres 14.
select r.routine_name, array_agg(p.data_type::text order by p.ordinal_position) from information_schema.routines r left join information_schema.parameters p on r.specific_name = p.specific_name
where r.routine_type = 'FUNCTION' and r.specific_schema = 'schema_name' and (p.parameter_mode = 'IN' or p.parameter_mode is null)
group by r.routine_name order by r.routine_name;