Перейти к основному содержимому

Система типов PostgreSQL

примечание

Эта страница переведена при помощи нейросети GigaChat.

Типы данных PostgreSQL могут быть разделены на базовые типы, контейнерные типы, домены и псевдотипы.

Основные типы

Основные типы – это такие как integer, которые реализованы ниже уровня языка SQL (обычно на низкоуровневом языке, таком как C). Они обычно соответствуют тому, что часто называют абстрактными типами данных. PostgreSQL может работать с такими типами только через функции, предоставляемые пользователем, и понимает поведение таких типов лишь постольку, поскольку пользователь их описывает.

Перечислимые (перечислительные) типы можно рассматривать как подкатегорию базовых типов. Основное отличие состоит в том, что они могут быть созданы с использованием только команд SQL, без какого-либо низкоуровневого программирования.

Контейнерные типы

В PostgreSQL есть три вида «контейнерных» типов, которые являются типами, содержащими несколько значений других типов. Это массивы, композиты и диапазоны.

Массивы могут содержать несколько значений одного и того же типа. Тип массива автоматически создается для каждого базового типа, составного типа, диапазона типов и доменного типа. Но нет массивов массивов. Что касается системы типов, многомерные массивы такие же, как одномерные массивы.

Составные типы или типы строк создаются каждый раз при создании пользователем таблицы. Также возможно использовать CREATE TYPE для определения автономного составного типа без связанной с ним таблицы. Составной тип - это просто список типов с ассоциированными именами полей. Значение составного типа - это строка или запись значений поля.

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

Домены

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

Псевдотипы

Существует несколько «псевдотипов» для специальных целей. Псевдотипы не могут появляться в столбцах таблиц или компонентах составных типов, но они могут использоваться для объявления типов аргументов и результатов функций. Это обеспечивает механизм внутри системы типов для идентификации специальных классов функций.

Полиморфные типы

Среди псевдотипов особый интерес представляют полиморфные типы, которые используются для объявления полиморфных функций. Эта мощная возможность позволяет одному определению функции оперировать множеством различных типов данных, при этом конкретный тип данных определяется типами данных, передаваемых ей в конкретном вызове. Полиморфные типы приведены в таблице ниже. Некоторые примеры их использования приведены в разделе «Полиморфные функции SQL».

Полиморфные типы:

ИмяСемействоОписание
anyelementПростойУказывает, что функция принимает любой тип данных
anyarrayПростойУказывает, что функция принимает любой тип массива данных
anynonarrayПростойУказывает, что функция принимает любой не массивовый тип данных
anyenumПростойУказывает, что функция принимает любой тип перечисляемого типа данных
anyrangeПростойУказывает, что функция принимает любой тип диапазона данных (см. раздел 8.17)
anymultirangeПростойУказывает на то, что функция принимает любой тип многодиапазонных данных
anycompatibleОбщийУказывает на то, что функция принимает любой тип данных с автоматической передачей нескольких аргументов к общему типу данных
anycompatiblearrayОбщийУказывает на то, что функция принимает любой тип массива данных с автоматической передачей нескольких аргументов к общему типу данных
anycompatiblenonarrayОбщийУказывает на то, что функция принимает любой не массивный тип данных с автоматической передачей нескольких аргументов к общему типу данных
anycompatiblerangeОбщийУказывает на то, что функция принимает любой диапазон типов данных с автоматической передачей нескольких аргументов к общему типу данных
anycompatiblemultirangeОбщийУказывает на то, что функция принимает любой мультидиапазонный тип данных с автоматической передачей нескольких аргументов к общему типу данных

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

Для семейства полиморфных типов «простые» правила сопоставления и вывода работают следующим образом:

Каждая позиция (будь то аргумент или возвращаемое значение), объявленная как anyelement, может иметь любой конкретный фактический тип данных, но в любом конкретном вызове они все должны быть одного и того же того же самого фактического типа. Каждая позиция, объявленная как anyarray, может иметь любой тип массива, но аналогично они все должны быть одного и того же типа. И аналогично, позиции, объявленные как anyrange, должны быть все одного и того же диапазона типов. То же самое касается anymultirange.

Кроме того, если есть позиции, объявленные anyarray и другие, объявленные anyelement, фактический массивный тип в позициях anyarray должен быть массивом, элементы которого имеют тот же тип, который появляется в позициях anyelement. anynonarray обрабатывается точно так же, как anyelement, но добавляет дополнительное ограничение, что фактический тип не должен быть типом массива. anyenum обрабатывается точно так же, как anyelement, но добавляет дополнительное ограничение, что фактический тип должен быть перечисляемым типом.

Аналогичным образом, если есть позиции, объявленные anyrange и другие, объявленные anyelement или anyarray, фактический диапазонный тип в позициях anyrange должен быть диапазоном, подтип которого является тем же самым типом, который появляется в позициях anyelement и совпадает с базовым типом элементов позиций anyarray. Если есть позиции, объявленные anymultirange, их фактический мультидиапазонный тип должен содержать диапазоны, соответствующие параметрам, объявленным anyrange, и базовые элементы, соответствующие параметрам, объявленным anyelement и anyarray.

Таким образом, когда более одного аргумента объявляется с полиморфным типом, общий эффект заключается в том, что допускаются только определенные комбинации фактических типов аргументов. Например, функция, объявленная как 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): оба фактических аргумента должны быть одного и того же перечислимого типа.

Для семейства полиморфных типов «общий» правила сопоставления и дедукции работают примерно так же, как для семейства «простой», с одним основным отличием: фактические типы аргументов не обязательно должны быть идентичными, если они могут быть неявно преобразованы в один общий тип. Общий тип выбирается по тем же правилам, что и для UNION и связанных конструкций. Выбор общего типа учитывает фактические типы входов anycompatible и anycompatiblenonarray, типы элементов массива для входов anycompatiblearray, подтипы диапазона для входов anycompatiblerange и подтипы мультидиапазонов для входов anycompatiblemultirange. Если присутствует anycompatiblenonarray, то требуется, чтобы общий тип был непотоковым типом. После определения общего типа аргументы в позициях anycompatible и anycompatiblenonarray автоматически приводятся к этому типу, а аргументы в позиции anycompatiblearray автоматически приводятся к типу массива для этого типа.

Поскольку нет способа выбрать тип диапазона, зная только его подтип, использование anycompatiblerange и/или anycompatiblemultirange требует, чтобы все аргументы, объявленные этим типом, имели одинаковый фактический диапазон и/или многодиапазонный тип, и чтобы этот подтип типа соответствовал выбранному общему типу, так что приведение значений диапазона не требуется. Как и в случае с anyrange и anymultirange, использование anycompatiblerange и anymultirange в качестве типа результата функции требует наличия аргумента anycompatiblerange или anycompatiblemultirange.

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

Простые и общие полиморфные семейства представляют два независимых набора переменных типа. Рассмотрим, например,

CREATE FUNCTION myfunc(a anyelement, b anyelement,
c anycompatible, d anycompatible)
RETURNS anycompatible AS ...

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

Функция с переменным числом аргументов (принимает переменное число аргументов, как в разделе «Функции SQL с переменным количеством аргументов») может быть полиморфной: это достигается путем объявления ее последнего параметра как VARIADIC anyarray или VARIADIC anycompatiblearray. Для целей сопоставления аргументов и определения фактического результирующего типа такая функция ведет себя так же, как если бы написали соответствующее количество параметров anynonarray или anycompatiblenonarray.