Skip to main content

概要

说明

chdb_hook 模块会挂接 PostgreSQL 的 COPY 命令, 使其能够借助 chDB,以 chDB 支持的任意数据格式将数据复制到 (TO) 或从 (FROM) 本地文件、AWS S3 桶、Google Cloud Storage 等位置读取。 该模块同样挂接 CREATE TABLE,使表能够从上述任意目标推导其列并加载其行。

加载

以 super user 身份,通过以下任一方式加载 chdb_hook。请选择最适合你的用例的方式:
  • 通过 LOAD 命令显式加载;作用范围为当前 session:
    ClickHouse Cloud 的 SQL 控制台尚不支持 LOAD 'chdb_hook' 命令,但可以通过 psql 或任何其他 database connection 运行该命令。 你也可以联系支持代表将其添加到你的 Postgres service 配置中,添加后即可在 SQL 控制台中使用。
  • 对所有 sessions 生效:在 postgresql.conf 中设置 [session_preload_libraries]:
    或通过 ALTER SYSTEM:
    该设置也可以通过 ALTER DATABASE 针对单个 database 设置:
    或通过 ALTER ROLE 针对特定用户和组设置:
  • 在 server 启动时通过 [shared_preload_libraries] 设置加载,使其始终对所有 sessions 和 databases 可用:
请注意,加载 chdb_hook 后,属于 pg_read_server_files 或 pg_write_server_files roles 的用户可以使用 COPY 读写 Postgres server 上的文件以及云存储中的数据。

COPY 重载

在加载时,chdb_hook 会挂接 Postgres 的 COPY 命令,从而以 chDB 支持的任意数据格式,将数据复制到 (TO) 或从 (FROM) 本地文件、AWS S3 桶、Google Cloud Storage 等位置读写。例如,若要从 S3 中的 CSV 文件加载数据到表中,请先创建表,然后使用 s3:// URL 调用 COPY:

特权

chdb_hook 的 COPY 所需的特权与它所替换的 COPY 相同:COPY TO 需要对该 relation 或每个被复制的列具有 SELECT 特权,COPY FROM 则需要 INSERT 特权。file:// URL 会读取或写入 server 上的文件,因此还需要属于 pg_read_server_files 或 pg_write_server_files 角色。COPY FROM 需要 read-write 事务。

URL 协议

chdb_hook 仅在 URL 形式的 COPY 目标使用以下协议之一时才会执行:

URL 格式

URL 的格式因目标 (target) 而异。

File 表引擎

必须是 Postgres 服务器上的绝对路径,使用相对路径会报错。Postgres 用户必须根据实际需要属于 pg_read_server_files 或 pg_write_server_files 角色,Postgres 系统用户也必须相应地具备该文件的读或写权限。对于 COPY TO,如果该 路径不存在,chdb_hook 会创建所有缺失的父目录,因此必须具备相应的文件系统权限。示例:

HTTP

任何常规 HTTP URL,包括位于公有云存储中的 URL。对于 COPY TO, chdb_hook 会尝试通过 POST 将数据发送到该 URL。示例:

S3

S3 URL 可以采用 S3 URI 的形式
或者采用对象 URL 的形式:

GCS

GCS 的 URL 采用公网 URL 的形式:
或者使用 Cloud Storage URI,chdb_hook 会将其转换为公网 URL:

Azure Blob 存储

使用以账户名作为子域名的 blob.windows.net URL:
或者使用其他主机名:

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 支持的 formats 之一,包括 TSV、CSV、Parquet、Iceberg、JSON 等。 若省略该参数或将其设为 auto,chDB 会根据 URL 末尾的文件扩展名自动判断格式。

structure

行的 chDB 数据结构。由列名、[ClickHouse 数据类型] 和修饰符组成的列表。若省略该选项,chdb_hook 会将 Postgres 数据类型映射为大体合适的 ClickHouse 类型,详见 Postgres 到 chDB。若设置为 auto,chDB 会尝试推断类型。 示例:

access_key 和 access_secret

AWS 账户用户用于对请求进行身份验证的长期凭据。

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 秒) 。

调试

出错时,chdb_hook 的 COPY 命令会将其尝试执行的 chDB 查询包含在错误上下文中:
chdb_hook 对查询参数使用 {name:Type} 形式的占位符,以防范 SQL 注入漏洞,并尽量降低将凭据等敏感数据写入日志的风险。 不过,如果你为排查问题需要查看这些参数的内容,可临时将 Postgres 的 [log_min_messages] GUC 设置为 DEBUG1 或更高级别,让 chdb_hook 将查询和参数输出到 Postgres 日志 (绝不会发送给客户端) ,其显示形式如下:
请勿在单次调试会话之外持续将 [log_min_messages] 设为调试级别, 以免记录凭据等敏感信息;此外,PostgreSQL 自身也会输出 大量调试信息,很快就会把日志占满。

CREATE TABLE 重载

chdb_hook 同样对 CREATE TABLE 进行了挂接,使表能够从 URL 推导出自身的列,并加载其中的行。 若要创建结构由 URL 推导而来的表,请在 structure_from 选项中传入该 URL,并将列清单留空:
使用 copy_from 同时加载行和列:
仅当语句本身未指定任何列时,copy_from 才会推断列。 列清单、INHERITS 子句、OF 类型或分区都会定义列, 此时 copy_from 仅会复制:
两种方式都支持与 COPY 相同的 URL 协议和选项:credentials、format、压缩、timeout,乃至显式指定的结构均同样适用。Postgres 会保留其余的存储参数:
structure_from 和 copy_from 均无法与 IF NOT EXISTS 搭配使用。请使用 COPY 来加载已有的 relation。

限制

由于一些已知问题以及 Postgres 与 chDB 之间数据类型行为的差异,chdb_hook 存在以下限制:
  • 如果关系上存在适用于当前复制角色的 row-level security 策略,则无法对其执行 COPY。Postgres 会通过将 COPY TO 重写为查询来实施此类策略,而 chdb_hook 不支持这种方式。
  • ClickHouse 没有 NULL 数组,因此 COPY TO 会将 NULL 存储为空数组 ([]) 。
  • ClickHouse 将与 lseg、path 或 polygon 等价的类型表示为数组;因此这些类型的 NULL 值经 COPY TO 后同样会输出为空数组 ([]) 。
  • 若指定的结构未将该列定义为 Nullable,则 NULL 值在输出时会变成其默认值。请始终在结构中显式定义可为空的列,以避免这种转换。
  • 若开放 path 的最后一个点与第一个点相同,则会输出为闭合路径。
  • Protobuf 的 repeated 字段中不存在 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 会将包含空字符串或零的 Protobuf Nullable 字段读取为 NULL。 (chdb-io/chdb-core#152)
  • COPY TO 为 Parquet 时,会丢弃 Nullable Tuple 自身 null map 中的 NULL。 (ClickHouse/ClickHouse#112427)
  • Parquet、Arrow、ArrowStream、ORC、Avro、Protobuf、ProtobufList、MsgPack 和 BSONEachRow 格式没有与 Postgres time 或 chDB Time64 对应的类型。请在显式结构中将 time 列配置为 String,以保留其值。
  • Protobuf 输出会将 timestamp 值截断到秒。
  • Protobuf 输出不支持早于 1970-01-01 的日期。请在显式结构中将 time 列配置为 String,以保留其值。 (ClickHouse/ClickHouse#111860)
  • CSVWithNames 和 CSVWithNamesAndTypes 格式目前无法导入 NULL 的 box 或 circle 值。 (ClickHouse/ClickHouse#115523)

数据类型

COPY 会将 relation 的 Postgres 类型映射为 chDB 类型, 而 CREATE TABLE 则将 URL 的 chDB 类型映射为 Postgres 类型。

Postgres 到 chDB

若未显式指定 structure 选项,chdb_hook 会将 Postgres 类型映射为合理的 chDB 对应类型。如果这些类型不适合你的使用场景, 可通过 structure 将自动生成的类型覆盖为你所需的类型。 数组类型会映射为相应元素类型的 Array。ClickHouse 以列为单位约束可空性, 而 Postgres 以数组为单位约束,因此元素始终为 Nullable。 没有任何 Postgres 类型会映射为 Map 或 Tuple,但可以在 structure 中指定这两种类型。Map 可转换为键值对数组,Tuple 可转换为数组。 若需支持异构数据,请使用 text[]。

时间戳转换

在纯文本格式 (TSV、CSV 等) 中,COPY hook 会以 ISO-8601 格式 YYYY-MM-DDThh:mm:ssZ 输出 DateTime 和 DateTime64 值,且不受当前 datestyle 设置的影响。这样可以保证 timestamptz 值始终保持一致,即使导入这些值的 source 使用了不同的时区。在 structure 输出中改用其他类型,例如 Datetime64(3, 'America/Los_Angeles'),并不会改变输出的偏移量,但会改变 precision。 Timestamp TZ 示例: COPY hook 还会将 timestamp 值从会话时区转换为 UTC,从而确保输出值以该时区为基准。 当这些值被加载到新系统中时,新系统应将其转换为自身的本地时区。因此,时区不同则数值不同, 但按时区差换算后是等价的。 timezone 设置对时间戳 2026-08-28T12:00:00 的影响示例:

chDB 到 Postgres

chdb_hook 会将 DESCRIBE 返回的 ClickHouse 类型映射为以下 Postgres 类型: 本表中未列出的所有 chDB 类型都会引发错误,其中包括 Nested、Variant 和 Dynamic。可使用将它们映射为 String 的结构,从而以文本形式读取。 其中有几种类型,Postgres 支持的取值范围比 chDB 更窄;因此,当 Time 或 Time64 超过 24 小时,或 Date32 超出 Postgres 的日期范围时,复制操作会引发错误。

文本编码

chDB 以字节形式读取 String、FixedString、Enum 和 JSON,不保证其编码。将此类列复制到 text 或任何其他非二进制类型时,会按照数据库编码校验字节,并对无法表示的数据引发错误:
所有编码都会拒绝 NUL,因为 Postgres 无法将其存储在 text 中。 复制到 bytea 可以保留 chDB 写入时的原始字节。请显式为这些列命名,因为 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 占满 CPU 而影响 PostgreSQL。

版本策略

chdb_hook 的公开发行版遵循 Semantic Versioning。
  • 主版本号在 API 发生变更时递增
  • 次版本号在发生向后兼容的 SQL 变更时递增
  • 补丁版本号在仅涉及二进制文件的变更时递增
安装完成后,可通过 Postgres 18 的 pg_get_loaded_modules() 函数在 PostgreSQL 中查看版本。

作者

Copyright (c) 2026, ClickHouse
最后修改于 2026年9月26日