CREATE TYPE

Define a new data type.

Summary

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

Description

CREATE TYPE registers a new data type for use in the current database. The user who defines the type becomes its owner.

If a schema name is provided, the type is created in the specified schema. Otherwise, it is created in the current schema. The type name must be different from the name of any existing type or domain in the same schema. The type name must also be different from the name of any existing table in the same schema.

As shown in the syntax overview above, there are five forms of CREATE TYPE. They create composite types, enumeration types, range types, base types, or shell types, respectively. The first four are discussed below. A shell type is simply a placeholder for a type to be defined later; it is created by issuing CREATE TYPE without any parameters except the type name. As described in these sections, shell types are used as forward references when creating range types and base types.

Combination type

The first form of CREATE TYPE creates a composite type. A composite type is specified by a list of attribute names and data types. If the data type of an attribute is sortable, you can also specify the sort rule for that attribute. A composite type is essentially the same as a table's row type, but using CREATE TYPE avoids creating an actual table if you only want to define a single type. Standalone composite types are also useful, for example as function parameters or return types.

To create a composite type, you must have USAGE privileges on all of its attribute types.

Enumeration type

As described in the PostgreSQL documentation on enumeration types, the second form of CREATE TYPE creates an enumeration type. An enumeration type must consist of a list of one or more quoted labels, each of which must be no longer than NAMEDATALEN bytes (64 bytes in the standard PostgreSQL compilation).

Scope type

As described in the range type specification, the third form of CREATE TYPE creates a range type.

The subtype of a range type can be any type that has an associated B-Tree operator class (used to determine the order of values in the range type). Typically, the default B-Tree operator class for the subtype is used to determine the order. To use a non-default operator class, specify its name using subtype_opclass. If the subtype is sortable and you want to use a non-default sorting rule for the range's order, you can specify it using the collation option.

The optional canonical function must accept a parameter of the defined range type and return a value of the same type. When applicable, it is used to convert range values into a canonical form. For more information, see Defining New Range Types. Creating a canonical function is a bit tricky because it must be defined before declaring the range type. To do this, you must first create a shell type, which is a placeholder type with no attributes other than a name and owner. This can be done by issuing the command CREATE TYPE name without any additional parameters. You can then use the shell type as a parameter and result to declare the function, and finally declare the range type with the same name. This will automatically replace the shell type entry with a valid range type.

The optional subtype_diff function must accept two subtype type values as parameters and return a double precision value representing the difference between the two given values. Although this is optional, providing this function makes the range type column more efficient when using a GiST index.

Basic type

The fourth form of CREATE TYPE creates a new base type (scalar type). To create a new base type, you must be a superuser. Parameters can appear in any order (not just the order shown in the syntax), and most are optional. Before defining the type, you must register two or more functions (using CREATE FUNCTION). The support functions input_function and output_function are required, while the functions receive_function, send_function, type_modifier_input_function, type_modifier_output_function, and analyze_function are optional. Typically, these functions must be written in C or another low-level language. In the YMatrix database, any functions used to implement data types must be defined as IMMUTABLE.

The input_function converts the external textual representation of the type into the internal representation used by the operators and functions defined for the type. The output_function performs the reverse conversion. The input function can be declared with a single cstring-type parameter, or with three parameters of types cstring, oid, and integer. The first parameter is the input text as a C string, the second parameter is the OID of the type itself (for array types, it is the OID of the element type), and the third parameter is the typmod of the target column, if known (otherwise -1 is passed). The input function must return a value of the same data type. Typically, an input function should be declared as STRICT. If not, when reading a NULL input value, the first parameter will be NULL when the function is called. In this case, the function must still return NULL unless an error occurs (this is primarily to support domain input functions, which may need to reject NULL inputs). Output functions must be declared with a parameter of the new data type. Output functions must return a cstring type. Output functions are not called for NULL values.

The optional receive_function converts the external binary representation of a type into its internal representation. If this function is not provided, the type cannot participate in binary input. Converting binary representations to internal forms is less costly but easier to port (for example, standard integer data types use network byte order as their external binary representation, while their internal representation uses machine-native byte order). The receive function should perform sufficient checks to ensure the value is valid. The receive function can be declared with a parameter of type internal, or with three parameters of types internal, oid, and integer. The first parameter is a pointer to a StringInfo buffer containing the received byte string. The remaining optional parameters are the same as those for the text input function. The receive function must return a value of the same data type as the input. Typically, a receive function should be declared as STRICT. If not, when reading a NULL input value, the first parameter will be NULL when the function is called. In this case, the function must still return NULL unless an error occurs (this is primarily to support domain receive functions, which may need to reject NULL inputs). Similarly, the optional send_function converts the internal representation to an external binary representation. If this function is not provided, the type cannot participate in binary output. The send function must be declared with a parameter of the new data type. The send function must return the type bytea. The send function is not called for NULL values.

If the type supports modifiers, optional type_modifier_input_function and type_modifier_output_function are required. Modifiers are optional constraints attached to type declarations, such as char(5) or numeric(30,2). Although the YMatrix database allows user-defined types to use one or more simple constants or identifiers as modifiers, this information must fit into a single non-negative integer value to be stored in the system catalog. The YMatrix database passes the declared modifiers to the type_modifier_input_function as a cstring array. The modifier input function must validate the value, and if the value is incorrect, it must raise an error. If the value is correct, the modifier input function returns a single non-negative integer value, which is stored by the YMatrix database in the typmod column. If the type is not defined using the type_modifier_input_function, the type modifier is rejected. The type_modifier_output_function converts the internal integer typmod value back to the correct format for user display. The modifier output function must return a cstring value, which is the exact string to be appended to the type name. For example, a numeric function might return (30,2). type_modifier_output_function is optional. If not specified, the default display format is the typmod integer value stored in parentheses.

By now, you may be wondering how input and output functions can be declared to have new types as results or parameters. This is because these two functions must be created before the new type is created. The answer to this question is that the new type should first be defined as a shell type, which is a placeholder type with no attributes other than its name and owner. This can be done using the command CREATE TYPE name without any additional parameters. Then the I/O functions can be defined to reference this shell type. Finally, replace the shell type with a fully defined, valid type definition using the CREATE TYPE command with a complete definition, after which the new type can be used normally. The like_type parameter provides an alternative method for specifying the basic representation properties of a data type: copying them from certain existing types. Copy the values internallength, passedbyvalue, alignment, and storage from the specified type. (Although this is typically not desired, some of these values can be overridden by specifying them alongside the LIKE clause.) Specifying the representation in this way is useful for the low-level implementation of the new type “riding” on existing types in some way. Although the details of the internal representation of the new type are known only to I/O functions and other functions you create to use with that type, some properties of the internal representation must be declared to the YMatrix database. The most important of these is internallength. Basic data types can be fixed-length (in which case internallength is a positive integer) or variable-length (indicated by setting internallength to VARIABLE). (Internally, this is represented by setting typlen to -1.) All variable-length types must begin their internal representation with a 4-byte integer indicating the total length of the type's values.

The optional PASSEDBYVALUE flag indicates that the value of this data type must be passed by value rather than by reference. You cannot pass value types whose internal representation exceeds the size of the Datum type (4 bytes on most computers, 8 bytes on a few).

The alignment parameter specifies the storage alignment requirements for the data type. Valid values correspond to alignment on 1-, 2-, 4-, or 8-byte boundaries. Note that parameters for variable-length types must be aligned to at least 4 bytes, as they require an int4 as their first component.

The storage parameter allows you to select a storage strategy for variable-length data types (only plain is allowed for fixed-length types). plain specifies that data of this type will always be stored in-line and will not be compressed. extended specifies that the system will first attempt to compress a long data value, and will move the value out of the main table row if the data is still too long. external allows values to be moved out of the main table, but the system will not attempt to compress them. main allows compression but discourages moving values out of the main table. (If there is no other way to make the row size appropriate, data items with this storage strategy will still be moved out of the main table, but they will be prioritized for retention in the main table compared to extended and external items.)

If the user wants the columns of a data type to default to a value other than null, a default value can be specified. Use the DEFAULT keyword to specify the default value. (This default value may be overridden by an explicit DEFAULT clause for a specific column.)

To specify that the type is an array, use the ELEMENT keyword to specify the type of the array elements. For example, to define an array of 4-byte integers (int4), specify ELEMENT = int4. More detailed information about array types is shown below.

The category and preferred parameters can be used to help control which implicit casting is applied in ambiguous cases. Each data type belongs to a category named with a single ASCII character, and each type is either “preferred” or not in its category. When this rule helps resolve overloaded functions or operators, the parser will prefer to cast to the preferred type (but only from other types in the same category). For types that do not have implicit conversions to other types or from any other types, the default settings are sufficient. However, for a set of related types with implicit conversions, it is often helpful to mark them all as belonging to a single category and select one or two “most general” types as the preferred types within that category. The category parameter is particularly useful when adding user-defined types (such as numeric or string types) to existing built-in categories. You can also create new categories consisting entirely of user-defined types. Choose any ASCII character other than uppercase letters to name such a category.

To specify the use of delimiters between values in the external representation of this type of array, you can set the delimiter to a specific character. The default delimiter is a comma (,). Note that the delimiter is associated with the array element type, not with the array type itself.

If the optional boolean parameter collatable is true, the column definitions and expressions of the type can carry sorting rule information using the COLLATE clause. The implementation of functions operating on the type is responsible for actually utilizing this information; simply marking the type as sortable does not automatically cause them to use such information.

Array type

Whenever a user-defined type is created, the YMatrix database automatically creates an associated array type whose name consists of the element type name prefixed with an underscore and truncated as necessary to make its length less than NAMEDATALEN bytes. If the generated name conflicts with an existing type name, the process is repeated until a non-conflicting name is found. This implicitly created array type is variable-length and uses the built-in input and output functions array_in and array_out. The array type tracks all changes to its element type's owner or pattern and is also deleted when the element type is deleted.

If the system automatically creates the correct array type, you might naturally ask why there is an ELEMENT option. The only useful case for the ELEMENT option is when you are creating a fixed-length type that is internally an array of multiple identical items, and you want to allow direct access to these items via subscripting in addition to the overall operations provided for the type. For example, the type point is represented as two floating-point numbers, which can be accessed using point[0] and point[1]. Note that this functionality is only applicable to fixed-length types whose internal form is precisely a sequence of identical fixed-length fields. Variable-length types that support index access must have a generalized internal representation using array_in and array_out. Due to historical reasons (i.e., it was clearly wrong, but it's too late to change now), the indices of fixed-length array types start from zero, unlike variable-length arrays.

Parameters

name

  • The name of the type to be created (can be specified by a pattern).

attribute_name

  • The name of the composite type attribute (column).

data_type

  • The name of the existing data type for composite columns.

collation

  • The name of the existing sort rule associated with a composite type column or range type.

label

  • String text representing a text label associated with a value of an enumeration type.

subtype

  • The scope type will represent the name of the element type that defines its scope.

subtype_operator_class

  • The name of the B-tree operator class for the subtype.

canonical_function

  • The name of the normalization function for the range type.

subtype_diff_function

  • The name of the difference function of the subtype.

input_function

  • The name of the function that converts data from an external text form to an internal form.

output_function

  • The name of the function that converts data from an internal type to an external text form.

receive_function

  • Function name for converting data from external binary form to internal form.

send_function

  • The name of the function that converts data from an internal type to an external binary form.

type_modifier_input_function

  • Convert the type modifier array to the internal form of the function name.

type_modifier_output_function

  • A function name that converts the internal form of a type modifier to an external text form.

internallength

  • A numeric constant specifying the length (in bytes) of the internal representation of the new type. The default assumption is variable length.

alignment

  • The storage alignment requirements for this data type. If specified, it must be char, int2, int4, or double. The default is int4.

storage

  • The storage strategy for this data type. Must be plain, external, extended, or main. The default is plain.

like_type

  • The name of an existing data type that has the same expression as the new type. The values of internallength, passedbyvalue, alignment, and storage will be copied from this type, unless explicitly overridden elsewhere in this CREATE TYPE command.

category

  • This type of category code (a single ASCII character). The default value is ‘U’, which indicates a user-defined type. You can find other standard category codes in the pg_type category code. You can also assign unused ASCII characters to custom categories you create.

preferred

  • If this type is the preferred type in its type category, then it is true; otherwise, it is false. The default value is false. Be careful when creating a new preferred type in an existing type category; this may result in unexpected behavior changes.

default

  • The default value for the data type. If omitted, the default value is NULL.

element

  • The type created is an array; this specifies the type of the array elements.

delimiter

  • Use delimiters between values in this type of array.

collatable

  • If this type of operation can use sorting rule information, then it is true. The default is false.

compression_type

  • Set to ZLIB (default), ZSTD, RLE_TYPE, or QUICKLZ1 to specify the compression type used in columns of this type.

compression_level

  • For ZSTD compression, set it to an integer value between 1 (fastest compression) and 19 (highest compression ratio). For ZLIB compression, the valid range is 1 to 9. The QuickLZ compression level can only be set to 1. For RLE_TYPE, the compression level can be set to an integer value between 1 (fastest compression) and 4 (highest compression ratio). The default compression level is 1. blocksize
  • Set the size of each block in the column (in bytes). BLOCKSIZE must be between 8192 and 2097152 bytes and a multiple of 8192. The default block size is 32768.

Note

User-defined type names cannot start with an underscore character (_) and can only be 62 characters long (or usually NAMEDATALEN - 2, not NAMEDATALEN - 1 character allowed by other names). The type name beginning with the underscore is reserved for the array type name created internally.

YMatrix database does not support adding storage options for rows or composite types.

Storage options defined at the table and column levels will override the default storage options defined as scalar types. Since there is no restriction once a data type is created, creating a base type or scope type is tantamount to granting public execution permissions to the functions mentioned in the type definition. (So, the creator of the type must have these functions.) This is usually not a problem for various functions that are useful in the type definition. But you may need to think twice when designing a type that converts it to an external format or converts from an external format that requires the use of "secret" information.

Example

This example creates a composite type and uses it in a function definition:

CREATE TYPE compfoo AS (f1 int, f2 text);

CREATE FUNCTION getfoo() RETURNS SETOF compfoo AS $$
    SELECT fooid, fooname FROM foo
$$ LANGUAGE SQL;

This example creates the enum type mood and uses it in the table definition.

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)

This example creates a scope type:

CREATE TYPE float8_range AS RANGE (subtype = float8, subtype_diff = float8mi);

This example creates the base data type box, and then uses it in the table definition:

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
);

If the internal structure of the box is an array of four float4 elements, you can use it instead:

CREATE TYPE box (
    INTERNALLENGTH = 16,
    INPUT = my_box_in_function,
    OUTPUT = my_box_out_function,
    ELEMENT = float4
);

This will allow access to the component number of the box value through the subscript. Otherwise, the type behaves the same as before.

This example creates a large object type and uses it in the table definition:

CREATE TYPE bigobj (
    INPUT = lo_filein, OUTPUT = lo_fileout,
    INTERNALLENGTH = VARIABLE
);

CREATE TABLE big_objs (
    id integer,
    obj bigobj
    );

compatibility

The first form of creating a composite type CREATE TYPE command is SQL-compliant. Other forms are YMatrix database extensions. The CREATE TYPE statement in the SQL standard also defines other forms not implemented in the YMatrix database.

The ability to create composite types with zero attributes is a standard-specific bias for YMatrix databases (similar to the same case in CREATE TABLE).

See also

ALTER TYPE, DROP TYPE