Skip to main content

개요

설명

chdb_hook 모듈은 PostgreSQL COPY 명령에 후크를 걸어, chDB를 사용해 로컬 파일, AWS S3 버킷, Google Cloud Storage 등에서 [chDB가 지원하는 데이터 포맷][formats] 중 하나로 데이터를 TO 또는 FROM 복사할 수 있도록 합니다. 또한 CREATE TABLE에도 후크를 걸어, 동일한 대상들로부터 테이블의 컬럼을 도출하고 행을 로드할 수 있게 합니다.

로딩

수퍼유저(super user) 권한으로 다음 방법 중 하나를 사용해 chdb_hook을 로드하십시오. 사용 사례에 가장 적합한 방법을 선택하십시오:
  • LOAD 명령으로 명시적으로 로드하며, 해당 세션이 유지되는 동안에만 적용됩니다:
    ClickHouse Cloud SQL 콘솔은 아직 LOAD 'chdb_hook' 명령을 지원하지 않지만, psql이나 다른 데이터베이스 연결을 통해 실행할 수 있습니다. 그렇지 않은 경우 지원 담당자에게 문의하여 Postgres 서비스 구성에 추가하면, 이후 SQL 콘솔에서도 사용할 수 있습니다.
  • 모든 세션에 적용하려면 postgresql.conf에서 [session_preload_libraries] 설정을 사용하십시오:
    또는 ALTER SYSTEM으로 설정합니다:
    이 설정은 ALTER DATABASE를 사용해 데이터베이스 단위로도 지정할 수 있습니다:
    또는 ALTER ROLE을 사용해 특정 사용자 및 그룹에 지정할 수 있습니다:
  • [shared_preload_libraries] 설정으로 서버 시작 시 로드하면, 모든 세션과 데이터베이스에서 항상 사용할 수 있습니다:
chdb_hook을 로드하면 pg_read_server_files 또는 pg_write_server_files 역할에 속한 사용자가 Postgres 서버의 파일은 물론 클라우드 스토리지를 대상으로 데이터를 COPY할 수 있게 되므로 유의하십시오.

COPY 오버로딩

loading 시 chdb_hook은 Postgres COPY 명령에 후크를 걸어, 로컬 파일, AWS S3 버킷, Google Cloud Storage 등에서 [chDB가 제공하는 데이터 포맷][formats] 중 하나로 데이터를 TO 또는 FROM 방향으로 복사합니다. 예를 들어 S3에 있는 CSV 파일에서 테이블을 로드하려면, 먼저 테이블을 CREATE한 다음 s3:// URL과 함께 COPY를 호출하십시오:

권한

chdb_hook COPY는 자신이 대체하는 COPY와 동일한 권한을 필요로 합니다. 즉, COPY TO에는 릴레이션 또는 복사되는 모든 컬럼에 대한 SELECT 권한이, COPY FROM에는 INSERT 권한이 필요합니다. file:// URL은 server의 파일을 읽거나 쓰기 때문에 pg_read_server_files 또는 pg_write_server_files 멤버십도 필요합니다. 또한 COPY FROM은 읽기-쓰기 transaction에서만 사용할 수 있습니다.

URL 스킴

chdb_hook은 다음 스킴 중 하나를 사용하는 URL COPY 대상에 대해서만 실행됩니다:

URL 포맷

URL 포맷은 대상(target)에 따라 다릅니다.

File

Postgres 서버의 절대 경로여야 합니다. 상대 경로를 지정하면 오류가 발생합니다. Postgres 사용자는 용도에 따라 pg_read_server_files 또는 pg_write_server_files 역할(Role)의 멤버여야 합니다. 또한 Postgres 시스템 사용자에게 해당 파일에 대한 읽기 또는 쓰기 액세스 권한이 있어야 합니다. COPY TO에서 경로가 존재하지 않으면 chdb_hook이 누락된 상위 디렉터리를 생성하며, 이때 필요한 파일 시스템 권한을 갖추고 있어야 합니다. 예시:

HTTP

퍼블릭 클라우드 스토리지를 포함한 일반적인 HTTP URL을 모두 지원합니다. COPY TO에서는 chdb_hook이 해당 URL로 데이터를 POST하려고 시도합니다. 예시:

S3

S3 URL은 S3 URI 형식일 수 있습니다
또는 객체 URL 형식:

GCS

GCS URL은 퍼블릭 URL 형식을 따릅니다:
또는 chdb_hook이 공개 URL로 변환해 주는 Cloud Storage URI를 사용할 수도 있습니다:

Azure Blob Storage

계정 이름을 하위 도메인으로 지정한 blob.windows.net URL을 사용하십시오:
또는 다른 host name을 사용할 수도 있습니다:

Azure ABFS

ABFS URL은 반드시 다음 포맷을 사용해야 합니다:

HDFS URL

HDFS URL은 일반적인 HTTP 스타일 URL 형식을 사용할 수 있으며, 포트는 선택 사항입니다:

경로 와일드카드

COPY FROM 명령어의 URL 경로에는 글롭 패턴을 사용할 수 있습니다. 파일은 접미사나 접두사만이 아니라 전체 경로 패턴과 일치해야 합니다. 단 한 가지 예외가 있는데, 경로가 기존 디렉터리를 가리키고 글롭 패턴을 사용하지 않는 경우에는 해당 디렉터리의 모든 파일을 선택하도록 경로 뒤에 *가 암시적으로 추가됩니다. 지원되는 와일드카드는 다음과 같습니다.
  • *: /를 제외한 임의 개수의 문자와 일치하며, 빈 문자열도 포함합니다.
  • ?: 임의의 단일 문자와 일치합니다.
  • {groucho,harpo,chico}: “groucho”, “harpo”, “chico” 문자열 중 하나로 대체합니다. 이 문자열에는 /가 포함될 수 있습니다.
  • {N..M}: >= N 이고 <= M 인 임의의 숫자와 일치합니다.
  • **: 디렉터리 내의 모든 파일을 재귀적으로 일치시킵니다.
예를 들어 다음 파일들의 데이터를 하나의 명령어로 로드하려는 경우를 살펴봅니다. 두 디렉터리 이름은 {some,another}_prefix로, 파일은 some_file_{1..3}.csv'로 일치시킵니다. 다음과 같이 작성하십시오:

옵션

chdb_hook의 COPY 명령은 다음 옵션을 지원합니다:

format:

읽거나 쓸 포맷입니다. chDB에서 제공하는 포맷 중 하나여야 하며, 여기에는 TSV, CSV, Parquet, Iceberg, JSON 등이 포함됩니다. 생략하거나 auto로 설정하면 chDB가 URL 끝의 파일 이름 확장자를 보고 포맷을 결정합니다.

structure

행의 chDB 데이터 구조입니다. 컬럼명 목록과 ClickHouse 데이터 타입, 수정자로 구성됩니다. 생략하면 chdb_hook이 Postgres 데이터 타입을 대체로 적합한 ClickHouse 타입으로 매핑합니다. 자세한 내용은 Postgres to chDB를 참조하십시오. auto로 설정하면 chDB가 타입을 추론합니다. 예시:

access_key와 access_secret

요청을 인증하는 데 사용되는 AWS 계정 사용자의 장기 자격 증명입니다.
  • S3: AWS [액세스 키 ID 및 액세스 시크릿]으로, 보통 AWS_ACCESS_KEY_ID 및 AWS_SECRET_ACCESS_KEY 환경 변수로 정의됩니다
  • GCS: GCP [HMAC 키 및 시크릿]
  • Azure: Azure 스토리지 계정 이름 및 [액세스 키]

session_token

access_key 및 access_secret과 함께 사용하는 AWS 세션 토큰으로, 보통 환경 변수 AWS_SESSION_TOKEN으로 정의됩니다. S3 URL에만 사용됩니다.

compression

파일 압축 포맷입니다. 파일 이름으로 압축 방식을 추론할 수 없을 때 사용합니다. 지원되는 값:
  • auto (기본값)
  • none
  • gzip 또는 gz
  • brotli 또는 br
  • xz 또는 LZMA
  • zstd 또는 zst
  • lz4
  • bz2
  • snappy

timeout

요청 타임아웃(밀리초 단위)입니다. HTTP, S3, GCS, Azure URL에 적용됩니다. 기본값은 30000(30초)입니다.

encoding_check

chDB의 String 및 JSON 값을 변환할 때 database encoding에서 유효하지 않은 문자를 처리하는 방식을 지정합니다. 다음 값 중 하나를 사용합니다.
  • fail (기본값): 오류를 발생시킵니다
  • remove: 유효하지 않은 바이트를 제거합니다
  • replace: UTF-8 인코딩에서는 유효하지 않은 바이트를 유니코드 대체 문자(�)로 대체합니다. 다른 인코딩에서는 remove와 동일하게 동작합니다
  • truncate: 처음으로 나타나는 유효하지 않은 바이트 위치에서 텍스트를 잘라냅니다

디버깅

오류가 발생하면 chdb_hook의 COPY 명령은 실행을 시도했던 chDB 쿼리를 오류 Context에 포함합니다:
chdb_hook은 SQL injection 취약점을 방지하고 자격 증명과 같은 민감한 데이터가 로깅될 위험을 최소화하기 위해 쿼리 매개변수에 {name:Type} 형식의 placeholder를 사용합니다. 다만 문제를 디버깅하기 위해 해당 매개변수의 내용을 확인해야 한다면, Postgres의 [log_min_messages] GUC를 일시적으로 DEBUG1 이상으로 설정하십시오. 그러면 chdb_hook이 쿼리와 매개변수를 Postgres 로그로 전송하며(클라이언트로는 절대 전송하지 않습니다), 다음과 같이 표시됩니다:
[log_min_messages]를 디버깅 수준으로 설정한 상태는 단일 디버깅 세션을 넘어 유지하지 마십시오. 자격 증명과 같은 민감한 정보가 로그에 기록되는 것을 방지하기 위한 것이며, PostgreSQL 자체도 디버깅 정보를 기록하므로 로그가 빠르게 가득 찰 수 있습니다.

CREATE TABLE 오버로딩

chdb_hook은 CREATE TABLE에도 후크를 연결하므로, 테이블이 URL에서 컬럼을 도출하고 행을 로드할 수 있습니다. URL에서 도출된 구조로 테이블을 생성하려면 structure_from 옵션에 URL을 전달하고 컬럼 목록은 비워 두십시오(주의: 이 공개 데이터 파일에는 4,100만 개의 행이 있습니다):
컬럼뿐만 아니라 행까지 로드하려면 copy_from을 사용하십시오:
copy_from은 statement가 자체 컬럼을 전혀 지정하지 않은 경우에만 컬럼을 추론합니다. 컬럼 목록, INHERITS 절, OF 유형, 파티션은 각각 컬럼을 정의하므로, 이 경우 copy_from은 다음 항목만 복사합니다:
copy_from이 컬럼을 추론할 때는 DESCRIBE가 반환하는 소스 스키마를 사용합니다. 이로 인해 Map, Tuple, Nested 값은 텍스트 배열 컬럼으로 로드되며, 이 컬럼에는 원래의 ClickHouse 타입 정보가 남지 않습니다. 두 옵션 모두 COPY와 동일한 URL scheme과 옵션을 지원하며, 자격 증명, 포맷, 압축, timeout, 심지어 명시적인 구조 지정까지 모두 적용됩니다. Postgres는 남아 있는 스토리지 매개변수를 그대로 유지합니다:
structure_from과 copy_from은 모두 IF NOT EXISTS와 함께 사용할 수 없습니다. 기존 릴레이션을 로드하려면 COPY를 사용하십시오.

제한 사항

Postgres와 chDB 간 데이터 타입 동작의 차이 및 몇 가지 알려진 문제로 인해 chdb_hook에는 다음과 같은 제한 사항이 있습니다:
  • 복사를 수행하는 역할에 적용되는 row-level security 정책이 있는 릴레이션은 COPY할 수 없습니다. Postgres는 COPY TO를 쿼리로 다시 작성하는 방식으로 이러한 정책을 적용하는데, chdb_hook은 이를 지원하지 않습니다.
  • WHERE 절을 사용하여 URL에서 COPY FROM을 수행할 수 없습니다.
  • chDB에는 NULL 배열이 없으므로, COPY TO는 NULL을 빈 배열([])로 저장합니다.
  • chDB는 lseg, path, polygon에 해당하는 값을 배열로 표현합니다. 따라서 이러한 타입의 NULL 값도 COPY TO 시 빈 배열([])로 출력됩니다.
  • ClickHouse에는 NULL 배열이 없으므로, COPY TO는 NULL을 빈 배열([])로 저장합니다.
  • ClickHouse는 lseg, path, polygon에 해당하는 값을 배열로 표현합니다. 따라서 이러한 타입의 NULL 값도 COPY TO 시 빈 배열([])로 출력됩니다.
  • 지정된 structure에서 해당 컬럼을 Nullable로 정의하지 않으면 NULL 값은 기본값으로 출력됩니다. 이러한 변환을 방지하려면 structure에 널 허용 컬럼을 항상 명시적으로 정의하십시오.
  • 마지막 점이 첫 번째 점과 같은 열린 path는 닫힌 경로로 출력됩니다.
  • Protobuf의 반복 필드에는 null이 없으므로 배열의 NULL 값은 생략됩니다.
  • chDB JSON type은 JSON 객체만 지원합니다. 모든 값이 JSON 객체인 경우에만 json 및 jsonb의 기본 String 매핑을 JSON으로 재정의하십시오. (ClickHouse/ClickHouse#68428)
  • chDB JSON type은 null을 무시하므로, NULL 값을 가진 객체 키는 출력 시 생략됩니다. 객체 값이 null이 아니거나 그 값의 손실을 허용할 수 있는 경우에만 json 및 jsonb의 기본 String 매핑을 JSON으로 재정의하십시오. (ClickHouse/ClickHouse#68428)
  • JSON, JSONCompact, JSONColumnsWithMetadata 포맷은 항상 UTF-8을 검사하므로, bytea 값을 대체 문자로 치환하여 출력합니다.
  • COPY FROM은 빈 문자열이나 0을 포함하는 Protobuf Nullable 필드를 NULL로 읽습니다. (chdb-io/chdb-core#152)
  • Parquet으로의 COPY TO는 Nullable Tuple 자체의 null map에서 NULL을 누락시킵니다. (ClickHouse/ClickHouse#112427)
  • Parquet, Arrow, ArrowStream, ORC, Avro, Protobuf, ProtobufList, MsgPack, BSONEachRow 포맷에는 Postgres time 또는 chDB Time64에 해당하는 타입이 없습니다. 값을 보존하려면 명시적인 structure에서 time 컬럼을 String으로 구성하십시오.
  • Protobuf 출력은 timestamp 값을 초 단위로 절삭합니다.
  • Protobuf 출력은 1970-01-01 이전 날짜를 지원하지 않습니다. 값을 보존하려면 명시적인 structure에서 time 컬럼을 String으로 구성하십시오. (ClickHouse/ClickHouse#111860)

데이터 타입

COPY는 릴레이션의 Postgres 타입을 chDB 타입으로 매핑하고, CREATE TABLE은 URL의 chDB 타입을 Postgres 타입으로 매핑합니다.

Postgres에서 chDB로

명시적인 structure 옵션이 없으면 chdb_hook은 Postgres 타입을 적절한 chDB 대응 타입으로 매핑합니다. 매핑된 타입이 사용 사례에 맞지 않으면 structure를 지정하여 생성된 타입을 원하는 타입으로 재정의하십시오. name, varchar, char, bit, timetz, money, enum 등 이 표에 없는 타입은 String으로 매핑됩니다. 배열 타입은 매핑된 원소 타입의 Array로 매핑됩니다. ClickHouse는 널 허용 여부를 컬럼 단위로 제한하는 반면 Postgres는 배열 단위로 제한하므로, 원소는 항상 Nullable입니다. Map, Tuple, Nested로 직접 매핑되는 Postgres 타입은 없지만, structure나 소스 파일에서 이러한 타입을 지정할 수 있습니다. Tuple은 튜플 필드마다 원소 하나씩을 담는 text[]로 읽거나, 필드 타입을 보존하려면 구조가 일치하는 composite type으로 읽을 수 있습니다. Map 또는 Nested는 키-값 쌍 또는 중첩 튜플마다 내부 배열 하나씩을 담는 text[][]로 읽거나, 구조가 일치하는 복합 타입의 배열로 읽을 수 있습니다. 예시는 수동 타입 매핑을 참조하십시오.

타임스탬프 변환

일반 텍스트 형식(TSV, CSV 등)에서 COPY 후크는 현재 datestyle 설정과 관계없이 DateTime 및 DateTime64 값을 ISO-8601 형식인 YYYY-MM-DDThh:mm:ssZ로 출력합니다. 이를 통해 값을 가져오는 소스가 다른 시간대를 사용하더라도 timestamptz 값이 일관되게 유지됩니다. structure 출력에서 Datetime64(3, 'America/Los_Angeles')와 같은 다른 유형을 사용해도 출력 오프셋에는 영향이 없으며, 정밀도만 달라집니다. Timestamp TZ 예시: 또한 COPY 후크는 timestamp 값을 세션 시간대에서 UTC로 변환하므로, 값이 항상 UTC를 기준으로 출력됩니다. 이 값을 새로운 시스템에 로드하면 해당 시스템의 로컬 시간대로 변환됩니다. 따라서 시간대가 다르면 표시되는 값도 달라지지만, 시간대 차이를 감안하면 동일한 시점을 가리킵니다. timezone 설정이 timestamp 2026-08-28T12:00:00에 미치는 영향의 예시:

chDB에서 Postgres로

기존 테이블에서는 값이 선언된 컬럼 타입으로 변환됩니다. 다른 스칼라 타입은 가능한 경우 PostgreSQL의 명시적 형변환을 사용하며, 배열 원소는 선언된 원소 타입으로 변환됩니다. 지원되지 않는 변환이나 범위를 벗어난 값은 오류를 발생시킵니다. chDB Interval 타입을 smallint, integer 또는 bigint에 매핑하면 해당 단위의 개수를 읽고 쓸 수 있습니다. 예를 들어 IntervalDay 값 3은 정수 3에 매핑됩니다. IntervalNanosecond를 bigint에 매핑하면 나노초 정밀도가 유지되지만, interval에 매핑하면 마이크로초 단위로 잘립니다. chdb_hook은 DESCRIBE가 보고하는 ClickHouse 타입을 기반으로 테이블을 생성할 때 아래의 기본 Postgres 타입을 사용합니다. 추가 읽기 대상은 명시적으로 선언된 컬럼에 적용되며, PostgreSQL 명시적 형변환 외의 변환도 포함합니다. 셀이 비어 있더라도 해당 형변환은 허용됩니다. 이 대상은 읽기에 해당하며, 쓰기에는 별도의 변환 규칙이 적용됩니다. 입력 호환 타입은 해당 PostgreSQL 입력 함수를 사용하여 문자열을 읽을 수 있습니다. 복합 타입은 필드의 구성과 순서가 일치해야 합니다. 튜플을 배열로 읽으려면 각 필드가 배열의 원소 타입으로 변환될 수 있어야 하며, 배열인 필드가 있어서는 안 됩니다. 배열로 읽을 때 Map은 키-값 쌍마다 한 행을, Nested는 중첩된 행마다 한 행을 사용합니다. 튜플을 box로 읽으려면 두 개의 점을 제공하고, circle로 읽으려면 점과 반지름을, line으로 읽으려면 세 개의 계수를 제공하십시오. 이 표에 없는 chDB 타입은 모두 오류를 발생시키며, Variant, Dynamic, AggregateFunction이 여기에 해당합니다. 이러한 타입을 텍스트로 읽으려면 해당 타입을 String으로 매핑하는 structure를 사용하십시오. Postgres는 이러한 타입 중 일부에서 chDB보다 좁은 범위만 지원합니다. 따라서 24시간을 초과하는 Time 또는 Time64 값, 그리고 Postgres의 날짜 범위를 벗어난 Date32 값을 복사하면 오류가 발생합니다.

수동 타입 매핑

컬럼 추론 시 enum은 text로, Tuple, Map, Nested 값은 텍스트 배열로 처리됩니다. 필드 타입을 유지하거나 enum 값을 제한하려면 PostgreSQL enum 타입과 복합 타입(composite type)을 생성한 다음, 해당 타입으로 컬럼을 선언하십시오. chDB 타입은 structure로 지정하거나, structure 'auto'를 사용하여 Postgres 테이블 대신 소스 데이터에서 추론하도록 할 수 있습니다. 예를 들어, 다음 타입을 사용하면 이벤트 상태, 좌표, 레이블, 중첩 항목을 로드할 수 있습니다.
복합 필드(composite field)는 호환되는 PostgreSQL 타입을 사용하여 chDB 필드 순서대로 선언하십시오. Map 값은 키 필드를 먼저 선언한 다음 값 필드를 선언하십시오. 각 Tuple은 하나의 복합 값이 되며, 각 Map 쌍 또는 Nested 행은 복합 배열의 원소 하나가 됩니다. chDB는 명시적 structure에 포함된 Nested를 필드마다 하나의 Array 컬럼으로 분할합니다. 위 예시처럼 Array(Tuple(...))를 사용하여 중첩된 행을 하나의 복합 배열 컬럼으로 읽거나, 타입 정보가 포함된 chDB 소스 포맷이라면 structure 'auto'를 사용하십시오.

텍스트 인코딩

chDB는 String, FixedString, Enum, JSON을 바이트로 읽으며, 인코딩은 보장하지 않습니다. 이러한 컬럼을 text 또는 그 외 비바이너리 타입으로 복사하면 데이터베이스 인코딩을 기준으로 바이트를 검증하고, 표현할 수 없는 데이터에 대해서는 오류를 발생시킵니다:
모든 인코딩은 NUL을 거부하며, Postgres는 이를 text에 저장할 수 없습니다. chDB가 기록한 바이트를 그대로 유지하려면 bytea로 복사하십시오. CREATE TABLE은 이러한 타입에 대해 text를 도출하므로, 다음과 같이 이름을 지정하십시오:
FixedString(N)은 길이가 짧은 값을 NUL 바이트로 채웁니다. text로 복사하면 뒤쪽의 NUL이 삭제되지만, bytea는 N 바이트 전체를 유지합니다.

설정

chdb_hook.max_memory

chDB 쿼리에 사용할 최대 메모리 양을 정의하며, chDB의 max_memory_usage 설정을 지정하는 데 사용됩니다. 슈퍼유저 권한이 필요합니다. 메가바이트 단위의 정수 값을 지정하거나 다음 메모리 단위 중 하나를 사용하십시오:
  • B (바이트)
  • kB (킬로바이트)
  • MB (메가바이트)
  • GB (기가바이트)
  • TB (테라바이트)
기본값은 0이며, 이 경우 메모리를 제한하지 않습니다.

chdb_hook.max_threads

chDB 쿼리의 최대 쿼리 처리 스레드 수로, chDB max_threads 설정을 지정하는 데 사용됩니다. 슈퍼유저 권한이 필요합니다. 기본값은 0이며, 이 경우 chDB가 값을 자동으로 결정합니다. 대규모 COPY를 실행하기 전에 chdb_hook.max_threads를 설정하여 chDB가 CPU 사용량을 독점해 PostgreSQL의 성능이 저하되는 것을 방지할 것을 강력히 권장합니다.

chdb_hook.max_parsing_threads

chDB가 병렬 파싱을 지원하는 입력 형식의 데이터를 파싱할 때 사용할 수 있는 최대 스레드 수이며, chDB max_parsing_threads 설정을 지정하는 데 사용됩니다. 슈퍼유저 권한이 필요합니다. 기본값은 0이며, 이 경우 chDB가 값을 직접 결정합니다. 대량의 데이터를 COPY하기 전에 chdb_hook.max_parsing_threads를 설정하여 chDB가 PostgreSQL을 희생시키면서 CPU 사용량을 최대치까지 점유하지 않도록 하는 것을 권장합니다.

버전 관리 정책

chdb_hook는 공개 릴리스에 Semantic Versioning을 따릅니다.
  • 메이저 버전은 API 변경 시 증가합니다
  • 마이너 버전은 하위 호환되는 SQL 변경 시 증가합니다
  • 패치 버전은 바이너리 전용 변경 시 증가합니다
설치 후에는 Postgres 18의 pg_get_loaded_modules() 함수를 통해 PostgreSQL에서 버전을 확인할 수 있습니다.

작성자

Copyright (c) 2026, ClickHouse