概要
说明
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 可用:
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 的形式GCS
GCS 的 URL 采用公网 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的数字。**:递归匹配目录下的所有文件。
- https://clickhouse-public-datasets.s3.amazonaws.com/my-test-bucket-768/some_prefix/some_file_1.csv
- https://clickhouse-public-datasets.s3.amazonaws.com/my-test-bucket-768/some_prefix/some_file_2.csv
- https://clickhouse-public-datasets.s3.amazonaws.com/my-test-bucket-768/some_prefix/some_file_3.csv
- https://clickhouse-public-datasets.s3.amazonaws.com/my-test-bucket-768/another_prefix/some_file_1.csv
- https://clickhouse-public-datasets.s3.amazonaws.com/my-test-bucket-768/another_prefix/some_file_2.csv
- https://clickhouse-public-datasets.s3.amazonaws.com/my-test-bucket-768/another_prefix/some_file_3.csv
{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 账户用户用于对请求进行身份验证的长期凭据。
- 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(默认)nonegzip或gzbrotli或brxz或LZMAzstd或zstlz4bz2snappy
timeout
请求超时时间 (毫秒) 。适用于 HTTP、S3、GCS 和 Azure URL。
默认值为 30000 (30 秒) 。
调试
出错时,chdb_hook 的COPY 命令会将其尝试执行的 chDB 查询包含在错误上下文中:
{name:Type} 形式的占位符,以防范 SQL 注入漏洞,并尽量降低将凭据等敏感数据写入日志的风险。
不过,如果你为排查问题需要查看这些参数的内容,可临时将 Postgres 的 [log_min_messages] GUC 设置为 DEBUG1 或更高级别,让 chdb_hook 将查询和参数输出到 Postgres 日志 (绝不会发送给客户端) ,其显示形式如下:
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会将包含空字符串或零的 ProtobufNullable字段读取为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或 chDBTime64对应的类型。请在显式结构中将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 或任何其他非二进制类型时,会按照数据库编码校验字节,并对无法表示的数据引发错误:
text 中。
复制到 bytea 可以保留 chDB 写入时的原始字节。请显式为这些列命名,因为 CREATE TABLE 会为这些类型推导出 text:
FixedString(N) 会使用 NUL 字节填充长度不足的值。复制到 text 时会去掉尾随的 NUL,而 bytea 会保留全部 N 个字节。
设置
chdb_hook.max_memory
max_memory_usage。需要 超级用户特权。可使用整数
表示兆字节数,或使用以下内存单位之一:
B(字节)kB(千字节)MB(兆字节)GB(吉字节)TB(太字节)
0,即不限制内存。
chdb_hook.max_threads
max_threads 参数。需要 超级用户特权。默认值为 0,即由 chDB 自行决定该值。
强烈建议在执行大规模 COPY 之前设置 chdb_hook.max_threads,以免 chDB 占满 CPU 资源,从而影响 PostgreSQL。
chdb_hook.max_parsing_threads
max_parsing_threads 设置。需要超级用户特权。默认为 0,即由 chDB 自行决定该值。
建议在 COPY 大量数据之前先设置 chdb_hook.max_parsing_threads,以避免 chDB 占满 CPU 而影响 PostgreSQL。
版本策略
chdb_hook 的公开发行版遵循 Semantic Versioning。- 主版本号在 API 发生变更时递增
- 次版本号在发生向后兼容的 SQL 变更时递增
- 补丁版本号在仅涉及二进制文件的变更时递增
pg_get_loaded_modules() 函数在 PostgreSQL 中查看版本。