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