8.19. Идентификаторы объектов

Идентификатор объекта (Object Identifier, OID) используется внутри Postgres Pro в качестве первичного ключа различных системных таблиц. Идентификатор объекта представляется в типе oid. Также существуют различные типы-псевдонимы для oid, с именами regсущность. Обзор этих типов приведён в Таблице 8.26.

В настоящее время тип oid реализован как четырёхбайтное целое число без знака. Таким образом, значение этого типа может быть недостаточно большим для обеспечения уникальности в базе данных или даже в отдельных больших таблицах.

Для самого типа oid помимо сравнения определены всего несколько операторов. Однако его можно привести к целому и затем задействовать в обычных целочисленных вычислениях. (При этом следует опасаться путаницы со знаковыми/беззнаковыми значениями.)

Типы-псевдонимы OID сами по себе не вводят новых операций и отличаются только специализированными функциями ввода/вывода. Эти функции могут принимать и выводить не просто числовые значения, как тип oid, а символические имена системных объектов. Эти типы позволяют упростить поиск объектов по значениям OID. Например, чтобы выбрать из pg_attribute строки, относящиеся к таблице mytable, можно написать:

SELECT * FROM pg_attribute WHERE attrelid = 'mytable'::regclass;

вместо:

SELECT * FROM pg_attribute
  WHERE attrelid = (SELECT oid FROM pg_class WHERE relname = 'mytable');

Хотя второй вариант выглядит не таким уж плохим, но это лишь очень простой запрос. Если же потребуется выбрать правильный OID, когда таблица mytable есть в нескольких схемах, вложенный подзапрос будет гораздо сложнее. Преобразователь вводимого значения типа regclass находит таблицу согласно заданному пути поиска схем, так что он делает «всё правильно» автоматически. Аналогично, приведя идентификатор таблицы к типу regclass, можно получить символическое представление числового кода.

Таблица 8.26. Идентификаторы объектов

ИмяСсылкиОписаниеПример значения
oidanyчисловой идентификатор объекта564182
regclasspg_classимя отношенияpg_type
regcollationpg_collationимя правила сортировки"POSIX"
regconfigpg_ts_configконфигурация текстового поискаenglish
regdictionarypg_ts_dictсловарь текстового поискаsimple
regnamespacepg_namespaceпространство имёнpg_catalog
regoperpg_operatorимя оператора+
regoperatorpg_operatorоператор с типами аргументов*(integer,​integer) или -(NONE,​integer)
regprocpg_procимя функцииsum
regprocedurepg_procфункция с типами аргументовsum(int4)
regrolepg_authidимя ролиsmithee
regtypepg_typeимя типа данныхinteger

Все типы псевдонимов OID для объектов, сгруппированных в пространство имён, принимают имена, дополненные именем схемы, и выводят имена со схемой, если данный объект нельзя будет найти в текущем пути поиска без имени схемы. Например, myschema.mytable является приемлемым входным значением для regclass (если существует такая таблица). Это значение может выводиться как myschema.mytable или просто mytable, в зависимости от текущего пути поиска. Типы regproc и regoper принимают только уникальные вводимые имена (не перегруженные), что ограничивает их применимость; в большинстве случаев лучше использовать regprocedure или regoperator. Для типа regoperator в записи унарного оператора неиспользуемый операнд заменяется словом NONE.

Функции ввода для данных типов допускают пробелы между компонентами и приводят буквы верхнего регистра к нижнему, за исключением строки в двойных кавычках; это сделано для того, чтобы правила записи были похожи на принятые для записи имён объектов в SQL. И наоборот, функции вывода будут добавлять двойные кавычки, если это необходимо, чтобы выводимая строка была допустимым идентификатором SQL. Например, OID функции с именем FooF в верхнем регистре), принимающей два целочисленных аргумента, можно ввести как ' "Foo" ( int, integer ) '::regprocedure. Результат будет выглядеть как "Foo"(integer,integer). И имя функции, и имена типов аргументов также могут быть дополнены схемой.

Многие встроенные функции PostgreSQL принимают OID таблицы или другого типа объекта БД и для удобства объявляются как принимающие regclass (или соответствующий тип-псевдоним OID). Это означает, что вам не нужно искать OID объекта вручную, а можно просто ввести его имя в виде строки. Например, функция nextval (regclass) принимает OID отношения последовательности, поэтому её можно вызвать так:

nextval('foo')              обращается к последовательности foo
nextval('FOO')              то же самое
nextval('"Foo"')            обращается к последовательности Foo
nextval('myschema.foo')     обращается к myschema.foo
nextval('"myschema".foo')   то же самое
nextval('foo')              ищет foo в пути поиска

Примечание

Когда аргумент такой функции записывается как текстовая строка в чистом виде, она становится константой типа regclass. Так как фактически это будет просто значение OID, оно будет привязано к изначально идентифицированной последовательности, несмотря на то, что она может быть переименована, перенесена в другую схему и т. д. Такое «раннее связывание» обычно желательно для ссылок на последовательности в значениях столбцов по умолчанию и представлениях. Но иногда возникает необходимость в «позднем связывании», когда ссылки на последовательности распознаются в процессе выполнения. Чтобы получить такое поведение, нужно принудительно изменить тип константы с regclass на text:

nextval('foo'::text)      foo распознаётся во время выполнения

Для поиска во время выполнения также может использоваться функция to_regclass() и подобные. См. Таблицу 9.70.

Другой практический пример использования regclass — поиск OID таблицы, отображённой в представлениях information_schema, которые не предоставляют такие OID напрямую. Например, можно вызвать функцию pg_relation_size(), для которой требуется OID таблицы. С учётом указанных выше правил, далее представлен корректный способ вызова данной функции

SELECT table_schema, table_name,
       pg_relation_size((quote_ident(table_schema) || '.' ||
                         quote_ident(table_name))::regclass)
FROM information_schema.tables
WHERE ...

. Функция quote_ident() заключит идентификатор в двойные кавычки, когда это необходимо. Более простым способом кажется

SELECT pg_relation_size(table_name)
FROM information_schema.tables
WHERE ...

но использовать его не рекомендуется, потому что он не сработает для таблиц, которые не входят в заданный путь поиска или имена которых нужно заключать в кавычки.

Дополнительным свойством большинства типов псевдонимов OID является образование зависимостей. Когда в сохранённом выражении фигурирует константа одного из этих типов (например, в представлении или в значении столбца по умолчанию), это создаёт зависимость от целевого объекта. Например, если значение по умолчанию определяется выражением nextval('my_seq'::regclass), Postgres Pro понимает, что это выражение зависит от последовательности my_seq, и не позволит удалить последовательность раньше, чем будет удалено это выражение. Альтернативная запись nextval('my_seq'::text) не создаёт зависимость. (Единственным исключением является тип regrole. Константы этого типа в таких выражениях не допускаются.)

Есть ещё один тип системных идентификаторов, xid, представляющий идентификатор транзакции (сокращённо xact). Этот тип имеют системные столбцы xmin и xmax. В Postgres Pro Enterprise идентификаторы транзакций реализованы как 64-битные счётчики, что позволяет предотвратить зацикливание идентификаторов. За подробностями обратитесь к Подразделу 24.1.5. В некоторых контекстах также используется тип xid8. Значения xid и xid8 увеличиваются строго монотонно и никогда не повторяются на протяжении всего существования кластера баз данных.

Третий тип идентификаторов, используемых в системе, — cid, идентификатор команды (command identifier). Этот тип данных имеют системные столбцы cmin и cmax. Идентификаторы команд — 32-битные числа.

И наконец, последний тип системных идентификаторов — tid, идентификатор строки/кортежа (tuple identifier). Этот тип данных имеет системный столбец ctid. Идентификатор кортежа представляет собой пару (из номера блока и индекса кортежа в блоке), идентифицирующую физическое расположение строки в таблице.

(Подробнее о системных столбцах рассказывается в Разделе 5.5.)