본문 바로가기
WIKI 기술 지식 베이스

데이터 타입

원문 보기 위키 갱신

Turso의 스토리지 클래스, 타입 어피니티, STRICT 테이블, 커스텀 타입을 정리한 문서예요. SQL 타입 시스템이 어떻게 동작하는지 차근차근 살펴볼게요.

출처: 문서

본문

Turso는 SQLite와 동일한 동적 타입 시스템을 사용해요. 값에는 타입이 있지만 컬럼은 단일 타입을 강제하지 않죠(STRICT 테이블을 쓰는 경우는 예외예요). Turso에 저장된 모든 값은 다섯 가지 스토리지 클래스 중 하나에 속해요. 그리고 Turso는 STRICT 테이블을 위해 커스텀 타입, 컴포짓 타입, 네이티브 배열 타입으로 이 시스템을 확장해요.

Storage Classes

Storage Class Description
NULL NULL 값
INTEGER 부호 있는 정수, 크기에 따라 1, 2, 3, 4, 6, 8바이트로 저장
REAL 8바이트 IEEE 754 부동소수점 수
TEXT UTF-8 인코딩 문자열
BLOB 입력 그대로 저장되는 원시 바이너리 데이터
SELECT typeof(NULL);       -- 'null'
SELECT typeof(42);         -- 'integer'
SELECT typeof(3.14);       -- 'real'
SELECT typeof('hello');    -- 'text'
SELECT typeof(x'CAFE');    -- 'blob'

Type Affinity

컬럼이 타입 이름으로 선언되면 Turso는 그 컬럼에 type affinity를 부여해요. 타입 어피니티는 값을 어떻게 저장할지에 대한 권고 사항이지 엄격한 제약이 아니에요(STRICT 테이블은 예외). Turso는 SQLite와 동일한 어피니티 규칙을 써요.

Affinity Determination Rules

컬럼의 타입 어피니티는 선언된 타입 이름으로 결정되고, 다음 규칙을 순서대로 적용해요:

Rule Condition Affinity Examples
1 타입 이름에 "INT" 포함 INTEGER INT, INTEGER, BIGINT, SMALLINT, TINYINT
2 타입 이름에 "CHAR", "CLOB", "TEXT" 포함 TEXT TEXT, VARCHAR(255), CLOB, CHARACTER(20)
3 타입 이름에 "BLOB" 포함 또는 타입 미지정 BLOB BLOB, (타입 없음)
4 타입 이름에 "REAL", "FLOA", "DOUB" 포함 REAL REAL, FLOAT, DOUBLE, DOUBLE PRECISION
5 그 외 NUMERIC NUMERIC, DECIMAL, BOOLEAN, DATE
-- Type affinity is a suggestion, not a constraint
CREATE TABLE flexible (
    id INTEGER,
    name TEXT,
    data BLOB
);

-- This works - TEXT value in an INTEGER column
INSERT INTO flexible VALUES ('not a number', 42, 'text in blob');
SELECT typeof(id), typeof(name), typeof(data) FROM flexible;
-- 'text', 'integer', 'text'

Type Conversions

값이 컬럼에 삽입되면 Turso는 그 값을 컬럼의 어피니티로 변환하려고 시도해요:

  • INTEGER affinity: 값이 정수처럼 보이는 TEXT 또는 REAL이면 Turso는 그 값을 INTEGER로 변환해요
  • REAL affinity: 값이 숫자처럼 보이는 TEXT면 Turso는 REAL로 변환해요. 값이 정수면 REAL로 변환해요
  • NUMERIC affinity: Turso는 INTEGER를 먼저 시도하고, 그다음 REAL, 그래도 안 되면 TEXT로 유지해요
  • TEXT affinity: INTEGER와 REAL 값은 텍스트 표현으로 변환돼요
  • BLOB affinity: 변환을 시도하지 않아요

STRICT Tables

STRICT 테이블은 스토리지 레이어에서 타입 검사를 강제해요. STRICT 테이블에 삽입되는 모든 값은 선언된 컬럼 타입과 일치하거나 그 타입으로 변환 가능해야 해요.

CREATE TABLE users (
    id INTEGER PRIMARY KEY,
    name TEXT NOT NULL,
    age INTEGER,
    score REAL
) STRICT;

-- This works - values match declared types
INSERT INTO users VALUES (1, 'Alice', 30, 95.5);

-- This fails - 'thirty' cannot be converted to INTEGER
INSERT INTO users VALUES (2, 'Bob', 'thirty', 80.0);
-- Error: cannot store TEXT value in INTEGER column

Allowed Types in STRICT Tables

STRICT 테이블은 다음 기본 타입 이름만 허용해요:

Type Description
INTEGER 부호 있는 정수
REAL 부동소수점 수
TEXT UTF-8 문자열
BLOB 원시 바이너리 데이터
ANY 모든 스토리지 클래스 (이 컬럼의 타입 검사를 비활성화)

Turso Extension: STRICT 테이블은 커스텀 타입 이름, 컴포짓 타입(STRUCT와 UNION), 배열 타입도 받아들여요. 타입 이름 뒤에 []를 붙이면 어떤 기본 타입도 배열 컬럼이 돼요(예: INTEGER[], TEXT[]). 배열, 커스텀 타입, 컴포짓 타입은 Turso 전용 기능이에요.

Custom Types

Turso Extension: 커스텀 타입은 SQLite에는 없는 Turso 전용 기능이에요. 커스텀 타입은 STRICT 테이블에서만 동작해요. 이 기능은 실험적이므로 사용 전에 활성화해야 해요.

커스텀 타입으로는 저장 전 인코딩과 읽을 때 디코딩 방식을 정의하고, 스토리지 레이어에서 도메인 제약을 강제하고, 연산자를 붙이고, 기본값을 제공할 수 있어요. 커스텀 타입은 CREATE TYPE 문으로 선언해요.

-- A type that stores monetary values as cents
CREATE TYPE cents BASE integer
    ENCODE value * 100
    DECODE value / 100;

CREATE TABLE prices (
    id INTEGER PRIMARY KEY,
    amount cents
) STRICT;

INSERT INTO prices VALUES (1, 42);
SELECT amount FROM prices;
-- 42  (stored on disk as 4200)

Built-in Custom Types

Turso는 STRICT 테이블에서 사용할 수 있는 여러 내장 커스텀 타입을 제공해요:

Type Base Description
date TEXT ISO 8601 날짜 (YYYY-MM-DD)
time TEXT ISO 8601 시간 (HH:MM:SS)
timestamp TEXT ISO 8601 datetime
varchar(N) TEXT 최대 길이 제약이 있는 텍스트
numeric(P,S) BLOB 정밀도와 스케일이 있는 고정소수점 decimal
smallint INTEGER -32768..32767로 제한된 정수
boolean INTEGER 0 또는 1로 제한된 정수
uuid BLOB 16바이트 blob으로 저장되고 문자열로 표시되는 UUID
bytea BLOB 바이너리 데이터 (PostgreSQL 호환 별칭)
inet TEXT IP 주소
json TEXT 검증된 JSON 텍스트
jsonb BLOB 바이너리 형식의 JSON
CREATE TABLE events (
    id uuid PRIMARY KEY,
    name varchar(100),
    event_date date,
    is_active boolean DEFAULT 1,
    metadata json
) STRICT;

INSERT INTO events VALUES (
    uuid4(),
    'Product Launch',
    '2025-03-15',
    1,
    '{"venue": "online"}'
);

ENCODE/DECODE, 연산자, 파라메트릭 타입, 검증을 포함한 커스텀 타입 전체 레퍼런스는 CREATE TYPE을 보세요.

Composite Types: STRUCT and UNION

Turso는 컴포짓 타입도 지원해요: STRUCT(이름 있는 product type)와 UNION(discriminated union)이요. 이 타입들을 쓰면 한 컬럼에 구조화된 데이터를 저장하고 dot 표기법으로 접근할 수 있어요.

-- STRUCT: group related fields, access with col.field
CREATE TYPE point AS STRUCT(x INT, y INT);
CREATE TABLE locations(id INT PRIMARY KEY, pos point) STRICT;
INSERT INTO locations VALUES (1, struct_pack(10, 20));
SELECT pos.x, pos.y FROM locations WHERE pos.x > 5;
-- 10|20

-- UNION: tagged variants, access with col.variant
CREATE TYPE platform_id AS UNION(telegram INT, slack TEXT);
CREATE TABLE contacts(id INT PRIMARY KEY, platform platform_id) STRICT;
INSERT INTO contacts VALUES (1, union_value('telegram', 12345));
INSERT INTO contacts VALUES (2, union_value('slack', 'U0ABC'));
SELECT id, platform.telegram, platform.slack FROM contacts ORDER BY id;
-- 1|12345|
-- 2||U0ABC

컴포짓 타입 전체 레퍼런스는 CREATE TYPE — Composite Types를 보세요.

Array Types

Turso Extension: 배열 타입은 SQLite에는 없는 Turso 전용 기능이에요. 배열 컬럼은 STRICT 테이블에서만 동작해요.

배열 컬럼은 값의 순서 있는 컬렉션을 저장해요. 기본 타입 이름 뒤에 []를 붙여서 선언해요:

CREATE TABLE sensors (
    id INTEGER PRIMARY KEY,
    readings REAL[],
    labels TEXT[],
    flags INTEGER[]
) STRICT;

브래킷 쌍을 여러 개 쓰면 다차원 배열도 지원해요:

CREATE TABLE matrices (
    id INTEGER PRIMARY KEY,
    data INTEGER[][]
) STRICT;

배열은 ARRAY[...] 생성자로 또는 JSON 텍스트로 삽입할 수 있어요:

INSERT INTO sensors VALUES (1, ARRAY[1.5, 2.5, 3.5], '["a","b"]', '[0, 1, 1]');

배열은 출력에서 JSON 배열로 표시돼요. 요소 타입은 선언된 기본 타입으로 검증돼요 — 예를 들어 INTEGER[] 컬럼은 숫자가 아닌 텍스트 요소를 거절해요.

배열 함수, 연산자, 서브스크립트 문법 전체는 Array Functions를 보세요.

Inspecting Types

사용 가능한 모든 타입(내장 및 커스텀)을 나열해요:

PRAGMA list_types;

모든 타입은 sqlite_turso_types 가상 테이블로도 접근할 수 있어요:

SELECT name, sql FROM sqlite_turso_types;

Comparison and Sorting

Turso는 SQLite와 동일한 비교 규칙을 사용해요. 다른 스토리지 클래스의 값은 다음 순서로 정렬돼요:

NULL < INTEGER/REAL < TEXT < BLOB
  • NULL 값은 다른 모든 값보다 작은 것으로 간주돼요
  • INTEGER와 REAL 값은 수치로 비교돼요
  • TEXT 값은 컬럼의 collation sequence로 비교돼요 (기본값: BINARY)
  • BLOB 값은 memcmp()로 비교돼요
SELECT 1 < 2;          -- 1 (true)
SELECT 'abc' < 'abd';  -- 1 (true)
SELECT 1 < '2';        -- 1 (true, numeric < text)
SELECT NULL < 1;        -- NULL (any comparison with NULL yields NULL)
SELECT NULL IS NULL;    -- 1 (use IS to test for NULL)

See Also

더 알아보기 (Learn more)