CREATE CAST — 새 캐스트 정의하기
CREATE CAST — 새 캐스트 정의하기
CREATE CAST 명령은 두 데이터 타입 사이의 변환을 수행하는 방법을 지정하는 새 캐스트(cast)를 정의하는 명령이에요. 명시적 혹은 암시적(implicit) 변환을 활성화해 타입 간 변환을 다루는 데 사용해요.
출처: PostgreSQL 문서
본문
Synopsis
CREATE CAST (source_type AS target_type)
WITH FUNCTION function_name [ (argument_type [, ...]) ]
[ AS ASSIGNMENT | AS IMPLICIT ]
CREATE CAST (source_type AS target_type)
WITHOUT FUNCTION
[ AS ASSIGNMENT | AS IMPLICIT ]
CREATE CAST (source_type AS target_type)
WITH INOUT
[ AS ASSIGNMENT | AS IMPLICIT ]
Description
CREATE CAST는 새 캐스트를 정의해요. 캐스트는 두 데이터 타입 사이의 변환을 수행하는 방법을 지정해요. 예를 들어,
SELECT CAST(42 AS float8);
이 구문은 정수 상수 42를 이전에 지정된 함수(이 경우 float8(int4))를 호출해 타입 float8로 변환해요. (적절한 캐스트가 정의되지 않았으면 변환은 실패해요.)
두 타입은 이진 강제 변환 가능(binary coercible)할 수 있는데, 이는 어떤 함수도 호출하지 않고 변환이 "공짜로" 수행될 수 있음을 뜻해요. 그러려면 해당 값들이 동일한 내부 표현을 사용해야 해요. 예를 들어 text와 varchar 타입은 양방향으로 이진 강제 변환 가능해요. 이진 강제 변환 가능성은 반드시 대칭 관계는 아니에요. 예를 들어 xml에서 text로의 캐스트는 현재 구현에서 공짜로 수행될 수 있지만, 반대 방향은 최소한 구문 검사를 수행하는 함수가 필요해요. (양방향으로 이진 강제 변환 가능한 두 타입은 이진 호환(binary compatible)이라고도 해요.)
WITH INOUT 문법을 사용해 캐스트를 I/O 변환 캐스트로 정의할 수 있어요. I/O 변환 캐스트는 소스 데이터 타입의 출력 함수를 호출하고, 그 결과 문자열을 대상 데이터 타입의 입력 함수에 전달해 수행돼요. 많은 일반적인 경우에 이 기능은 변환을 위한 별도의 캐스트 함수를 작성할 필요를 없애줘요. I/O 변환 캐스트는 일반 함수 기반 캐스트와 동일하게 동작해요. 구현만 다를 뿐이에요.
기본적으로 캐스트는 명시적 캐스트 요청, 즉 명시적 CAST(*x* AS *typename*) 또는 x::typename 구조로만 호출될 수 있어요.
캐스트가 AS ASSIGNMENT로 표시되면 대상 데이터 타입의 컬럼에 값을 할당할 때 암시적으로 호출될 수 있어요. 예를 들어 foo.f1이 text 타입의 컬럼이라고 가정하면:
INSERT INTO foo (f1) VALUES (42);
이 구문은 integer에서 text로의 캐스트가 AS ASSIGNMENT로 표시되면 허용되고, 그렇지 않으면 허용되지 않아요. (우리는 일반적으로 이런 종류의 캐스트를 할당 캐스트(assignment cast)라고 해요.)
캐스트가 AS IMPLICIT로 표시되면 할당이든 표현식 내부이든 어떤 문맥에서든 암시적으로 호출될 수 있어요. (우리는 일반적으로 이런 종류의 캐스트를 암시적 캐스트(implicit cast)라고 해요.) 예를 들어 이 쿼리를 생각해 보세요:
SELECT 2 + 4.0;
파서는 처음에 상수를 각각 integer와 numeric 타입으로 표시해요. 시스템 카탈로그에는 integer + numeric 연산자는 없지만 numeric + numeric 연산자는 있어요. 따라서 integer에서 numeric으로의 캐스트가 있고 AS IMPLICIT로 표시되면(실제로 그렇습니다) 이 쿼리는 성공해요. 파서는 암시적 캐스트를 적용하고 마치 이렇게 작성된 것처럼 쿼리를 해석해요:
SELECT CAST ( 2 AS numeric ) + 4.0;
이제 카탈로그는 numeric에서 integer로의 캐스트도 제공해요. 그 캐스트가 AS IMPLICIT로 표시되면(사실 그렇지 않습니다) 파서는 위 해석과, numeric 상수를 integer로 캐스팅하고 integer + integer 연산자를 적용하는 대안 사이에서 선택해야 하는 상황에 직면하게 돼요. 어떤 선택을 선호할지 아무 지식도 없으면 파서는 포기하고 쿼리를 모호하다고 선언할 거예요. 두 캐스트 중 하나만 암시적이라는 사실이 혼합된 numeric-과-integer 표현식을 numeric으로 해석하도록 파서를 가르치는 방식이에요. 그에 대한 내장 지식은 없어요.
캐스트를 암시적으로 표시하는 데는 보수적일 필요가 있어요. 암시적 캐스팅 경로가 과도하게 많으면 PostgreSQL이 명령을 놀라운 방식으로 해석하거나, 가능한 해석이 여러 개라 명령을 전혀 해석하지 못하게 만들 수 있어요. 좋은 경험 법칙은 같은 일반 타입 범주 안의 타입들 사이에서 정보를 보존하는 변환에만 캐스트를 암시적으로 호출 가능하게 만드는 거예요. 예를 들어 int2에서 int4로의 캐스트는 합리적으로 암시적일 수 있지만, float8에서 int4로의 캐스트는 아마 할당 전용이어야 해요. text에서 int4로 같은 교차 타입 범주 캐스트는 명시적 전용으로 만드는 것이 가장 좋아요.
참고 (Note)
때로는 사용성 또는 표준 준수 이유로 한 타입 집합 안에 여러 암시적 캐스트를 제공해야 해서, 위처럼 피할 수 없는 모호성이 생길 수 있어요. 파서는 타입 범주와 선호 타입에 기반한 폴백 휴리스틱을 가지고 있는데, 이런 경우에 원하는 동작을 제공하는 데 도움이 될 수 있어요. 자세한 내용은 CREATE TYPE을 참고해요.
캐스트를 만들려면 소스 또는 대상 데이터 타입을 소유하고 다른 타입에 대한 USAGE 권한이 있어야 해요. 이진 강제 변환 캐스트를 만들려면 슈퍼유저여야 해요. (잘못된 이진 강제 변환 캐스트 변환은 서버를 쉽게 충돌시킬 수 있기 때문이에요.)
Parameters
source_type
캐스트의 소스 데이터 타입 이름이에요.
target_type
캐스트의 대상 데이터 타입 이름이에요.
function_name[(argument_type [, ...])]
캐스트를 수행하는 데 사용되는 함수예요. 함수 이름은 스키마 한정일 수 있어요. 그렇지 않으면 스키마 검색 경로에서 조회돼요. 함수의 결과 데이터 타입은 캐스트의 대상 타입과 일치해야 해요. 그 인자는 아래에서 논의돼요. 인자 목록이 지정되지 않으면 함수 이름은 그 스키마에서 고유해야 해요.
WITHOUT FUNCTION
소스 타입이 대상 타입으로 이진 강제 변환 가능해서, 캐스트를 수행할 함수가 필요하지 않음을 나타내요.
WITH INOUT
캐스트가 I/O 변환 캐스트임을 나타내요. 소스 데이터 타입의 출력 함수를 호출하고, 그 결과 문자열을 대상 데이터 타입의 입력 함수에 전달해 수행돼요.
AS ASSIGNMENT
캐스트가 할당 문맥에서 암시적으로 호출될 수 있음을 나타내요.
AS IMPLICIT
캐스트가 어떤 문맥에서든 암시적으로 호출될 수 있음을 나타내요.
캐스트 구현 함수는 1개에서 3개의 인자를 가질 수 있어요. 첫 번째 인자 타입은 캐스트의 소스 타입과 동일하거나 그로부터 이진 강제 변환 가능해야 해요. 두 번째 인자가 있으면 integer 타입이어야 하며, 대상 타입과 연결된 타입 수정자(type modifier)를 받거나, 없으면 -1을 받아요. 세 번째 인자가 있으면 boolean 타입이어야 하며, 캐스트가 명시적 캐스트면 true, 그렇지 않으면 false를 받아요. (이상하게도 SQL 표준은 어떤 경우 명시적 캐스트와 암시적 캐스트에 대해 다른 동작을 요구해요. 이 인자는 그런 캐스트를 구현해야 하는 함수를 위해 제공돼요. 데이터 타입을 직접 설계할 때 이것이 중요해지도록 만들지 않는 것이 좋아요.)
캐스트 함수의 반환 타입은 캐스트의 대상 타입과 동일하거나 그로 이진 강제 변환 가능해야 해요.
보통 캐스트는 서로 다른 소스와 대상 데이터 타입을 가져야 해요. 하지만 캐스트 구현 함수가 인자를 두 개 이상 가지면 동일한 소스와 대상 타입으로 캐스트를 선언하는 것이 허용돼요. 이는 시스템 카탈로그에서 타입별 길이 강제 변환 함수를 나타내는 데 사용돼요. 명명된 함수는 타입의 값을 두 번째 인자가 주는 타입 수정자 값으로 강제 변환하는 데 사용돼요.
캐스트가 서로 다른 소스와 대상 타입을 가지고 둘 이상의 인자를 취하는 함수를 가질 때, 한 타입에서 다른 타입으로 변환하고 길이 강제 변환을 한 단계로 적용하는 것을 지원해요. 그런 항목이 없을 때, 타입 수정자를 사용하는 타입으로의 강제 변환은 두 단계의 캐스트 단계를 포함해요. 하나는 데이터 타입 사이를 변환하고 다른 하나는 수정자를 적용하는 거예요.
도메인 타입으로 또는 도메인 타입에서의 캐스트는 현재 효과가 없어요. 도메인으로 또는 도메인에서 캐스팅할 때는 그 기반 타입과 연결된 캐스트를 사용해요.
Notes
사용자 정의 캐스트를 제거하려면 DROP CAST를 사용해요.
양방향으로 타입을 변환할 수 있게 하려면 양방향 캐스트를 모두 명시적으로 선언해야 한다는 것을 기억하세요.
사용자 정의 타입과 표준 문자열 타입(문자열 범주에 정의된 사용자 정의 타입뿐 아니라 text, varchar, char(*n*)) 사이에 캐스트를 만드는 것은 보통 필요하지 않아요. PostgreSQL이 자동 I/O 변환 캐스트를 제공하기 때문이에요. 문자열 타입으로의 자동 캐스트는 할당 캐스트로 취급되고, 문자열 타입에서의 자동 캐스트는 명시적 전용이에요. 자동 캐스트를 대체하기 위해 자신만의 캐스트를 선언해 이 동작을 재정의할 수 있지만, 보통 그렇게 하는 유일한 이유는 표준의 할당 전용 또는 명시적 전용 설정보다 변환이 더 쉽게 호출되기를 원할 때예요. 또 다른 가능한 이유는 타입의 I/O 함수와 다르게 동작하는 변환을 원할 때예요. 하지만 그건 충분히 놀라운 일이라 그것이 좋은 생각인지 두 번 생각해 봐야 해요. (내장 타입 중 소수는 실제로 변환에 대해 다른 동작을 가지는데, 대부분 SQL 표준의 요구 때문이에요.)
필수는 아니지만, 캐스트 구현 함수를 대상 데이터 타입을 따서 이름 짓는 이 오래된 관례를 계속 따르는 것이 좋아요. 많은 사용자들이 함수 스타일 표기법, 즉 typename(x)로 데이터 타입을 캐스팅할 수 있기를 기대해요. 이 표기법은 사실 캐스트 구현 함수의 호출 그 이상도 이하도 아니며, 특별히 캐스트로 취급되지 않아요. 변환 함수 이름이 이 관례를 지원하도록 지어지지 않았다면 사용자들은 놀랄 거예요. PostgreSQL은 같은 함수 이름을 다른 인자 타입으로 오버로딩하는 것을 허용하므로, 서로 다른 타입에서 대상 타입의 이름을 모두 사용하는 여러 변환 함수를 갖는 데 어려움이 없어요.
참고 (Note)
실제로 위 문단은 지나친 단순화예요. 함수 호출 구조가 실제 함수에 매치되지 않고도 캐스트 요청으로 취급되는 두 가지 경우가 있어요. 함수 호출
name(x)가 기존 함수와 정확히 일치하지 않지만 *name*이 데이터 타입의 이름이고pg_cast가 *x*의 타입에서 이 타입으로의 이진 강제 변환 캐스트를 제공하면, 그 호출은 이진 강제 변환 캐스트로 해석돼요. 이 예외는 함수가 부족하더라도 기능적 문법으로 이진 강제 변환 캐스트를 호출할 수 있도록 만들어졌어요. 마찬가지로pg_cast항목이 없지만 캐스트가 문자열 타입으로 또는 문자열 타입에서 이루어질 것이면, 그 호출은 I/O 변환 캐스트로 해석돼요. 이 예외는 I/O 변환 캐스트를 기능적 문법으로 호출할 수 있게 해줘요.
참고 (Note)
예외에도 예외가 있어요. 복합 타입에서 문자열 타입으로의 I/O 변환 캐스트는 기능적 문법으로 호출할 수 없고, 명시적 캐스트 문법(
CAST또는::표기법)으로 작성해야 해요. 이 예외는 자동 제공 I/O 변환 캐스트 도입 후, 함수나 컬럼 참조를 의도했을 때 그런 캐스트를 실수로 호출하기 너무 쉬운 것이 발견돼 추가됐어요.
Examples
int4(bigint) 함수를 사용해 타입 bigint에서 타입 int4로의 할당 캐스트를 만들기:
CREATE CAST (bigint AS int4) WITH FUNCTION int4(bigint) AS ASSIGNMENT;
(이 캐스트는 시스템에 이미 미리 정의되어 있어요.)
Compatibility
CREATE CAST 명령은 SQL 표준을 따르는 명령이에요. 다만 SQL은 이진 강제 변환 타입이나 구현 함수에 대한 추가 인자에 대한 조항이 없어요. AS IMPLICIT도 PostgreSQL 확장이에요.