Определяет новый тип данных.
CREATE TYPE name AS
( attribute_name data_type [ COLLATE collation ] [, ... ] ] )
CREATE TYPE name AS ENUM
( [ 'label' [, ... ] ] )
CREATE TYPE name AS RANGE (
SUBTYPE = subtype
[ , SUBTYPE_OPCLASS = subtype_operator_class ]
[ , COLLATION = collation ]
[ , CANONICAL = canonical_function ]
[ , SUBTYPE_DIFF = subtype_diff_function ]
)
CREATE TYPE name (
INPUT = input_function,
OUTPUT = output_function
[, RECEIVE = receive_function]
[, SEND = send_function]
[, TYPMOD_IN = type_modifier_input_function ]
[, TYPMOD_OUT = type_modifier_output_function ]
[, INTERNALLENGTH = {internallength | VARIABLE}]
[, PASSEDBYVALUE]
[, ALIGNMENT = alignment]
[, STORAGE = storage]
[, LIKE = like_type
[, CATEGORY = category]
[, PREFERRED = preferred]
[, DEFAULT = default]
[, ELEMENT = element]
[, DELIMITER = delimiter]
[, COLLATABLE = collatable]
[, COMPRESSTYPE = compression_type]
[, COMPRESSLEVEL = compression_level]
[, BLOCKSIZE = blocksize] )
CREATE TYPE name
Команда CREATE TYPE регистрирует новый тип данных для использования в текущей базе данных. Пользователь, определивший тип, становится его владельцем.
Если указано имя схемы, тип создаётся в указанной схеме. В противном случае он создаётся в текущей схеме. Имя типа должно отличаться от имён всех существующих типов или доменов в этой схеме. Имя типа также должно отличаться от имён всех существующих таблиц в той же схеме.
Как показано в обзоре синтаксиса выше, существует пять форм команды CREATE TYPE. Они создают соответственно составные типы, перечисления, типы-диапазоны, базовые типы или «пустышки» (shell types). Первые четыре формы описаны ниже. «Пустышка» (shell type) — это просто заглушка для типа, который будет определён позже; она создаётся путём выполнения команды CREATE TYPE с указанием только имени типа. Как описано в этих разделах, «пустышки» используются как опережающие ссылки при создании типов-диапазонов и базовых типов.
Первая форма команды CREATE TYPE создаёт составной тип. Составной тип задаётся списком имён атрибутов и их типов данных. Если тип данных атрибута поддерживает сортировку, вы можете также указать правило сортировки для этого атрибута. Составной тип по сути аналогичен типу строки таблицы, однако использование команды CREATE TYPE позволяет избежать создания реальной таблицы, если вам нужно определить лишь один тип. Отдельно стоящие составные типы также полезны, например, в качестве параметров или возвращаемых значений функций.
Для создания составного типа необходимо иметь привилегию USAGE на все типы его атрибутов.
Вторая форма команды CREATE TYPE, как описано в документации PostgreSQL по типам-перечислениям, создаёт тип-перечисление. Такой тип должен состоять из списка из одного или более заключённых в кавычки меток, каждая из которых не должна превышать NAMEDATALEN байт (64 байта при стандартной компиляции PostgreSQL).
Третья форма команды CREATE TYPE создаёт тип-диапазон, как описано в спецификации типов-диапазонов.
Базовый тип (subtype) типа-диапазона может быть любым типом, для которого определён класс операторов B-Tree (используется для определения порядка значений в диапазоне). Обычно для определения порядка используется класс операторов B-Tree по умолчанию для базового типа. Чтобы использовать непо умолчанию класс операторов, укажите его имя с помощью параметра subtype_opclass. Если базовый тип допускает сортировку и вы хотите использовать отличное от умолчания правило сортировки для порядка в диапазоне, вы можете указать его с помощью параметра collation.
Необязательная каноническая функция (canonical function) должна принимать один параметр типа создаваемого диапазона и возвращать значение того же типа. При наличии такая функция используется для преобразования значений диапазона в каноническую форму. Более подробную информацию см. в разделе «Определение новых типов-диапазонов». Создание канонической функции немного затруднено тем, что она должна быть определена до объявления самого типа-диапазона. Для этого сначала необходимо создать «пустышку» (shell type) — тип-заглушку, не имеющий никаких атрибутов, кроме имени и владельца. Это делается с помощью команды CREATE TYPE name без дополнительных параметров. Затем можно использовать этот тип-заглушку как тип параметра и результата при объявлении функции, а после этого объявить тип-диапазон с тем же именем. Это автоматически заменит запись «пустышки» на корректный тип-диапазон.
Необязательная функция subtype_diff должна принимать два значения базового типа в качестве параметров и возвращать значение типа double precision, представляющее разницу между двумя заданными значениями. Хотя эта функция не обязательна, её наличие повышает эффективность столбцов типа-диапазона при использовании индекса GiST.
Четвёртая форма команды CREATE TYPE создаёт новый базовый тип (скалярный тип). Чтобы создать новый базовый тип, вы должны быть суперпользователем. Параметры могут указываться в любом порядке (не обязательно в том, который показан в синтаксисе), и большинство из них являются необязательными. Перед определением типа необходимо зарегистрировать две или более функции (с помощью команды CREATE FUNCTION). Обязательными являются вспомогательные функции input_function и output_function, а функции receive_function, send_function, type_modifier_input_function, type_modifier_output_function и analyze_function — необязательны. Как правило, эти функции должны быть написаны на языке C или другом низкоуровневом языке. В базе данных YMatrix все функции, используемые для реализации типов данных, должны быть определены как IMMUTABLE.
Функция input_function преобразует внешнее текстовое представление типа во внутреннее представление, используемое операторами и функциями, определёнными для этого типа. Функция output_function выполняет обратное преобразование. Функция ввода может быть объявлена с одним параметром типа cstring или с тремя параметрами типов cstring, oid и integer. Первый параметр — это входной текст в виде строки C, второй параметр — OID самого типа (для массивных типов это OID типа элемента), а третий параметр — значение typmod целевого столбца, если оно известно (в противном случае передаётся -1). Функция ввода должна возвращать значение того же типа данных. Обычно функцию ввода следует объявлять как STRICT. Если она не является строгой, при чтении значения NULL первый параметр будет равен NULL при вызове функции. В этом случае функция также должна вернуть NULL, если только не произошла ошибка (это в первую очередь нужно для поддержки функций ввода доменов, которым может потребоваться отклонять входные значения NULL). Функции вывода должны быть объявлены с параметром нового типа данных. Функции вывода должны возвращать тип cstring. Функции вывода не вызываются для значений NULL.
Необязательная функция receive_function преобразует внешнее двоичное представление типа во внутреннее представление. Если эта функция не предоставлена, тип не сможет участвовать в двоичном вводе. Преобразование двоичных представлений во внутреннюю форму менее затратно, но легче переносится (например, стандартные целочисленные типы данных используют порядок байтов в сети как внешнее двоичное представление, а их внутреннее представление использует машинный порядок байтов). Функция receive должна выполнять достаточные проверки, чтобы гарантировать корректность значения. Функция receive может быть объявлена с параметром типа internal или с тремя параметрами типов internal, oid и integer. Первый параметр — это указатель на буфер StringInfo, содержащий полученные байты. Остальные необязательные параметры такие же, как и у текстовой функции ввода. Функция receive должна возвращать значение того же типа данных, что и входной тип. Обычно функцию receive следует объявлять как STRICT. Если она не является строгой, при чтении значения NULL первый параметр будет равен NULL при вызове функции. В этом случае функция также должна вернуть NULL, если только не произошла ошибка (это в первую очередь нужно для поддержки функций receive доменов, которым может потребоваться отклонять входные значения NULL). Аналогично, необязательная функция send_function преобразует внутреннее представление во внешнее двоичное представление. Если эта функция не предоставлена, тип не сможет участвовать в двоичном выводе. Функция send должна быть объявлена с параметром нового типа данных. Функция send должна возвращать тип bytea. Функция send не вызывается для значений NULL.
Если тип поддерживает модификаторы, требуются необязательные функции type_modifier_input_function и type_modifier_output_function. Модификаторы — это дополнительные ограничения, присоединяемые к объявлению типа, например char(5) или numeric(30,2). Хотя база данных YMatrix позволяет пользовательским типам использовать один или несколько простых констант или идентификаторов в качестве модификаторов, эта информация должна помещаться в одно неотрицательное целое число, чтобы храниться в системном каталоге. База данных YMatrix передаёт объявленные модификаторы функции type_modifier_input_function в виде массива строк типа cstring. Функция ввода модификатора должна проверить значение, и если оно некорректно, должна вызвать ошибку. Если значение корректно, функция ввода модификатора возвращает одно неотрицательное целое число, которое база данных YMatrix сохраняет в столбце typmod. Если тип не определён с использованием функции type_modifier_input_function, модификатор типа отклоняется. Функция type_modifier_output_function преобразует внутреннее целочисленное значение typmod обратно в правильный формат для отображения пользователю. Функция вывода модификатора должна возвращать значение типа cstring — это точная строка, которая будет добавлена к имени типа. Например, функция для типа numeric может вернуть (30,2). Функция type_modifier_output_function является необязательной. Если она не указана, формат отображения по умолчанию — это целочисленное значение typmod, заключённое в скобки.
На данный момент вы можете задаться вопросом, как функции ввода и вывода могут быть объявлены с новыми типами в качестве результатов или параметров. Ответ в том, что эти две функции должны быть созданы до создания нового типа. Решение состоит в том, чтобы сначала определить новый тип как «пустышку» (shell type) — это тип-заглушка, не имеющий никаких атрибутов, кроме имени и владельца. Это можно сделать с помощью команды CREATE TYPE name без дополнительных параметров. Затем можно определить функции ввода/вывода, ссылающиеся на этот заглушечный тип. Наконец, замените заглушечный тип полным определением с помощью команды CREATE TYPE с полным описанием, после чего новый тип можно будет использовать обычным образом. Параметр like_type предоставляет альтернативный способ указания основных свойств представления типа данных: копирования их из уже существующего типа. При этом копируются значения internallength, passedbyvalue, alignment и storage из указанного типа. (Хотя обычно это не требуется, некоторые из этих значений можно переопределить, указав их вместе с предложением LIKE.) Указание представления таким способом удобно при низкоуровневой реализации нового типа, основанной на существующих типах. Хотя детали внутреннего представления нового типа известны только функциям ввода/вывода и другим функциям, которые вы создаёте для его использования, некоторые свойства внутреннего представления должны быть объявлены базе данных YMatrix. Наиболее важным из них является internallength. Базовые типы данных могут иметь фиксированную длину (в этом случае internallength — положительное целое число) или переменную длину (что указывается установкой internallength в значение VARIABLE). (Внутренне это реализуется путём установки typlen в -1.) Все типы переменной длины должны начинать своё внутреннее представление с 4-байтового целого числа, указывающего общую длину значений типа.
Необязательный флаг PASSEDBYVALUE указывает, что значение данного типа данных должно передаваться по значению, а не по ссылке. Нельзя передавать по значению типы, чьё внутреннее представление превышает размер типа Datum (4 байта на большинстве компьютеров, 8 байт на некоторых).
Параметр alignment задаёт требования к выравниванию хранилища для типа данных. Допустимые значения соответствуют выравниванию по границам 1, 2, 4 или 8 байт. Обратите внимание, что параметры для типов переменной длины должны быть выровнены как минимум по 4-байтовой границе, поскольку они требуют int4 в качестве первого компонента.
Параметр storage позволяет выбрать стратегию хранения для типов переменной длины (для типов фиксированной длины разрешено только значение plain). Значение plain означает, что данные такого типа всегда будут храниться внутри строки и не будут сжиматься. extended означает, что система сначала попытается сжать длинное значение, а если оно всё ещё слишком велико, переместит его за пределы основной строки таблицы. external позволяет перемещать значения за пределы основной строки, но система не будет пытаться их сжимать. main разрешает сжатие, но препятствует перемещению значений за пределы основной строки. (Если нет другого способа уменьшить размер строки, элементы данных с такой стратегией хранения всё равно будут перемещены за пределы основной строки, но им будет отдан приоритет на сохранение внутри строки по сравнению с элементами со стратегиями extended и external.)
Если пользователь хочет, чтобы столбцы данного типа по умолчанию имели значение, отличное от null, можно указать значение по умолчанию. Для этого используется ключевое слово DEFAULT. (Это значение по умолчанию может быть переопределено явным предложением DEFAULT для конкретного столбца.)
Чтобы указать, что тип является массивом, используйте ключевое слово ELEMENT для указания типа элементов массива. Например, чтобы определить массив 4-байтовых целых чисел (int4), укажите ELEMENT = int4. Более подробная информация о типах массивов приведена ниже.
Параметры category и preferred могут использоваться для управления тем, какие неявные преобразования применяются в неоднозначных случаях. Каждый тип данных принадлежит категории, обозначенной одной ASCII-буквой, и каждый тип либо является «предпочтительным», либо нет в своей категории. Когда это правило помогает разрешить перегруженные функции или операторы, парсер предпочитает выполнять приведение к предпочтительному типу (но только из других типов той же категории). Для типов, у которых нет неявных преобразований ни к другим типам, ни от других типов, значения по умолчанию достаточны. Однако для набора связанных типов с неявными преобразованиями часто бывает полезно пометить их как принадлежащие одной категории и выбрать один или два «наиболее общих» типа в качестве предпочтительных в этой категории. Параметр category особенно полезен при добавлении пользовательских типов (например, числовых или строковых) в существующие встроенные категории. Вы также можете создавать новые категории, состоящие исключительно из пользовательских типов. Выберите любой символ ASCII, кроме заглавных букв, чтобы назвать такую категорию.
Чтобы указать использование разделителя между значениями во внешнем представлении массива этого типа, можно установить разделитель на определённый символ. Разделитель по умолчанию — запятая (,). Обратите внимание, что разделитель связан с типом элемента массива, а не с самим типом массива.
Если необязательный логический параметр collatable имеет значение true, определения столбцов и выражения этого типа могут содержать информацию о правилах сортировки с использованием предложения COLLATE. Реализация функций, работающих с этим типом, отвечает за фактическое использование этой информации; простое указание типа как поддерживающего сортировку автоматически не заставляет функции использовать эту информацию.
Каждый раз, когда создаётся пользовательский тип, база данных YMatrix автоматически создаёт связанный с ним тип массива, имя которого состоит из имени типа элемента с префиксом подчёркивания и усекается при необходимости, чтобы длина была меньше NAMEDATALEN байт. Если сгенерированное имя конфликтует с существующим именем типа, процесс повторяется до тех пор, пока не будет найдено уникальное имя. Этот неявно созданный тип массива имеет переменную длину и использует встроенные функции ввода и вывода array_in и array_out. Тип массива отслеживает все изменения владельца или схемы своего типа элемента и также удаляется при удалении типа элемента.
Если система автоматически создаёт правильный тип массива, возникает естественный вопрос: зачем тогда нужен параметр ELEMENT? Единственный полезный случай для параметра ELEMENT — это когда вы создаёте тип фиксированной длины, который внутренне представляет собой массив нескольких одинаковых элементов, и хотите разрешить прямой доступ к этим элементам через индексацию, в дополнение к операциям над типом в целом. Например, тип point представлен как два числа с плавающей точкой, к которым можно обращаться с помощью point[0] и point[1]. Обратите внимание, что эта функциональность применима только к типам фиксированной длины, внутренняя структура которых точно представляет собой последовательность одинаковых полей фиксированной длины. Типы переменной длины, поддерживающие доступ по индексу, должны иметь обобщённое внутреннее представление, использующее array_in и array_out. По историческим причинам (то есть это было очевидной ошибкой, но сейчас уже слишком поздно менять) индексы типов массивов фиксированной длины начинаются с нуля, в отличие от массивов переменной длины.
name
attribute_name
data_type
collation
label
subtype
subtype_operator_class
canonical_function
subtype_diff_function
input_function
output_function
receive_function
send_function
type_modifier_input_function
type_modifier_output_function
internallength
alignment
storage
like_type
category
preferred
default
element
delimiter
collatable
compression_type
compression_level
Имена пользовательских типов не могут начинаться с символа подчёркивания (_) и могут содержать не более 62 символов (или обычно NAMEDATALEN - 2, а не NAMEDATALEN - 1 символ, разрешённый для других имён). Имена типов, начинающиеся с подчёркивания, зарезервированы для внутренне создаваемых имён типов массивов.
База данных YMatrix не поддерживает добавление параметров хранения для строк или составных типов.
Параметры хранения, определённые на уровнях таблицы и столбца, переопределяют параметры хранения по умолчанию, определённые как скалярные типы. Поскольку после создания типа никаких ограничений нет, создание базового типа или типа диапазона эквивалентно предоставлению публичных прав на выполнение функций, указанных в определении типа. (Следовательно, создатель типа должен обладать этими функциями.) Обычно это не представляет проблемы для различных функций, полезных в определении типа. Однако следует внимательно продумать создание типа, который преобразует данные во внешний формат или из внешнего формата, особенно если требуется использование «секретной» информации.
В этом примере создаётся составной тип и используется в определении функции:
CREATE TYPE compfoo AS (f1 int, f2 text);
CREATE FUNCTION getfoo() RETURNS SETOF compfoo AS $$
SELECT fooid, fooname FROM foo
$$ LANGUAGE SQL;
В этом примере создаётся перечислимый тип mood и используется в определении таблицы:
CREATE TYPE mood AS ENUM ('sad', 'ok', 'happy');
CREATE TABLE person (
name text,
current_mood mood
);
INSERT INTO person VALUES ('Moe', 'happy');
SELECT * FROM person WHERE current_mood = 'happy';
name | current_mood
-----+------------------
Moe | happy
(1 row)
В этом примере создаётся тип диапазона:
CREATE TYPE float8_range AS RANGE (subtype = float8, subtype_diff = float8mi);
В этом примере создаётся базовый тип данных box, который затем используется в определении таблицы:
CREATE TYPE box;
CREATE FUNCTION my_box_in_function(cstring) RETURNS box AS
... ;
CREATE FUNCTION my_box_out_function(box) RETURNS cstring AS
... ;
CREATE TYPE box (
INTERNALLENGTH = 16,
INPUT = my_box_in_function,
OUTPUT = my_box_out_function
);
CREATE TABLE myboxes (
id integer,
description box
);
Если внутренняя структура типа box представляет собой массив из четырёх элементов типа float4, можно использовать следующий вариант:
CREATE TYPE box (
INTERNALLENGTH = 16,
INPUT = my_box_in_function,
OUTPUT = my_box_out_function,
ELEMENT = float4
);
Это позволит обращаться к компонентам значения box с помощью индексации. Во всём остальном тип ведёт себя так же, как и ранее.
В этом примере создаётся тип большого объекта и используется в определении таблицы:
CREATE TYPE bigobj (
INPUT = lo_filein, OUTPUT = lo_fileout,
INTERNALLENGTH = VARIABLE
);
CREATE TABLE big_objs (
id integer,
obj bigobj
);
Первая форма команды CREATE TYPE для создания составного типа соответствует стандарту SQL. Остальные формы являются расширениями базы данных YMatrix. Оператор CREATE TYPE в стандарте SQL также определяет другие формы, которые не реализованы в базе данных YMatrix.
Возможность создания составных типов без атрибутов является особенностью базы данных YMatrix, отличающейся от стандарта (аналогично аналогичному случаю в CREATE TABLE).