CREATE CAST

CREATE CAST — определить новое приведение


Синтаксис

CREATE CAST (исходный_тип AS целевой_тип)
    WITH FUNCTION имя_функции [ (тип_аргумента [, ...]) ]
    [ AS ASSIGNMENT | AS IMPLICIT ]

CREATE CAST (исходный_тип AS целевой_тип)
    WITHOUT FUNCTION
    [ AS ASSIGNMENT | AS IMPLICIT ]

CREATE CAST (исходный_тип AS целевой_тип)
    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 имя_типа) или x::имя_типа.

Если приведение помечено как 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; отдельного встроенного знания об этом нет.

Разумно проявлять консерватизм в отношении того, объявлять ли приведения неявными. Переизбыток неявных способов приведения может привести к тому, что QHB выберет неожиданные интерпретации команд или даже не сможет их выполнить из-за наличия нескольких возможных интерпретаций. Хорошее эмпирическое правило состоит в том, чтобы сделать приведение неявно вызываемым только для сохраняющих информацию преобразований между типами в одной и той же категории типов. Например, приведение int2 к int4 разумно сделать неявным, но приведение float8 к int4, возможно, лучше сделать только приведением присваивания. Приведения типов разных категорий, например text к int4, лучше делать только явными.

Примечание
Иногда по соображениям удобства использования или соответствия стандартам необходимо обеспечить несколько неявных приведений для набора типов, что приводит к неоднозначности, которую нельзя избежать способом, указанным выше. Чтобы в таких случаях синтаксический анализатор мог обеспечить желаемое поведение, он дополнительно принимает во внимание категории типов и предпочитаемые типы. Более подробную информацию см. на справочной странице команды CREATE TYPE.

Чтобы создать приведение, нужно быть владельцем исходного или целевого типа данных и иметь право USAGE для другого типа. Чтобы создать двоично-сводимое приведение, нужно быть суперпользователем. (Это ограничение введено потому, что преобразование данных с ошибочным двоичным сведением легко может вызвать сбой сервера.)


Параметры

исходный_тип

Имя исходного типа данных для приведения.

целевой_тип

Имя целевого типа данных для приведения.

имя_функции[(тип_аргумента [, ...])]

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

WITHOUT FUNCTION

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

WITH INOUT

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

AS ASSIGNMENT

Указывает, что приведение может быть вызвано неявно в контекстах присвоения.

AS IMPLICIT

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

Функции, реализующие приведение, могут иметь от одного до трех аргументов. Тип первого аргумента должен быть идентичным или двоично-сводимым из исходного типа приведения. Второй аргумент, если он присутствует, должен иметь тип integer; он получает модификатор типа, связанный с типом назначения, или -1, если их вообще нет. Третий аргумент, если он присутствует, должен иметь тип boolean; если приведение является явным, в нем передается true; иначе false. (Как ни странно, в некоторых случаях стандарт SQL требует различного поведения для явных и неявных приведений. Этот аргумент предназначен для функций, которые должны реализовывать такие приведения. Однако создавать собственные типы данных, для которых это имело бы значение, не рекомендуется.)

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

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

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

Приведение из типа домена или к типу домена в настоящее время не осуществляется. При попытке выполнить такое приведение, вместо этого выполняется приведение, связанное с его нижележащим типом.


Примечания

Для удаления приведений, созданных пользователем, применяется команда DROP CAST.

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

Обычно нет необходимости создавать приведения между пользовательскими типами и стандартными строковыми типами (text, varchar и char(n), а также пользовательскими типами, относящимися к категории строковых). QHB предоставляет для этого автоматические преобразования ввода/вывода. Автоматические приведения к строковым типам обрабатываются как приведения присваивания, тогда как автоматические приведения из строковых типов могут быть только явными. Это поведение можно переопределить, объявив свое собственное приведение на замену автоматическому, но обычно это нужно, только чтобы сделать вызов более удобным, чем стандартное присваивание или явное указание. Другая возможная причина заключается в желании, чтобы преобразование вело себя иначе, чем функция ввода/вывода типа; но это выглядит достаточно странно, поэтому стоит дважды подумать, хорошая ли это идея. (На самом деле у небольшого количества встроенных типов имеются приведения с разным поведением, в основном из-за требований стандарта SQL.)

Несмотря на то, что это необязательно, рекомендуется продолжать следовать старому соглашению именования функций, реализующих приведение, по целевому типу данных. Многие пользователи привыкли иметь возможность приводить типы данных, используя нотацию в стиле функций, т. е. имя_типа(x). Эта нотация на самом деле ни что иное, как вызов функции, реализующей приведение; такой вызов не воспринимается как именно приведение. Если не называть функции преобразования, следуя этому соглашению, это может удивить пользователей. Поскольку QHB позволяет перегружать одно и то же имя функции с различными типами аргументов, ничто не мешает иметь несколько функций преобразования из разных типов, названных по имени этого целевого типа.

Примечание
На самом деле в предыдущем абзаце содержится некоторое упрощение: есть два случая, в которых конструкция вызова функции будет рассматриваться как запрос на приведение без сопоставления его с фактической функцией. Если вызову функции имя(x) в точности не соответствует никакая существующая функция, но имеется тип данных имя и в pg_cast есть двоично-сводимое приведение типа x из этого типа, такой вызов будет воспринят как двоично-сводимое приведение. Это исключение введено, чтобы двоично-сводимое приведение можно было вызвать, используя синтаксис вызова функции, даже если никакой функции преобразования у него нет. Аналогично если запись приведения в pg_cast отсутствует, но приведение было бы к или из строкового типа, вызов будет воспринят как преобразование ввода/вывода. Это исключение позволяет вызывать преобразования ввода/вывода, используя синтаксис вызова функции.

Примечание
Существует также исключение и из этого исключения: преобразование ввода/вывода из составных типов в строковые нельзя вызвать, используя синтаксис вызова функции; его необходимо записать как явное приведение (используя CAST или нотацию ::) Это исключение было добавлено, так как после введения автоматически предоставляемых преобразований ввода/вывода обнаружилось, что такое приведение слишком легко вызвать случайно, намереваясь на самом деле дать ссылку на столбец или функцию.


Примеры

Создание приведения присваивания типа bigint к типу int4 с помощью функции int4(bigint):

CREATE CAST (bigint AS int4) WITH FUNCTION int4(bigint) AS ASSIGNMENT;

(Это приведение уже предопределено в системе.)


Совместимость

Команда CREATE CAST соответствует стандарту SQL, за исключением того, что в стандарте ничего не говорится о двоично-сводимых типах и дополнительных аргументах реализующих функций. Указание AS IMPLICIT тоже является расширением QHB.


См. также

CREATE FUNCTION, CREATE TYPE, DROP CAST