CREATE CAST#
CREATE CAST
CREATE CAST — определить новое преобразование
Синтаксис
CREATE CAST (source_type
AStarget_type
) WITH FUNCTIONfunction_name
[ (argument_type
[, ...]) ] [ AS ASSIGNMENT | AS IMPLICIT ] CREATE CAST (source_type
AStarget_type
) WITHOUT FUNCTION [ AS ASSIGNMENT | AS IMPLICIT ] CREATE CAST (source_type
AStarget_type
) WITH INOUT [ AS ASSIGNMENT | AS IMPLICIT ]
Описание
CREATE CAST
определяет новое приведение типов. Приведение типов определяет, как выполнить преобразование между двумя типами данных. Например,
SELECT CAST(42 AS float8);
преобразует целочисленную константу 42 в тип float8
путем вызова
ранее определенной функции, в данном случае
float8(int4)
. (Если не было определено подходящего преобразования,
преобразование завершается неудачей).
Два типа могут быть бинарно приводимыми, что означает, что преобразование может быть выполнено “бесплатно” без вызова какой-либо функции. Для этого требуется, чтобы соответствующие значения использовали одно и то же внутреннее представление. Например, типы text
и varchar
являются бинарно приводимыми в обоих направлениях. Бинарная приводимость не обязательно является симметричным отношением. Например, преобразование из типа xml
в тип text
может быть выполнено бесплатно в текущей реализации, но обратное направление требует функции, которая выполняет как минимум проверку синтаксиса. (Два типа, которые являются бинарно приводимыми в обоих направлениях, также называются бинарно совместимыми).
Вы можете определить преобразование типов данных как преобразование ввода-вывода, используя синтаксис WITH INOUT
. Преобразование ввода-вывода выполняется путем вызова функции вывода исходного типа данных и передачи полученной строки функции ввода целевого типа данных. Во многих обычных случаях это позволяет избежать необходимости написания отдельной функции преобразования. Преобразование ввода-вывода действует так же, как и обычное преобразование на основе функций, только реализация отличается.
По умолчанию приведение типов может быть вызвано только явным запросом на приведение, то есть явным приведением CAST(
или конструкцией x
AS
typename
)x
::
typename
.
Если приведение помечено AS ASSIGNMENT
, то оно может быть вызвано неявно при присваивании значения столбцу целевого типа данных. Например, предположим, что foo.f1
- это столбец типа text
, тогда:
INSERT INTO foo (f1) VALUES (42);
будет разрешено, если приведение типа integer
к типу text
помечено как AS ASSIGNMENT
, в противном случае - нет.
(Мы обычно используем термин приведение с присваиванием для описания такого рода приведения).
Если приведение помечено AS IMPLICIT
, то оно может быть вызвано
неявно в любом контексте, будь то присваивание или внутренне в
выражении. (Мы обычно используем термин неявное
приведение для описания такого типа приведения).
Например, рассмотрим следующий запрос:
SELECT 2 + 4.0;
Парсер изначально помечает константы как тип integer
и numeric
соответственно. В системных каталогах нет оператора integer
+
numeric
, но есть оператор numeric
+
numeric
. Запрос будет успешным, если доступно приведение типа из integer
в numeric
и оно помечено как AS IMPLICIT
- что на самом деле так и есть. Парсер применит неявное приведение и разрешит запрос, как если бы он был написан.
SELECT CAST ( 2 AS numeric ) + 4.0;
Теперь каталоги также предоставляют преобразование из numeric
в integer
. Если бы это преобразование было помечено как AS IMPLICIT
- что не так - то парсер столкнулся бы с выбором между вышеуказанным толкованием и альтернативой преобразования числовой константы numeric
в integer
и применения оператора integer
+
integer
. Не имея никаких сведений о предпочтительном выборе, он бы отказался и объявил запрос неоднозначным. Тот факт, что только одно из двух преобразований является неявным, является способом, которым мы учим парсер предпочитать разрешение смешанного выражения numeric
-и-integer
как numeric
; о таком знании нет встроенной информации.
Разумно быть осторожным при отметке приведений типов как неявных. Избыток неявных путей приведения типов может привести к тому, что Tantor SE выберет неожиданные интерпретации команд или не сможет разрешить команды вообще из-за наличия нескольких возможных интерпретаций. Хорошим правилом является делать приведение типов неявно вызываемым только для сохранения информации при преобразованиях между типами в одной общей категории типов. Например, приведение типа int2
к типу int4
может быть неявным, но приведение типа float8
к типу int4
вероятно должно быть только для присваивания. Приведения между категориями типов, такие как text
к типу int4
, лучше делать только явными.
Примечание
Иногда по соображениям удобства или соответствия стандартам требуется предоставить несколько неявных преобразований между набором типов, что приводит к неизбежной неоднозначности, как описано выше. Парсер имеет запасной эвристический алгоритм, основанный на категориях типов и предпочтительных типах, который может помочь достичь желаемого поведения в таких случаях. Дополнительную информацию см. в разделе CREATE TYPE.
Чтобы создать приведение типов, вы должны владеть исходным или целевым типом данных и иметь привилегию USAGE
на другом типе. Чтобы создать приведение типов с возможностью бинарного преобразования, вы должны быть суперпользователем. (Это ограничение сделано, потому что неправильное бинарное преобразование типов может легко привести к сбою сервера).
Параметры
source_type
Имя исходного типа данных приведения.
target_type
Имя целевого типа данных приведения.
function_name
[(argument_type
[, ...])]Функция, используемая для выполнения приведения типов. Имя функции может быть указано с указанием схемы. Если это не так, функция будет искаться в пути поиска схемы. Тип данных результата функции должен соответствовать целевому типу приведения. Ее аргументы обсуждаются ниже. Если список аргументов не указан, имя функции должно быть уникальным в своей схеме.
WITHOUT FUNCTION
Указывает, что тип источника может быть приведен к типу назначения с помощью преобразования в двоичном формате, поэтому для выполнения приведения не требуется функция.
WITH INOUT
Указывает, что преобразование является преобразованием ввода-вывода (I/O), выполняемым путем вызова функции вывода исходного типа данных и передачи полученной строки функции ввода целевого типа данных.
AS ASSIGNMENT
Указывает, что приведение типов может быть вызвано неявно в контекстах присваивания.
AS IMPLICIT
Указывает, что приведение типов может быть вызвано неявно в любом контексте.
Функции реализации приведения типов могут иметь от одного до трех аргументов.
Первый аргумент должен быть идентичным или бинарно приводимым от исходного типа приведения. Второй аргумент,
если присутствует, должен иметь тип integer
; он получает модификатор типа, связанный с целевым типом, или -1
,
если такового нет. Третий аргумент,
если присутствует, должен иметь тип boolean
; он получает значение true
,
если приведение типов явное, и false
в противном случае.
(Странно, но стандарт SQL требует различного поведения для явных и неявных приведений в некоторых случаях. Этот аргумент предоставляется для функций,
которые должны реализовывать такие приведения. Не рекомендуется проектировать собственные типы данных таким образом, чтобы это имело значение).
Тип возвращаемого значения функции приведения должен быть идентичным или бинарно приводимым к целевому типу приведения.
Обычно приведение типов должно иметь разные исходный и целевой типы данных. Однако разрешается объявить приведение типов с идентичными исходными и целевыми типами, если у него есть функция реализации приведения с более чем одним аргументом. Это используется для представления функций приведения длины, специфичных для типа, в системных каталогах. Именованная функция используется для приведения значения типа к значению модификатора типа, заданному вторым аргументом.
Когда приведение имеет разные исходный и целевой типы и функция, принимающая более одного аргумента, поддерживает преобразование из одного типа в другой и применение принудительного изменения длины в одном шаге. Когда такая запись недоступна, приведение к типу, использующему модификатор типа, включает два шага приведения: одно для преобразования между типами данных и второе для применения модификатора.
Приведение к типу домена в настоящее время не имеет эффекта. Приведение к типу домена или от него использует приведения, связанные с его базовым типом.
Примечания
Используйте DROP CAST
, чтобы удалить пользовательские приведения типов.
Не забывайте, что если нужно иметь возможность преобразовывать типы в обоих направлениях, необходимо явно объявить приведения в обоих направлениях.
Необходимость создания приведений между пользовательскими типами и стандартными строковыми типами (text
, varchar
и char(
), а также пользовательскими типами, определенными в категории строк, обычно отсутствует. Tantor SE предоставляет автоматические приведения ввода-вывода для этого. Автоматические приведения к строковым типам рассматриваются как приведения присваивания, в то время как автоматические приведения от строковых типов являются явными. Вы можете изменить это поведение, объявив свое собственное приведение для замены автоматического приведения, но обычно это делается только в том случае, если нужно, чтобы преобразование было более легко вызываемым, чем стандартная настройка только для присваивания или только явная настройка. Еще одна возможная причина - это желание, чтобы преобразование вело себя иначе, чем функция ввода-вывода типа; но это настолько неожиданно, что стоит дважды подумать, стоит ли это делать. (Небольшое количество встроенных типов действительно имеют различное поведение для преобразований, в основном из-за требований стандарта SQL).
n
)
Хотя это необязательно, рекомендуется продолжать следовать старой
схеме именования функций реализации приведения типов по имени целевого
типа данных. Многие пользователи привыкли приводить типы данных с помощью
записи вызова, то есть
typename
(x
). Эта запись на самом деле
не что иное, как вызов функции реализации приведения типов; она не обрабатывается
особым образом как приведение типов. Если ваши функции преобразования не
названы по этой схеме, то у вас могут возникнуть проблемы с пользователями.
Поскольку Tantor SE позволяет перегрузку одного и того же имени функции
с разными типами аргументов, допустимо наличие
нескольких функций преобразования из разных типов, которые все используют
имя целевого типа.
Примечание
На самом деле, предыдущий абзац является упрощением: есть два случая, когда конструкция вызова функции будет рассматриваться как запрос на приведение типа, не сопоставленный с фактической функцией.
Если вызов функции name
(x
) не соответствует ни одной существующей функции, но name
является именем типа данных, а pg_cast
предоставляет приведение типов, совместимое с данным типом из типа x
, то вызов будет рассматриваться как приведение типов, совместимое с данным типом. Это исключение сделано для того, чтобы бинарно-совместимые приведения типов могли быть вызваны с использованием функционального синтаксиса, даже если у них нет никакой функции. Аналогично, если нет записи pg_cast
, но приведение типов будет к строковому типу или от него, вызов будет рассматриваться как приведение типов ввода-вывода. Это исключение позволяет вызывать приведения типов ввода-вывода с использованием функционального синтаксиса.
Примечание
Существует также исключение к исключению: преобразования ввода-вывода из составных типов в строковые типы не могут быть вызваны с использованием функционального синтаксиса, а должны быть записаны в явном синтаксисе преобразования (либо с использованием CAST
, либо с использованием ::
). Это исключение было добавлено, потому что после введения автоматически предоставляемых преобразований ввода-вывода оказалось слишком легко случайно вызвать такое преобразование, когда требовалась ссылка на функцию или столбец.
Примеры
Для создания приведения типа bigint
к типу int4
с использованием функции int4(bigint)
:
CREATE CAST (bigint AS int4) WITH FUNCTION int4(bigint) AS ASSIGNMENT;
(Это преобразование уже предопределено в системе).
Совместимость
Команда CREATE CAST
соответствует стандарту
SQL, за исключением того, что SQL не предусматривает
приведение типов с помощью бинарных операций или дополнительных аргументов
для функций реализации.
AS IMPLICIT
также является расширением Tantor SE.