CREATE TYPE
CREATE TYPE
PostgreSQL에는 많은 내장 타입이 있지만, 때로는 내가 쓰는 도메인에 딱 맞는 타입이 따로 필요할 때가 있어요. CREATE TYPE이 현재 데이터베이스에서 쓸 새 데이터 타입을 등록하는 명령이에요. 타입을 정의한 사용자가 그 소유자가 돼요.
스키마 이름을 주면 타입이 지정된 스키마에 만들어지고, 생략하면 현재 스키마에 만들어져요. 타입 이름은 같은 스키마의 기존 타입·도메인 이름과 달라야 해요. (테이블도 연관 데이터 타입을 가지므로 타입 이름은 같은 스키마의 기존 테이블 이름과도 달라야 해요.)
CREATE TYPE에는 위 문법 요약에 보이는 다섯 가지 형태가 있어요. 각각 복합 타입, enum 타입, 범위 타입, 베이스 타입, 셸 타입을 만들어요. 처음 네 가지는 아래에서 차례로 다룰게요. 셸 타입(shell type)은 나중에 정의할 타입의 자리 표시자일 뿐이에요. 타입 이름 외에 매개변수 없이 CREATE TYPE을 실행하면 만들어져요. 범위 타입과 베이스 타입을 만들 때 순방향 참조(forward reference)로 셸 타입이 필요해요.
출처: PostgreSQL 문서
본문
Synopsis
CREATE TYPE name AS
( [ attribute_name data_type [ COLLATE collation ] [, ... ] ] )
CREATE TYPE name AS ENUM
( [ 'label' [, ... ] ] )
CREATE TYPE name AS RANGE (
SUBTYPE = subtype
[ , SUBTYPE_OPCLASS = subtype_operator_class ]
[ , COLLATION = collation ]
[ , CANONICAL = canonical_function ]
[ , SUBTYPE_DIFF = subtype_diff_function ]
[ , MULTIRANGE_TYPE_NAME = multirange_type_name ]
)
CREATE TYPE name (
INPUT = input_function,
OUTPUT = output_function
[ , RECEIVE = receive_function ]
[ , SEND = send_function ]
[ , TYPMOD_IN = type_modifier_input_function ]
[ , TYPMOD_OUT = type_modifier_output_function ]
[ , ANALYZE = analyze_function ]
[ , SUBSCRIPT = subscript_function ]
[ , INTERNALLENGTH = { internallength | VARIABLE } ]
[ , PASSEDBYVALUE ]
[ , ALIGNMENT = alignment ]
[ , STORAGE = storage ]
[ , LIKE = like_type ]
[ , CATEGORY = category ]
[ , PREFERRED = preferred ]
[ , DEFAULT = default ]
[ , ELEMENT = element ]
[ , DELIMITER = delimiter ]
[ , COLLATABLE = collatable ]
)
CREATE TYPE name
Description
CREATE TYPE은 현재 데이터베이스에서 쓸 새 데이터 타입을 등록해요. 타입을 정의한 사용자가 그 소유자가 돼요.
스키마 이름을 주면 타입이 지정된 스키마에 만들어지고, 생략하면 현재 스키마에 만들어져요. 타입 이름은 같은 스키마의 기존 타입·도메인 이름과 달라야 해요. (테이블도 연관 데이터 타입을 가지므로 타입 이름은 같은 스키마의 기존 테이블 이름과도 달라야 해요.)
위 문법 요약에 보이는 것처럼 CREATE TYPE에는 다섯 가지 형태가 있어요. 각각 복합 타입, enum 타입, 범위 타입, 베이스 타입, 셸 타입을 만들어요. 처음 네 가지는 아래에서 차례로 다룰게요. 셸 타입은 나중에 정의할 타입의 자리 표시자일 뿐이에요. 타입 이름 외에 매개변수 없이 CREATE TYPE을 실행하면 만들어져요. 범위 타입과 베이스 타입을 만들 때는 그 절들에서 논의하듯 순방향 참조로 셸 타입이 필요해요.
Composite Types
첫 번째 형태의 CREATE TYPE은 복합 타입을 만들어요. 복합 타입은 속성 이름과 데이터 타입 목록으로 지정돼요. 속성의 데이터 타입이 콜레이션 가능하면 속성의 콜레이션도 지정할 수 있어요. 복합 타입은 본질적으로 테이블의 행 타입과 같지만, 타입만 정의하면 될 때는 실제 테이블을 만들 필요가 없도록 CREATE TYPE을 쓰는 거예요. 독립형 복합 타입은 예를 들어 함수의 인자·반환 타입으로 유용해요.
복합 타입을 만들려면 모든 속성 타입에 대한 USAGE 권한이 있어야 해요.
Enumerated Types
두 번째 형태의 CREATE TYPE은 열거형(enum) 타입을 만들어요. 8.7절에서 설명해요. Enum 타입은 따옴표로 감싼 레이블 목록을 받는데, 각 레이블은 NAMEDATALEN 바이트(표준 PostgreSQL 빌드에서 64바이트)보다 짧아야 해요. (레이블이 0개인 열거형 타입을 만드는 것도 가능하지만, ALTER TYPE으로 레이블을 적어도 하나 추가하기 전에는 그런 타입으로 값을 담을 수 없어요.)
Range Types
세 번째 형태의 CREATE TYPE은 새 범위 타입을 만들어요. 8.17절에서 설명해요.
범위 타입의 subtype은 연관 b-트리 연산자 클래스가 있는 어떤 타입이든 될 수 있어요(범위 타입의 값 순서를 정하려고). 보통 subtype의 기본 b-트리 연산자 클래스가 순서 결정에 사용돼요. 기본이 아닌 연산자 클래스를 쓰려면 그 이름을 subtype_opclass로 지정해요. subtype이 콜레이션 가능하고 범위 순서에 기본이 아닌 콜레이션을 쓰려면 collation 옵션으로 원하는 콜레이션을 지정해요.
선택적인 canonical 함수는 정의되는 범위 타입의 인자 하나를 받고 같은 타입의 값을 반환해야 해요. 적용 가능할 때 범위 값을 정규 형식으로 변환하는 데 쓰여요. 자세한 내용은 8.17.8절을 참고하세요. canonical 함수를 만드는 건 약간 까다로워요. 범위 타입을 선언하기 전에 정의해야 하기 때문이죠. 이렇게 하려면 먼저 셸 타입을 만들어야 해요. 셸 타입은 이름과 소유자 외에 속성이 없는 자리 표시자 타입이에요. 매개변수 없이 CREATE TYPE name 명령을 내려서 만들죠. 그다음 셸 타입을 인자·결과로 사용해 함수를 선언하고, 마지막으로 같은 이름으로 범위 타입을 선언해요. 이러면 셸 타입 항목이 자동으로 유효한 범위 타입으로 대체돼요.
선택적인 subtype_diff 함수는 subtype 타입의 값 두 개를 인자로 받고, 주어진 두 값 사이의 차이를 나타내는 double precision 값을 반환해야 해요. 선택 사항이지만 제공하면 범위 타입 컬럼의 GiST 인덱스 효율이 훨씬 좋아져요. 자세한 내용은 8.17.8절을 참고하세요.
선택적인 multirange_type_name 매개변수는 해당 멀티범위 타입의 이름을 지정해요. 지정하지 않으면 이름이 다음과 같이 자동으로 선택돼요. 범위 타입 이름에 range 부분 문자열이 있으면 범위 타입 이름에서 range 부분을 multirange로 바꿔 멀티범위 타입 이름을 만들어요. 그렇지 않으면 범위 타입 이름에 _multirange 접미사를 붙여 멀티범위 타입 이름을 만들어요.
범위 타입을 만들려면 subtype에 대한 USAGE 권한이 있어야 해요.
Base Types
네 번째 형태의 CREATE TYPE은 새 베이스 타입(스칼라 타입)을 만들어요. 새 베이스 타입을 만들려면 슈퍼유저여야 해요. (잘못된 타입 정의가 서버를 혼란시키거나 심지어 크래시시킬 수 있기 때문에 이 제한이 있어요.)
매개변수는 위에 보인 순서뿐 아니라 어떤 순서로든 나타날 수 있고, 대부분 선택 사항이에요. 타입을 정의하기 전에 함수 두 개 이상을(CREATE FUNCTION으로) 등록해야 해요. 지원 함수 input_function과 output_function은 필수이고, receive_function, send_function, type_modifier_input_function, type_modifier_output_function, analyze_function, subscript_function은 선택 사항이에요. 일반적으로 이 함수들은 C나 다른 저수준 언어로 코딩해야 해요.
input_function은 타입의 외부 텍스트 표현을 그 타입에 대해 정의된 연산자·함수가 쓰는 내부 표현으로 변환해요. output_function은 역변환을 수행해요. 입력 함수는 cstring 타입의 인자 하나를 받는 것으로 선언하거나, cstring, oid, integer 타입의 인자 세 개를 받는 것으로 선언할 수 있어요. 첫 번째 인자는 C 문자열인 입력 텍스트, 두 번째 인자는 타입 자신의 OID(배열 타입은 예외로 요소 타입의 OID를 받음), 세 번째는 알고 있다면 대상 컬럼의 typmod(-1을 모르는 경우 전달)예요. 입력 함수는 데이터 타입 자신의 값을 반환해야 해요. 보통 입력 함수는 STRICT로 선언해야 해요. 그렇지 않으면 NULL 입력 값을 읽을 때 NULL 첫 매개변수로 호출돼요. 함수는 이 경우 오류를 일으키지 않는 한 여전히 NULL을 반환해야 해요. (이 경우는 주로 NULL 입력을 거부해야 할 수도 있는 도메인 입력 함수를 지원하기 위한 거예요.) 출력 함수는 새 데이터 타입의 인자 하나를 받는 것으로 선언해야 해요. 출력 함수는 cstring 타입을 반환해야 해요. 출력 함수는 NULL 값에 대해 호출되지 않아요.
선택적인 receive_function은 타입의 외부 이진 표현을 내부 표현으로 변환해요. 이 함수를 제공하지 않으면 타입은 이진 입력에 참여할 수 없어요. 이진 표현은 합리적으로 이식 가능하면서 내부 형태로 변환하기 싼 것으로 골라야 해요. (예를 들어 표준 정수 데이터 타입은 외부 이진 표현으로 네트워크 바이트 순서를 쓰는 반면, 내부 표현은 머신의 네이티브 바이트 순서예요.) receive 함수는 값이 유효한지 적절히 검사해야 해요. receive 함수는 internal 타입의 인자 하나를 받는 것으로 선언하거나, internal, oid, integer 타입의 인자 세 개를 받는 것으로 선언할 수 있어요. 첫 번째 인자는 받은 바이트 문자열을 담은 StringInfo 버퍼에 대한 포인터이고, 선택적 인자는 텍스트 입력 함수와 동일해요. receive 함수는 데이터 타입 자신의 값을 반환해야 해요. 보통 receive 함수는 STRICT로 선언해야 해요. 그렇지 않으면 NULL 입력 값을 읽을 때 NULL 첫 매개변수로 호출돼요. 함수는 이 경우 오류를 일으키지 않는 한 여전히 NULL을 반환해야 해요. (이 경우는 주로 NULL 입력을 거부해야 할 수도 있는 도메인 receive 함수를 지원하기 위한 거예요.) 비슷하게 선택적인 send_function은 내부 표현에서 외부 이진 표현으로 변환해요. 이 함수를 제공하지 않으면 타입은 이진 출력에 참여할 수 없어요. send 함수는 새 데이터 타입의 인자 하나를 받는 것으로 선언해야 해요. send 함수는 bytea 타입을 반환해야 해요. send 함수는 NULL 값에 대해 호출되지 않아요.
이쯤에서 입력·출력 함수가 새 타입이 만들어지기 전에 생성되어야 하는데, 어떻게 새 타입의 결과나 인자를 가질 수 있는지 궁금할 거예요. 답은 타입을 먼저 셸 타입으로 정의해야 한다는 거예요. 셸 타입은 이름과 소유자 외에 속성이 없는 자리 표시자 타입이에요. 매개변수 없이 CREATE TYPE name 명령을 내려 만들죠. 그다음 C I/O 함수를 셸 타입을 참조해 정의할 수 있어요. 마지막으로 완전한 정의를 가진 CREATE TYPE이 셸 항목을 완전하고 유효한 타입 정의로 대체하면, 그 후엔 새 타입을 정상적으로 쓸 수 있어요.
선택적인 type_modifier_input_function과 type_modifier_output_function은 타입이 수식어(modifier), 즉 char(5)나 numeric(30,2) 같은 타입 선언에 붙는 선택적 제약을 지원할 때 필요해요. PostgreSQL은 사용자 정의 타입이 수식어로 단순 상수나 식별자를 하나 이상 받는 것을 허용해요. 다만 이 정보는 시스템 카탈로그에 저장하기 위해 단일 비음수 정수 값으로 압축할 수 있어야 해요. type_modifier_input_function은 선언된 수식어(들)를 cstring 배열 형태로 받아요. 값의 유효성을 검사하고(틀리면 오류를 던지고), 맞으면 컬럼 "typmod"로 저장될 단일 비음수 integer 값을 반환해야 해요. 타입에 type_modifier_input_function이 없으면 타입 수식어는 거부돼요. type_modifier_output_function은 내부 정수 typmod 값을 사용자 표시용 올바른 형태로 다시 변환해요. 타입 이름에 덧붙일 정확한 문자열인 cstring 값을 반환해야 해요. 예를 들어 numeric의 함수는 (30,2)를 반환할 수 있어요. type_modifier_output_function을 생략해도 되는데, 그 경우 기본 표시 형식은 저장된 typmod 정수 값을 괄호로 감싼 것일 뿐이에요.
선택적인 analyze_function은 데이터 타입의 컬럼에 대한 타입별 통계 수집을 수행해요. 기본적으로 ANALYZE는 타입에 기본 b-트리 연산자 클래스가 있으면 타입의 "equals"·"less-than" 연산자를 사용해 통계를 모으려고 시도해요. 비-스칼라 타입에는 이 동작이 부적합할 가능성이 높으므로, 사용자 지정 분석 함수를 지정해 덮어쓸 수 있어요. 분석 함수는 internal 타입의 인자 하나를 받고 boolean 결과를 반환하도록 선언해야 해요. 분석 함수의 상세 API는 src/include/commands/vacuum.h에 있어요.
선택적인 subscript_function은 데이터 타입이 SQL 명령에서 첨자(subscript)될 수 있게 해 줘요. 이 함수를 지정해도 타입이 "진짜" 배열 타입으로 간주되지는 않아요. 예를 들어 ARRAY[] 구성의 결과 타입 후보가 되지 않아요. 하지만 그 타입의 값을 첨자로 여기는 것이 데이터를 추출하는 자연스러운 표기라면, 그 의미를 정의하는 subscript_function을 쓸 수 있어요. subscript 함수는 internal 타입의 인자 하나를 받고, 첨자를 구현하는 메서드(함수)들의 구조체에 대한 포인터인 internal 결과를 반환하도록 선언해야 해요. subscript 함수의 상세 API는 src/include/nodes/subscripting.h에 있어요. 또한 src/backend/utils/adt/arraysubs.c의 배열 구현이나, contrib/hstore/hstore_subs.c의 더 단순한 코드를 읽어보는 것도 유용할 수 있어요. 추가 정보는 아래 Array Types에 있어요.
새 타입의 내부 표현 세부 사항은 I/O 함수와 그 타입으로 작업하도록 만든 다른 함수만 알지만, 내부 표현의 몇 가지 속성은 PostgreSQL에 선언해야 해요. 그중 가장 중요한 것이 internallength이에요. 베이스 데이터 타입은 고정 길이일 수 있는데, 그 경우 internallength는 양의 정수예요. 또는 internallength를 VARIABLE로 설정해 가변 길이를 나타낼 수 있어요. (내부적으로는 typlen을 -1로 설정해 나타내요.) 모든 가변 길이 타입의 내부 표현은 이 타입의 값의 총 길이를 주는 4바이트 정수로 시작해야 해요. (길이 필드는 66.2절에서 설명하듯 종종 인코딩된다는 점을 유의하세요. 직접 접근하는 건 현명하지 않아요.)
선택적 플래그 PASSEDBYVALUE는 이 데이터 타입의 값이 참조가 아니라 값으로 전달됨을 나타내요. 값으로 전달되는 타입은 고정 길이여야 하고, 그 내부 표현은 Datum 타입 크기(어떤 머신은 4바이트, 다른 머신은 8바이트)보다 클 수 없어요.
alignment 매개변수는 데이터 타입에 요구되는 저장 정렬을 지정해요. 허용되는 값은 1, 2, 4, 8바이트 경계 정렬에 해당해요. 가변 길이 타입은 첫 구성 요소로 int4를 반드시 포함하므로 정렬이 적어도 4여야 한다는 점을 유의하세요.
storage 매개변수는 가변 길이 데이터 타입의 저장 전략 선택을 허용해요. (고정 길이 타입에는 plain만 허용돼요.) plain은 그 타입의 데이터가 항상 인라인으로 저장되고 압축되지 않음을 지정해요. extended는 시스템이 먼저 긴 데이터 값을 압축하려 시도하고, 여전히 너무 길면 값을 기본 테이블 행 밖으로 옮길 것을 지정해요. external은 값을 기본 테이블 밖으로 옮길 수 있게 하지만 시스템은 압축을 시도하지 않아요. main은 압축은 허용하지만 값을 기본 테이블 밖으로 옮기는 것은 권장하지 않아요. (이 저장 전략을 가진 데이터 항목은 행을 맞추는 다른 방법이 없으면 여전히 기본 테이블 밖으로 옮겨질 수 있지만, extended·external 항목보다 기본 테이블에 우선적으로 유지돼요.)
plain 외의 모든 storage 값은 데이터 타입의 함수들이 66.2절과 36.13.1절에서 설명하는 대로 토스트된(toasted) 값을 처리할 수 있음을 의미해요. 주어진 다른 특정 값은 토스트 가능한 데이터 타입의 컬럼에 대한 기본 TOAST 저장 전략을 결정할 뿐이에요. 사용자는 ALTER TABLE SET STORAGE로 개별 컬럼에 다른 전략을 선택할 수 있어요.
like_type 매개변수는 데이터 타입의 기본 표현 속성을 지정하는 대체 방법을 제공해요. 기존 타입에서 복사하죠. internallength, passedbyvalue, alignment, storage 값이 지명된 타입에서 복사돼요. (LIKE 절과 함께 이 값들 중 일부를 지정해 덮어쓰는 것도 가능하지만, 보통 바람직하지 않아요.) 이 방식으로 표현을 지정하는 것은 새 타입의 저수준 구현이 어떤 방식으로든 기존 타입에 "piggyback"할 때 특히 유용해요.
category와 preferred 매개변수는 모호한 상황에서 어떤 암묵적 캐스트를 적용할지 제어하는 데 쓰일 수 있어요. 각 데이터 타입은 단일 ASCII 문자로 이름 붙은 카테고리에 속하고, 각 타입은 자신의 카테고리 안에서 "preferred"이거나 아닙니다. 파서는 오버로드된 함수·연산자를 해석할 때 이 규칙이 도움이 되면 preferred 타입으로의 캐스팅을 선호해요(하지만 같은 카테고리의 다른 타입에서만). 더 자세한 내용은 10장을 참고하세요. 다른 타입과의 암묵적 캐스트가 없는 타입에는 이 설정들을 기본값으로 두는 것으로 충분해요. 다만 암묵적 캐스트가 있는 관련 타입 그룹에는 모두 한 카테고리에 속하게 표시하고, 카테고리 안에서 "가장 일반적인" 타입 한두 개를 preferred로 선택하는 게 도움이 되는 경우가 많아요. category 매개변수는 숫자나 문자열 타입 같은 기존 내장 카테고리에 사용자 정의 타입을 추가할 때 특히 유용해요. 하지만 완전히 사용자 정의된 새 타입 카테고리를 만드는 것도 가능해요. 그런 카테고리 이름에는 대문자 이외의 ASCII 문자를 선택해요.
사용자가 데이터 타입의 컬럼이 null 외의 다른 값으로 기본 설정되길 원할 경우, 기본값을 지정할 수 있어요. DEFAULT 키워드로 기본값을 지정하세요. (이런 기본값은 특정 컬럼에 붙은 명시적 DEFAULT 절로 덮어쓸 수 있어요.)
타입이 고정 길이 배열 타입임을 나타내려면 ELEMENT 키워드로 배열 요소의 타입을 지정해요. 예를 들어 4바이트 정수(int4)의 배열을 정의하려면 ELEMENT = int4를 지정해요. 자세한 내용은 아래 Array Types를 참고하세요.
이 타입의 배열의 외부 표현에서 값 사이에 사용할 구분자를 나타내려면 delimiter를 특정 문자로 설정할 수 있어요. 기본 구분자는 쉼표(,)예요. 구분자는 배열 타입 자체가 아니라 배열 요소 타입과 연관된다는 점을 유의하세요.
선택적 Boolean 매개변수 collatable이 true면, 그 타입의 컬럼 정의와 표현식이 COLLATE 절을 통해 콜레이션 정보를 전달할 수 있어요. 콜레이션 정보를 실제로 활용하는 것은 그 타입에 대해 동작하는 함수의 구현에 달려 있어요. 타입을 콜레이션 가능으로 표시한다고 자동으로 일어나지 않아요.
Array Types
사용자 정의 타입이 만들어질 때마다 PostgreSQL은 연관 배열 타입을 자동으로 만들어요. 그 이름은 요소 타입 이름에 밑줄을 접두사로 붙이고, 필요하면 NAMEDATALEN 바이트보다 짧게 유지하도록 잘라요. (그렇게 생성된 이름이 기존 타입 이름과 충돌하면 충돌하지 않는 이름을 찾을 때까지 과정을 반복해요.) 이 암묵적으로 만들어진 배열 타입은 가변 길이이고 내장 입력·출력 함수 array_in과 array_out을 사용해요. 게다가 이 타입이 사용자 정의 타입 위의 ARRAY[] 같은 구문에 시스템이 사용하는 타입이에요. 배열 타입은 요소 타입의 소유자·스키마 변경을 추적하고, 요소 타입이 삭제되면 함께 삭제돼요.
시스템이 올바른 배열 타입을 자동으로 만든다면 왜 ELEMENT 옵션이 있는지 합리적으로 궁금할 수 있어요. ELEMENT를 쓰는 게 유용한 주요 경우는, 내부적으로 여러 개의 동일한 것의 배열인데다 고정 길이인 타입을 만들 때, 그리고 그 타입 전체에 대해 계획한 작업에 더해 이 항목들을 첨자로 직접 접근할 수 있게 하고 싶을 때예요. 예를 들어 point 타입은 두 개의 부동소수점 수로 표현되는데, point[0]과 point[1]로 접근할 수 있어요. 이 기능은 내부 형태가 정확히 동일한 고정 길이 필드들의 연속인 고정 길이 타입에서만 작동한다는 점을 유의하세요. 역사적 이유(즉 명백히 잘못됐지만 바꾸기에는 너무 늦었음)로 고정 길이 배열 타입의 첨자는 가변 길이 배열과 달리 1이 아니라 0에서 시작해요.
SUBSCRIPT 옵션을 지정하면 데이터 타입이 첨자될 수 있게 해 줘요. 시스템이 그 타입을 배열 타입으로 간주하지 않더라도 말이죠. 고정 길이 배열에 대해 방금 설명한 동작은 실제로 raw_array_subscript_handler라는 SUBSCRIPT 핸들러 함수로 구현돼요. 고정 길이 타입에 ELEMENT를 지정하면서 SUBSCRIPT를 쓰지 않으면 이 함수가 자동으로 사용돼요.
사용자 지정 SUBSCRIPT 함수를 지정할 때는, SUBSCRIPT 핸들러 함수가 무엇을 반환할지 알아내기 위해 typelem을 참조할 필요가 없는 한 ELEMENT를 지정할 필요가 없어요. ELEMENT를 지정하면 시스템이 새 타입이 요소 타입을 포함하거나 어떤 식으로든 물리적으로 의존한다고 가정한다는 점을 유의하세요. 그래서 예를 들어 의존 타입의 컬럼이 있으면 요소 타입의 속성 변경이 허용되지 않아요.
Parameters
name
만들 타입의 이름(스키마 한정 가능)이에요.
attribute_name
복합 타입의 속성(컬럼) 이름이에요.
data_type
복합 타입의 컬럼이 될 기존 데이터 타입의 이름이에요.
collation
복합 타입의 컬럼이나 범위 타입과 연관시킬 기존 콜레이션의 이름이에요.
label
enum 타입의 한 값과 연관된 텍스트 레이블을 나타내는 문자열 리터럴이에요.
subtype
범위 타입이 범위를 나타낼 요소 타입의 이름이에요.
subtype_operator_class
subtype에 대한 b-트리 연산자 클래스의 이름이에요.
canonical_function
범위 타입의 정규화 함수 이름이에요.
subtype_diff_function
subtype에 대한 차이 함수의 이름이에요.
multirange_type_name
해당 멀티범위 타입의 이름이에요.
input_function
데이터를 타입의 외부 텍스트 형태에서 내부 형태로 변환하는 함수의 이름이에요.
output_function
데이터를 타입의 내부 형태에서 외부 텍스트 형태로 변환하는 함수의 이름이에요.
receive_function
데이터를 타입의 외부 이진 형태에서 내부 형태로 변환하는 함수의 이름이에요.
send_function
데이터를 타입의 내부 형태에서 외부 이진 형태로 변환하는 함수의 이름이에요.
type_modifier_input_function
타입의 수식어 배열을 내부 형태로 변환하는 함수의 이름이에요.
type_modifier_output_function
타입의 수식어의 내부 형태를 외부 텍스트 형태로 변환하는 함수의 이름이에요.
analyze_function
데이터 타입에 대한 통계 분석을 수행하는 함수의 이름이에요.
subscript_function
데이터 타입 값의 첨자가 무엇을 하는지 정의하는 함수의 이름이에요.
internallength
새 타입의 내부 표현 길이를 바이트 단위로 지정하는 숫자 상수예요. 기본 가정은 가변 길이라는 거예요.
alignment
데이터 타입의 저장 정렬 요구 사항이에요. 지정하면 char, int2, int4, double 중 하나여야 하고, 기본값은 int4예요.
storage
데이터 타입의 저장 전략이에요. 지정하면 plain, external, extended, main 중 하나여야 하고, 기본값은 plain이에요.
like_type
새 타입이 같은 표현을 가질 기존 데이터 타입의 이름이에요. internallength, passedbyvalue, alignment, storage 값은 이 CREATE TYPE 명령의 다른 곳에서 명시적으로 덮어쓰지 않는 한 그 타입에서 복사돼요.
category
이 타입의 카테고리 코드(단일 ASCII 문자)예요. 기본값은 "사용자 정의 타입"을 뜻하는 'U'예요. 다른 표준 카테고리 코드는 52.65 표에서 찾을 수 있어요. 사용자 정의 카테고리를 만들기 위해 다른 ASCII 문자를 선택할 수도 있어요.
preferred
이 타입이 자신의 타입 카테고리 안에서 preferred 타입이면 true, 아니면 false예요. 기본값은 false예요. 기존 타입 카테고리 안에 새 preferred 타입을 만드는 것은 놀라운 동작 변화를 일으킬 수 있으니 매우 조심하세요.
default
데이터 타입의 기본값이에요. 생략하면 기본값은 null이에요.
element
만들어지는 타입이 배열이라는 뜻이고, 배열 요소의 타입을 지정해요.
delimiter
이 타입으로 만들어진 배열에서 값 사이에 사용할 구분 문자예요.
collatable
이 타입의 연산이 콜레이션 정보를 사용할 수 있으면 true예요. 기본값은 false예요.
Notes
타입이 한 번 만들어지면 사용에 제한이 없으므로, 베이스 타입이나 범위 타입을 만드는 것은 타입 정의에 언급된 함수들에 대한 public 실행 권한을 부여하는 것과 같아요. 이는 보통 타입 정의에 유용한 종류의 함수들에게는 문제가 되지 않아요. 하지만 타입을 외부 형태로(또는 그 반대로) 변환할 때 "비밀" 정보를 사용해야 하는 방식으로 타입을 설계하는 것은 신중히 생각해 볼 가치가 있어요.
PostgreSQL 8.3 이전에는 생성된 배열 타입의 이름이 항상 요소 타입 이름에 밑줄 문자(_) 하나를 접두사로 붙인 것이 정확히였어요. (그래서 타입 이름 길이는 다른 이름보다 한 문자 짧게 제한됐죠.) 지금도 보통 그렇지만, 배열 타입 이름은 최대 길이 이름이거나 밑줄로 시작하는 사용자 타입 이름과의 충돌 시에는 달라질 수 있어요. 이 규약에 의존하는 코드를 쓰는 것은 더 이상 권장하지 않아요. 대신 pg_type.typarray를 사용해 주어진 타입과 연관된 배열 타입을 찾으세요.
밑줄로 시작하는 타입·테이블 이름을 피하는 게 좋을 수 있어요. 서버가 생성된 배열 타입 이름을 바꿔서 사용자 제공 이름과의 충돌을 피하긴 하지만, 특히 밑줄로 시작하는 타입 이름이 항상 배열을 나타낸다고 가정할 수 있는 오래된 클라이언트 소프트웨어에서 혼란의 위험이 여전히 있어요.
PostgreSQL 8.2 이전에는 셸 타입 생성 문법 CREATE TYPE name이 존재하지 않았어요. 새 베이스 타입을 만드는 방식은 먼저 입력 함수를 만드는 것이었어요. 이 방식에서 PostgreSQL은 먼저 입력 함수의 반환 타입으로 새 데이터 타입의 이름을 보게 돼요. 이 상황에서 셸 타입이 암묵적으로 만들어지고, 그다음 나머지 I/O 함수의 정의에서 참조될 수 있어요. 이 방식은 여전히 작동하지만 더 이상 권장하지 않고, 향후 릴리스에서 허용되지 않을 수도 있어요. 또한 함수 정의의 단순한 오타로 인해 실수로 카탈로그를 셸 타입으로 어지럽히는 것을 피하기 위해, 셸 타입은 입력 함수가 C로 작성되었을 때만 이 방식으로 만들어져요.
PostgreSQL 16 이상에서는 베이스 타입의 입력 함수가 이전 버전처럼 ereport() 예외를 던지는 대신, 새 errsave()/ereturn() 메커니즘을 사용해 "부드러운(soft)" 오류를 반환하는 것이 바람직해요. 자세한 내용은 src/backend/utils/fmgr/README를 참고하세요.
Examples
이 예시는 복합 타입을 만들고 함수 정의에서 사용해요.
CREATE TYPE compfoo AS (f1 int, f2 text);
CREATE FUNCTION getfoo() RETURNS SETOF compfoo AS $$
SELECT fooid, fooname FROM foo
$$ LANGUAGE SQL;
이 예시는 열거형 타입을 만들고 테이블 정의에서 사용해요.
CREATE TYPE bug_status AS ENUM ('new', 'open', 'closed');
CREATE TABLE bug (
id serial,
description text,
status bug_status
);
이 예시는 범위 타입을 만들어요.
CREATE TYPE float8_range AS RANGE (subtype = float8, subtype_diff = float8mi);
이 예시는 베이스 데이터 타입 box를 만들고 그 타입을 테이블 정의에서 사용해요.
CREATE TYPE box;
CREATE FUNCTION my_box_in_function(cstring) RETURNS box AS ... ;
CREATE FUNCTION my_box_out_function(box) RETURNS cstring AS ... ;
CREATE TYPE box (
INTERNALLENGTH = 16,
INPUT = my_box_in_function,
OUTPUT = my_box_out_function
);
CREATE TABLE myboxes (
id integer,
description box
);
box의 내부 구조가 네 개의 float4 요소의 배열이라면, 대신 이렇게 쓸 수도 있어요.
CREATE TYPE box (
INTERNALLENGTH = 16,
INPUT = my_box_in_function,
OUTPUT = my_box_out_function,
ELEMENT = float4
);
이렇게 하면 box 값을 첨자로 구성 숫자에 접근할 수 있어요. 그 외에는 타입이 이전과 같게 동작해요.
이 예시는 대형 객체 타입을 만들고 테이블 정의에서 사용해요.
CREATE TYPE bigobj (
INPUT = lo_filein, OUTPUT = lo_fileout,
INTERNALLENGTH = VARIABLE
);
CREATE TABLE big_objs (
id integer,
obj bigobj
);
적절한 입력·출력 함수를 포함한 더 많은 예시는 36.13절에 있어요.
Compatibility
복합 타입을 만드는 CREATE TYPE 명령의 첫 번째 형태는 SQL 표준을 따르는 편이에요. 다른 형태들은 PostgreSQL 확장 기능이에요. SQL 표준의 CREATE TYPE 문은 PostgreSQL이 구현하지 않은 다른 형태도 정의해요.
속성이 0개인 복합 타입을 만들 수 있는 능력은 PostgreSQL만의 표준 편차예요(CREATE TABLE의 같은 경우와 유사해요).
더 알아보기 (Learn more)
CREATE TYPE AS를 쓰는 복합 타입 — 복합 타입의 사용법을 다루는 8.16절이에요.ALTER TYPE— 타입의 정의·속성을 바꿀 때 써요.DROP TYPE— 타입을 삭제할 때 써요.CREATE FUNCTION— 타입의 I/O·지원 함수를 만들 때 써요.- CREATE TABLE — 만든 타입을 컬럼 타입으로 쓰는 테이블을 만들 때 써요.