Can psql output a description of all tables, but only tables? - postgresql

When I do \d public.* I get a list of descriptions of tables, but also of all other indices etc.
When I do \dt public.* I get a list of tablenames, but not the full descriptions of those tables.
Is there a command that gives me the full descriptions of all tables without the other object types?
Version used: psql --version outputs psql (PostgreSQL) 11.5

You can use obj_description() for that:
select tbl.relname as table_name,
obj_description(tbl.oid) as comment
from pg_class tbl
join pg_namespace n on n.oid = tbl.relnamespace
where n.nspname = 'public'
and tbl.relkind = 'r' ;

Related

Why my empty postgres database is 7MB?

I just created an new database and it already takes up 7MB. Do you know what is taking up this much space? Is there a way to get the "real" size of the database used as in how much data is stored?
0f41ba72-a1ea-4516-a9f0-de8a3609bc4a=> select pg_size_pretty(pg_database_size(current_database()));
pg_size_pretty
----------------
7055 kB
(1 row)
0f41ba72-a1ea-4516-a9f0-de8a3609bc4a=> \dt
No relations found.
Well, even you don't created any relation yet the new database is not empty. When a CREATE DATABASE is issued, Postgres copy a TEMPLATE database - which comes with catalog tables - to a new database. In fact, "Nothing is created, everything is transformed". You can use commands below to inspect this:
--Size per table
SELECT pg_size_pretty(pg_total_relation_size(oid)), relname FROM pg_class WHERE relkind = 'r' AND NOT relisshared;
--Total size
SELECT pg_size_pretty(sum(pg_total_relation_size(oid))) FROM pg_class WHERE relkind = 'r' AND NOT relisshared;
--Total size of databases
SELECT pg_size_pretty(pg_database_size(oid)), datname FROM pg_database;
A quote from the docs:
By default, the new database will be created by cloning the standard
system database template1.
An empty database contains system catalogs and The Information Schema.
Execute this query to see them:
select nspname as schema, relname as table, pg_total_relation_size(c.oid)
from pg_class c
join pg_namespace n on n.oid = relnamespace
order by 3 desc;
schema | table | pg_total_relation_size
--------------------+-----------------------------+------------------------
pg_catalog | pg_depend | 1146880
pg_catalog | pg_proc | 950272
pg_catalog | pg_rewrite | 589824
pg_catalog | pg_attribute | 581632
... etc
You can get the total size of non-system relations with the query:
select sum(pg_total_relation_size(c.oid))
from pg_class c
join pg_namespace n on n.oid = relnamespace
where nspname not in ('information_schema', 'pg_catalog', 'pg_toast');
The query returns null on empty database.
Every PostgreSQL databases has own system catalogue .. 7MB. So your numbers are correct. PostgreSQL is designed for client-server architecture and 1GB and longer databases - so this cost is not significant.
If you need reduced space allocation, you can try embedded databases like SQLite or Firebird.

How to retrieve the comment of a PostgreSQL database?

I recently discovered you can attach a comment to all sort of objects in PostgreSQL. In particular, I'm interested on playing with the comment of a database. For example, to set the comment of a database:
COMMENT ON DATABASE mydatabase IS 'DB Comment';
However, what is the opposite statement, to get the comment of mydatabase?
From the psql command line, I can see the comment along with other information as a result of the \l+ command; which I could use with the aid of awk in order to achieve my goal. But I'd rather use an SQL statement, if possible.
First off, your query for table comments can be simplified using a cast to the appropriate object identifier type:
SELECT description
FROM pg_description
WHERE objoid = 'myschema.mytbl'::regclass;
The schema part is optional. If you omit it, your current search_path decides visibility of any table named mytbl.
Better yet, there are dedicated functions in PostgreSQL to simplify and canonize these queries. The manual:
obj_description(object_oid, catalog_name) ... get comment for a
database object
shobj_description(object_oid, catalog_name) ... get comment for a shared database object
Description for table:
SELECT obj_description('myschema.mytbl'::regclass, 'pg_class');
Description for database:
SELECT pg_catalog.shobj_description(d.oid, 'pg_database') AS "Description"
FROM pg_catalog.pg_database d
WHERE datname = 'mydb';
How do you find out about that?
Well, reading the excellent manual is enlightening. :)
But there is a more direct route in this case: most psql meta commands are implemented with plain SQL. Start a session with psql -E, to see the magic behind the curtains. The manual:
-E
--echo-hidden
Echo the actual queries generated by \d and other backslash commands. You can use this to study psql's internal operations. This
is equivalent to setting the variable ECHO_HIDDEN to on.
To get the comment on the database, use the following query:
select description from pg_shdescription
join pg_database on objoid = pg_database.oid
where datname = '<database name>'
This query will get you table comment for the given table name:
select description from pg_description
join pg_class on pg_description.objoid = pg_class.oid
where relname = '<your table name>'
If you use the same table name in different schemas, you need to modify it a bit:
select description from pg_description
join pg_class on pg_description.objoid = pg_class.oid
join pg_namespace on pg_class.relnamespace = pg_namespace.oid
where relname = '<table name>' and nspname='<schema name>'
For tables, try
\dd TABLENAME
This shows the comment I added to a table
This query will get only table comment for all tables
SELECT RelName,Description
FROM pg_Description
JOIN pg_Class
ON pg_Description.ObjOID = pg_Class.OID
WHERE ObjSubID = 0
This query will return the comment of a table
SELECT obj_description('public.myTable'::regclass)
FROM pg_class
WHERE relkind = 'r' limit 1
To get the comments on all the databases (not on their objects like tables etc.) :
SELECT datname, shobj_description( oid, 'pg_database' ) AS comment
FROM pg_database
ORDER BY datname
An example showing databases, sizes and descriptions from a shell script:
psql -U postgres -c "SELECT datname,
format('%8s MB.', pg_database_size(datname)/1000000) AS size,
shobj_description( oid, 'pg_database' ) as comment
FROM pg_database ORDER BY datname"
Sample output:
datname | size | comment
----------------------+--------------+-----------------------------------------------------
last_wikidb | 18 MB. | Wiki backup from yesterday
postgres | 7 MB. | default administrative connection database
previous_wikidb | 18 MB. | Wiki backup from the day before yesterday
some_db | 82 MB. |
template0 | 7 MB. | unmodifiable empty database
template1 | 7 MB. | default template for new databases

Dumping tables and schemas that are accessible to me only?

Is it possible to dump tables and schemas that are accessible to me only in PostgreSQL?
First find the relations you have access to (this can be tweaked to pull schemas too)
with relnames as (SELECT relname FROM pg_class
WHERE relkind='r' and relnamespace = (select oid from pg_namespace where nspname = 'public'))
select array_agg(relname) from relnames WHERE has_table_privilege(SESSION_USER, relname, 'SELECT');
Now we aren't quite done now because that just creates an array of tables we have access to. We now need to change this to use array_to_string to get something we can feed into pg_dump:
with relnames as (SELECT relname FROM pg_class
WHERE relkind='r' and relnamespace = (select oid from pg_namespace where nspname = 'public'))
select array_to_string(array_agg(relname), ' -t ') from relnames WHERE has_table_privilege(SESSION_USER, relname, 'SELECT');
the above queries can be tweaked (changing the pg_namespace subquery) to pull namespaces you have access to and you could change it to a join to pull fully qualified table names.

Query the schema details of a table in PostgreSQL?

I need to know the column type in PostgreSQL (i.e. varchar(20)). I know that I could probably find this using \d something in psql, but I need it to be done with a select query.
Is this possible in PostgreSQL?
There is a much simpler way in PostgreSQL to get the type of a column.
SELECT pg_typeof(col)::text FROM tbl LIMIT 1
The table must hold at least one row, of course. And you only get the base type without type modifiers (if any). Use the alternative below if you need that, too.
You can use the function for constants as well. The manual on pg_typeof().
For an empty (or any) table you can use query the system catalog pg_attribute to get the full list of columns and their respective type in order:
SELECT attnum, attname AS column, format_type(atttypid, atttypmod) AS type
FROM pg_attribute
WHERE attrelid = 'myschema.mytbl'::regclass -- optionally schema-qualified
AND NOT attisdropped
AND attnum > 0
ORDER BY attnum;
The manual on format_type() and on object identifier types like regclass.
You can fully describe a table using postgres with the following query:
SELECT
a.attname as Column,
pg_catalog.format_type(a.atttypid, a.atttypmod) as Datatype
FROM
pg_catalog.pg_attribute a
WHERE
a.attnum > 0
AND NOT a.attisdropped
AND a.attrelid = (
SELECT c.oid
FROM pg_catalog.pg_class c
LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
WHERE c.relname ~ '^(TABLENAME)$'
AND pg_catalog.pg_table_is_visible(c.oid)
)
Tith this you will retrieve column names and data type.
It is also possible to start psql client using the -E option
$ psql -E
And then a simple \d mytable will output the queries used by postgres to describe the table. It work for every psql describe commands.
Yes, look at the information_schema.

How to check permissions to functions under psql console

Could you tell me please how to check permissions to functions with psql console but without being overwhelmed with source code and descirption (like when using \df+).
For a simpler query, use:
SELECT proacl FROM pg_proc WHERE proname='FUNCTION-NAME';
The results is like:
proacl
----------------------------------------------------
{=X/postgres,postgres=X/postgres,test1=X/postgres}
(1 row)
which shows that test1 user also has access to this function.
For more details, see the discussion on psql's mailing list: psql missing feature: show permissions for functions.
You could query the system tables:
SELECT proname, rolname
FROM pg_proc pr,
pg_type tp,
pg_authid id
WHERE proowner = id.oid
AND tp.oid = pr.prorettype
AND pr.proisagg = FALSE
AND tp.typname <> 'trigger'
AND pr.pronamespace IN (
SELECT oid
FROM pg_namespace
WHERE nspname NOT LIKE 'pg_%'
AND nspname != 'information_schema'
);