CREATE DOMAIN
CREATE DOMAIN은 기본 타입 위에 이름이 붙은 제약 래퍼를 정의해요. STRICT 테이블에서 컬럼 타입으로 쓸 수 있어요.
출처: 문서
본문
**Turso 확장 기능**: CREATE DOMAIN은 표준 SQLite에는 없는 Turso 전용 문이에요. 도메인은 STRICT 테이블과 커스텀 타입 실험 기능이 필요해요. 이 기능은 사용 전에 [활성화](/sql-reference/experimental-features)해야 해요.CREATE DOMAIN 문은 선택적인 제약을 갖춘 이름 붙은 타입 별칭을 정의해요. CREATE TYPE과 달리, 도메인은 커스텀 ENCODE/DECODE 로직이나 OPERATOR를 지정하지 않아요. 대신 도메인은 기본 타입 위에 NOT NULL과 CHECK 제약을 얹고, 값은 기본 타입의 고유 저장 형식으로 저장돼요.
문법
CREATE DOMAIN [IF NOT EXISTS] domain-name AS base-type
[DEFAULT default-expr]
[NOT NULL]
[[CONSTRAINT constraint-name] CHECK (expr)]
...;
설명
도메인은 기본 타입을 검증 제약으로 감싸요. 도메인 타입 컬럼에 값을 쓸 때 CHECK 제약과 NOT NULL 제한(있다면)이 검증돼요. 검증을 통과하면 값은 기본 타입의 고유 형식으로 저장돼요. 값을 읽을 때는 그대로 반환돼요.
도메인은 ORDER BY, 인덱싱, 산술, 집계 같은 연산에서 쿼리 엔진에게 투명해요. 도메인 컬럼은 입력 검증이 더해진 점만 빼면 기본 타입 컬럼과 정확히 똑같이 동작해요.
도메인은 STRICT 테이블에서만 동작해요. STRICT가 아닌 테이블에서 도메인 이름을 써도 효과가 없어요.
절
IF NOT EXISTS
같은 이름의 도메인이 이미 존재할 때 생길 오류를 억제해요. 기존 도메인은 그대로 유지돼요.
CREATE DOMAIN IF NOT EXISTS positive_int AS integer CHECK (value > 0);
AS base-type
기반 타입을 지정해요. 기본 타입은 원시 타입(integer, real, text, blob)이나 다른 도메인이 될 수 있어서, 도메인을 겹겹이 쌓을 수 있어요.
CREATE DOMAIN percentage AS integer
CHECK (value >= 0)
CHECK (value <= 100);
DEFAULT
이 도메인 타입 컬럼의 기본값을 설정해요. 컬럼 수준의 DEFAULT가 도메인 수준의 DEFAULT를 이겨요.
CREATE DOMAIN status AS text DEFAULT 'active';
CREATE TABLE accounts (
id INTEGER PRIMARY KEY,
state status
) STRICT;
INSERT INTO accounts(id) VALUES (1);
SELECT state FROM accounts;
-- active
NOT NULL
도메인에 NOT NULL 제약을 추가해요. 이 도메인 타입 컬럼에 NULL을 넣거나 갱신하려는 시도는, 컬럼 정의에 NOT NULL이 없어도 실패해요.
CREATE DOMAIN required_text AS text NOT NULL;
CREATE TABLE contacts (
id INTEGER PRIMARY KEY,
name required_text
) STRICT;
INSERT INTO contacts VALUES (1, 'Alice');
-- OK
INSERT INTO contacts VALUES (2, NULL);
-- Error: domain required_text does not allow null values
컬럼 수준의 NULL 선언은 도메인의 NOT NULL 제약을 이길 수 없어요.
CHECK
검증 제약을 추가해요. 표현식은 검사 중인 입력 값을 가리킬 때 value를 참조할 수 있어요. CHECK 제약은 여러 개 지정할 수 있고, 모두 통과해야 해요.
CREATE DOMAIN positive_int AS integer CHECK (value > 0);
CREATE TABLE measurements (
id INTEGER PRIMARY KEY,
reading positive_int
) STRICT;
INSERT INTO measurements VALUES (1, 42);
-- OK
INSERT INTO measurements VALUES (2, -5);
-- Error: domain positive_int constraint violation
CONSTRAINT name CHECK
CHECK 제약에는 문서화 목적으로 이름을 붙일 수 있어요.
CREATE DOMAIN valid_score AS integer
CONSTRAINT non_negative CHECK (value >= 0)
CONSTRAINT max_hundred CHECK (value <= 100);
도메인 체이닝
도메인은 다른 도메인을 기본 타입으로 쓸 수 있어요. 도메인이 체인처럼 이어지면, 체인 안의 모든 제약이 자식에서 조상까지 강제돼요.
CREATE DOMAIN base_amount AS integer CHECK (value > 0);
CREATE DOMAIN small_amount AS base_amount CHECK (value < 1000);
CREATE TABLE orders (
id INTEGER PRIMARY KEY,
quantity small_amount
) STRICT;
INSERT INTO orders VALUES (1, 50);
-- OK: passes both value > 0 and value < 1000
INSERT INTO orders VALUES (2, -1);
-- Error: fails base_amount's CHECK (value > 0)
INSERT INTO orders VALUES (3, 5000);
-- Error: fails small_amount's CHECK (value < 1000)
세 단계 이상의 체이닝도 지원해요:
CREATE DOMAIN text_val AS text;
CREATE DOMAIN nonempty AS text_val CHECK (length(value) > 0);
CREATE DOMAIN short_text AS nonempty CHECK (length(value) < 50);
CREATE TABLE labels (
id INTEGER PRIMARY KEY,
name short_text
) STRICT;
INSERT INTO labels VALUES (1, 'OK');
-- OK
INSERT INTO labels VALUES (2, '');
-- Error: fails nonempty's CHECK (length(value) > 0)
UPDATE 강제
도메인 제약은 INSERT뿐 아니라 UPDATE에서도 강제돼요.
CREATE DOMAIN positive_int AS integer CHECK (value > 0);
CREATE TABLE items (
id INTEGER PRIMARY KEY,
stock positive_int
) STRICT;
INSERT INTO items VALUES (1, 10);
UPDATE items SET stock = 20 WHERE id = 1;
SELECT stock FROM items;
-- 20
UPDATE items SET stock = -1 WHERE id = 1;
-- Error: domain positive_int constraint violation
CAST 지원
CAST는 도메인의 검증 제약을 적용해요:
CREATE DOMAIN positive_int AS integer CHECK (value > 0);
SELECT CAST(42 AS positive_int);
-- 42
SELECT CAST(-1 AS positive_int);
-- Error: domain positive_int constraint violation
NULL을 NOT NULL 도메인으로 캐스팅하는 건 거절돼요:
CREATE DOMAIN notnull_int AS integer NOT NULL;
SELECT CAST(NULL AS notnull_int);
-- Error: domain notnull_int does not allow null values
테이블 수준 CHECK와 함께 쓰기
도메인 CHECK 제약과 테이블 수준 CHECK 제약은 둘 다 적용돼요. 도메인 제약은 인코딩 중에 검사되고, 테이블 CHECK는 별도로 검사돼요.
CREATE DOMAIN positive_int AS integer CHECK (value > 0);
CREATE TABLE bounded (
id INTEGER PRIMARY KEY,
val positive_int CHECK (val < 100)
) STRICT;
INSERT INTO bounded VALUES (1, 50);
-- OK: passes domain CHECK (> 0) and table CHECK (< 100)
INSERT INTO bounded VALUES (2, -1);
-- Error: fails domain CHECK
INSERT INTO bounded VALUES (3, 200);
-- Error: fails table CHECK
도메인 컬럼에서의 연산
도메인 컬럼은 기본 타입과 같은 연산을 지원해요: 산술, 비교, 정렬, 집계.
CREATE DOMAIN myint AS integer;
CREATE TABLE data (
id INTEGER PRIMARY KEY,
a myint,
b myint
) STRICT;
INSERT INTO data VALUES (1, 10, 3);
SELECT a + b, a - b, a * b FROM data;
-- 13|7|30
CREATE DOMAIN myint AS integer;
CREATE TABLE scores (
id INTEGER PRIMARY KEY,
val myint
) STRICT;
INSERT INTO scores VALUES (1, 30);
INSERT INTO scores VALUES (2, 10);
INSERT INTO scores VALUES (3, 20);
SELECT val FROM scores ORDER BY val;
-- 10
-- 20
-- 30
도메인 삭제하기
도메인은 DROP DOMAIN으로 삭제하지, DROP TYPE으로 삭제하지 않아요. 도메인에 DROP TYPE을 쓰면(또는 타입에 DROP DOMAIN을 쓰면) 오류가 발생해요.
도메인은 어떤 테이블 컬럼이나 다른 도메인이 참조하는 동안에는 삭제할 수 없어요.
CREATE DOMAIN my_domain AS integer;
CREATE TABLE t(x my_domain) STRICT;
DROP DOMAIN my_domain;
-- Error: type 'my_domain' is in use
DROP TABLE t;
DROP DOMAIN my_domain;
-- OK
제한 사항
- STRICT 테이블 전용: STRICT가 아닌 테이블에서 도메인 타입을 쓰면 CREATE TABLE과 ALTER TABLE ADD COLUMN 시점에 거절돼요. STRICT가 아닌 테이블은 임의의 타입 이름을 어피니티 힌트로 받아들이지만, 도메인 제약(CHECK, NOT NULL, DEFAULT)은 STRICT 테이블에서만 강제되기 때문에 허용하면 오해를 살 수 있어요.
- 사용 중일 때 삭제 불가: 도메인은 어떤 테이블 컬럼이나 다른 도메인이 참조하는 동안에는 삭제할 수 없어요.
- UNIQUE, PRIMARY KEY, REFERENCES 없음: 이 제약들은 도메인 정의에서 지원되지 않아요. 대신 테이블 수준 제약을 쓰세요.
- 절 중복 없음: 같은 정의에 DEFAULT나 NOT NULL 절이 여러 개면 거절돼요. 서로 충돌하는 NULL과 NOT NULL 절도 거절돼요.
더 알아보기 (Learn more)
- DROP DOMAIN - 도메인 삭제하기
- CREATE TYPE - ENCODE/DECODE 로직이 있는 커스텀 타입 정의
- 데이터 타입 - 타입 시스템 개요
- CREATE TABLE - STRICT 테이블 정의