Создадим базу данных и тестовые объекты:
=> CREATE DATABASE data_catalog;
CREATE DATABASE
=> \c data_catalog
You are now connected to database "data_catalog" as user "postgres".
=> CREATE TABLE employees(id serial PRIMARY KEY, name text, manager integer);
CREATE TABLE
=> CREATE VIEW top_managers AS SELECT * FROM employees WHERE manager IS NULL;
CREATE VIEW
Некоторые таблицы системного каталога нам уже знакомы из предыдущей темы. Это базы данных:
=> SELECT * FROM pg_database WHERE datname = 'data_catalog' \gx
-[ RECORD 1 ]-+------------- datname | data_catalog datdba | 10 encoding | 6 datcollate | en_US.UTF-8 datctype | en_US.UTF-8 datistemplate | f datallowconn | t datconnlimit | -1 datlastsysoid | 12327 datfrozenxid | 548 datminmxid | 1 dattablespace | 1663 datacl |
И схемы:
=> SELECT * FROM pg_namespace WHERE nspname = 'public' \gx
-[ RECORD 1 ]--------------------------------- nspname | public nspowner | 10 nspacl | {postgres=UC/postgres,=UC/postgres}
Важная таблица pg_class хранит описание целого ряда объектов: таблиц, представлений (включая материализованные), индексов, последовательностей. Все эти объекты называются в PostgreSQL общим словом "отношение" (relation), отсюда и префикс "rel" в названии столбцов:
=> SELECT relname, relkind, relnamespace, relfilenode, relowner, reltablespace FROM pg_class WHERE relname ~ '^(emp|top).*';
relname | relkind | relnamespace | relfilenode | relowner | reltablespace ------------------+---------+--------------+-------------+----------+--------------- employees_id_seq | S | 2200 | 16454 | 10 | 0 employees | r | 2200 | 16456 | 10 | 0 employees_pkey | i | 2200 | 16463 | 10 | 0 top_managers | v | 2200 | 16465 | 10 | 0 (4 rows)
Типы объектов различаются по столбцу relkind.
Конечно, для каждого типа объектов имеет смысл только часть столбцов; кроме того, удобнее смотреть не на многочисленные OID, а на нормальные значения. Для этого существуют различные представления, например:
=> SELECT schemaname, tablename, tableowner, tablespace FROM pg_tables WhERE schemaname = 'public';
schemaname | tablename | tableowner | tablespace ------------+-----------+------------+------------ public | employees | postgres | (1 row)
=> SELECT * FROM pg_views WHERE schemaname = 'public';
schemaname | viewname | viewowner | definition ------------+--------------+-----------+-------------------------------------- public | top_managers | postgres | SELECT employees.id, + | | | employees.name, + | | | employees.manager + | | | FROM employees + | | | WHERE (employees.manager IS NULL); (1 row)
Список всех "отношений" можно посмотреть командой \d* в psql, где * - символ, обозначающий тип объекта (как relkind). Например, таблицы:
=> \dt
List of relations Schema | Name | Type | Owner --------+-----------+-------+---------- public | employees | table | postgres (1 row)
Или представления:
=> \dv
List of relations Schema | Name | Type | Owner --------+--------------+------+---------- public | top_managers | view | postgres (1 row)
Эти команды можно снабдить модификатором "+", чтобы получить больше информации:
=> \dt+
List of relations Schema | Name | Type | Owner | Size | Description --------+-----------+-------+----------+------------+------------- public | employees | table | postgres | 8192 bytes | (1 row)
Чтобы получить детальную информацию о конкретном объекте, надо воспользоваться командой \d (без дополнительной буквы):
=> \d top_managers
View "public.top_managers" Column | Type | Collation | Nullable | Default ---------+---------+-----------+----------+--------- id | integer | | | name | text | | | manager | integer | | |
Модификатор "+" остается в силе.
=> \d+ top_managers
View "public.top_managers" Column | Type | Collation | Nullable | Default | Storage | Description ---------+---------+-----------+----------+---------+----------+------------- id | integer | | | | plain | name | text | | | | extended | manager | integer | | | | plain | View definition: SELECT employees.id, employees.name, employees.manager FROM employees WHERE employees.manager IS NULL;
Помимо "отношений", аналогичным образом можно смотреть и на другие объекты, такие, как схемы (\dn) или функции (\df).
Модификатор "S" позволяет вывести не только пользовательские, но и системные объекты. А с помощью шаблона можно ограничить выборку:
=> \dfS pg*size
List of functions Schema | Name | Result data type | Argument data types | Type ------------+------------------------+------------------+---------------------+-------- pg_catalog | pg_column_size | integer | "any" | normal pg_catalog | pg_database_size | bigint | name | normal pg_catalog | pg_database_size | bigint | oid | normal pg_catalog | pg_indexes_size | bigint | regclass | normal pg_catalog | pg_relation_size | bigint | regclass | normal pg_catalog | pg_relation_size | bigint | regclass, text | normal pg_catalog | pg_table_size | bigint | regclass | normal pg_catalog | pg_tablespace_size | bigint | name | normal pg_catalog | pg_tablespace_size | bigint | oid | normal pg_catalog | pg_total_relation_size | bigint | regclass | normal (10 rows)
Psql предлагает большое количество команд для просмотра системного каталога. Как правило, они имеют мнемонические имена. Например, \df - describe function, \sf - show function:
=> \sf pg_catalog.pg_database_size(oid)
CREATE OR REPLACE FUNCTION pg_catalog.pg_database_size(oid) RETURNS bigint LANGUAGE internal PARALLEL SAFE STRICT AS $function$pg_database_size_oid$function$
Полный список всегда можно посмотреть в документации или командой \?.
Все команды psql, описывающие объекты, обращаются к таблицам системного каталога. Чтобы посмотреть, какие запросы на самом деле выполняет psql, можно установить переменную ECHO_HIDDEN:
=> \set ECHO_HIDDEN on
=> \dt employees
********* QUERY ********** SELECT n.nspname as "Schema", c.relname as "Name", CASE c.relkind WHEN 'r' THEN 'table' WHEN 'v' THEN 'view' WHEN 'm' THEN 'materialized view' WHEN 'i' THEN 'index' WHEN 'S' THEN 'sequence' WHEN 's' THEN 'special' WHEN 'f' THEN 'foreign table' WHEN 'p' THEN 'table' END as "Type", pg_catalog.pg_get_userbyid(c.relowner) as "Owner" FROM pg_catalog.pg_class c LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE c.relkind IN ('r','p','s','') AND n.nspname !~ '^pg_toast' AND c.relname ~ '^(employees)$' AND pg_catalog.pg_table_is_visible(c.oid) ORDER BY 1,2; ************************** List of relations Schema | Name | Type | Owner --------+-----------+-------+---------- public | employees | table | postgres (1 row)
=> \unset ECHO_HIDDEN
Как мы видели, описания таблиц и представлений хранятся в pg_class. А столбцы располагаются в отдельной таблице pg_attribute. Чтобы получить список столбцов конкретной таблицы, надо соединить pg_class и pg_attribute:
=> SELECT a.attname, a.atttypid FROM pg_attribute a WHERE a.attrelid = ( SELECT oid FROM pg_class WHERE relname = 'employees' ) AND a.attnum > 0;
attname | atttypid ---------+---------- id | 23 name | 25 manager | 23 (3 rows)
Используя reg-типы, запрос можно написать проще, без явного обращения к pg_class:
=> SELECT a.attname, a.atttypid FROM pg_attribute a WHERE a.attrelid = 'employees'::regclass AND a.attnum > 0;
attname | atttypid ---------+---------- id | 23 name | 25 manager | 23 (3 rows)
Здесь мы преобразовали строку 'employees' к типу OID. Аналогично мы можем вывести OID как текстовое значение:
=> SELECT a.attname, a.atttypid::regtype FROM pg_attribute a WHERE a.attrelid = 'employees'::regclass AND a.attnum > 0;
attname | atttypid ---------+---------- id | integer name | text manager | integer (3 rows)
Конец демонстрации.