{"Entry":{"collection":"sql","key":"create-type","name":"CREATE TYPE","aliases":["createtype"],"metadata":{"aliases":["createtype"],"changed_in":["7.0","7.1","7.2","7.3","7.4","8.0","8.2","8.3","8.4","9.0","9.1","9.2","14"],"changes":[{"from":"6.4","purpose_changed":false,"renamed":null,"sections":{"added":[],"changed":["description","examples"],"removed":[]},"status":"changed","synopsis":null,"to":"6.5"},{"from":"6.5","purpose_changed":false,"renamed":null,"sections":{"added":[],"changed":["description","examples"],"removed":[]},"status":"changed","synopsis":{"added":[", INTERNALLENGTH = { internallength | VARIABLE } [ , EXTERNALLENGTH = { externallength | VARIABLE } ]","[ , DEFAULT = \"default\" ]"],"removed":[", INTERNALLENGTH = (internallength | VARIABLE)","[ , EXTERNALLENGTH = (externallength | VARIABLE) ]","[ , DELIMITER      = delimiter ]","[ , DEFAULT        = \"default\" ]"]},"to":"7.0"},{"from":"7.0","purpose_changed":false,"renamed":{"from_file":"sql-createtype.htm","to_file":"sql-createtype.html"},"sections":{"added":[],"changed":["description","examples"],"removed":[]},"status":"changed","synopsis":{"added":["[ , ALIGNMENT = alignment ]","[ , STORAGE = storage ]"],"removed":[]},"to":"7.1"},{"from":"7.1","purpose_changed":true,"renamed":null,"sections":{"added":["notes","see_also"],"changed":["description","examples","compatibility"],"removed":[]},"status":"changed","synopsis":{"added":["[ , DEFAULT = default ]"],"removed":["[ , DEFAULT = \"default\" ]"]},"to":"7.2"},{"from":"7.2","purpose_changed":false,"renamed":null,"sections":{"added":[],"changed":["description","notes","examples","see_also"],"removed":[]},"status":"changed","synopsis":{"added":["CREATE TYPE typename AS","( column_name data_type [, ... ] )"],"removed":["[ , EXTERNALLENGTH = { externallength | VARIABLE } ]","[ , DEFAULT = default ]","[ , SEND = send_function ] [ , RECEIVE = receive_function ]","[ , PASSEDBYVALUE ]"]},"to":"7.3"},{"from":"7.3","purpose_changed":false,"renamed":null,"sections":{"added":["parameters"],"changed":["description","notes","examples","see_also"],"removed":[]},"status":"changed","synopsis":{"added":["CREATE TYPE name AS","( attribute_name data_type [, ... ] )","CREATE TYPE name (","[ , RECEIVE = receive_function ]","[ , SEND = send_function ]","[ , INTERNALLENGTH = { internallength | VARIABLE } ]","[ , PASSEDBYVALUE ]","[ , ALIGNMENT = alignment ]","[ , STORAGE = storage ]"],"removed":["CREATE TYPE typename ( INPUT = input_function, OUTPUT = output_function","[ , PASSEDBYVALUE ]","[ , ALIGNMENT = alignment ]","[ , STORAGE = storage ]","CREATE TYPE typename AS","( column_name data_type [, ... ] )"]},"to":"7.4"},{"from":"7.4","purpose_changed":false,"renamed":null,"sections":{"added":[],"changed":["description","parameters","examples","compatibility","see_also"],"removed":[]},"status":"changed","synopsis":{"added":["[ , SEND = send_function ]","[ , ANALYZE = analyze_function ]"],"removed":[]},"to":"8.0"},{"from":"8.0","purpose_changed":false,"renamed":null,"sections":{"added":[],"changed":["description","examples","compatibility"],"removed":[]},"status":"changed","synopsis":null,"to":"8.1"},{"from":"8.1","purpose_changed":false,"renamed":null,"sections":{"added":[],"changed":["description","notes","examples","see_also"],"removed":[]},"status":"changed","synopsis":{"added":["CREATE TYPE name"],"removed":[]},"to":"8.2"},{"from":"8.2","purpose_changed":false,"renamed":null,"sections":{"added":[],"changed":["description","parameters","notes","examples"],"removed":[]},"status":"changed","synopsis":{"added":["( attribute_name data_type [, ... ] )","CREATE TYPE name AS ENUM","( 'label' [, ... ] )","[ , SEND = send_function ]","[ , TYPMOD_IN = type_modifier_input_function ]","[ , TYPMOD_OUT = type_modifier_output_function ]"],"removed":[]},"to":"8.3"},{"from":"8.3","purpose_changed":false,"renamed":null,"sections":{"added":[],"changed":["description","parameters","notes"],"removed":[]},"status":"changed","synopsis":{"added":["[ , LIKE = like_type ]","[ , CATEGORY = category ]","[ , PREFERRED = preferred ]","[ , DEFAULT = default ]"],"removed":[]},"to":"8.4"},{"from":"8.4","purpose_changed":false,"renamed":null,"sections":{"added":[],"changed":["parameters","examples"],"removed":[]},"status":"changed","synopsis":{"added":["( [ 'label' [, ... ] ] )"],"removed":[]},"to":"9.0"},{"from":"9.0","purpose_changed":false,"renamed":null,"sections":{"added":[],"changed":["description","parameters","compatibility","see_also"],"removed":[]},"status":"changed","synopsis":{"added":["( [ attribute_name data_type [ COLLATE collation ] [, ... ] ] )","[ , COLLATABLE = collatable ]"],"removed":[]},"to":"9.1"},{"from":"9.1","purpose_changed":false,"renamed":null,"sections":{"added":[],"changed":["description","parameters","notes","examples","compatibility"],"removed":[]},"status":"changed","synopsis":{"added":["( [ 'label' [, ... ] ] )","CREATE TYPE name AS RANGE (","SUBTYPE = subtype","[ , SUBTYPE_OPCLASS = subtype_operator_class ]","[ , COLLATION = collation ]","[ , CANONICAL = canonical_function ]","[ , SUBTYPE_DIFF = subtype_diff_function ]"],"removed":[]},"to":"9.2"},{"from":"9.2","purpose_changed":false,"renamed":null,"sections":{"added":[],"changed":["description","parameters"],"removed":[]},"status":"changed","synopsis":null,"to":"9.3"},{"from":"9.3","purpose_changed":false,"renamed":null,"sections":{"added":[],"changed":["description","parameters"],"removed":[]},"status":"changed","synopsis":null,"to":"9.4"},{"from":"9.4","purpose_changed":false,"renamed":null,"sections":{"added":[],"changed":["description","parameters"],"removed":[]},"status":"changed","synopsis":null,"to":"9.5"},{"from":"9.5","purpose_changed":false,"renamed":null,"sections":{"added":[],"changed":["description","parameters","notes","examples"],"removed":[]},"status":"changed","synopsis":null,"to":"9.6"},{"from":"9.6","purpose_changed":false,"renamed":null,"sections":{"added":[],"changed":["description","parameters","notes","examples"],"removed":[]},"status":"changed","synopsis":null,"to":"10"},{"from":"10","purpose_changed":false,"renamed":null,"sections":{"added":[],"changed":["description","parameters","examples"],"removed":[]},"status":"changed","synopsis":null,"to":"11"},{"from":"11","purpose_changed":false,"renamed":null,"sections":{"added":[],"changed":["description","parameters","examples"],"removed":[]},"status":"changed","synopsis":null,"to":"12"},{"from":"12","purpose_changed":false,"renamed":null,"sections":{"added":[],"changed":["parameters","notes"],"removed":[]},"status":"changed","synopsis":null,"to":"13"},{"from":"13","purpose_changed":false,"renamed":null,"sections":{"added":[],"changed":["description","parameters","examples"],"removed":[]},"status":"changed","synopsis":{"added":["[ , MULTIRANGE_TYPE_NAME = multirange_type_name ]","[ , ANALYZE = analyze_function ]","[ , SUBSCRIPT = subscript_function ]"],"removed":[]},"to":"14"},{"from":"14","purpose_changed":false,"renamed":null,"sections":{"added":[],"changed":["description","parameters"],"removed":[]},"status":"changed","synopsis":null,"to":"15"},{"from":"15","purpose_changed":false,"renamed":null,"sections":{"added":[],"changed":["notes"],"removed":[]},"status":"changed","synopsis":null,"to":"16"},{"from":"16","purpose_changed":false,"renamed":null,"sections":{"added":[],"changed":["description","parameters","examples"],"removed":[]},"status":"changed","synopsis":null,"to":"17"},{"from":"17","purpose_changed":false,"renamed":null,"sections":{"added":[],"changed":["description","parameters"],"removed":[]},"status":"changed","synopsis":null,"to":"18"}],"content_hash":"106321f54e0015df6229cec37821dce34907b3a1dced9b049875fcab59245c5b","editorial":{},"first_version":"6.4","group":"type","imported_at":"2026-09-30T17:43:37.62957+08:00","last_version":"20","name":"CREATE TYPE","object":"TYPE","position":3020,"present_in":["6.4","6.5","7.0","7.1","7.2","7.3","7.4","8.0","8.1","8.2","8.3","8.4","9.0","9.1","9.2","9.3","9.4","9.5","9.6","10","11","12","13","14","15","16","17","18","19","20"],"purpose":"define a new data type","purpose_zh":"","related":["alter-type","create-domain","create-function","drop-type"],"slug":"create-type","source_rev":"a709ab85","synopsis":"CREATE TYPE name AS\n( [ attribute_name data_type [ COLLATE collation ] [, ... ] ] )\n\nCREATE TYPE name AS ENUM\n( [ 'label' [, ... ] ] )\n\nCREATE TYPE name AS RANGE (\nSUBTYPE = subtype\n[ , SUBTYPE_OPCLASS = subtype_operator_class ]\n[ , COLLATION = collation ]\n[ , CANONICAL = canonical_function ]\n[ , SUBTYPE_DIFF = subtype_diff_function ]\n[ , MULTIRANGE_TYPE_NAME = multirange_type_name ]\n)\n\nCREATE TYPE name (\nINPUT = input_function,\nOUTPUT = output_function\n[ , RECEIVE = receive_function ]\n[ , SEND = send_function ]\n[ , TYPMOD_IN = type_modifier_input_function ]\n[ , TYPMOD_OUT = type_modifier_output_function ]\n[ , ANALYZE = analyze_function ]\n[ , SUBSCRIPT = subscript_function ]\n[ , INTERNALLENGTH = { internallength | VARIABLE } ]\n[ , PASSEDBYVALUE ]\n[ , ALIGNMENT = alignment ]\n[ , STORAGE = storage ]\n[ , LIKE = like_type ]\n[ , CATEGORY = category ]\n[ , PREFERRED = preferred ]\n[ , DEFAULT = default ]\n[ , ELEMENT = element ]\n[ , DELIMITER = delimiter ]\n[ , COLLATABLE = collatable ]\n)\n\nCREATE TYPE name","verb":"CREATE"}},"Definition":{"Collection":"sql","Key":"create-type","SourceDatabase":"center","Version":"18","SourceTable":"sqlcmd","SourceKey":"create-type","SourceRevision":"a709ab85","Facts":{"anchor":"SQL-CREATETYPE","file":"sql-createtype.html","lang":"en","name":"CREATE TYPE","purpose":"define a new data type","purpose_zh":"","related":["alter-type","create-domain","create-function","drop-type"],"sections":[{"html":"\u003cp\u003e\u003ccode class=\"command\"\u003eCREATE TYPE\u003c/code\u003e registers a new data type for use in the current database. The user who defines a type becomes its owner.\u003c/p\u003e\u003cp\u003eIf a schema name is given then the type is created in the specified schema. Otherwise it is created in the current schema. The type name must be distinct from the name of any existing type or domain in the same schema. (Because tables have associated data types, the type name must also be distinct from the name of any existing table in the same schema.)\u003c/p\u003e\u003cp\u003eThere are five forms of \u003ccode class=\"command\"\u003eCREATE TYPE\u003c/code\u003e, as shown in the syntax synopsis above. They respectively create a \u003cem class=\"firstterm\"\u003ecomposite type\u003c/em\u003e, an \u003cem class=\"firstterm\"\u003eenum type\u003c/em\u003e, a \u003cem class=\"firstterm\"\u003erange type\u003c/em\u003e, a \u003cem class=\"firstterm\"\u003ebase type\u003c/em\u003e, or a \u003cem class=\"firstterm\"\u003eshell type\u003c/em\u003e. The first four of these are discussed in turn below. A shell type is simply a placeholder for a type to be defined later; it is created by issuing \u003ccode class=\"command\"\u003eCREATE TYPE\u003c/code\u003e with no parameters except for the type name. Shell types are needed as forward references when creating range types and base types, as discussed in those sections.\u003c/p\u003e\u003cdiv class=\"refsect2\"\u003e\u003ch3\u003eComposite Types\u003c/h3\u003e\u003cp\u003eThe first form of \u003ccode class=\"command\"\u003eCREATE TYPE\u003c/code\u003e creates a composite type. The composite type is specified by a list of attribute names and data types. An attribute's collation can be specified too, if its data type is collatable. A composite type is essentially the same as the row type of a table, but using \u003ccode class=\"command\"\u003eCREATE TYPE\u003c/code\u003e avoids the need to create an actual table when all that is wanted is to define a type. A stand-alone composite type is useful, for example, as the argument or return type of a function.\u003c/p\u003e\u003cp\u003eTo be able to create a composite type, you must have \u003ccode class=\"literal\"\u003eUSAGE\u003c/code\u003e privilege on all attribute types.\u003c/p\u003e\u003c/div\u003e\u003cdiv class=\"refsect2\"\u003e\u003ch3\u003eEnumerated Types\u003c/h3\u003e\u003cp\u003eThe second form of \u003ccode class=\"command\"\u003eCREATE TYPE\u003c/code\u003e creates an enumerated (enum) type, as described in \u003ca href=\"/docs/18/datatype-enum.html\" title=\"8.7. Enumerated Types\"\u003eSection 8.7\u003c/a\u003e. Enum types take a list of quoted labels, each of which must be less than \u003ccode class=\"symbol\"\u003eNAMEDATALEN\u003c/code\u003e bytes long (64 bytes in a standard \u003cspan class=\"productname\"\u003ePostgreSQL\u003c/span\u003e build). (It is possible to create an enumerated type with zero labels, but such a type cannot be used to hold values before at least one label is added using \u003ca href=\"/docs/18/sql-altertype.html\" title=\"ALTER TYPE\"\u003e\u003ccode class=\"command\"\u003eALTER TYPE\u003c/code\u003e\u003c/a\u003e.)\u003c/p\u003e\u003c/div\u003e\u003cdiv class=\"refsect2\"\u003e\u003ch3\u003eRange Types\u003c/h3\u003e\u003cp\u003eThe third form of \u003ccode class=\"command\"\u003eCREATE TYPE\u003c/code\u003e creates a new range type, as described in \u003ca href=\"/docs/18/rangetypes.html\" title=\"8.17. Range Types\"\u003eSection 8.17\u003c/a\u003e.\u003c/p\u003e\u003cp\u003eThe range type's \u003cem class=\"replaceable\"\u003e\u003ccode\u003esubtype\u003c/code\u003e\u003c/em\u003e can be any type with an associated b-tree operator class (to determine the ordering of values for the range type). Normally the subtype's default b-tree operator class is used to determine ordering; to use a non-default operator class, specify its name with \u003cem class=\"replaceable\"\u003e\u003ccode\u003esubtype_opclass\u003c/code\u003e\u003c/em\u003e. If the subtype is collatable, and you want to use a non-default collation in the range's ordering, specify the desired collation with the \u003cem class=\"replaceable\"\u003e\u003ccode\u003ecollation\u003c/code\u003e\u003c/em\u003e option.\u003c/p\u003e\u003cp\u003eThe optional \u003cem class=\"replaceable\"\u003e\u003ccode\u003ecanonical\u003c/code\u003e\u003c/em\u003e function must take one argument of the range type being defined, and return a value of the same type. This is used to convert range values to a canonical form, when applicable. See \u003ca href=\"/docs/18/rangetypes.html#RANGETYPES-DEFINING\" title=\"8.17.8. Defining New Range Types\"\u003eSection 8.17.8\u003c/a\u003e for more information. Creating a \u003cem class=\"replaceable\"\u003e\u003ccode\u003ecanonical\u003c/code\u003e\u003c/em\u003e function is a bit tricky, since it must be defined before the range type can be declared. To do this, you must first create a shell type, which is a placeholder type that has no properties except a name and an owner. This is done by issuing the command \u003ccode class=\"literal\"\u003eCREATE TYPE \u003cem class=\"replaceable\"\u003e\u003ccode\u003ename\u003c/code\u003e\u003c/em\u003e\u003c/code\u003e, with no additional parameters. Then the function can be declared using the shell type as argument and result, and finally the range type can be declared using the same name. This automatically replaces the shell type entry with a valid range type.\u003c/p\u003e\u003cp\u003eThe optional \u003cem class=\"replaceable\"\u003e\u003ccode\u003esubtype_diff\u003c/code\u003e\u003c/em\u003e function must take two values of the \u003cem class=\"replaceable\"\u003e\u003ccode\u003esubtype\u003c/code\u003e\u003c/em\u003e type as argument, and return a \u003ccode class=\"type\"\u003edouble precision\u003c/code\u003e value representing the difference between the two given values. While this is optional, providing it allows much greater efficiency of GiST indexes on columns of the range type. See \u003ca href=\"/docs/18/rangetypes.html#RANGETYPES-DEFINING\" title=\"8.17.8. Defining New Range Types\"\u003eSection 8.17.8\u003c/a\u003e for more information.\u003c/p\u003e\u003cp\u003eThe optional \u003cem class=\"replaceable\"\u003e\u003ccode\u003emultirange_type_name\u003c/code\u003e\u003c/em\u003e parameter specifies the name of the corresponding multirange type. If not specified, this name is chosen automatically as follows. If the range type name contains the substring \u003ccode class=\"literal\"\u003erange\u003c/code\u003e, then the multirange type name is formed by replacement of the \u003ccode class=\"literal\"\u003erange\u003c/code\u003e substring with \u003ccode class=\"literal\"\u003emultirange\u003c/code\u003e in the range type name. Otherwise, the multirange type name is formed by appending a \u003ccode class=\"literal\"\u003e_multirange\u003c/code\u003e suffix to the range type name.\u003c/p\u003e\u003cp\u003eTo be able to create a range type, you must have \u003ccode class=\"literal\"\u003eUSAGE\u003c/code\u003e privilege on the subtype.\u003c/p\u003e\u003c/div\u003e\u003cdiv class=\"refsect2\"\u003e\u003ch3\u003eBase Types\u003c/h3\u003e\u003cp\u003eThe fourth form of \u003ccode class=\"command\"\u003eCREATE TYPE\u003c/code\u003e creates a new base type (scalar type). To create a new base type, you must be a superuser. (This restriction is made because an erroneous type definition could confuse or even crash the server.)\u003c/p\u003e\u003cp\u003eThe parameters can appear in any order, not only that illustrated above, and most are optional. You must register two or more functions (using \u003ccode class=\"command\"\u003eCREATE FUNCTION\u003c/code\u003e) before defining the type. The support functions \u003cem class=\"replaceable\"\u003e\u003ccode\u003einput_function\u003c/code\u003e\u003c/em\u003e and \u003cem class=\"replaceable\"\u003e\u003ccode\u003eoutput_function\u003c/code\u003e\u003c/em\u003e are required, while the functions \u003cem class=\"replaceable\"\u003e\u003ccode\u003ereceive_function\u003c/code\u003e\u003c/em\u003e, \u003cem class=\"replaceable\"\u003e\u003ccode\u003esend_function\u003c/code\u003e\u003c/em\u003e, \u003cem class=\"replaceable\"\u003e\u003ccode\u003etype_modifier_input_function\u003c/code\u003e\u003c/em\u003e, \u003cem class=\"replaceable\"\u003e\u003ccode\u003etype_modifier_output_function\u003c/code\u003e\u003c/em\u003e, \u003cem class=\"replaceable\"\u003e\u003ccode\u003eanalyze_function\u003c/code\u003e\u003c/em\u003e, and \u003cem class=\"replaceable\"\u003e\u003ccode\u003esubscript_function\u003c/code\u003e\u003c/em\u003e are optional. Generally these functions have to be coded in C or another low-level language.\u003c/p\u003e\u003cp\u003eThe \u003cem class=\"replaceable\"\u003e\u003ccode\u003einput_function\u003c/code\u003e\u003c/em\u003e converts the type's external textual representation to the internal representation used by the operators and functions defined for the type. \u003cem class=\"replaceable\"\u003e\u003ccode\u003eoutput_function\u003c/code\u003e\u003c/em\u003e performs the reverse transformation. The input function can be declared as taking one argument of type \u003ccode class=\"type\"\u003ecstring\u003c/code\u003e, or as taking three arguments of types \u003ccode class=\"type\"\u003ecstring\u003c/code\u003e, \u003ccode class=\"type\"\u003eoid\u003c/code\u003e, \u003ccode class=\"type\"\u003einteger\u003c/code\u003e. The first argument is the input text as a C string, the second argument is the type's own OID (except for array types, which instead receive their element type's OID), and the third is the \u003ccode class=\"literal\"\u003etypmod\u003c/code\u003e of the destination column, if known (-1 will be passed if not). The input function must return a value of the data type itself. Usually, an input function should be declared STRICT; if it is not, it will be called with a NULL first parameter when reading a NULL input value. The function must still return NULL in this case, unless it raises an error. (This case is mainly meant to support domain input functions, which might need to reject NULL inputs.) The output function must be declared as taking one argument of the new data type. The output function must return type \u003ccode class=\"type\"\u003ecstring\u003c/code\u003e. Output functions are not invoked for NULL values.\u003c/p\u003e\u003cp\u003eThe optional \u003cem class=\"replaceable\"\u003e\u003ccode\u003ereceive_function\u003c/code\u003e\u003c/em\u003e converts the type's external binary representation to the internal representation. If this function is not supplied, the type cannot participate in binary input. The binary representation should be chosen to be cheap to convert to internal form, while being reasonably portable. (For example, the standard integer data types use network byte order as the external binary representation, while the internal representation is in the machine's native byte order.) The receive function should perform adequate checking to ensure that the value is valid. The receive function can be declared as taking one argument of type \u003ccode class=\"type\"\u003einternal\u003c/code\u003e, or as taking three arguments of types \u003ccode class=\"type\"\u003einternal\u003c/code\u003e, \u003ccode class=\"type\"\u003eoid\u003c/code\u003e, \u003ccode class=\"type\"\u003einteger\u003c/code\u003e. The first argument is a pointer to a \u003ccode class=\"type\"\u003eStringInfo\u003c/code\u003e buffer holding the received byte string; the optional arguments are the same as for the text input function. The receive function must return a value of the data type itself. Usually, a receive function should be declared STRICT; if it is not, it will be called with a NULL first parameter when reading a NULL input value. The function must still return NULL in this case, unless it raises an error. (This case is mainly meant to support domain receive functions, which might need to reject NULL inputs.) Similarly, the optional \u003cem class=\"replaceable\"\u003e\u003ccode\u003esend_function\u003c/code\u003e\u003c/em\u003e converts from the internal representation to the external binary representation. If this function is not supplied, the type cannot participate in binary output. The send function must be declared as taking one argument of the new data type. The send function must return type \u003ccode class=\"type\"\u003ebytea\u003c/code\u003e. Send functions are not invoked for NULL values.\u003c/p\u003e\u003cp\u003eYou should at this point be wondering how the input and output functions can be declared to have results or arguments of the new type, when they have to be created before the new type can be created. The answer is that the type should first be defined as a \u003cem class=\"firstterm\"\u003eshell type\u003c/em\u003e, which is a placeholder type that has no properties except a name and an owner. This is done by issuing the command \u003ccode class=\"literal\"\u003eCREATE TYPE \u003cem class=\"replaceable\"\u003e\u003ccode\u003ename\u003c/code\u003e\u003c/em\u003e\u003c/code\u003e, with no additional parameters. Then the C I/O functions can be defined referencing the shell type. Finally, \u003ccode class=\"command\"\u003eCREATE TYPE\u003c/code\u003e with a full definition replaces the shell entry with a complete, valid type definition, after which the new type can be used normally.\u003c/p\u003e\u003cp\u003eThe optional \u003cem class=\"replaceable\"\u003e\u003ccode\u003etype_modifier_input_function\u003c/code\u003e\u003c/em\u003e and \u003cem class=\"replaceable\"\u003e\u003ccode\u003etype_modifier_output_function\u003c/code\u003e\u003c/em\u003e are needed if the type supports modifiers, that is optional constraints attached to a type declaration, such as \u003ccode class=\"literal\"\u003echar(5)\u003c/code\u003e or \u003ccode class=\"literal\"\u003enumeric(30,2)\u003c/code\u003e. \u003cspan class=\"productname\"\u003ePostgreSQL\u003c/span\u003e allows user-defined types to take one or more simple constants or identifiers as modifiers. However, this information must be capable of being packed into a single non-negative integer value for storage in the system catalogs. The \u003cem class=\"replaceable\"\u003e\u003ccode\u003etype_modifier_input_function\u003c/code\u003e\u003c/em\u003e is passed the declared modifier(s) in the form of a \u003ccode class=\"type\"\u003ecstring\u003c/code\u003e array. It must check the values for validity (throwing an error if they are wrong), and if they are correct, return a single non-negative \u003ccode class=\"type\"\u003einteger\u003c/code\u003e value that will be stored as the column \u003cspan class=\"quote\"\u003e“\u003cspan class=\"quote\"\u003etypmod\u003c/span\u003e”\u003c/span\u003e. Type modifiers will be rejected if the type does not have a \u003cem class=\"replaceable\"\u003e\u003ccode\u003etype_modifier_input_function\u003c/code\u003e\u003c/em\u003e. The \u003cem class=\"replaceable\"\u003e\u003ccode\u003etype_modifier_output_function\u003c/code\u003e\u003c/em\u003e converts the internal integer typmod value back to the correct form for user display. It must return a \u003ccode class=\"type\"\u003ecstring\u003c/code\u003e value that is the exact string to append to the type name; for example \u003ccode class=\"type\"\u003enumeric\u003c/code\u003e's function might return \u003ccode class=\"literal\"\u003e(30,2)\u003c/code\u003e. It is allowed to omit the \u003cem class=\"replaceable\"\u003e\u003ccode\u003etype_modifier_output_function\u003c/code\u003e\u003c/em\u003e, in which case the default display format is just the stored typmod integer value enclosed in parentheses.\u003c/p\u003e\u003cp\u003eThe optional \u003cem class=\"replaceable\"\u003e\u003ccode\u003eanalyze_function\u003c/code\u003e\u003c/em\u003e performs type-specific statistics collection for columns of the data type. By default, \u003ccode class=\"command\"\u003eANALYZE\u003c/code\u003e will attempt to gather statistics using the type's \u003cspan class=\"quote\"\u003e“\u003cspan class=\"quote\"\u003eequals\u003c/span\u003e”\u003c/span\u003e and \u003cspan class=\"quote\"\u003e“\u003cspan class=\"quote\"\u003eless-than\u003c/span\u003e”\u003c/span\u003e operators, if there is a default b-tree operator class for the type. For non-scalar types this behavior is likely to be unsuitable, so it can be overridden by specifying a custom analysis function. The analysis function must be declared to take a single argument of type \u003ccode class=\"type\"\u003einternal\u003c/code\u003e, and return a \u003ccode class=\"type\"\u003eboolean\u003c/code\u003e result. The detailed API for analysis functions appears in \u003ccode class=\"filename\"\u003esrc/include/commands/vacuum.h\u003c/code\u003e.\u003c/p\u003e\u003cp\u003eThe optional \u003cem class=\"replaceable\"\u003e\u003ccode\u003esubscript_function\u003c/code\u003e\u003c/em\u003e allows the data type to be subscripted in SQL commands. Specifying this function does not cause the type to be considered a \u003cspan class=\"quote\"\u003e“\u003cspan class=\"quote\"\u003etrue\u003c/span\u003e”\u003c/span\u003e array type; for example, it will not be a candidate for the result type of \u003ccode class=\"literal\"\u003eARRAY[]\u003c/code\u003e constructs. But if subscripting a value of the type is a natural notation for extracting data from it, then a \u003cem class=\"replaceable\"\u003e\u003ccode\u003esubscript_function\u003c/code\u003e\u003c/em\u003e can be written to define what that means. The subscript function must be declared to take a single argument of type \u003ccode class=\"type\"\u003einternal\u003c/code\u003e, and return an \u003ccode class=\"type\"\u003einternal\u003c/code\u003e result, which is a pointer to a struct of methods (functions) that implement subscripting. The detailed API for subscript functions appears in \u003ccode class=\"filename\"\u003esrc/include/nodes/subscripting.h\u003c/code\u003e. It may also be useful to read the array implementation in \u003ccode class=\"filename\"\u003esrc/backend/utils/adt/arraysubs.c\u003c/code\u003e, or the simpler code in \u003ccode class=\"filename\"\u003econtrib/hstore/hstore_subs.c\u003c/code\u003e. Additional information appears in \u003ca href=\"/docs/18/sql-createtype.html#SQL-CREATETYPE-ARRAY\" title=\"Array Types\"\u003eArray Types\u003c/a\u003e below.\u003c/p\u003e\u003cp\u003eWhile the details of the new type's internal representation are only known to the I/O functions and other functions you create to work with the type, there are several properties of the internal representation that must be declared to \u003cspan class=\"productname\"\u003ePostgreSQL\u003c/span\u003e. Foremost of these is \u003cem class=\"replaceable\"\u003e\u003ccode\u003einternallength\u003c/code\u003e\u003c/em\u003e. Base data types can be fixed-length, in which case \u003cem class=\"replaceable\"\u003e\u003ccode\u003einternallength\u003c/code\u003e\u003c/em\u003e is a positive integer, or variable-length, indicated by setting \u003cem class=\"replaceable\"\u003e\u003ccode\u003einternallength\u003c/code\u003e\u003c/em\u003e to \u003ccode class=\"literal\"\u003eVARIABLE\u003c/code\u003e. (Internally, this is represented by setting \u003ccode class=\"literal\"\u003etyplen\u003c/code\u003e to -1.) The internal representation of all variable-length types must start with a 4-byte integer giving the total length of this value of the type. (Note that the length field is often encoded, as described in \u003ca href=\"/docs/18/storage-toast.html\" title=\"66.2. TOAST\"\u003eSection 66.2\u003c/a\u003e; it's unwise to access it directly.)\u003c/p\u003e\u003cp\u003eThe optional flag \u003ccode class=\"literal\"\u003ePASSEDBYVALUE\u003c/code\u003e indicates that values of this data type are passed by value, rather than by reference. Types passed by value must be fixed-length, and their internal representation cannot be larger than the size of the \u003ccode class=\"type\"\u003eDatum\u003c/code\u003e type (4 bytes on some machines, 8 bytes on others).\u003c/p\u003e\u003cp\u003eThe \u003cem class=\"replaceable\"\u003e\u003ccode\u003ealignment\u003c/code\u003e\u003c/em\u003e parameter specifies the storage alignment required for the data type. The allowed values equate to alignment on 1, 2, 4, or 8 byte boundaries. Note that variable-length types must have an alignment of at least 4, since they necessarily contain an \u003ccode class=\"type\"\u003eint4\u003c/code\u003e as their first component.\u003c/p\u003e\u003cp\u003eThe \u003cem class=\"replaceable\"\u003e\u003ccode\u003estorage\u003c/code\u003e\u003c/em\u003e parameter allows selection of storage strategies for variable-length data types. (Only \u003ccode class=\"literal\"\u003eplain\u003c/code\u003e is allowed for fixed-length types.) \u003ccode class=\"literal\"\u003eplain\u003c/code\u003e specifies that data of the type will always be stored in-line and not compressed. \u003ccode class=\"literal\"\u003eextended\u003c/code\u003e specifies that the system will first try to compress a long data value, and will move the value out of the main table row if it's still too long. \u003ccode class=\"literal\"\u003eexternal\u003c/code\u003e allows the value to be moved out of the main table, but the system will not try to compress it. \u003ccode class=\"literal\"\u003emain\u003c/code\u003e allows compression, but discourages moving the value out of the main table. (Data items with this storage strategy might still be moved out of the main table if there is no other way to make a row fit, but they will be kept in the main table preferentially over \u003ccode class=\"literal\"\u003eextended\u003c/code\u003e and \u003ccode class=\"literal\"\u003eexternal\u003c/code\u003e items.)\u003c/p\u003e\u003cp\u003eAll \u003cem class=\"replaceable\"\u003e\u003ccode\u003estorage\u003c/code\u003e\u003c/em\u003e values other than \u003ccode class=\"literal\"\u003eplain\u003c/code\u003e imply that the functions of the data type can handle values that have been \u003cem class=\"firstterm\"\u003etoasted\u003c/em\u003e, as described in \u003ca href=\"/docs/18/storage-toast.html\" title=\"66.2. TOAST\"\u003eSection 66.2\u003c/a\u003e and \u003ca href=\"/docs/18/xtypes.html#XTYPES-TOAST\" title=\"36.13.1. TOAST Considerations\"\u003eSection 36.13.1\u003c/a\u003e. The specific other value given merely determines the default TOAST storage strategy for columns of a toastable data type; users can pick other strategies for individual columns using \u003ccode class=\"literal\"\u003eALTER TABLE SET STORAGE\u003c/code\u003e.\u003c/p\u003e\u003cp\u003eThe \u003cem class=\"replaceable\"\u003e\u003ccode\u003elike_type\u003c/code\u003e\u003c/em\u003e parameter provides an alternative method for specifying the basic representation properties of a data type: copy them from some existing type. The values of \u003cem class=\"replaceable\"\u003e\u003ccode\u003einternallength\u003c/code\u003e\u003c/em\u003e, \u003cem class=\"replaceable\"\u003e\u003ccode\u003epassedbyvalue\u003c/code\u003e\u003c/em\u003e, \u003cem class=\"replaceable\"\u003e\u003ccode\u003ealignment\u003c/code\u003e\u003c/em\u003e, and \u003cem class=\"replaceable\"\u003e\u003ccode\u003estorage\u003c/code\u003e\u003c/em\u003e are copied from the named type. (It is possible, though usually undesirable, to override some of these values by specifying them along with the \u003ccode class=\"literal\"\u003eLIKE\u003c/code\u003e clause.) Specifying representation this way is especially useful when the low-level implementation of the new type \u003cspan class=\"quote\"\u003e“\u003cspan class=\"quote\"\u003epiggybacks\u003c/span\u003e”\u003c/span\u003e on an existing type in some fashion.\u003c/p\u003e\u003cp\u003eThe \u003cem class=\"replaceable\"\u003e\u003ccode\u003ecategory\u003c/code\u003e\u003c/em\u003e and \u003cem class=\"replaceable\"\u003e\u003ccode\u003epreferred\u003c/code\u003e\u003c/em\u003e parameters can be used to help control which implicit cast will be applied in ambiguous situations. Each data type belongs to a category named by a single ASCII character, and each type is either \u003cspan class=\"quote\"\u003e“\u003cspan class=\"quote\"\u003epreferred\u003c/span\u003e”\u003c/span\u003e or not within its category. The parser will prefer casting to preferred types (but only from other types within the same category) when this rule is helpful in resolving overloaded functions or operators. For more details see \u003ca href=\"/docs/18/typeconv.html\" title=\"Chapter 10. Type Conversion\"\u003eChapter 10\u003c/a\u003e. For types that have no implicit casts to or from any other types, it is sufficient to leave these settings at the defaults. However, for a group of related types that have implicit casts, it is often helpful to mark them all as belonging to a category and select one or two of the \u003cspan class=\"quote\"\u003e“\u003cspan class=\"quote\"\u003emost general\u003c/span\u003e”\u003c/span\u003e types as being preferred within the category. The \u003cem class=\"replaceable\"\u003e\u003ccode\u003ecategory\u003c/code\u003e\u003c/em\u003e parameter is especially useful when adding a user-defined type to an existing built-in category, such as the numeric or string types. However, it is also possible to create new entirely-user-defined type categories. Select any ASCII character other than an upper-case letter to name such a category.\u003c/p\u003e\u003cp\u003eA default value can be specified, in case a user wants columns of the data type to default to something other than the null value. Specify the default with the \u003ccode class=\"literal\"\u003eDEFAULT\u003c/code\u003e key word. (Such a default can be overridden by an explicit \u003ccode class=\"literal\"\u003eDEFAULT\u003c/code\u003e clause attached to a particular column.)\u003c/p\u003e\u003cp\u003eTo indicate that a type is a fixed-length array type, specify the type of the array elements using the \u003ccode class=\"literal\"\u003eELEMENT\u003c/code\u003e key word. For example, to define an array of 4-byte integers (\u003ccode class=\"type\"\u003eint4\u003c/code\u003e), specify \u003ccode class=\"literal\"\u003eELEMENT = int4\u003c/code\u003e. For more details, see \u003ca href=\"/docs/18/sql-createtype.html#SQL-CREATETYPE-ARRAY\" title=\"Array Types\"\u003eArray Types\u003c/a\u003e below.\u003c/p\u003e\u003cp\u003eTo indicate the delimiter to be used between values in the external representation of arrays of this type, \u003cem class=\"replaceable\"\u003e\u003ccode\u003edelimiter\u003c/code\u003e\u003c/em\u003e can be set to a specific character. The default delimiter is the comma (\u003ccode class=\"literal\"\u003e,\u003c/code\u003e). Note that the delimiter is associated with the array element type, not the array type itself.\u003c/p\u003e\u003cp\u003eIf the optional Boolean parameter \u003cem class=\"replaceable\"\u003e\u003ccode\u003ecollatable\u003c/code\u003e\u003c/em\u003e is true, column definitions and expressions of the type may carry collation information through use of the \u003ccode class=\"literal\"\u003eCOLLATE\u003c/code\u003e clause. It is up to the implementations of the functions operating on the type to actually make use of the collation information; this does not happen automatically merely by marking the type collatable.\u003c/p\u003e\u003c/div\u003e\u003cdiv class=\"refsect2\"\u003e\u003ch3\u003eArray Types\u003c/h3\u003e\u003cp\u003eWhenever a user-defined type is created, \u003cspan class=\"productname\"\u003ePostgreSQL\u003c/span\u003e automatically creates an associated array type, whose name consists of the element type's name prepended with an underscore, and truncated if necessary to keep it less than \u003ccode class=\"symbol\"\u003eNAMEDATALEN\u003c/code\u003e bytes long. (If the name so generated collides with an existing type name, the process is repeated until a non-colliding name is found.) This implicitly-created array type is variable length and uses the built-in input and output functions \u003ccode class=\"literal\"\u003earray_in\u003c/code\u003e and \u003ccode class=\"literal\"\u003earray_out\u003c/code\u003e. Furthermore, this type is what the system uses for constructs such as \u003ccode class=\"literal\"\u003eARRAY[]\u003c/code\u003e over the user-defined type. The array type tracks any changes in its element type's owner or schema, and is dropped if the element type is.\u003c/p\u003e\u003cp\u003eYou might reasonably ask why there is an \u003ccode class=\"option\"\u003eELEMENT\u003c/code\u003e option, if the system makes the correct array type automatically. The main case where it's useful to use \u003ccode class=\"option\"\u003eELEMENT\u003c/code\u003e is when you are making a fixed-length type that happens to be internally an array of a number of identical things, and you want to allow these things to be accessed directly by subscripting, in addition to whatever operations you plan to provide for the type as a whole. For example, type \u003ccode class=\"type\"\u003epoint\u003c/code\u003e is represented as just two floating-point numbers, which can be accessed using \u003ccode class=\"literal\"\u003epoint[0]\u003c/code\u003e and \u003ccode class=\"literal\"\u003epoint[1]\u003c/code\u003e. Note that this facility only works for fixed-length types whose internal form is exactly a sequence of identical fixed-length fields. For historical reasons (i.e., this is clearly wrong but it's far too late to change it), subscripting of fixed-length array types starts from zero, rather than from one as for variable-length arrays.\u003c/p\u003e\u003cp\u003eSpecifying the \u003ccode class=\"option\"\u003eSUBSCRIPT\u003c/code\u003e option allows a data type to be subscripted, even though the system does not otherwise regard it as an array type. The behavior just described for fixed-length arrays is actually implemented by the \u003ccode class=\"option\"\u003eSUBSCRIPT\u003c/code\u003e handler function \u003ccode class=\"function\"\u003eraw_array_subscript_handler\u003c/code\u003e, which is used automatically if you specify \u003ccode class=\"option\"\u003eELEMENT\u003c/code\u003e for a fixed-length type without also writing \u003ccode class=\"option\"\u003eSUBSCRIPT\u003c/code\u003e.\u003c/p\u003e\u003cp\u003eWhen specifying a custom \u003ccode class=\"option\"\u003eSUBSCRIPT\u003c/code\u003e function, it is not necessary to specify \u003ccode class=\"option\"\u003eELEMENT\u003c/code\u003e unless the \u003ccode class=\"option\"\u003eSUBSCRIPT\u003c/code\u003e handler function needs to consult \u003ccode class=\"structfield\"\u003etypelem\u003c/code\u003e to find out what to return. Be aware that specifying \u003ccode class=\"option\"\u003eELEMENT\u003c/code\u003e causes the system to assume that the new type contains, or is somehow physically dependent on, the element type; thus for example changing properties of the element type won't be allowed if there are any columns of the dependent type.\u003c/p\u003e\u003c/div\u003e","key":"description","title":"Description"},{"html":"\u003cdiv class=\"variablelist\"\u003e\u003cdl class=\"variablelist\"\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003ename\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003eThe name (optionally schema-qualified) of a type to be created.\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003eattribute_name\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003eThe name of an attribute (column) for the composite type.\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003edata_type\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003eThe name of an existing data type to become a column of the composite type.\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003ecollation\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003eThe name of an existing collation to be associated with a column of a composite type, or with a range type.\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003elabel\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003eA string literal representing the textual label associated with one value of an enum type.\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003esubtype\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003eThe name of the element type that the range type will represent ranges of.\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003esubtype_operator_class\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003eThe name of a b-tree operator class for the subtype.\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003ecanonical_function\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003eThe name of the canonicalization function for the range type.\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003esubtype_diff_function\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003eThe name of a difference function for the subtype.\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003emultirange_type_name\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003eThe name of the corresponding multirange type.\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003einput_function\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003eThe name of a function that converts data from the type's external textual form to its internal form.\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003eoutput_function\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003eThe name of a function that converts data from the type's internal form to its external textual form.\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003ereceive_function\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003eThe name of a function that converts data from the type's external binary form to its internal form.\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003esend_function\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003eThe name of a function that converts data from the type's internal form to its external binary form.\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003etype_modifier_input_function\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003eThe name of a function that converts an array of modifier(s) for the type into internal form.\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003etype_modifier_output_function\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003eThe name of a function that converts the internal form of the type's modifier(s) to external textual form.\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003eanalyze_function\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003eThe name of a function that performs statistical analysis for the data type.\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003esubscript_function\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003eThe name of a function that defines what subscripting a value of the data type does.\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003einternallength\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003eA numeric constant that specifies the length in bytes of the new type's internal representation. The default assumption is that it is variable-length.\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003ealignment\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003eThe storage alignment requirement of the data type. If specified, it must be \u003ccode class=\"literal\"\u003echar\u003c/code\u003e, \u003ccode class=\"literal\"\u003eint2\u003c/code\u003e, \u003ccode class=\"literal\"\u003eint4\u003c/code\u003e, or \u003ccode class=\"literal\"\u003edouble\u003c/code\u003e; the default is \u003ccode class=\"literal\"\u003eint4\u003c/code\u003e.\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003estorage\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003eThe storage strategy for the data type. If specified, must be \u003ccode class=\"literal\"\u003eplain\u003c/code\u003e, \u003ccode class=\"literal\"\u003eexternal\u003c/code\u003e, \u003ccode class=\"literal\"\u003eextended\u003c/code\u003e, or \u003ccode class=\"literal\"\u003emain\u003c/code\u003e; the default is \u003ccode class=\"literal\"\u003eplain\u003c/code\u003e.\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003elike_type\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003eThe name of an existing data type that the new type will have the same representation as. The values of \u003cem class=\"replaceable\"\u003e\u003ccode\u003einternallength\u003c/code\u003e\u003c/em\u003e, \u003cem class=\"replaceable\"\u003e\u003ccode\u003epassedbyvalue\u003c/code\u003e\u003c/em\u003e, \u003cem class=\"replaceable\"\u003e\u003ccode\u003ealignment\u003c/code\u003e\u003c/em\u003e, and \u003cem class=\"replaceable\"\u003e\u003ccode\u003estorage\u003c/code\u003e\u003c/em\u003e are copied from that type, unless overridden by explicit specification elsewhere in this \u003ccode class=\"command\"\u003eCREATE TYPE\u003c/code\u003e command.\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003ecategory\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003eThe category code (a single ASCII character) for this type. The default is \u003ccode class=\"literal\"\u003e'U'\u003c/code\u003e for \u003cspan class=\"quote\"\u003e“\u003cspan class=\"quote\"\u003euser-defined type\u003c/span\u003e”\u003c/span\u003e. Other standard category codes can be found in \u003ca href=\"/docs/18/catalog-pg-type.html#CATALOG-TYPCATEGORY-TABLE\" title=\"Table 52.65. typcategory Codes\"\u003eTable 52.65\u003c/a\u003e. You may also choose other ASCII characters in order to create custom categories.\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003epreferred\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003eTrue if this type is a preferred type within its type category, else false. The default is false. Be very careful about creating a new preferred type within an existing type category, as this could cause surprising changes in behavior.\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003edefault\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003eThe default value for the data type. If this is omitted, the default is null.\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003eelement\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003eThe type being created is an array; this specifies the type of the array elements.\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003edelimiter\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003eThe delimiter character to be used between values in arrays made of this type.\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003ecollatable\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003eTrue if this type's operations can use collation information. The default is false.\u003c/p\u003e\u003c/dd\u003e\u003c/dl\u003e\u003c/div\u003e","key":"parameters","title":"Parameters"},{"html":"\u003cp\u003eBecause there are no restrictions on use of a data type once it's been created, creating a base type or range type is tantamount to granting public execute permission on the functions mentioned in the type definition. This is usually not an issue for the sorts of functions that are useful in a type definition. But you might want to think twice before designing a type in a way that would require \u003cspan class=\"quote\"\u003e“\u003cspan class=\"quote\"\u003esecret\u003c/span\u003e”\u003c/span\u003e information to be used while converting it to or from external form.\u003c/p\u003e\u003cp\u003eBefore \u003cspan class=\"productname\"\u003ePostgreSQL\u003c/span\u003e version 8.3, the name of a generated array type was always exactly the element type's name with one underscore character (\u003ccode class=\"literal\"\u003e_\u003c/code\u003e) prepended. (Type names were therefore restricted in length to one fewer character than other names.) While this is still usually the case, the array type name may vary from this in case of maximum-length names or collisions with user type names that begin with underscore. Writing code that depends on this convention is therefore deprecated. Instead, use \u003ccode class=\"structname\"\u003epg_type\u003c/code\u003e.\u003ccode class=\"structfield\"\u003etyparray\u003c/code\u003e to locate the array type associated with a given type.\u003c/p\u003e\u003cp\u003eIt may be advisable to avoid using type and table names that begin with underscore. While the server will change generated array type names to avoid collisions with user-given names, there is still risk of confusion, particularly with old client software that may assume that type names beginning with underscores always represent arrays.\u003c/p\u003e\u003cp\u003eBefore \u003cspan class=\"productname\"\u003ePostgreSQL\u003c/span\u003e version 8.2, the shell-type creation syntax \u003ccode class=\"literal\"\u003eCREATE TYPE \u003cem class=\"replaceable\"\u003e\u003ccode\u003ename\u003c/code\u003e\u003c/em\u003e\u003c/code\u003e did not exist. The way to create a new base type was to create its input function first. In this approach, \u003cspan class=\"productname\"\u003ePostgreSQL\u003c/span\u003e will first see the name of the new data type as the return type of the input function. The shell type is implicitly created in this situation, and then it can be referenced in the definitions of the remaining I/O functions. This approach still works, but is deprecated and might be disallowed in some future release. Also, to avoid accidentally cluttering the catalogs with shell types as a result of simple typos in function definitions, a shell type will only be made this way when the input function is written in C.\u003c/p\u003e\u003cp\u003eIn \u003cspan class=\"productname\"\u003ePostgreSQL\u003c/span\u003e version 16 and later, it is desirable for base types' input functions to return \u003cspan class=\"quote\"\u003e“\u003cspan class=\"quote\"\u003esoft\u003c/span\u003e”\u003c/span\u003e errors using the new \u003ccode class=\"function\"\u003eerrsave()\u003c/code\u003e/\u003ccode class=\"function\"\u003eereturn()\u003c/code\u003e mechanism, rather than throwing \u003ccode class=\"function\"\u003eereport()\u003c/code\u003e exceptions as in previous versions. See \u003ccode class=\"filename\"\u003esrc/backend/utils/fmgr/README\u003c/code\u003e for more information.\u003c/p\u003e","key":"notes","title":"Notes"},{"html":"\u003cp\u003eThis example creates a composite type and uses it in a function definition:\u003c/p\u003e\u003cpre class=\"programlisting\"\u003eCREATE TYPE compfoo AS (f1 int, f2 text);\n\nCREATE FUNCTION getfoo() RETURNS SETOF compfoo AS $$\n    SELECT fooid, fooname FROM foo\n$$ LANGUAGE SQL;\n\u003c/pre\u003e\u003cp\u003eThis example creates an enumerated type and uses it in a table definition:\u003c/p\u003e\u003cpre class=\"programlisting\"\u003eCREATE TYPE bug_status AS ENUM ('new', 'open', 'closed');\n\nCREATE TABLE bug (\n    id serial,\n    description text,\n    status bug_status\n);\n\u003c/pre\u003e\u003cp\u003eThis example creates a range type:\u003c/p\u003e\u003cpre class=\"programlisting\"\u003eCREATE TYPE float8_range AS RANGE (subtype = float8, subtype_diff = float8mi);\n\u003c/pre\u003e\u003cp\u003eThis example creates the base data type \u003ccode class=\"type\"\u003ebox\u003c/code\u003e and then uses the type in a table definition:\u003c/p\u003e\u003cpre class=\"programlisting\"\u003eCREATE TYPE box;\n\nCREATE FUNCTION my_box_in_function(cstring) RETURNS box AS ... ;\nCREATE FUNCTION my_box_out_function(box) RETURNS cstring AS ... ;\n\nCREATE TYPE box (\n    INTERNALLENGTH = 16,\n    INPUT = my_box_in_function,\n    OUTPUT = my_box_out_function\n);\n\nCREATE TABLE myboxes (\n    id integer,\n    description box\n);\n\u003c/pre\u003e\u003cp\u003eIf the internal structure of \u003ccode class=\"type\"\u003ebox\u003c/code\u003e were an array of four \u003ccode class=\"type\"\u003efloat4\u003c/code\u003e elements, we might instead use:\u003c/p\u003e\u003cpre class=\"programlisting\"\u003eCREATE TYPE box (\n    INTERNALLENGTH = 16,\n    INPUT = my_box_in_function,\n    OUTPUT = my_box_out_function,\n    ELEMENT = float4\n);\n\u003c/pre\u003e\u003cp\u003ewhich would allow a box value's component numbers to be accessed by subscripting. Otherwise the type behaves the same as before.\u003c/p\u003e\u003cp\u003eThis example creates a large object type and uses it in a table definition:\u003c/p\u003e\u003cpre class=\"programlisting\"\u003eCREATE TYPE bigobj (\n    INPUT = lo_filein, OUTPUT = lo_fileout,\n    INTERNALLENGTH = VARIABLE\n);\nCREATE TABLE big_objs (\n    id integer,\n    obj bigobj\n);\n\u003c/pre\u003e\u003cp\u003eMore examples, including suitable input and output functions, are in \u003ca href=\"/docs/18/xtypes.html\" title=\"36.13. User-Defined Types\"\u003eSection 36.13\u003c/a\u003e.\u003c/p\u003e","key":"examples","title":"Examples"},{"html":"\u003cp\u003eThe first form of the \u003ccode class=\"command\"\u003eCREATE TYPE\u003c/code\u003e command, which creates a composite type, conforms to the \u003cacronym\u003eSQL\u003c/acronym\u003e standard. The other forms are \u003cspan class=\"productname\"\u003ePostgreSQL\u003c/span\u003e extensions. The \u003ccode class=\"command\"\u003eCREATE TYPE\u003c/code\u003e statement in the \u003cacronym\u003eSQL\u003c/acronym\u003e standard also defines other forms that are not implemented in \u003cspan class=\"productname\"\u003ePostgreSQL\u003c/span\u003e.\u003c/p\u003e\u003cp\u003eThe ability to create a composite type with zero attributes is a \u003cspan class=\"productname\"\u003ePostgreSQL\u003c/span\u003e-specific deviation from the standard (analogous to the same case in \u003ccode class=\"command\"\u003eCREATE TABLE\u003c/code\u003e).\u003c/p\u003e","key":"compatibility","title":"Compatibility"},{"html":"\u003cspan class=\"simplelist\"\u003e\u003ca href=\"/wiki/sql/alter-type/?v=18\" title=\"ALTER TYPE\"\u003e\u003cspan class=\"refentrytitle\"\u003eALTER TYPE\u003c/span\u003e\u003c/a\u003e, \u003ca href=\"/wiki/sql/create-domain/?v=18\" title=\"CREATE DOMAIN\"\u003e\u003cspan class=\"refentrytitle\"\u003eCREATE DOMAIN\u003c/span\u003e\u003c/a\u003e, \u003ca href=\"/wiki/sql/create-function/?v=18\" title=\"CREATE FUNCTION\"\u003e\u003cspan class=\"refentrytitle\"\u003eCREATE FUNCTION\u003c/span\u003e\u003c/a\u003e, \u003ca href=\"/wiki/sql/drop-type/?v=18\" title=\"DROP TYPE\"\u003e\u003cspan class=\"refentrytitle\"\u003eDROP TYPE\u003c/span\u003e\u003c/a\u003e\u003c/span\u003e","key":"see_also","title":"See Also"}],"sections_same_as":"","slug":"18","synopsis_html":"CREATE TYPE \u003cem class=\"replaceable\"\u003e\u003ccode\u003ename\u003c/code\u003e\u003c/em\u003e AS\n    ( [ \u003cem class=\"replaceable\"\u003e\u003ccode\u003eattribute_name\u003c/code\u003e\u003c/em\u003e \u003cem class=\"replaceable\"\u003e\u003ccode\u003edata_type\u003c/code\u003e\u003c/em\u003e [ COLLATE \u003cem class=\"replaceable\"\u003e\u003ccode\u003ecollation\u003c/code\u003e\u003c/em\u003e ] [, ... ] ] )\n\nCREATE TYPE \u003cem class=\"replaceable\"\u003e\u003ccode\u003ename\u003c/code\u003e\u003c/em\u003e AS ENUM\n    ( [ '\u003cem class=\"replaceable\"\u003e\u003ccode\u003elabel\u003c/code\u003e\u003c/em\u003e' [, ... ] ] )\n\nCREATE TYPE \u003cem class=\"replaceable\"\u003e\u003ccode\u003ename\u003c/code\u003e\u003c/em\u003e AS RANGE (\n    SUBTYPE = \u003cem class=\"replaceable\"\u003e\u003ccode\u003esubtype\u003c/code\u003e\u003c/em\u003e\n    [ , SUBTYPE_OPCLASS = \u003cem class=\"replaceable\"\u003e\u003ccode\u003esubtype_operator_class\u003c/code\u003e\u003c/em\u003e ]\n    [ , COLLATION = \u003cem class=\"replaceable\"\u003e\u003ccode\u003ecollation\u003c/code\u003e\u003c/em\u003e ]\n    [ , CANONICAL = \u003cem class=\"replaceable\"\u003e\u003ccode\u003ecanonical_function\u003c/code\u003e\u003c/em\u003e ]\n    [ , SUBTYPE_DIFF = \u003cem class=\"replaceable\"\u003e\u003ccode\u003esubtype_diff_function\u003c/code\u003e\u003c/em\u003e ]\n    [ , MULTIRANGE_TYPE_NAME = \u003cem class=\"replaceable\"\u003e\u003ccode\u003emultirange_type_name\u003c/code\u003e\u003c/em\u003e ]\n)\n\nCREATE TYPE \u003cem class=\"replaceable\"\u003e\u003ccode\u003ename\u003c/code\u003e\u003c/em\u003e (\n    INPUT = \u003cem class=\"replaceable\"\u003e\u003ccode\u003einput_function\u003c/code\u003e\u003c/em\u003e,\n    OUTPUT = \u003cem class=\"replaceable\"\u003e\u003ccode\u003eoutput_function\u003c/code\u003e\u003c/em\u003e\n    [ , RECEIVE = \u003cem class=\"replaceable\"\u003e\u003ccode\u003ereceive_function\u003c/code\u003e\u003c/em\u003e ]\n    [ , SEND = \u003cem class=\"replaceable\"\u003e\u003ccode\u003esend_function\u003c/code\u003e\u003c/em\u003e ]\n    [ , TYPMOD_IN = \u003cem class=\"replaceable\"\u003e\u003ccode\u003etype_modifier_input_function\u003c/code\u003e\u003c/em\u003e ]\n    [ , TYPMOD_OUT = \u003cem class=\"replaceable\"\u003e\u003ccode\u003etype_modifier_output_function\u003c/code\u003e\u003c/em\u003e ]\n    [ , ANALYZE = \u003cem class=\"replaceable\"\u003e\u003ccode\u003eanalyze_function\u003c/code\u003e\u003c/em\u003e ]\n    [ , SUBSCRIPT = \u003cem class=\"replaceable\"\u003e\u003ccode\u003esubscript_function\u003c/code\u003e\u003c/em\u003e ]\n    [ , INTERNALLENGTH = { \u003cem class=\"replaceable\"\u003e\u003ccode\u003einternallength\u003c/code\u003e\u003c/em\u003e | VARIABLE } ]\n    [ , PASSEDBYVALUE ]\n    [ , ALIGNMENT = \u003cem class=\"replaceable\"\u003e\u003ccode\u003ealignment\u003c/code\u003e\u003c/em\u003e ]\n    [ , STORAGE = \u003cem class=\"replaceable\"\u003e\u003ccode\u003estorage\u003c/code\u003e\u003c/em\u003e ]\n    [ , LIKE = \u003cem class=\"replaceable\"\u003e\u003ccode\u003elike_type\u003c/code\u003e\u003c/em\u003e ]\n    [ , CATEGORY = \u003cem class=\"replaceable\"\u003e\u003ccode\u003ecategory\u003c/code\u003e\u003c/em\u003e ]\n    [ , PREFERRED = \u003cem class=\"replaceable\"\u003e\u003ccode\u003epreferred\u003c/code\u003e\u003c/em\u003e ]\n    [ , DEFAULT = \u003cem class=\"replaceable\"\u003e\u003ccode\u003edefault\u003c/code\u003e\u003c/em\u003e ]\n    [ , ELEMENT = \u003cem class=\"replaceable\"\u003e\u003ccode\u003eelement\u003c/code\u003e\u003c/em\u003e ]\n    [ , DELIMITER = \u003cem class=\"replaceable\"\u003e\u003ccode\u003edelimiter\u003c/code\u003e\u003c/em\u003e ]\n    [ , COLLATABLE = \u003cem class=\"replaceable\"\u003e\u003ccode\u003ecollatable\u003c/code\u003e\u003c/em\u003e ]\n)\n\nCREATE TYPE \u003cem class=\"replaceable\"\u003e\u003ccode\u003ename\u003c/code\u003e\u003c/em\u003e","synopsis_text":"CREATE TYPE name AS\n( [ attribute_name data_type [ COLLATE collation ] [, ... ] ] )\n\nCREATE TYPE name AS ENUM\n( [ 'label' [, ... ] ] )\n\nCREATE TYPE name AS RANGE (\nSUBTYPE = subtype\n[ , SUBTYPE_OPCLASS = subtype_operator_class ]\n[ , COLLATION = collation ]\n[ , CANONICAL = canonical_function ]\n[ , SUBTYPE_DIFF = subtype_diff_function ]\n[ , MULTIRANGE_TYPE_NAME = multirange_type_name ]\n)\n\nCREATE TYPE name (\nINPUT = input_function,\nOUTPUT = output_function\n[ , RECEIVE = receive_function ]\n[ , SEND = send_function ]\n[ , TYPMOD_IN = type_modifier_input_function ]\n[ , TYPMOD_OUT = type_modifier_output_function ]\n[ , ANALYZE = analyze_function ]\n[ , SUBSCRIPT = subscript_function ]\n[ , INTERNALLENGTH = { internallength | VARIABLE } ]\n[ , PASSEDBYVALUE ]\n[ , ALIGNMENT = alignment ]\n[ , STORAGE = storage ]\n[ , LIKE = like_type ]\n[ , CATEGORY = category ]\n[ , PREFERRED = preferred ]\n[ , DEFAULT = default ]\n[ , ELEMENT = element ]\n[ , DELIMITER = delimiter ]\n[ , COLLATABLE = collatable ]\n)\n\nCREATE TYPE name"},"ManualEvidence":{},"MeasuredEvidence":{}},"Text":{"Collection":"sql","Key":"create-type","SourceDatabase":"pgweb","Version":"18","Locale":"zh-Hans","Title":"CREATE TYPE","Summary":"定义一种新数据类型","BodyHTML":"\u003cpre\u003eCREATE TYPE name AS\n( [ attribute_name data_type [ COLLATE collation ] [, ... ] ] )\n\nCREATE TYPE name AS ENUM\n( [ \u0026#39;label\u0026#39; [, ... ] ] )\n\nCREATE TYPE name AS RANGE (\nSUBTYPE = subtype\n[ , SUBTYPE_OPCLASS = subtype_operator_class ]\n[ , COLLATION = collation ]\n[ , CANONICAL = canonical_function ]\n[ , SUBTYPE_DIFF = subtype_diff_function ]\n[ , MULTIRANGE_TYPE_NAME = multirange_type_name ]\n)\n\nCREATE TYPE name (\nINPUT = input_function,\nOUTPUT = output_function\n[ , RECEIVE = receive_function ]\n[ , SEND = send_function ]\n[ , TYPMOD_IN = type_modifier_input_function ]\n[ , TYPMOD_OUT = type_modifier_output_function ]\n[ , ANALYZE = analyze_function ]\n[ , SUBSCRIPT = subscript_function ]\n[ , INTERNALLENGTH = { internallength | VARIABLE } ]\n[ , PASSEDBYVALUE ]\n[ , ALIGNMENT = alignment ]\n[ , STORAGE = storage ]\n[ , LIKE = like_type ]\n[ , CATEGORY = category ]\n[ , PREFERRED = preferred ]\n[ , DEFAULT = default ]\n[ , ELEMENT = element ]\n[ , DELIMITER = delimiter ]\n[ , COLLATABLE = collatable ]\n)\n\nCREATE TYPE name\u003c/pre\u003e\u003csection\u003e\u003ch2\u003e描述\u003c/h2\u003e\u003cp\u003e\u003ccode\u003eCREATE TYPE\u003c/code\u003e在当前数据库中注册一种新的数据类型。定义该类型的用户将成为其拥有者。\u003c/p\u003e\u003cp\u003e如果给出了模式名，则该类型会在指定模式中创建；否则会在当前模式中创建。类型名必须不同于同一模式中任何现有类型或域的名称。（由于表也具有关联的数据类型，类型名还必须不同于同一模式中任何现有表的名称。）\u003c/p\u003e\u003cp\u003e如上面的语法概要所示，\u003ccode\u003eCREATE TYPE\u003c/code\u003e有五种形式。它们分别用于创建\u003cem\u003e复合类型\u003c/em\u003e、\u003cem\u003e枚举类型\u003c/em\u003e、\u003cem\u003e范围类型\u003c/em\u003e、\u003cem\u003e基础类型\u003c/em\u003e或\u003cem\u003eshell 类型\u003c/em\u003e。下文将依次讨论前四种。shell 类型只是稍后定义某种类型时使用的占位符；它通过执行除类型名外不带任何参数的\u003ccode\u003eCREATE TYPE\u003c/code\u003e来创建。正如相应小节所述，创建范围类型和基础类型时，需要用 shell 类型作为前向引用。\u003c/p\u003e\u003cdiv\u003e\u003ch3\u003e复合类型\u003c/h3\u003e\u003cp\u003e第一种形式的\u003ccode\u003eCREATE TYPE\u003c/code\u003e创建复合类型。复合类型由属性名和数据类型列表指定。如果某个属性的数据类型支持排序规则，还可以指定该属性的排序规则。复合类型本质上与表的行类型相同，但如果目的只是定义一种类型，使用\u003ccode\u003eCREATE TYPE\u003c/code\u003e 就不必实际创建表。例如，独立的复合类型可用作函数的参数类型或返回类型。\u003c/p\u003e\u003cp\u003e要创建复合类型，必须对所有属性类型都拥有\u003ccode\u003eUSAGE\u003c/code\u003e 权限。\u003c/p\u003e\u003c/div\u003e\u003cdiv\u003e\u003ch3\u003e枚举类型\u003c/h3\u003e\u003cp\u003e如\u003ca href=\"/docs/18/datatype-enum.html\" rel=\"nofollow\"\u003e第 8.7 节\u003c/a\u003e中所述，第二种形式的 \u003ccode\u003eCREATE TYPE\u003c/code\u003e创建枚举（enum）类型。枚举类型接受一个带引号标签的列表，其中每个标签的长度都必须小于 \u003ccode\u003eNAMEDATALEN\u003c/code\u003e字节（在标准 \u003cspan\u003ePostgreSQL\u003c/span\u003e构建中为 64 字节）。（也可以创建零标签的枚举类型，但在使用\u003ca href=\"/docs/18/sql-altertype.html\" title=\"ALTER TYPE\" rel=\"nofollow\"\u003e\u003ccode\u003eALTER TYPE\u003c/code\u003e\u003c/a\u003e 至少添加一个标签之前，这种类型不能用来保存值。）\u003c/p\u003e\u003c/div\u003e\u003cdiv\u003e\u003ch3\u003e范围类型\u003c/h3\u003e\u003cp\u003e如\u003ca href=\"/docs/18/rangetypes.html\" rel=\"nofollow\"\u003e第 8.17 节\u003c/a\u003e中所述，第三种形式的 \u003ccode\u003eCREATE TYPE\u003c/code\u003e创建范围类型。\u003c/p\u003e\u003cp\u003e范围类型的\u003cem\u003e\u003ccode\u003esubtype\u003c/code\u003e\u003c/em\u003e可以是任何带有关联 B-树操作符类的类型（该操作符类用于确定范围类型值的顺序）。通常使用子类型默认的 B-树操作符类来确定顺序；若要使用非默认操作符类，可用\u003cem\u003e\u003ccode\u003esubtype_opclass\u003c/code\u003e\u003c/em\u003e指定其名称。如果子类型支持排序规则，而你希望在范围排序中使用非默认排序规则，可用 \u003cem\u003e\u003ccode\u003ecollation\u003c/code\u003e\u003c/em\u003e选项指定所需排序规则。\u003c/p\u003e\u003cp\u003e可选的\u003cem\u003e\u003ccode\u003ecanonical\u003c/code\u003e\u003c/em\u003e函数必须接受一个正在定义的范围类型值作为参数，并返回同一类型的值。在适用时，它用于将范围值转换为规范形式。更多信息见\u003ca href=\"/docs/18/rangetypes.html#RANGETYPES-DEFINING\" rel=\"nofollow\"\u003e第 8.17.8 节\u003c/a\u003e。创建 \u003cem\u003e\u003ccode\u003ecanonical\u003c/code\u003e\u003c/em\u003e函数有些棘手，因为它必须在声明范围类型之前定义。为此，必须先创建一种 shell 类型，它除了名称和拥有者外没有任何属性，只是一个占位符类型。这可通过执行不带任何附加参数的命令\u003ccode\u003eCREATE TYPE \u003cem\u003e\u003ccode\u003ename\u003c/code\u003e\u003c/em\u003e\u003c/code\u003e完成。然后就可以把该 shell 类型用作参数类型和结果类型来声明该函数，最后再用同一名称声明范围类型。这样会自动用有效的范围类型替换 shell 类型条目。\u003c/p\u003e\u003cp\u003e可选的\u003cem\u003e\u003ccode\u003esubtype_diff\u003c/code\u003e\u003c/em\u003e 函数必须接受两个\u003cem\u003e\u003ccode\u003esubtype\u003c/code\u003e\u003c/em\u003e类型的值作为参数，并返回一个表示这两个给定值之差的\u003ccode\u003edouble precision\u003c/code\u003e值。虽然这是可选的，但提供该函数可显著提高该范围类型列上 GiST 索引的效率。详见\u003ca href=\"/docs/18/rangetypes.html#RANGETYPES-DEFINING\" rel=\"nofollow\"\u003e第 8.17.8 节\u003c/a\u003e。\u003c/p\u003e\u003cp\u003e可选的\u003cem\u003e\u003ccode\u003emultirange_type_name\u003c/code\u003e\u003c/em\u003e参数指定对应多范围类型的名称。若未指定，将按如下规则自动选择：如果范围类型名称包含子串\u003ccode\u003erange\u003c/code\u003e，则把类型名中的 \u003ccode\u003erange\u003c/code\u003e替换为\u003ccode\u003emultirange\u003c/code\u003e，作为多范围类型名；否则就在范围类型名后附加 \u003ccode\u003e_multirange\u003c/code\u003e后缀。\u003c/p\u003e\u003cp\u003e要创建范围类型，你必须拥有子类型的 \u003ccode\u003eUSAGE\u003c/code\u003e 权限。\u003c/p\u003e\u003c/div\u003e\u003cdiv\u003e\u003ch3\u003e基础类型\u003c/h3\u003e\u003cp\u003e第四种形式的\u003ccode\u003eCREATE TYPE\u003c/code\u003e创建一种新的基础类型（标量类型）。要创建新的基础类型，你必须是超级用户。（这样限制是因为错误的类型定义可能使服务器陷入混乱，甚至导致其崩溃。）\u003c/p\u003e\u003cp\u003e这些参数可以按任意顺序出现，不必局限于上面展示的顺序，而且大多数都是可选的。在定义该类型之前，必须先注册两个或更多函数（使用 \u003ccode\u003eCREATE FUNCTION\u003c/code\u003e）。支持函数 \u003cem\u003e\u003ccode\u003einput_function\u003c/code\u003e\u003c/em\u003e和 \u003cem\u003e\u003ccode\u003eoutput_function\u003c/code\u003e\u003c/em\u003e是必需的；\u003cem\u003e\u003ccode\u003ereceive_function\u003c/code\u003e\u003c/em\u003e、\u003cem\u003e\u003ccode\u003esend_function\u003c/code\u003e\u003c/em\u003e、\u003cem\u003e\u003ccode\u003etype_modifier_input_function\u003c/code\u003e\u003c/em\u003e、\u003cem\u003e\u003ccode\u003etype_modifier_output_function\u003c/code\u003e\u003c/em\u003e、\u003cem\u003e\u003ccode\u003eanalyze_function\u003c/code\u003e\u003c/em\u003e以及 \u003cem\u003e\u003ccode\u003esubscript_function\u003c/code\u003e\u003c/em\u003e则是可选的。通常这些函数必须用 C 或其他低级语言编写。\u003c/p\u003e\u003cp\u003e\u003cem\u003e\u003ccode\u003einput_function\u003c/code\u003e\u003c/em\u003e将类型的外部文本表示转换为该类型的操作符和函数所使用的内部表示。\u003cem\u003e\u003ccode\u003eoutput_function\u003c/code\u003e\u003c/em\u003e 执行相反的转换。输入函数可以声明为接受一个\u003ccode\u003ecstring\u003c/code\u003e 参数，或者接受三个参数，类型分别为\u003ccode\u003ecstring\u003c/code\u003e、\u003ccode\u003eoid\u003c/code\u003e、\u003ccode\u003einteger\u003c/code\u003e。第一个参数是以 C 字符串表示的输入文本，第二个参数是该类型自身的 OID（数组类型例外，此时传入的是其元素类型的 OID），第三个参数是在已知情况下目标列的 \u003ccode\u003etypmod\u003c/code\u003e（未知则传入 -1）。输入函数必须返回该数据类型本身的值。通常输入函数应声明为 STRICT；否则，在读取 NULL 输入值时会以 NULL 作为第一个参数调用它。除非函数抛出错误，否则在这种情况下仍必须返回 NULL。（这种情况主要是为了支持可能需要拒绝 NULL 输入的域输入函数。）输出函数必须声明为接受一个新数据类型参数，并且必须返回\u003ccode\u003ecstring\u003c/code\u003e类型。对于 NULL 值不会调用输出函数。\u003c/p\u003e\u003cp\u003e可选的\u003cem\u003e\u003ccode\u003ereceive_function\u003c/code\u003e\u003c/em\u003e 把类型的外部二进制表示转换为内部表示。如果未提供此函数，该类型就不能参与二进制输入。外部二进制表示应选择为既能低成本转换为内部形式，又具有合理可移植性。（例如，标准整数数据类型把网络字节序用作外部二进制表示，而内部表示则使用机器的本地字节序。）\u003cem\u003e\u003ccode\u003ereceive_function\u003c/code\u003e\u003c/em\u003e 应进行充分检查以确保值有效。它可以声明为接受一个 \u003ccode\u003einternal\u003c/code\u003e参数，或者接受三个参数，类型分别为 \u003ccode\u003einternal\u003c/code\u003e、\u003ccode\u003eoid\u003c/code\u003e、\u003ccode\u003einteger\u003c/code\u003e。第一个参数是指向保存已接收字节串的\u003ccode\u003eStringInfo\u003c/code\u003e缓冲区的指针；其余可选参数与文本输入函数相同。接收函数必须返回该数据类型本身的值。通常，接收函数应声明为 STRICT；否则，在读取 NULL 输入值时会以 NULL 作为第一个参数调用它。除非函数抛出错误，否则在这种情况下仍必须返回 NULL。（这种情况主要是为了支持可能需要拒绝 NULL 输入的域接收函数。）类似地，可选的 \u003cem\u003e\u003ccode\u003esend_function\u003c/code\u003e\u003c/em\u003e把内部表示转换为外部二进制表示。如果未提供此函数，该类型就不能参与二进制输出。发送函数必须声明为接受一个新数据类型参数，并且必须返回 \u003ccode\u003ebytea\u003c/code\u003e类型。对于 NULL 值不会调用发送函数。\u003c/p\u003e\u003cp\u003e读到这里，你可能会问：既然新类型本身还没创建，输入和输出函数怎么能声明为返回或接受这个新类型呢？答案是，应先把该类型定义为一种 \u003cem\u003eshell 类型\u003c/em\u003e，它除了名称和拥有者外没有任何属性，只是一个占位符类型。这可通过执行不带任何附加参数的命令 \u003ccode\u003eCREATE TYPE \u003cem\u003e\u003ccode\u003ename\u003c/code\u003e\u003c/em\u003e\u003c/code\u003e 完成。然后就可以定义引用该 shell 类型的 C I/O 函数。最后，再用带完整定义的\u003ccode\u003eCREATE TYPE\u003c/code\u003e替换该 shell 条目，生成一个完整且有效的类型定义，此后新类型就能正常使用。\u003c/p\u003e\u003cp\u003e如果该类型支持修饰符，也就是附加在类型声明上的可选约束，例如 \u003ccode\u003echar(5)\u003c/code\u003e或\u003ccode\u003enumeric(30,2)\u003c/code\u003e，就需要可选的\u003cem\u003e\u003ccode\u003etype_modifier_input_function\u003c/code\u003e\u003c/em\u003e和 \u003cem\u003e\u003ccode\u003etype_modifier_output_function\u003c/code\u003e\u003c/em\u003e。\u003cspan\u003ePostgreSQL\u003c/span\u003e允许用户定义类型接受一个或多个简单常量或标识符作为修饰符。不过，这些信息必须能够打包成单个非负整数值，以便存储在系统目录中。声明的修饰符会以 \u003ccode\u003ecstring\u003c/code\u003e数组的形式传递给\u003cem\u003e\u003ccode\u003etype_modifier_input_function\u003c/code\u003e\u003c/em\u003e。它必须检查这些值是否有效（若无效则抛出错误），若有效则返回一个非负\u003ccode\u003einteger\u003c/code\u003e值，该值将作为列的\u003cspan\u003e“\u003cspan\u003etypmod\u003c/span\u003e”\u003c/span\u003e存储。如果该类型没有\u003cem\u003e\u003ccode\u003etype_modifier_input_function\u003c/code\u003e\u003c/em\u003e，就会拒绝类型修饰符。\u003cem\u003e\u003ccode\u003etype_modifier_output_function\u003c/code\u003e\u003c/em\u003e 则把内部整数 typmod 值转换回适合用户显示的正确形式。它必须返回一个\u003ccode\u003ecstring\u003c/code\u003e值，即精确追加到类型名后的字符串；例如，\u003ccode\u003enumeric\u003c/code\u003e的该函数可能返回 \u003ccode\u003e(30,2)\u003c/code\u003e。允许省略\u003cem\u003e\u003ccode\u003etype_modifier_output_function\u003c/code\u003e\u003c/em\u003e；在这种情况下，默认显示格式只是把存储的 typmod 整数值放在圆括号中。\u003c/p\u003e\u003cp\u003e可选的\u003cem\u003e\u003ccode\u003eanalyze_function\u003c/code\u003e\u003c/em\u003e 为该数据类型的列执行类型专用的统计信息收集。默认情况下，如果该类型有默认的 B-树操作符类，\u003ccode\u003eANALYZE\u003c/code\u003e将尝试使用该类型的\u003cspan\u003e“\u003cspan\u003e等于\u003c/span\u003e”\u003c/span\u003e和\u003cspan\u003e“\u003cspan\u003e小于\u003c/span\u003e”\u003c/span\u003e操作符收集统计信息。对于非标量类型，这种行为很可能不合适，因此可以通过指定自定义分析函数来覆盖。分析函数必须声明为接受一个 \u003ccode\u003einternal\u003c/code\u003e参数并返回\u003ccode\u003eboolean\u003c/code\u003e结果。分析函数的详细 API 见\u003ccode\u003esrc/include/commands/vacuum.h\u003c/code\u003e。\u003c/p\u003e\u003cp\u003e可选的\u003cem\u003e\u003ccode\u003esubscript_function\u003c/code\u003e\u003c/em\u003e允许在 SQL 命令中对该数据类型进行下标访问。指定此函数并不会使该类型被视为\u003cspan\u003e“\u003cspan\u003e真正的\u003c/span\u003e”\u003c/span\u003e数组类型；例如，它不会成为 \u003ccode\u003eARRAY[]\u003c/code\u003e构造结果类型的候选者。但如果对这种类型的值使用下标是提取其中数据的一种自然记法，就可以编写 \u003cem\u003e\u003ccode\u003esubscript_function\u003c/code\u003e\u003c/em\u003e 来定义其含义。下标函数必须声明为接受一个\u003ccode\u003einternal\u003c/code\u003e 参数，并返回一个\u003ccode\u003einternal\u003c/code\u003e结果，也就是指向实现下标操作的方法（函数）结构体的指针。下标函数的详细 API 见 \u003ccode\u003esrc/include/nodes/subscripting.h\u003c/code\u003e。阅读 \u003ccode\u003esrc/backend/utils/adt/arraysubs.c\u003c/code\u003e中的数组实现，或更简单的\u003ccode\u003econtrib/hstore/hstore_subs.c\u003c/code\u003e 代码，也可能有所帮助。更多信息见下文\u003ca href=\"/docs/18/sql-createtype.html#SQL-CREATETYPE-ARRAY\" title=\"数组类型\" rel=\"nofollow\"\u003e数组类型\u003c/a\u003e。\u003c/p\u003e\u003cp\u003e虽然新类型内部表示的细节只有 I/O 函数以及你为该类型编写的其他函数才知道，但仍有若干内部表示属性必须向 \u003cspan\u003ePostgreSQL\u003c/span\u003e声明。其中最重要的是 \u003cem\u003e\u003ccode\u003einternallength\u003c/code\u003e\u003c/em\u003e。基础类型可以是定长的，此时\u003cem\u003e\u003ccode\u003einternallength\u003c/code\u003e\u003c/em\u003e为正整数；也可以是变长的，此时将\u003cem\u003e\u003ccode\u003einternallength\u003c/code\u003e\u003c/em\u003e设为 \u003ccode\u003eVARIABLE\u003c/code\u003e。（在内部，这通过把 \u003ccode\u003etyplen\u003c/code\u003e设为 -1 表示。）所有变长类型的内部表示都必须以一个 4 字节整数开头，用来给出该类型该值的总长度。（注意，如\u003ca href=\"/docs/18/storage-toast.html\" rel=\"nofollow\"\u003e第 66.2 节\u003c/a\u003e中所述，长度字段通常是经过编码的；直接访问它并不明智。）\u003c/p\u003e\u003cp\u003e可选标志\u003ccode\u003ePASSEDBYVALUE\u003c/code\u003e表示该数据类型的值按值传递，而不是按引用传递。按值传递的类型必须是定长的，且其内部表示不能大于\u003ccode\u003eDatum\u003c/code\u003e类型的大小（某些机器上为 4 字节，另一些为 8 字节）。\u003c/p\u003e\u003cp\u003e\u003cem\u003e\u003ccode\u003ealignment\u003c/code\u003e\u003c/em\u003e参数指定该数据类型所需的存储对齐方式。允许的值分别对应按 1、2、4 或 8 字节边界对齐。注意，变长类型的对齐至少必须为 4，因为它们的第一个组成部分必然是一个\u003ccode\u003eint4\u003c/code\u003e。\u003c/p\u003e\u003cp\u003e\u003cem\u003e\u003ccode\u003estorage\u003c/code\u003e\u003c/em\u003e参数允许为变长数据类型选择存储策略。（定长类型只允许 \u003ccode\u003eplain\u003c/code\u003e。）\u003ccode\u003eplain\u003c/code\u003e表示该类型数据始终行内存储且不压缩。\u003ccode\u003eextended\u003c/code\u003e表示系统会先尝试压缩较长的数据值，如果仍然过长，就把该值移出主表行。\u003ccode\u003eexternal\u003c/code\u003e允许把值移出主表，但系统不会尝试压缩它。\u003ccode\u003emain\u003c/code\u003e允许压缩，但不鼓励把值移出主表。（采用这种存储策略的数据项在没有其他办法让一行适配时仍可能被移出主表，但与\u003ccode\u003eextended\u003c/code\u003e和\u003ccode\u003eexternal\u003c/code\u003e 数据项相比，它们会被优先保留在主表中。）\u003c/p\u003e\u003cp\u003e如\u003ca href=\"/docs/18/storage-toast.html\" rel=\"nofollow\"\u003e第 66.2 节\u003c/a\u003e和\u003ca href=\"/docs/18/xtypes.html#XTYPES-TOAST\" rel=\"nofollow\"\u003e第 36.13.1 节\u003c/a\u003e所述，除\u003ccode\u003eplain\u003c/code\u003e之外所有\u003cem\u003e\u003ccode\u003estorage\u003c/code\u003e\u003c/em\u003e值都意味着该数据类型的函数能够处理经过\u003cem\u003eTOAST 处理\u003c/em\u003e的值。具体指定哪一种其他值，只是决定可 TOAST 数据类型列的默认 TOAST 存储策略；用户仍可使用\u003ccode\u003eALTER TABLE SET STORAGE\u003c/code\u003e 为单个列选择其他策略。\u003c/p\u003e\u003cp\u003e\u003cem\u003e\u003ccode\u003elike_type\u003c/code\u003e\u003c/em\u003e参数提供了指定数据类型基本表示属性的另一种方法：从某个现有类型复制这些属性。\u003cem\u003e\u003ccode\u003einternallength\u003c/code\u003e\u003c/em\u003e、\u003cem\u003e\u003ccode\u003epassedbyvalue\u003c/code\u003e\u003c/em\u003e、\u003cem\u003e\u003ccode\u003ealignment\u003c/code\u003e\u003c/em\u003e和 \u003cem\u003e\u003ccode\u003estorage\u003c/code\u003e\u003c/em\u003e的值都从指定类型复制而来。（虽然可以通过同时给出\u003ccode\u003eLIKE\u003c/code\u003e子句和这些选项来覆盖其中某些值，但通常不建议这样做。）当新类型的底层实现以某种方式\u003cspan\u003e“\u003cspan\u003e借用\u003c/span\u003e”\u003c/span\u003e现有类型时，以这种方式指定表示属性尤其有用。\u003c/p\u003e\u003cp\u003e\u003cem\u003e\u003ccode\u003ecategory\u003c/code\u003e\u003c/em\u003e和 \u003cem\u003e\u003ccode\u003epreferred\u003c/code\u003e\u003c/em\u003e参数可用于在存在歧义时帮助控制应用哪一种隐式类型转换。每种数据类型都属于一个由单个 ASCII 字符命名的类别，并且在其类别内要么是\u003cspan\u003e“\u003cspan\u003e首选\u003c/span\u003e”\u003c/span\u003e的，要么不是。当这一规则有助于解析重载函数或操作符时，解析器会优先转换为首选类型（但只会从同一类别中的其他类型转换）。更多细节见\u003ca href=\"/docs/18/typeconv.html\" rel=\"nofollow\"\u003e第 10 章\u003c/a\u003e。对于与任何其他类型之间都没有隐式类型转换的类型，保持这些设置的默认值就足够了。不过，对于一组彼此存在隐式类型转换的相关类型，把它们都标记为属于同一类别，并选择一两个\u003cspan\u003e“\u003cspan\u003e最通用\u003c/span\u003e”\u003c/span\u003e的类型作为该类别的首选类型，通常会有帮助。\u003cem\u003e\u003ccode\u003ecategory\u003c/code\u003e\u003c/em\u003e参数在将用户定义类型加入现有内置类别（例如数值类型或字符串类型）时尤其有用。不过，也可以创建全新的纯用户定义类型类别。为这种类别命名时，可选择任一非大写字母的 ASCII 字符。\u003c/p\u003e\u003cp\u003e如果用户希望该数据类型列的默认值不是空值，可以指定默认值。用 \u003ccode\u003eDEFAULT\u003c/code\u003e关键字指定默认值。（该默认值可以被附加到具体列上的显式\u003ccode\u003eDEFAULT\u003c/code\u003e子句覆盖。）\u003c/p\u003e\u003cp\u003e若要表明一种类型是定长数组类型，可用\u003ccode\u003eELEMENT\u003c/code\u003e 关键字指定数组元素的类型。例如，要定义由 4 字节整数（\u003ccode\u003eint4\u003c/code\u003e）构成的数组，可指定 \u003ccode\u003eELEMENT = int4\u003c/code\u003e。更多细节见下文\u003ca href=\"/docs/18/sql-createtype.html#SQL-CREATETYPE-ARRAY\" title=\"数组类型\" rel=\"nofollow\"\u003e数组类型\u003c/a\u003e。\u003c/p\u003e\u003cp\u003e若要指定该类型数组在外部表示中用于分隔各值的分隔符，可把 \u003cem\u003e\u003ccode\u003edelimiter\u003c/code\u003e\u003c/em\u003e设为特定字符。默认分隔符是逗号（\u003ccode\u003e,\u003c/code\u003e）。注意，这个分隔符关联的是数组元素类型，而不是数组类型本身。\u003c/p\u003e\u003cp\u003e如果可选的布尔参数 \u003cem\u003e\u003ccode\u003ecollatable\u003c/code\u003e\u003c/em\u003e为真，则该类型的列定义和表达式可以通过\u003ccode\u003eCOLLATE\u003c/code\u003e子句携带排序规则信息。是否实际使用这些排序规则信息取决于操作该类型的函数实现；仅仅把类型标记为支持排序规则并不会自动实现这一点。\u003c/p\u003e\u003c/div\u003e\u003cdiv\u003e\u003ch3\u003e数组类型\u003c/h3\u003e\u003cp\u003e每当创建用户定义类型时，\u003cspan\u003ePostgreSQL\u003c/span\u003e 都会自动创建一个关联的数组类型，其名称由元素类型名前加一个下划线组成；必要时还会截断，以保持其长度小于 \u003ccode\u003eNAMEDATALEN\u003c/code\u003e字节。（如果这样生成的名称与现有类型名冲突，就会重复这一过程，直到找到不冲突的名称。）这种隐式创建的数组类型是变长的，并使用内置输入/输出函数 \u003ccode\u003earray_in\u003c/code\u003e和\u003ccode\u003earray_out\u003c/code\u003e。此外，系统在处理基于该用户定义类型的\u003ccode\u003eARRAY[]\u003c/code\u003e 等构造时，使用的也是这种类型。该数组类型会跟踪其元素类型的拥有者或模式的任何变化，并在元素类型被删除时一并删除。\u003c/p\u003e\u003cp\u003e如果系统会自动创建正确的数组类型，你可能会合理地问，为什么还需要\u003ccode\u003eELEMENT\u003c/code\u003e选项。\u003ccode\u003eELEMENT\u003c/code\u003e最主要的用途是：你正在创建一种定长类型，而它在内部恰好是若干相同元素组成的数组，并且除了为整个类型提供的操作之外，你还希望允许通过下标直接访问这些元素。例如，类型\u003ccode\u003epoint\u003c/code\u003e在内部就表示为两个浮点数，可以用\u003ccode\u003epoint[0]\u003c/code\u003e和 \u003ccode\u003epoint[1]\u003c/code\u003e访问。注意，这种机制只适用于内部形式恰好是一串相同定长字段的定长类型。由于历史原因（也就是说这显然不对，但现在改已经太晚了），定长数组类型的下标从零开始，而变长数组则从一开始。\u003c/p\u003e\u003cp\u003e指定\u003ccode\u003eSUBSCRIPT\u003c/code\u003e选项允许对某种数据类型使用下标，即使系统在其他方面并不把它视为数组类型。上面刚描述的定长数组行为，实际上是由\u003ccode\u003eSUBSCRIPT\u003c/code\u003e处理函数 \u003ccode\u003eraw_array_subscript_handler\u003c/code\u003e实现的；如果你为定长类型指定了\u003ccode\u003eELEMENT\u003c/code\u003e而没有同时写 \u003ccode\u003eSUBSCRIPT\u003c/code\u003e，系统就会自动使用该函数。\u003c/p\u003e\u003cp\u003e指定自定义\u003ccode\u003eSUBSCRIPT\u003c/code\u003e函数时，通常不必再指定 \u003ccode\u003eELEMENT\u003c/code\u003e，除非\u003ccode\u003eSUBSCRIPT\u003c/code\u003e处理函数需要查阅\u003ccode\u003etypelem\u003c/code\u003e来确定应返回什么。请注意，指定\u003ccode\u003eELEMENT\u003c/code\u003e会让系统认为新类型包含元素类型，或者在物理上以某种方式依赖元素类型；因此，例如，如果存在该依赖类型的列，就不允许更改元素类型的属性。\u003c/p\u003e\u003c/div\u003e\u003c/section\u003e\u003csection\u003e\u003ch2\u003e参数\u003c/h2\u003e\u003cdiv\u003e\u003cdl\u003e\u003cdt\u003e\u003cspan\u003e\u003cem\u003e\u003ccode\u003ename\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e要创建的类型名称（可选地带有模式限定）。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan\u003e\u003cem\u003e\u003ccode\u003eattribute_name\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e复合类型的一个属性（列）的名称。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan\u003e\u003cem\u003e\u003ccode\u003edata_type\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e将成为复合类型一列的现有数据类型名称。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan\u003e\u003cem\u003e\u003ccode\u003ecollation\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e要与复合类型的某一列或范围类型关联的现有排序规则名称。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan\u003e\u003cem\u003e\u003ccode\u003elabel\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e表示枚举类型某个值所关联文本标签的字符串字面量。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan\u003e\u003cem\u003e\u003ccode\u003esubtype\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e范围类型所表示范围的元素类型名称。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan\u003e\u003cem\u003e\u003ccode\u003esubtype_operator_class\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e子类型的 B-树操作符类名称。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan\u003e\u003cem\u003e\u003ccode\u003ecanonical_function\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e范围类型规范化函数的名称。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan\u003e\u003cem\u003e\u003ccode\u003esubtype_diff_function\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e子类型差分函数的名称。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan\u003e\u003cem\u003e\u003ccode\u003emultirange_type_name\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e对应多范围类型的名称。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan\u003e\u003cem\u003e\u003ccode\u003einput_function\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e将数据从类型的外部文本形式转换为内部形式的函数名。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan\u003e\u003cem\u003e\u003ccode\u003eoutput_function\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e将数据从类型的内部形式转换为外部文本形式的函数名。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan\u003e\u003cem\u003e\u003ccode\u003ereceive_function\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e将数据从类型的外部二进制形式转换成内部形式的函数名。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan\u003e\u003cem\u003e\u003ccode\u003esend_function\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e将数据从类型的内部形式转换为外部二进制形式的函数名。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan\u003e\u003cem\u003e\u003ccode\u003etype_modifier_input_function\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e将类型的修饰符数组转换为内部形式的函数名。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan\u003e\u003cem\u003e\u003ccode\u003etype_modifier_output_function\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e将类型修饰符的内部形式转换为外部文本形式的函数名。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan\u003e\u003cem\u003e\u003ccode\u003eanalyze_function\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e为该数据类型执行统计分析的函数名。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan\u003e\u003cem\u003e\u003ccode\u003esubscript_function\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e定义对该数据类型值进行下标访问时行为的函数名。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan\u003e\u003cem\u003e\u003ccode\u003einternallength\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e一个数字常量，用于指定新类型内部表示的字节长度。默认假定它是变长的。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan\u003e\u003cem\u003e\u003ccode\u003ealignment\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e该数据类型的存储对齐需求。如果被指定，它必须是 \u003ccode\u003echar\u003c/code\u003e、\u003ccode\u003eint2\u003c/code\u003e、\u003ccode\u003eint4\u003c/code\u003e或者\u003ccode\u003edouble\u003c/code\u003e。默认是 \u003ccode\u003eint4\u003c/code\u003e。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan\u003e\u003cem\u003e\u003ccode\u003estorage\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e该数据类型的存储策略。如果被指定，必须是 \u003ccode\u003eplain\u003c/code\u003e、\u003ccode\u003eexternal\u003c/code\u003e、\u003ccode\u003eextended\u003c/code\u003e或者\u003ccode\u003emain\u003c/code\u003e。默认是\u003ccode\u003eplain\u003c/code\u003e。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan\u003e\u003cem\u003e\u003ccode\u003elike_type\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e与新类型具有相同表示形式的现有数据类型名称。除非在本 \u003ccode\u003eCREATE TYPE\u003c/code\u003e命令的其他位置显式覆盖，否则 \u003cem\u003e\u003ccode\u003einternallength\u003c/code\u003e\u003c/em\u003e、\u003cem\u003e\u003ccode\u003epassedbyvalue\u003c/code\u003e\u003c/em\u003e、\u003cem\u003e\u003ccode\u003ealignment\u003c/code\u003e\u003c/em\u003e和 \u003cem\u003e\u003ccode\u003estorage\u003c/code\u003e\u003c/em\u003e的值都会从该类型复制。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan\u003e\u003cem\u003e\u003ccode\u003ecategory\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e该类型的类别码（单个 ASCII 字符）。默认值是表示\u003cspan\u003e“\u003cspan\u003e用户定义类型\u003c/span\u003e”\u003c/span\u003e的\u003ccode\u003e\u0026#39;U\u0026#39;\u003c/code\u003e。其他标准类别码见\u003ca href=\"/docs/18/catalog-pg-type.html#CATALOG-TYPCATEGORY-TABLE\" rel=\"nofollow\"\u003e表 52.65\u003c/a\u003e。你也可以选择其他 ASCII 字符来创建自定义类别。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan\u003e\u003cem\u003e\u003ccode\u003epreferred\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e若该类型是其类型类别中的首选类型，则为真，否则为假。默认值为假。在现有类型类别中创建新的首选类型时要格外小心，因为这可能导致出人意料的行为变化。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan\u003e\u003cem\u003e\u003ccode\u003edefault\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e该数据类型的默认值。若省略，默认值为 null。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan\u003e\u003cem\u003e\u003ccode\u003eelement\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e正在创建的类型是数组；该参数指定数组元素类型。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan\u003e\u003cem\u003e\u003ccode\u003edelimiter\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e在由该类型构成的数组中各值之间使用的分隔符字符。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan\u003e\u003cem\u003e\u003ccode\u003ecollatable\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e如果该类型的操作可以使用排序规则信息，则为真。默认为假。\u003c/p\u003e\u003c/dd\u003e\u003c/dl\u003e\u003c/div\u003e\u003c/section\u003e\u003csection\u003e\u003ch2\u003e注解\u003c/h2\u003e\u003cp\u003e由于数据类型一旦创建，其使用方式就不再受限制，因此创建基础类型或范围类型，相当于对类型定义中提到的那些函数授予公共执行权限。这对适合用于类型定义的那类函数来说通常不是问题。但如果设计一种类型时，需要在把它转换为外部形式或从外部形式转换回来时使用\u003cspan\u003e“\u003cspan\u003e秘密\u003c/span\u003e”\u003c/span\u003e信息，就应当三思。\u003c/p\u003e\u003cp\u003e在\u003cspan\u003ePostgreSQL\u003c/span\u003e 8.3 之前，自动生成的数组类型名称总是恰好等于元素类型名称前加一个下划线字符（\u003ccode\u003e_\u003c/code\u003e）。（因此，类型名称的长度限制比其他名称少一个字符。）虽然现在通常仍是这样，但在名称达到最大长度或与以下划线开头的用户类型名冲突时，数组类型名称可能与此不同。因此，依赖这一约定编写代码的做法已经弃用。请改用 \u003ccode\u003epg_type\u003c/code\u003e.\u003ccode\u003etyparray\u003c/code\u003e 来定位与给定类型关联的数组类型。\u003c/p\u003e\u003cp\u003e建议避免使用以下划线开头的类型名和表名。虽然服务器会改变生成的数组类型名称以避免与用户给定的名称冲突，但仍然存在混淆风险，特别是对旧客户端软件而言，它们可能会假定以下划线开头的类型名总是表示数组。\u003c/p\u003e\u003cp\u003e在\u003cspan\u003ePostgreSQL\u003c/span\u003e 8.2 之前，不存在 shell 类型创建语法\u003ccode\u003eCREATE TYPE \u003cem\u003e\u003ccode\u003ename\u003c/code\u003e\u003c/em\u003e\u003c/code\u003e。创建新基础类型的做法是先创建它的输入函数。在这种做法下，\u003cspan\u003ePostgreSQL\u003c/span\u003e会首先把新数据类型名视为输入函数的返回类型。此时 shell 类型会被隐式创建，然后就可以在其余 I/O 函数的定义中引用它。这种做法仍然有效，但已弃用，并且可能在未来某个版本中被禁止。另外，为避免由于函数定义中的简单拼写错误而意外使系统目录充满 shell 类型，只有在输入函数用 C 编写时，才会以这种方式创建 shell 类型。\u003c/p\u003e\u003cp\u003e在\u003cspan\u003ePostgreSQL\u003c/span\u003e 16 及更高版本中，基础类型的输入函数最好使用新的 \u003ccode\u003eerrsave()\u003c/code\u003e/\u003ccode\u003eereturn()\u003c/code\u003e机制返回\u003cspan\u003e“\u003cspan\u003e软\u003c/span\u003e”\u003c/span\u003e错误，而不是像早期版本那样抛出 \u003ccode\u003eereport()\u003c/code\u003e异常。更多信息见 \u003ccode\u003esrc/backend/utils/fmgr/README\u003c/code\u003e。\u003c/p\u003e\u003c/section\u003e\u003csection\u003e\u003ch2\u003e示例\u003c/h2\u003e\u003cp\u003e这个示例创建一种复合类型，并在函数定义中使用它：\u003c/p\u003e\u003cpre\u003eCREATE TYPE compfoo AS (f1 int, f2 text);\n\nCREATE FUNCTION getfoo() RETURNS SETOF compfoo AS $$\n    SELECT fooid, fooname FROM foo\n$$ LANGUAGE SQL;\n\u003c/pre\u003e\u003cp\u003e这个示例创建一种枚举类型，并在表定义中使用它：\u003c/p\u003e\u003cpre\u003eCREATE TYPE bug_status AS ENUM (\u0026#39;new\u0026#39;, \u0026#39;open\u0026#39;, \u0026#39;closed\u0026#39;);\n\nCREATE TABLE bug (\n    id serial,\n    description text,\n    status bug_status\n);\n\u003c/pre\u003e\u003cp\u003e这个示例创建一种范围类型：\u003c/p\u003e\u003cpre\u003eCREATE TYPE float8_range AS RANGE (subtype = float8, subtype_diff = float8mi);\n\u003c/pre\u003e\u003cp\u003e这个示例创建基础类型\u003ccode\u003ebox\u003c/code\u003e，然后在表定义中使用它：\u003c/p\u003e\u003cpre\u003eCREATE TYPE box;\n\nCREATE FUNCTION my_box_in_function(cstring) RETURNS box AS ... ;\nCREATE FUNCTION my_box_out_function(box) RETURNS cstring AS ... ;\n\nCREATE TYPE box (\n    INTERNALLENGTH = 16,\n    INPUT = my_box_in_function,\n    OUTPUT = my_box_out_function\n);\n\nCREATE TABLE myboxes (\n    id integer,\n    description box\n);\n\u003c/pre\u003e\u003cp\u003e如果\u003ccode\u003ebox\u003c/code\u003e的内部结构是由四个 \u003ccode\u003efloat4\u003c/code\u003e元素构成的数组，则也可以改为这样写：\u003c/p\u003e\u003cpre\u003eCREATE TYPE box (\n    INTERNALLENGTH = 16,\n    INPUT = my_box_in_function,\n    OUTPUT = my_box_out_function,\n    ELEMENT = float4\n);\n\u003c/pre\u003e\u003cp\u003e这样就能通过下标访问 box 值的各个分量。除此之外，该类型的行为与前例相同。\u003c/p\u003e\u003cp\u003e这个示例创建一种大对象类型，并在表定义中使用它：\u003c/p\u003e\u003cpre\u003eCREATE TYPE bigobj (\n    INPUT = lo_filein, OUTPUT = lo_fileout,\n    INTERNALLENGTH = VARIABLE\n);\nCREATE TABLE big_objs (\n    id integer,\n    obj bigobj\n);\n\u003c/pre\u003e\u003cp\u003e更多示例（包括配套的输入和输出函数）请见\u003ca href=\"/docs/18/xtypes.html\" rel=\"nofollow\"\u003e第 36.13 节\u003c/a\u003e。\u003c/p\u003e\u003c/section\u003e\u003csection\u003e\u003ch2\u003e兼容性\u003c/h2\u003e\u003cp\u003e第一种\u003ccode\u003eCREATE TYPE\u003c/code\u003e形式，即创建复合类型的形式，符合\u003cacronym\u003eSQL\u003c/acronym\u003e标准。其他形式都是 \u003cspan\u003ePostgreSQL\u003c/span\u003e扩展。\u003cacronym\u003eSQL\u003c/acronym\u003e标准中的\u003ccode\u003eCREATE TYPE\u003c/code\u003e 语句还定义了\u003cspan\u003ePostgreSQL\u003c/span\u003e尚未实现的其他形式。\u003c/p\u003e\u003cp\u003e支持创建零属性的复合类型，是 \u003cspan\u003ePostgreSQL\u003c/span\u003e对标准的一种特有背离（类似于\u003ccode\u003eCREATE TABLE\u003c/code\u003e中的同类情况）。\u003c/p\u003e\u003c/section\u003e\u003csection\u003e\u003ch2\u003e另见\u003c/h2\u003e\u003cspan\u003e\u003ca href=\"/wiki/sql/alter-type/?v=18\" title=\"ALTER TYPE\" rel=\"nofollow\"\u003e\u003cspan\u003eALTER TYPE\u003c/span\u003e\u003c/a\u003e, \u003ca href=\"/wiki/sql/create-domain/?v=18\" title=\"CREATE DOMAIN\" rel=\"nofollow\"\u003e\u003cspan\u003eCREATE DOMAIN\u003c/span\u003e\u003c/a\u003e, \u003ca href=\"/wiki/sql/create-function/?v=18\" title=\"CREATE FUNCTION\" rel=\"nofollow\"\u003e\u003cspan\u003eCREATE FUNCTION\u003c/span\u003e\u003c/a\u003e, \u003ca href=\"/wiki/sql/drop-type/?v=18\" title=\"DROP TYPE\" rel=\"nofollow\"\u003e\u003cspan\u003eDROP TYPE\u003c/span\u003e\u003c/a\u003e\u003c/span\u003e\u003c/section\u003e","SourceRevision":"1b5ca64c","ContentHash":"7bdc0f1882f712ddedc814aee156136e94e9dd70ae32aae29c2af94dc7db9331","Payload":{"purpose_zh":"定义一种新数据类型","sections":[{"html":"\u003cp\u003e\u003ccode class=\"command\"\u003eCREATE TYPE\u003c/code\u003e在当前数据库中注册一种新的数据类型。定义该类型的用户将成为其拥有者。\u003c/p\u003e\u003cp\u003e如果给出了模式名，则该类型会在指定模式中创建；否则会在当前模式中创建。类型名必须不同于同一模式中任何现有类型或域的名称。（由于表也具有关联的数据类型，类型名还必须不同于同一模式中任何现有表的名称。）\u003c/p\u003e\u003cp\u003e如上面的语法概要所示，\u003ccode class=\"command\"\u003eCREATE TYPE\u003c/code\u003e有五种形式。它们分别用于创建\u003cem class=\"firstterm\"\u003e复合类型\u003c/em\u003e、\u003cem class=\"firstterm\"\u003e枚举类型\u003c/em\u003e、\u003cem class=\"firstterm\"\u003e范围类型\u003c/em\u003e、\u003cem class=\"firstterm\"\u003e基础类型\u003c/em\u003e或\u003cem class=\"firstterm\"\u003eshell 类型\u003c/em\u003e。下文将依次讨论前四种。shell 类型只是稍后定义某种类型时使用的占位符；它通过执行除类型名外不带任何参数的\u003ccode class=\"command\"\u003eCREATE TYPE\u003c/code\u003e来创建。正如相应小节所述，创建范围类型和基础类型时，需要用 shell 类型作为前向引用。\u003c/p\u003e\u003cdiv class=\"refsect2\"\u003e\u003ch3\u003e复合类型\u003c/h3\u003e\u003cp\u003e第一种形式的\u003ccode class=\"command\"\u003eCREATE TYPE\u003c/code\u003e创建复合类型。复合类型由属性名和数据类型列表指定。如果某个属性的数据类型支持排序规则，还可以指定该属性的排序规则。复合类型本质上与表的行类型相同，但如果目的只是定义一种类型，使用\u003ccode class=\"command\"\u003eCREATE TYPE\u003c/code\u003e 就不必实际创建表。例如，独立的复合类型可用作函数的参数类型或返回类型。\u003c/p\u003e\u003cp\u003e要创建复合类型，必须对所有属性类型都拥有\u003ccode class=\"literal\"\u003eUSAGE\u003c/code\u003e 权限。\u003c/p\u003e\u003c/div\u003e\u003cdiv class=\"refsect2\"\u003e\u003ch3\u003e枚举类型\u003c/h3\u003e\u003cp\u003e如\u003ca href=\"/docs/18/datatype-enum.html\" title=\"8.7. 枚举类型\"\u003e第 8.7 节\u003c/a\u003e中所述，第二种形式的 \u003ccode class=\"command\"\u003eCREATE TYPE\u003c/code\u003e创建枚举（enum）类型。枚举类型接受一个带引号标签的列表，其中每个标签的长度都必须小于 \u003ccode class=\"symbol\"\u003eNAMEDATALEN\u003c/code\u003e字节（在标准 \u003cspan class=\"productname\"\u003ePostgreSQL\u003c/span\u003e构建中为 64 字节）。（也可以创建零标签的枚举类型，但在使用\u003ca href=\"/docs/18/sql-altertype.html\" title=\"ALTER TYPE\"\u003e\u003ccode class=\"command\"\u003eALTER TYPE\u003c/code\u003e\u003c/a\u003e 至少添加一个标签之前，这种类型不能用来保存值。）\u003c/p\u003e\u003c/div\u003e\u003cdiv class=\"refsect2\"\u003e\u003ch3\u003e范围类型\u003c/h3\u003e\u003cp\u003e如\u003ca href=\"/docs/18/rangetypes.html\" title=\"8.17. 范围类型\"\u003e第 8.17 节\u003c/a\u003e中所述，第三种形式的 \u003ccode class=\"command\"\u003eCREATE TYPE\u003c/code\u003e创建范围类型。\u003c/p\u003e\u003cp\u003e范围类型的\u003cem class=\"replaceable\"\u003e\u003ccode\u003esubtype\u003c/code\u003e\u003c/em\u003e可以是任何带有关联 B-树操作符类的类型（该操作符类用于确定范围类型值的顺序）。通常使用子类型默认的 B-树操作符类来确定顺序；若要使用非默认操作符类，可用\u003cem class=\"replaceable\"\u003e\u003ccode\u003esubtype_opclass\u003c/code\u003e\u003c/em\u003e指定其名称。如果子类型支持排序规则，而你希望在范围排序中使用非默认排序规则，可用 \u003cem class=\"replaceable\"\u003e\u003ccode\u003ecollation\u003c/code\u003e\u003c/em\u003e选项指定所需排序规则。\u003c/p\u003e\u003cp\u003e可选的\u003cem class=\"replaceable\"\u003e\u003ccode\u003ecanonical\u003c/code\u003e\u003c/em\u003e函数必须接受一个正在定义的范围类型值作为参数，并返回同一类型的值。在适用时，它用于将范围值转换为规范形式。更多信息见\u003ca href=\"/docs/18/rangetypes.html#RANGETYPES-DEFINING\" title=\"8.17.8. 定义新的范围类型\"\u003e第 8.17.8 节\u003c/a\u003e。创建 \u003cem class=\"replaceable\"\u003e\u003ccode\u003ecanonical\u003c/code\u003e\u003c/em\u003e函数有些棘手，因为它必须在声明范围类型之前定义。为此，必须先创建一种 shell 类型，它除了名称和拥有者外没有任何属性，只是一个占位符类型。这可通过执行不带任何附加参数的命令\u003ccode class=\"literal\"\u003eCREATE TYPE \u003cem class=\"replaceable\"\u003e\u003ccode\u003ename\u003c/code\u003e\u003c/em\u003e\u003c/code\u003e完成。然后就可以把该 shell 类型用作参数类型和结果类型来声明该函数，最后再用同一名称声明范围类型。这样会自动用有效的范围类型替换 shell 类型条目。\u003c/p\u003e\u003cp\u003e可选的\u003cem class=\"replaceable\"\u003e\u003ccode\u003esubtype_diff\u003c/code\u003e\u003c/em\u003e 函数必须接受两个\u003cem class=\"replaceable\"\u003e\u003ccode\u003esubtype\u003c/code\u003e\u003c/em\u003e类型的值作为参数，并返回一个表示这两个给定值之差的\u003ccode class=\"type\"\u003edouble precision\u003c/code\u003e值。虽然这是可选的，但提供该函数可显著提高该范围类型列上 GiST 索引的效率。详见\u003ca href=\"/docs/18/rangetypes.html#RANGETYPES-DEFINING\" title=\"8.17.8. 定义新的范围类型\"\u003e第 8.17.8 节\u003c/a\u003e。\u003c/p\u003e\u003cp\u003e可选的\u003cem class=\"replaceable\"\u003e\u003ccode\u003emultirange_type_name\u003c/code\u003e\u003c/em\u003e参数指定对应多范围类型的名称。若未指定，将按如下规则自动选择：如果范围类型名称包含子串\u003ccode class=\"literal\"\u003erange\u003c/code\u003e，则把类型名中的 \u003ccode class=\"literal\"\u003erange\u003c/code\u003e替换为\u003ccode class=\"literal\"\u003emultirange\u003c/code\u003e，作为多范围类型名；否则就在范围类型名后附加 \u003ccode class=\"literal\"\u003e_multirange\u003c/code\u003e后缀。\u003c/p\u003e\u003cp\u003e要创建范围类型，你必须拥有子类型的 \u003ccode class=\"literal\"\u003eUSAGE\u003c/code\u003e 权限。\u003c/p\u003e\u003c/div\u003e\u003cdiv class=\"refsect2\"\u003e\u003ch3\u003e基础类型\u003c/h3\u003e\u003cp\u003e第四种形式的\u003ccode class=\"command\"\u003eCREATE TYPE\u003c/code\u003e创建一种新的基础类型（标量类型）。要创建新的基础类型，你必须是超级用户。（这样限制是因为错误的类型定义可能使服务器陷入混乱，甚至导致其崩溃。）\u003c/p\u003e\u003cp\u003e这些参数可以按任意顺序出现，不必局限于上面展示的顺序，而且大多数都是可选的。在定义该类型之前，必须先注册两个或更多函数（使用 \u003ccode class=\"command\"\u003eCREATE FUNCTION\u003c/code\u003e）。支持函数 \u003cem class=\"replaceable\"\u003e\u003ccode\u003einput_function\u003c/code\u003e\u003c/em\u003e和 \u003cem class=\"replaceable\"\u003e\u003ccode\u003eoutput_function\u003c/code\u003e\u003c/em\u003e是必需的；\u003cem class=\"replaceable\"\u003e\u003ccode\u003ereceive_function\u003c/code\u003e\u003c/em\u003e、\u003cem class=\"replaceable\"\u003e\u003ccode\u003esend_function\u003c/code\u003e\u003c/em\u003e、\u003cem class=\"replaceable\"\u003e\u003ccode\u003etype_modifier_input_function\u003c/code\u003e\u003c/em\u003e、\u003cem class=\"replaceable\"\u003e\u003ccode\u003etype_modifier_output_function\u003c/code\u003e\u003c/em\u003e、\u003cem class=\"replaceable\"\u003e\u003ccode\u003eanalyze_function\u003c/code\u003e\u003c/em\u003e以及 \u003cem class=\"replaceable\"\u003e\u003ccode\u003esubscript_function\u003c/code\u003e\u003c/em\u003e则是可选的。通常这些函数必须用 C 或其他低级语言编写。\u003c/p\u003e\u003cp\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003einput_function\u003c/code\u003e\u003c/em\u003e将类型的外部文本表示转换为该类型的操作符和函数所使用的内部表示。\u003cem class=\"replaceable\"\u003e\u003ccode\u003eoutput_function\u003c/code\u003e\u003c/em\u003e 执行相反的转换。输入函数可以声明为接受一个\u003ccode class=\"type\"\u003ecstring\u003c/code\u003e 参数，或者接受三个参数，类型分别为\u003ccode class=\"type\"\u003ecstring\u003c/code\u003e、\u003ccode class=\"type\"\u003eoid\u003c/code\u003e、\u003ccode class=\"type\"\u003einteger\u003c/code\u003e。第一个参数是以 C 字符串表示的输入文本，第二个参数是该类型自身的 OID（数组类型例外，此时传入的是其元素类型的 OID），第三个参数是在已知情况下目标列的 \u003ccode class=\"literal\"\u003etypmod\u003c/code\u003e（未知则传入 -1）。输入函数必须返回该数据类型本身的值。通常输入函数应声明为 STRICT；否则，在读取 NULL 输入值时会以 NULL 作为第一个参数调用它。除非函数抛出错误，否则在这种情况下仍必须返回 NULL。（这种情况主要是为了支持可能需要拒绝 NULL 输入的域输入函数。）输出函数必须声明为接受一个新数据类型参数，并且必须返回\u003ccode class=\"type\"\u003ecstring\u003c/code\u003e类型。对于 NULL 值不会调用输出函数。\u003c/p\u003e\u003cp\u003e可选的\u003cem class=\"replaceable\"\u003e\u003ccode\u003ereceive_function\u003c/code\u003e\u003c/em\u003e 把类型的外部二进制表示转换为内部表示。如果未提供此函数，该类型就不能参与二进制输入。外部二进制表示应选择为既能低成本转换为内部形式，又具有合理可移植性。（例如，标准整数数据类型把网络字节序用作外部二进制表示，而内部表示则使用机器的本地字节序。）\u003cem class=\"replaceable\"\u003e\u003ccode\u003ereceive_function\u003c/code\u003e\u003c/em\u003e 应进行充分检查以确保值有效。它可以声明为接受一个 \u003ccode class=\"type\"\u003einternal\u003c/code\u003e参数，或者接受三个参数，类型分别为 \u003ccode class=\"type\"\u003einternal\u003c/code\u003e、\u003ccode class=\"type\"\u003eoid\u003c/code\u003e、\u003ccode class=\"type\"\u003einteger\u003c/code\u003e。第一个参数是指向保存已接收字节串的\u003ccode class=\"type\"\u003eStringInfo\u003c/code\u003e缓冲区的指针；其余可选参数与文本输入函数相同。接收函数必须返回该数据类型本身的值。通常，接收函数应声明为 STRICT；否则，在读取 NULL 输入值时会以 NULL 作为第一个参数调用它。除非函数抛出错误，否则在这种情况下仍必须返回 NULL。（这种情况主要是为了支持可能需要拒绝 NULL 输入的域接收函数。）类似地，可选的 \u003cem class=\"replaceable\"\u003e\u003ccode\u003esend_function\u003c/code\u003e\u003c/em\u003e把内部表示转换为外部二进制表示。如果未提供此函数，该类型就不能参与二进制输出。发送函数必须声明为接受一个新数据类型参数，并且必须返回 \u003ccode class=\"type\"\u003ebytea\u003c/code\u003e类型。对于 NULL 值不会调用发送函数。\u003c/p\u003e\u003cp\u003e读到这里，你可能会问：既然新类型本身还没创建，输入和输出函数怎么能声明为返回或接受这个新类型呢？答案是，应先把该类型定义为一种 \u003cem class=\"firstterm\"\u003eshell 类型\u003c/em\u003e，它除了名称和拥有者外没有任何属性，只是一个占位符类型。这可通过执行不带任何附加参数的命令 \u003ccode class=\"literal\"\u003eCREATE TYPE \u003cem class=\"replaceable\"\u003e\u003ccode\u003ename\u003c/code\u003e\u003c/em\u003e\u003c/code\u003e 完成。然后就可以定义引用该 shell 类型的 C I/O 函数。最后，再用带完整定义的\u003ccode class=\"command\"\u003eCREATE TYPE\u003c/code\u003e替换该 shell 条目，生成一个完整且有效的类型定义，此后新类型就能正常使用。\u003c/p\u003e\u003cp\u003e如果该类型支持修饰符，也就是附加在类型声明上的可选约束，例如 \u003ccode class=\"literal\"\u003echar(5)\u003c/code\u003e或\u003ccode class=\"literal\"\u003enumeric(30,2)\u003c/code\u003e，就需要可选的\u003cem class=\"replaceable\"\u003e\u003ccode\u003etype_modifier_input_function\u003c/code\u003e\u003c/em\u003e和 \u003cem class=\"replaceable\"\u003e\u003ccode\u003etype_modifier_output_function\u003c/code\u003e\u003c/em\u003e。\u003cspan class=\"productname\"\u003ePostgreSQL\u003c/span\u003e允许用户定义类型接受一个或多个简单常量或标识符作为修饰符。不过，这些信息必须能够打包成单个非负整数值，以便存储在系统目录中。声明的修饰符会以 \u003ccode class=\"type\"\u003ecstring\u003c/code\u003e数组的形式传递给\u003cem class=\"replaceable\"\u003e\u003ccode\u003etype_modifier_input_function\u003c/code\u003e\u003c/em\u003e。它必须检查这些值是否有效（若无效则抛出错误），若有效则返回一个非负\u003ccode class=\"type\"\u003einteger\u003c/code\u003e值，该值将作为列的\u003cspan class=\"quote\"\u003e“\u003cspan class=\"quote\"\u003etypmod\u003c/span\u003e”\u003c/span\u003e存储。如果该类型没有\u003cem class=\"replaceable\"\u003e\u003ccode\u003etype_modifier_input_function\u003c/code\u003e\u003c/em\u003e，就会拒绝类型修饰符。\u003cem class=\"replaceable\"\u003e\u003ccode\u003etype_modifier_output_function\u003c/code\u003e\u003c/em\u003e 则把内部整数 typmod 值转换回适合用户显示的正确形式。它必须返回一个\u003ccode class=\"type\"\u003ecstring\u003c/code\u003e值，即精确追加到类型名后的字符串；例如，\u003ccode class=\"type\"\u003enumeric\u003c/code\u003e的该函数可能返回 \u003ccode class=\"literal\"\u003e(30,2)\u003c/code\u003e。允许省略\u003cem class=\"replaceable\"\u003e\u003ccode\u003etype_modifier_output_function\u003c/code\u003e\u003c/em\u003e；在这种情况下，默认显示格式只是把存储的 typmod 整数值放在圆括号中。\u003c/p\u003e\u003cp\u003e可选的\u003cem class=\"replaceable\"\u003e\u003ccode\u003eanalyze_function\u003c/code\u003e\u003c/em\u003e 为该数据类型的列执行类型专用的统计信息收集。默认情况下，如果该类型有默认的 B-树操作符类，\u003ccode class=\"command\"\u003eANALYZE\u003c/code\u003e将尝试使用该类型的\u003cspan class=\"quote\"\u003e“\u003cspan class=\"quote\"\u003e等于\u003c/span\u003e”\u003c/span\u003e和\u003cspan class=\"quote\"\u003e“\u003cspan class=\"quote\"\u003e小于\u003c/span\u003e”\u003c/span\u003e操作符收集统计信息。对于非标量类型，这种行为很可能不合适，因此可以通过指定自定义分析函数来覆盖。分析函数必须声明为接受一个 \u003ccode class=\"type\"\u003einternal\u003c/code\u003e参数并返回\u003ccode class=\"type\"\u003eboolean\u003c/code\u003e结果。分析函数的详细 API 见\u003ccode class=\"filename\"\u003esrc/include/commands/vacuum.h\u003c/code\u003e。\u003c/p\u003e\u003cp\u003e可选的\u003cem class=\"replaceable\"\u003e\u003ccode\u003esubscript_function\u003c/code\u003e\u003c/em\u003e允许在 SQL 命令中对该数据类型进行下标访问。指定此函数并不会使该类型被视为\u003cspan class=\"quote\"\u003e“\u003cspan class=\"quote\"\u003e真正的\u003c/span\u003e”\u003c/span\u003e数组类型；例如，它不会成为 \u003ccode class=\"literal\"\u003eARRAY[]\u003c/code\u003e构造结果类型的候选者。但如果对这种类型的值使用下标是提取其中数据的一种自然记法，就可以编写 \u003cem class=\"replaceable\"\u003e\u003ccode\u003esubscript_function\u003c/code\u003e\u003c/em\u003e 来定义其含义。下标函数必须声明为接受一个\u003ccode class=\"type\"\u003einternal\u003c/code\u003e 参数，并返回一个\u003ccode class=\"type\"\u003einternal\u003c/code\u003e结果，也就是指向实现下标操作的方法（函数）结构体的指针。下标函数的详细 API 见 \u003ccode class=\"filename\"\u003esrc/include/nodes/subscripting.h\u003c/code\u003e。阅读 \u003ccode class=\"filename\"\u003esrc/backend/utils/adt/arraysubs.c\u003c/code\u003e中的数组实现，或更简单的\u003ccode class=\"filename\"\u003econtrib/hstore/hstore_subs.c\u003c/code\u003e 代码，也可能有所帮助。更多信息见下文\u003ca href=\"/docs/18/sql-createtype.html#SQL-CREATETYPE-ARRAY\" title=\"数组类型\"\u003e数组类型\u003c/a\u003e。\u003c/p\u003e\u003cp\u003e虽然新类型内部表示的细节只有 I/O 函数以及你为该类型编写的其他函数才知道，但仍有若干内部表示属性必须向 \u003cspan class=\"productname\"\u003ePostgreSQL\u003c/span\u003e声明。其中最重要的是 \u003cem class=\"replaceable\"\u003e\u003ccode\u003einternallength\u003c/code\u003e\u003c/em\u003e。基础类型可以是定长的，此时\u003cem class=\"replaceable\"\u003e\u003ccode\u003einternallength\u003c/code\u003e\u003c/em\u003e为正整数；也可以是变长的，此时将\u003cem class=\"replaceable\"\u003e\u003ccode\u003einternallength\u003c/code\u003e\u003c/em\u003e设为 \u003ccode class=\"literal\"\u003eVARIABLE\u003c/code\u003e。（在内部，这通过把 \u003ccode class=\"literal\"\u003etyplen\u003c/code\u003e设为 -1 表示。）所有变长类型的内部表示都必须以一个 4 字节整数开头，用来给出该类型该值的总长度。（注意，如\u003ca href=\"/docs/18/storage-toast.html\" title=\"66.2. TOAST\"\u003e第 66.2 节\u003c/a\u003e中所述，长度字段通常是经过编码的；直接访问它并不明智。）\u003c/p\u003e\u003cp\u003e可选标志\u003ccode class=\"literal\"\u003ePASSEDBYVALUE\u003c/code\u003e表示该数据类型的值按值传递，而不是按引用传递。按值传递的类型必须是定长的，且其内部表示不能大于\u003ccode class=\"type\"\u003eDatum\u003c/code\u003e类型的大小（某些机器上为 4 字节，另一些为 8 字节）。\u003c/p\u003e\u003cp\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003ealignment\u003c/code\u003e\u003c/em\u003e参数指定该数据类型所需的存储对齐方式。允许的值分别对应按 1、2、4 或 8 字节边界对齐。注意，变长类型的对齐至少必须为 4，因为它们的第一个组成部分必然是一个\u003ccode class=\"type\"\u003eint4\u003c/code\u003e。\u003c/p\u003e\u003cp\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003estorage\u003c/code\u003e\u003c/em\u003e参数允许为变长数据类型选择存储策略。（定长类型只允许 \u003ccode class=\"literal\"\u003eplain\u003c/code\u003e。）\u003ccode class=\"literal\"\u003eplain\u003c/code\u003e表示该类型数据始终行内存储且不压缩。\u003ccode class=\"literal\"\u003eextended\u003c/code\u003e表示系统会先尝试压缩较长的数据值，如果仍然过长，就把该值移出主表行。\u003ccode class=\"literal\"\u003eexternal\u003c/code\u003e允许把值移出主表，但系统不会尝试压缩它。\u003ccode class=\"literal\"\u003emain\u003c/code\u003e允许压缩，但不鼓励把值移出主表。（采用这种存储策略的数据项在没有其他办法让一行适配时仍可能被移出主表，但与\u003ccode class=\"literal\"\u003eextended\u003c/code\u003e和\u003ccode class=\"literal\"\u003eexternal\u003c/code\u003e 数据项相比，它们会被优先保留在主表中。）\u003c/p\u003e\u003cp\u003e如\u003ca href=\"/docs/18/storage-toast.html\" title=\"66.2. TOAST\"\u003e第 66.2 节\u003c/a\u003e和\u003ca href=\"/docs/18/xtypes.html#XTYPES-TOAST\" title=\"36.13.1. TOAST 注意事项\"\u003e第 36.13.1 节\u003c/a\u003e所述，除\u003ccode class=\"literal\"\u003eplain\u003c/code\u003e之外所有\u003cem class=\"replaceable\"\u003e\u003ccode\u003estorage\u003c/code\u003e\u003c/em\u003e值都意味着该数据类型的函数能够处理经过\u003cem class=\"firstterm\"\u003eTOAST 处理\u003c/em\u003e的值。具体指定哪一种其他值，只是决定可 TOAST 数据类型列的默认 TOAST 存储策略；用户仍可使用\u003ccode class=\"literal\"\u003eALTER TABLE SET STORAGE\u003c/code\u003e 为单个列选择其他策略。\u003c/p\u003e\u003cp\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003elike_type\u003c/code\u003e\u003c/em\u003e参数提供了指定数据类型基本表示属性的另一种方法：从某个现有类型复制这些属性。\u003cem class=\"replaceable\"\u003e\u003ccode\u003einternallength\u003c/code\u003e\u003c/em\u003e、\u003cem class=\"replaceable\"\u003e\u003ccode\u003epassedbyvalue\u003c/code\u003e\u003c/em\u003e、\u003cem class=\"replaceable\"\u003e\u003ccode\u003ealignment\u003c/code\u003e\u003c/em\u003e和 \u003cem class=\"replaceable\"\u003e\u003ccode\u003estorage\u003c/code\u003e\u003c/em\u003e的值都从指定类型复制而来。（虽然可以通过同时给出\u003ccode class=\"literal\"\u003eLIKE\u003c/code\u003e子句和这些选项来覆盖其中某些值，但通常不建议这样做。）当新类型的底层实现以某种方式\u003cspan class=\"quote\"\u003e“\u003cspan class=\"quote\"\u003e借用\u003c/span\u003e”\u003c/span\u003e现有类型时，以这种方式指定表示属性尤其有用。\u003c/p\u003e\u003cp\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003ecategory\u003c/code\u003e\u003c/em\u003e和 \u003cem class=\"replaceable\"\u003e\u003ccode\u003epreferred\u003c/code\u003e\u003c/em\u003e参数可用于在存在歧义时帮助控制应用哪一种隐式类型转换。每种数据类型都属于一个由单个 ASCII 字符命名的类别，并且在其类别内要么是\u003cspan class=\"quote\"\u003e“\u003cspan class=\"quote\"\u003e首选\u003c/span\u003e”\u003c/span\u003e的，要么不是。当这一规则有助于解析重载函数或操作符时，解析器会优先转换为首选类型（但只会从同一类别中的其他类型转换）。更多细节见\u003ca href=\"/docs/18/typeconv.html\" title=\"第 10 章 类型转换\"\u003e第 10 章\u003c/a\u003e。对于与任何其他类型之间都没有隐式类型转换的类型，保持这些设置的默认值就足够了。不过，对于一组彼此存在隐式类型转换的相关类型，把它们都标记为属于同一类别，并选择一两个\u003cspan class=\"quote\"\u003e“\u003cspan class=\"quote\"\u003e最通用\u003c/span\u003e”\u003c/span\u003e的类型作为该类别的首选类型，通常会有帮助。\u003cem class=\"replaceable\"\u003e\u003ccode\u003ecategory\u003c/code\u003e\u003c/em\u003e参数在将用户定义类型加入现有内置类别（例如数值类型或字符串类型）时尤其有用。不过，也可以创建全新的纯用户定义类型类别。为这种类别命名时，可选择任一非大写字母的 ASCII 字符。\u003c/p\u003e\u003cp\u003e如果用户希望该数据类型列的默认值不是空值，可以指定默认值。用 \u003ccode class=\"literal\"\u003eDEFAULT\u003c/code\u003e关键字指定默认值。（该默认值可以被附加到具体列上的显式\u003ccode class=\"literal\"\u003eDEFAULT\u003c/code\u003e子句覆盖。）\u003c/p\u003e\u003cp\u003e若要表明一种类型是定长数组类型，可用\u003ccode class=\"literal\"\u003eELEMENT\u003c/code\u003e 关键字指定数组元素的类型。例如，要定义由 4 字节整数（\u003ccode class=\"type\"\u003eint4\u003c/code\u003e）构成的数组，可指定 \u003ccode class=\"literal\"\u003eELEMENT = int4\u003c/code\u003e。更多细节见下文\u003ca href=\"/docs/18/sql-createtype.html#SQL-CREATETYPE-ARRAY\" title=\"数组类型\"\u003e数组类型\u003c/a\u003e。\u003c/p\u003e\u003cp\u003e若要指定该类型数组在外部表示中用于分隔各值的分隔符，可把 \u003cem class=\"replaceable\"\u003e\u003ccode\u003edelimiter\u003c/code\u003e\u003c/em\u003e设为特定字符。默认分隔符是逗号（\u003ccode class=\"literal\"\u003e,\u003c/code\u003e）。注意，这个分隔符关联的是数组元素类型，而不是数组类型本身。\u003c/p\u003e\u003cp\u003e如果可选的布尔参数 \u003cem class=\"replaceable\"\u003e\u003ccode\u003ecollatable\u003c/code\u003e\u003c/em\u003e为真，则该类型的列定义和表达式可以通过\u003ccode class=\"literal\"\u003eCOLLATE\u003c/code\u003e子句携带排序规则信息。是否实际使用这些排序规则信息取决于操作该类型的函数实现；仅仅把类型标记为支持排序规则并不会自动实现这一点。\u003c/p\u003e\u003c/div\u003e\u003cdiv class=\"refsect2\"\u003e\u003ch3\u003e数组类型\u003c/h3\u003e\u003cp\u003e每当创建用户定义类型时，\u003cspan class=\"productname\"\u003ePostgreSQL\u003c/span\u003e 都会自动创建一个关联的数组类型，其名称由元素类型名前加一个下划线组成；必要时还会截断，以保持其长度小于 \u003ccode class=\"symbol\"\u003eNAMEDATALEN\u003c/code\u003e字节。（如果这样生成的名称与现有类型名冲突，就会重复这一过程，直到找到不冲突的名称。）这种隐式创建的数组类型是变长的，并使用内置输入/输出函数 \u003ccode class=\"literal\"\u003earray_in\u003c/code\u003e和\u003ccode class=\"literal\"\u003earray_out\u003c/code\u003e。此外，系统在处理基于该用户定义类型的\u003ccode class=\"literal\"\u003eARRAY[]\u003c/code\u003e 等构造时，使用的也是这种类型。该数组类型会跟踪其元素类型的拥有者或模式的任何变化，并在元素类型被删除时一并删除。\u003c/p\u003e\u003cp\u003e如果系统会自动创建正确的数组类型，你可能会合理地问，为什么还需要\u003ccode class=\"option\"\u003eELEMENT\u003c/code\u003e选项。\u003ccode class=\"option\"\u003eELEMENT\u003c/code\u003e最主要的用途是：你正在创建一种定长类型，而它在内部恰好是若干相同元素组成的数组，并且除了为整个类型提供的操作之外，你还希望允许通过下标直接访问这些元素。例如，类型\u003ccode class=\"type\"\u003epoint\u003c/code\u003e在内部就表示为两个浮点数，可以用\u003ccode class=\"literal\"\u003epoint[0]\u003c/code\u003e和 \u003ccode class=\"literal\"\u003epoint[1]\u003c/code\u003e访问。注意，这种机制只适用于内部形式恰好是一串相同定长字段的定长类型。由于历史原因（也就是说这显然不对，但现在改已经太晚了），定长数组类型的下标从零开始，而变长数组则从一开始。\u003c/p\u003e\u003cp\u003e指定\u003ccode class=\"option\"\u003eSUBSCRIPT\u003c/code\u003e选项允许对某种数据类型使用下标，即使系统在其他方面并不把它视为数组类型。上面刚描述的定长数组行为，实际上是由\u003ccode class=\"option\"\u003eSUBSCRIPT\u003c/code\u003e处理函数 \u003ccode class=\"function\"\u003eraw_array_subscript_handler\u003c/code\u003e实现的；如果你为定长类型指定了\u003ccode class=\"option\"\u003eELEMENT\u003c/code\u003e而没有同时写 \u003ccode class=\"option\"\u003eSUBSCRIPT\u003c/code\u003e，系统就会自动使用该函数。\u003c/p\u003e\u003cp\u003e指定自定义\u003ccode class=\"option\"\u003eSUBSCRIPT\u003c/code\u003e函数时，通常不必再指定 \u003ccode class=\"option\"\u003eELEMENT\u003c/code\u003e，除非\u003ccode class=\"option\"\u003eSUBSCRIPT\u003c/code\u003e处理函数需要查阅\u003ccode class=\"structfield\"\u003etypelem\u003c/code\u003e来确定应返回什么。请注意，指定\u003ccode class=\"option\"\u003eELEMENT\u003c/code\u003e会让系统认为新类型包含元素类型，或者在物理上以某种方式依赖元素类型；因此，例如，如果存在该依赖类型的列，就不允许更改元素类型的属性。\u003c/p\u003e\u003c/div\u003e","key":"description","title":"描述"},{"html":"\u003cdiv class=\"variablelist\"\u003e\u003cdl class=\"variablelist\"\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003ename\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e要创建的类型名称（可选地带有模式限定）。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003eattribute_name\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e复合类型的一个属性（列）的名称。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003edata_type\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e将成为复合类型一列的现有数据类型名称。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003ecollation\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e要与复合类型的某一列或范围类型关联的现有排序规则名称。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003elabel\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e表示枚举类型某个值所关联文本标签的字符串字面量。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003esubtype\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e范围类型所表示范围的元素类型名称。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003esubtype_operator_class\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e子类型的 B-树操作符类名称。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003ecanonical_function\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e范围类型规范化函数的名称。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003esubtype_diff_function\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e子类型差分函数的名称。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003emultirange_type_name\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e对应多范围类型的名称。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003einput_function\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e将数据从类型的外部文本形式转换为内部形式的函数名。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003eoutput_function\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e将数据从类型的内部形式转换为外部文本形式的函数名。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003ereceive_function\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e将数据从类型的外部二进制形式转换成内部形式的函数名。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003esend_function\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e将数据从类型的内部形式转换为外部二进制形式的函数名。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003etype_modifier_input_function\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e将类型的修饰符数组转换为内部形式的函数名。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003etype_modifier_output_function\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e将类型修饰符的内部形式转换为外部文本形式的函数名。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003eanalyze_function\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e为该数据类型执行统计分析的函数名。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003esubscript_function\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e定义对该数据类型值进行下标访问时行为的函数名。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003einternallength\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e一个数字常量，用于指定新类型内部表示的字节长度。默认假定它是变长的。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003ealignment\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e该数据类型的存储对齐需求。如果被指定，它必须是 \u003ccode class=\"literal\"\u003echar\u003c/code\u003e、\u003ccode class=\"literal\"\u003eint2\u003c/code\u003e、\u003ccode class=\"literal\"\u003eint4\u003c/code\u003e或者\u003ccode class=\"literal\"\u003edouble\u003c/code\u003e。默认是 \u003ccode class=\"literal\"\u003eint4\u003c/code\u003e。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003estorage\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e该数据类型的存储策略。如果被指定，必须是 \u003ccode class=\"literal\"\u003eplain\u003c/code\u003e、\u003ccode class=\"literal\"\u003eexternal\u003c/code\u003e、\u003ccode class=\"literal\"\u003eextended\u003c/code\u003e或者\u003ccode class=\"literal\"\u003emain\u003c/code\u003e。默认是\u003ccode class=\"literal\"\u003eplain\u003c/code\u003e。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003elike_type\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e与新类型具有相同表示形式的现有数据类型名称。除非在本 \u003ccode class=\"command\"\u003eCREATE TYPE\u003c/code\u003e命令的其他位置显式覆盖，否则 \u003cem class=\"replaceable\"\u003e\u003ccode\u003einternallength\u003c/code\u003e\u003c/em\u003e、\u003cem class=\"replaceable\"\u003e\u003ccode\u003epassedbyvalue\u003c/code\u003e\u003c/em\u003e、\u003cem class=\"replaceable\"\u003e\u003ccode\u003ealignment\u003c/code\u003e\u003c/em\u003e和 \u003cem class=\"replaceable\"\u003e\u003ccode\u003estorage\u003c/code\u003e\u003c/em\u003e的值都会从该类型复制。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003ecategory\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e该类型的类别码（单个 ASCII 字符）。默认值是表示\u003cspan class=\"quote\"\u003e“\u003cspan class=\"quote\"\u003e用户定义类型\u003c/span\u003e”\u003c/span\u003e的\u003ccode class=\"literal\"\u003e'U'\u003c/code\u003e。其他标准类别码见\u003ca href=\"/docs/18/catalog-pg-type.html#CATALOG-TYPCATEGORY-TABLE\" title=\"表 52.65. typcategory 代码\"\u003e表 52.65\u003c/a\u003e。你也可以选择其他 ASCII 字符来创建自定义类别。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003epreferred\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e若该类型是其类型类别中的首选类型，则为真，否则为假。默认值为假。在现有类型类别中创建新的首选类型时要格外小心，因为这可能导致出人意料的行为变化。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003edefault\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e该数据类型的默认值。若省略，默认值为 null。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003eelement\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e正在创建的类型是数组；该参数指定数组元素类型。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003edelimiter\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e在由该类型构成的数组中各值之间使用的分隔符字符。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003ecollatable\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e如果该类型的操作可以使用排序规则信息，则为真。默认为假。\u003c/p\u003e\u003c/dd\u003e\u003c/dl\u003e\u003c/div\u003e","key":"parameters","title":"参数"},{"html":"\u003cp\u003e由于数据类型一旦创建，其使用方式就不再受限制，因此创建基础类型或范围类型，相当于对类型定义中提到的那些函数授予公共执行权限。这对适合用于类型定义的那类函数来说通常不是问题。但如果设计一种类型时，需要在把它转换为外部形式或从外部形式转换回来时使用\u003cspan class=\"quote\"\u003e“\u003cspan class=\"quote\"\u003e秘密\u003c/span\u003e”\u003c/span\u003e信息，就应当三思。\u003c/p\u003e\u003cp\u003e在\u003cspan class=\"productname\"\u003ePostgreSQL\u003c/span\u003e 8.3 之前，自动生成的数组类型名称总是恰好等于元素类型名称前加一个下划线字符（\u003ccode class=\"literal\"\u003e_\u003c/code\u003e）。（因此，类型名称的长度限制比其他名称少一个字符。）虽然现在通常仍是这样，但在名称达到最大长度或与以下划线开头的用户类型名冲突时，数组类型名称可能与此不同。因此，依赖这一约定编写代码的做法已经弃用。请改用 \u003ccode class=\"structname\"\u003epg_type\u003c/code\u003e.\u003ccode class=\"structfield\"\u003etyparray\u003c/code\u003e 来定位与给定类型关联的数组类型。\u003c/p\u003e\u003cp\u003e建议避免使用以下划线开头的类型名和表名。虽然服务器会改变生成的数组类型名称以避免与用户给定的名称冲突，但仍然存在混淆风险，特别是对旧客户端软件而言，它们可能会假定以下划线开头的类型名总是表示数组。\u003c/p\u003e\u003cp\u003e在\u003cspan class=\"productname\"\u003ePostgreSQL\u003c/span\u003e 8.2 之前，不存在 shell 类型创建语法\u003ccode class=\"literal\"\u003eCREATE TYPE \u003cem class=\"replaceable\"\u003e\u003ccode\u003ename\u003c/code\u003e\u003c/em\u003e\u003c/code\u003e。创建新基础类型的做法是先创建它的输入函数。在这种做法下，\u003cspan class=\"productname\"\u003ePostgreSQL\u003c/span\u003e会首先把新数据类型名视为输入函数的返回类型。此时 shell 类型会被隐式创建，然后就可以在其余 I/O 函数的定义中引用它。这种做法仍然有效，但已弃用，并且可能在未来某个版本中被禁止。另外，为避免由于函数定义中的简单拼写错误而意外使系统目录充满 shell 类型，只有在输入函数用 C 编写时，才会以这种方式创建 shell 类型。\u003c/p\u003e\u003cp\u003e在\u003cspan class=\"productname\"\u003ePostgreSQL\u003c/span\u003e 16 及更高版本中，基础类型的输入函数最好使用新的 \u003ccode class=\"function\"\u003eerrsave()\u003c/code\u003e/\u003ccode class=\"function\"\u003eereturn()\u003c/code\u003e机制返回\u003cspan class=\"quote\"\u003e“\u003cspan class=\"quote\"\u003e软\u003c/span\u003e”\u003c/span\u003e错误，而不是像早期版本那样抛出 \u003ccode class=\"function\"\u003eereport()\u003c/code\u003e异常。更多信息见 \u003ccode class=\"filename\"\u003esrc/backend/utils/fmgr/README\u003c/code\u003e。\u003c/p\u003e","key":"notes","title":"注解"},{"html":"\u003cp\u003e这个示例创建一种复合类型，并在函数定义中使用它：\u003c/p\u003e\u003cpre class=\"programlisting\"\u003eCREATE TYPE compfoo AS (f1 int, f2 text);\n\nCREATE FUNCTION getfoo() RETURNS SETOF compfoo AS $$\n    SELECT fooid, fooname FROM foo\n$$ LANGUAGE SQL;\n\u003c/pre\u003e\u003cp\u003e这个示例创建一种枚举类型，并在表定义中使用它：\u003c/p\u003e\u003cpre class=\"programlisting\"\u003eCREATE TYPE bug_status AS ENUM ('new', 'open', 'closed');\n\nCREATE TABLE bug (\n    id serial,\n    description text,\n    status bug_status\n);\n\u003c/pre\u003e\u003cp\u003e这个示例创建一种范围类型：\u003c/p\u003e\u003cpre class=\"programlisting\"\u003eCREATE TYPE float8_range AS RANGE (subtype = float8, subtype_diff = float8mi);\n\u003c/pre\u003e\u003cp\u003e这个示例创建基础类型\u003ccode class=\"type\"\u003ebox\u003c/code\u003e，然后在表定义中使用它：\u003c/p\u003e\u003cpre class=\"programlisting\"\u003eCREATE TYPE box;\n\nCREATE FUNCTION my_box_in_function(cstring) RETURNS box AS ... ;\nCREATE FUNCTION my_box_out_function(box) RETURNS cstring AS ... ;\n\nCREATE TYPE box (\n    INTERNALLENGTH = 16,\n    INPUT = my_box_in_function,\n    OUTPUT = my_box_out_function\n);\n\nCREATE TABLE myboxes (\n    id integer,\n    description box\n);\n\u003c/pre\u003e\u003cp\u003e如果\u003ccode class=\"type\"\u003ebox\u003c/code\u003e的内部结构是由四个 \u003ccode class=\"type\"\u003efloat4\u003c/code\u003e元素构成的数组，则也可以改为这样写：\u003c/p\u003e\u003cpre class=\"programlisting\"\u003eCREATE TYPE box (\n    INTERNALLENGTH = 16,\n    INPUT = my_box_in_function,\n    OUTPUT = my_box_out_function,\n    ELEMENT = float4\n);\n\u003c/pre\u003e\u003cp\u003e这样就能通过下标访问 box 值的各个分量。除此之外，该类型的行为与前例相同。\u003c/p\u003e\u003cp\u003e这个示例创建一种大对象类型，并在表定义中使用它：\u003c/p\u003e\u003cpre class=\"programlisting\"\u003eCREATE TYPE bigobj (\n    INPUT = lo_filein, OUTPUT = lo_fileout,\n    INTERNALLENGTH = VARIABLE\n);\nCREATE TABLE big_objs (\n    id integer,\n    obj bigobj\n);\n\u003c/pre\u003e\u003cp\u003e更多示例（包括配套的输入和输出函数）请见\u003ca href=\"/docs/18/xtypes.html\" title=\"36.13. 用户定义的类型\"\u003e第 36.13 节\u003c/a\u003e。\u003c/p\u003e","key":"examples","title":"示例"},{"html":"\u003cp\u003e第一种\u003ccode class=\"command\"\u003eCREATE TYPE\u003c/code\u003e形式，即创建复合类型的形式，符合\u003cacronym\u003eSQL\u003c/acronym\u003e标准。其他形式都是 \u003cspan class=\"productname\"\u003ePostgreSQL\u003c/span\u003e扩展。\u003cacronym\u003eSQL\u003c/acronym\u003e标准中的\u003ccode class=\"command\"\u003eCREATE TYPE\u003c/code\u003e 语句还定义了\u003cspan class=\"productname\"\u003ePostgreSQL\u003c/span\u003e尚未实现的其他形式。\u003c/p\u003e\u003cp\u003e支持创建零属性的复合类型，是 \u003cspan class=\"productname\"\u003ePostgreSQL\u003c/span\u003e对标准的一种特有背离（类似于\u003ccode class=\"command\"\u003eCREATE TABLE\u003c/code\u003e中的同类情况）。\u003c/p\u003e","key":"compatibility","title":"兼容性"},{"html":"\u003cspan class=\"simplelist\"\u003e\u003ca href=\"/wiki/sql/alter-type/?v=18\" title=\"ALTER TYPE\"\u003e\u003cspan class=\"refentrytitle\"\u003eALTER TYPE\u003c/span\u003e\u003c/a\u003e, \u003ca href=\"/wiki/sql/create-domain/?v=18\" title=\"CREATE DOMAIN\"\u003e\u003cspan class=\"refentrytitle\"\u003eCREATE DOMAIN\u003c/span\u003e\u003c/a\u003e, \u003ca href=\"/wiki/sql/create-function/?v=18\" title=\"CREATE FUNCTION\"\u003e\u003cspan class=\"refentrytitle\"\u003eCREATE FUNCTION\u003c/span\u003e\u003c/a\u003e, \u003ca href=\"/wiki/sql/drop-type/?v=18\" title=\"DROP TYPE\"\u003e\u003cspan class=\"refentrytitle\"\u003eDROP TYPE\u003c/span\u003e\u003c/a\u003e\u003c/span\u003e","key":"see_also","title":"另见"}],"sections_same_as":"","synopsis_html":"CREATE TYPE \u003cem class=\"replaceable\"\u003e\u003ccode\u003ename\u003c/code\u003e\u003c/em\u003e AS\n    ( [ \u003cem class=\"replaceable\"\u003e\u003ccode\u003eattribute_name\u003c/code\u003e\u003c/em\u003e \u003cem class=\"replaceable\"\u003e\u003ccode\u003edata_type\u003c/code\u003e\u003c/em\u003e [ COLLATE \u003cem class=\"replaceable\"\u003e\u003ccode\u003ecollation\u003c/code\u003e\u003c/em\u003e ] [, ... ] ] )\n\nCREATE TYPE \u003cem class=\"replaceable\"\u003e\u003ccode\u003ename\u003c/code\u003e\u003c/em\u003e AS ENUM\n    ( [ '\u003cem class=\"replaceable\"\u003e\u003ccode\u003elabel\u003c/code\u003e\u003c/em\u003e' [, ... ] ] )\n\nCREATE TYPE \u003cem class=\"replaceable\"\u003e\u003ccode\u003ename\u003c/code\u003e\u003c/em\u003e AS RANGE (\n    SUBTYPE = \u003cem class=\"replaceable\"\u003e\u003ccode\u003esubtype\u003c/code\u003e\u003c/em\u003e\n    [ , SUBTYPE_OPCLASS = \u003cem class=\"replaceable\"\u003e\u003ccode\u003esubtype_operator_class\u003c/code\u003e\u003c/em\u003e ]\n    [ , COLLATION = \u003cem class=\"replaceable\"\u003e\u003ccode\u003ecollation\u003c/code\u003e\u003c/em\u003e ]\n    [ , CANONICAL = \u003cem class=\"replaceable\"\u003e\u003ccode\u003ecanonical_function\u003c/code\u003e\u003c/em\u003e ]\n    [ , SUBTYPE_DIFF = \u003cem class=\"replaceable\"\u003e\u003ccode\u003esubtype_diff_function\u003c/code\u003e\u003c/em\u003e ]\n    [ , MULTIRANGE_TYPE_NAME = \u003cem class=\"replaceable\"\u003e\u003ccode\u003emultirange_type_name\u003c/code\u003e\u003c/em\u003e ]\n)\n\nCREATE TYPE \u003cem class=\"replaceable\"\u003e\u003ccode\u003ename\u003c/code\u003e\u003c/em\u003e (\n    INPUT = \u003cem class=\"replaceable\"\u003e\u003ccode\u003einput_function\u003c/code\u003e\u003c/em\u003e,\n    OUTPUT = \u003cem class=\"replaceable\"\u003e\u003ccode\u003eoutput_function\u003c/code\u003e\u003c/em\u003e\n    [ , RECEIVE = \u003cem class=\"replaceable\"\u003e\u003ccode\u003ereceive_function\u003c/code\u003e\u003c/em\u003e ]\n    [ , SEND = \u003cem class=\"replaceable\"\u003e\u003ccode\u003esend_function\u003c/code\u003e\u003c/em\u003e ]\n    [ , TYPMOD_IN = \u003cem class=\"replaceable\"\u003e\u003ccode\u003etype_modifier_input_function\u003c/code\u003e\u003c/em\u003e ]\n    [ , TYPMOD_OUT = \u003cem class=\"replaceable\"\u003e\u003ccode\u003etype_modifier_output_function\u003c/code\u003e\u003c/em\u003e ]\n    [ , ANALYZE = \u003cem class=\"replaceable\"\u003e\u003ccode\u003eanalyze_function\u003c/code\u003e\u003c/em\u003e ]\n    [ , SUBSCRIPT = \u003cem class=\"replaceable\"\u003e\u003ccode\u003esubscript_function\u003c/code\u003e\u003c/em\u003e ]\n    [ , INTERNALLENGTH = { \u003cem class=\"replaceable\"\u003e\u003ccode\u003einternallength\u003c/code\u003e\u003c/em\u003e | VARIABLE } ]\n    [ , PASSEDBYVALUE ]\n    [ , ALIGNMENT = \u003cem class=\"replaceable\"\u003e\u003ccode\u003ealignment\u003c/code\u003e\u003c/em\u003e ]\n    [ , STORAGE = \u003cem class=\"replaceable\"\u003e\u003ccode\u003estorage\u003c/code\u003e\u003c/em\u003e ]\n    [ , LIKE = \u003cem class=\"replaceable\"\u003e\u003ccode\u003elike_type\u003c/code\u003e\u003c/em\u003e ]\n    [ , CATEGORY = \u003cem class=\"replaceable\"\u003e\u003ccode\u003ecategory\u003c/code\u003e\u003c/em\u003e ]\n    [ , PREFERRED = \u003cem class=\"replaceable\"\u003e\u003ccode\u003epreferred\u003c/code\u003e\u003c/em\u003e ]\n    [ , DEFAULT = \u003cem class=\"replaceable\"\u003e\u003ccode\u003edefault\u003c/code\u003e\u003c/em\u003e ]\n    [ , ELEMENT = \u003cem class=\"replaceable\"\u003e\u003ccode\u003eelement\u003c/code\u003e\u003c/em\u003e ]\n    [ , DELIMITER = \u003cem class=\"replaceable\"\u003e\u003ccode\u003edelimiter\u003c/code\u003e\u003c/em\u003e ]\n    [ , COLLATABLE = \u003cem class=\"replaceable\"\u003e\u003ccode\u003ecollatable\u003c/code\u003e\u003c/em\u003e ]\n)\n\nCREATE TYPE \u003cem class=\"replaceable\"\u003e\u003ccode\u003ename\u003c/code\u003e\u003c/em\u003e","synopsis_text":"CREATE TYPE name AS\n( [ attribute_name data_type [ COLLATE collation ] [, ... ] ] )\n\nCREATE TYPE name AS ENUM\n( [ 'label' [, ... ] ] )\n\nCREATE TYPE name AS RANGE (\nSUBTYPE = subtype\n[ , SUBTYPE_OPCLASS = subtype_operator_class ]\n[ , COLLATION = collation ]\n[ , CANONICAL = canonical_function ]\n[ , SUBTYPE_DIFF = subtype_diff_function ]\n[ , MULTIRANGE_TYPE_NAME = multirange_type_name ]\n)\n\nCREATE TYPE name (\nINPUT = input_function,\nOUTPUT = output_function\n[ , RECEIVE = receive_function ]\n[ , SEND = send_function ]\n[ , TYPMOD_IN = type_modifier_input_function ]\n[ , TYPMOD_OUT = type_modifier_output_function ]\n[ , ANALYZE = analyze_function ]\n[ , SUBSCRIPT = subscript_function ]\n[ , INTERNALLENGTH = { internallength | VARIABLE } ]\n[ , PASSEDBYVALUE ]\n[ , ALIGNMENT = alignment ]\n[ , STORAGE = storage ]\n[ , LIKE = like_type ]\n[ , CATEGORY = category ]\n[ , PREFERRED = preferred ]\n[ , DEFAULT = default ]\n[ , ELEMENT = element ]\n[ , DELIMITER = delimiter ]\n[ , COLLATABLE = collatable ]\n)\n\nCREATE TYPE name"}},"RequestedLocale":"zh-Hans","Fallback":false,"Versions":["10","11","12","13","14","15","16","17","18","19","20","6.4","6.5","7.0","7.1","7.2","7.3","7.4","8.0","8.1","8.2","8.3","8.4","9.0","9.1","9.2","9.3","9.4","9.5","9.6"],"Locales":["en","zh-Hans"],"Signatures":null,"Spellings":null,"SQLState":null,"Evidence":null}
