35.2. Система типов PostgreSQL
Типы данных PostgreSQL делятся на базовые, составные, доменные и псевдотипы.
35.2.1. Базовые типы
Базовые типы — это типы вроде int4
, которые реализуются ниже уровня языка SQL (обычно на низкоуровневом языке, например, C). В общих чертах они соответствуют так называемым абстрактным типам данных. PostgreSQL может работать с такими типами только через функции, предоставленные пользователем, и понимать их поведение только в той степени, в какой его опишет пользователь. Базовые типы подразделяются на скалярные типы и массивы. Для каждого скалярного типа автоматически создаётся тип массива, который может содержать множество значений этого скалярного типа переменного размера.
35.2.2. Составные типы
Составные типы, или типы строк, образуются при создании любой таблицы. С помощью команды CREATE TYPE также можно определить «независимый» составной тип, не связанный с таблицей. Составной тип представляет собой просто список типов с определёнными именами полей. Значением составного типа является строка таблицы или запись из значений полей. Пользователь может обращаться к этим полям из запросов SQL. За дополнительными сведениями о составных типах обратитесь к Разделу 8.16.
35.2.3. Домены
Домен основывается на определённом базовом типе и во многих аспектах взаимозаменяем с ним. Однако домен может иметь дополнительные ограничения, уменьшающие множество допустимых значений относительно нижележащего базового типа.
Доменные типы можно создавать, используя SQL-команду CREATE DOMAIN. Их создание и применение в этой главе не рассматривается.
35.2.4. Псевдотипы
Для специальных целей существует также несколько «псевдотипов». Псевдотипы не могут применяться в столбцах таблицы или атрибутах составных типов, но их можно использовать в объявлениях аргументов и результатов функций. Это даёт возможность выделить в системе типов специальные классы функций. Все существующие псевдотипы перечислены в Таблице 8.25.
35.2.5. Полиморфные типы
Особый интерес представляют пять псевдотипов: anyelement
, anyarray
, anynonarray
, anyenum
и anyrange
, которые называются полиморфными типами. Функция, в объявлении которой используются эти типы, называется полиморфной. Полиморфная функция может работать со множеством различных типов данных; конкретный тип определяется в зависимости от значения, переданного при вызове.
Полиморфные аргументы и результаты связываются друг с другом и сводятся к определённому типу данных при разборе запроса, вызывающего полиморфную функцию. В каждой позиции (в аргументах или возвращаемом значении), объявленной как anyelement
, может передаваться любой фактический тип данных, но в каждом конкретном вызове все эти фактические типы должны быть одинаковыми. Аналогичным образом, в каждой позиции, объявленной как anyarray
, может передаваться любой тип данных массива, но все фактические типы должны совпадать. Так же и во всех позициях, объявленных как anyrange
, должен передаваться одинаковый диапазонный тип. Более того, если некоторые позиции объявлены как anyarray
, а другие как anyelement
, то фактическим типом в позициях anyarray
должен быть массив, элементы которого имеют тот же тип, что и значения в позициях anyelement
. Подобным образом, если одни позиции объявлены как anyrange
, а другие как anyelement
или anyarray
, фактическим типом в позициях anyrange
должен быть диапазон, подтип которого совпадает с типом элементов в позициях anyelement
и с типом, передаваемым в позициях anyarray
. Псевдотип anynonarray
обрабатывается так же, как anyelement
, но с дополнительным ограничением — фактический тип не должен быть типом массива. Псевдотип anyenum
тоже обрабатывается как anyelement
, но его фактические типы ограничиваются перечислениями.
Таким образом, когда с полиморфным типом объявлено несколько аргументов, в итоге допускаются только определённые комбинации фактических типов. Например, функция, объявленная как equal(anyelement, anyelement)
, примет в аргументах любые два значения, но только если их типы данных совпадают.
Когда с полиморфным типом объявлено возвращаемое значение функции, так же полиморфным должен быть минимум один аргумент, и фактический тип результата при конкретном вызове определится по типу фактически переданного аргумента. Например, если бы отсутствовал механизм обращения к элементам массива, его можно было бы реализовать, создав функцию subscript(anyarray, integer) returns anyelement
. С таким объявлением первым фактическим аргументом должен быть массив, и из него будет выведен правильный тип результата при разборе запроса. В качестве другого примера можно привести функцию f(anyarray) returns anyenum
, которая будет принимать только массивы перечислений.
В большинстве случаев при разборе функции фактический тип данных для полиморфного результата может быть выведен из аргументов, имеющих другой полиморфный тип; например, подтип anyarray
может выводиться из anyelement
и наоборот. Исключение представляет полиморфный результат типа anyrange
— для него требуется аргумент типа anyrange
; вывести его фактический тип из типа аргументов anyarray
или anyelement
нельзя. Это объясняется тем, что на одном подтипе могут базироваться несколько диапазонных типов.
Заметьте, что anynonarray
и anyenum
представляют не отдельные типы переменных; это те же типы, что и anyelement
, но с дополнительными ограничениями. Например, объявление функции f(anyelement, anyenum)
равнозначно объявлению f(anyenum, anyenum)
: оба фактических аргумента должны быть одинаковыми типами-перечислениями.
Функции с переменным числом аргументом (описанные в Подразделе 35.4.5) тоже могут быть полиморфными: для этого их последний параметр описывается как VARIADIC
anyarray
. Для целей сопоставления аргументов и определения фактического типа результата такая функция представляется так же, как если бы в ней явно объявлялось нужное число параметров anynonarray
.