概要
说明
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 秒) 。
encoding_check
指定在转换 chDB String 和 JSON 值时,如何处理数据库编码下的无效字符。可选值如下:
fail(默认) :引发错误remove:移除无效字节replace:在 UTF-8 编码下,将无效字节替换为 Unicode 替换字符 (�) ;对于其他编码, 其行为与remove相同truncate:在第一个无效字节处截断文本
调试
出错时,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,并将列清单留空 (注意:该公开数据文件包含 4100 万行) :
copy_from 同时加载行和列:
copy_from 才会推断列。
列清单、INHERITS 子句、OF 类型或分区都会定义列,
此时 copy_from 仅会复制:
copy_from 推断列时,会使用 DESCRIBE 返回的源 schema。
因此,Map、Tuple 和 Nested 值会以文本 array 列的形式加载,
而这些列无法体现其原始的 ClickHouse 类型。
两种方式都支持与 COPY 相同的 URL 协议和选项:凭证、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 不支持这种方式。 - 无法对带有
WHERE子句的 URL 执行COPY FROM。 - chDB 没有 NULL array,因此
COPY TO会将 NULL 存储为空 array ([]) 。 - chDB 将与
lseg、path或polygon等价的类型表示为 array;因此这些类型的 NULL 值经COPY TO后同样会输出为空 array ([]) 。 - ClickHouse 没有 NULL array,因此
COPY TO会将NULL存储为空 array ([]) 。 - ClickHouse 将与
lseg、path或polygon等价的类型表示为 array;因此这些类型的 NULL 值经COPY TO后同样会输出为空 array ([]) 。 - 若指定的结构未将该列定义为 Nullable,则 NULL 值在输出时会变成其默认值。请始终在结构中显式定义可为空的列,以避免这种转换。
- 若开放
path的最后一个点与第一个点相同,则会输出为闭合路径。 - Protobuf 的 repeated 字段中不存在 null,因此 array 中的 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)
数据类型
COPY 会将 relation 的 Postgres 类型映射为 chDB 类型, 而 CREATE TABLE 则将 URL 的 chDB 类型映射为 Postgres 类型。Postgres 到 chDB
在未显式指定 结构 选项时,chdb_hook 会将 Postgres 类型映射为合适的 chDB 等价类型。如果这些映射不符合您的使用场景,可指定 结构,用所需类型覆盖自动生成的类型。
此表中未列出的类型,例如
name、varchar、char、bit、timetz、money 以及枚举类型,均映射为 String。
array 类型映射为以映射后元素类型为元素的 Array。ClickHouse 按列约束可空性,而 Postgres 按 array 约束可空性,因此元素始终为 Nullable。
没有任何 Postgres 类型直接映射到 Map、Tuple 或 Nested,但可以通过 结构 或源文件指定这些类型。Tuple 可以读取到 text[] 中 (每个元组字段对应一个元素) ,也可以读取到匹配的 composite type 中以保留字段类型。Map 或 Nested 可以读取到 text[][] 中 (每个键值对或嵌套元组对应一个内层 array) ,也可以读取到匹配复合类型的 array 中。示例请参见手动类型映射。
时间戳转换
在纯文本格式 (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
对于已有的表,值会被转换为所声明的列类型。 其他标量类型会尽可能使用 PostgreSQL 的显式类型转换, array 元素则会被转换为所声明的元素类型。不支持的 转换以及超出范围的值会引发错误。 将 chDB 的Interval 类型映射到 smallint、integer 或 bigint,即可按其单位数量进行读取和
写入。例如,值为 3 的 IntervalDay 会映射
为整数 3。将 IntervalNanosecond 映射到 bigint 可保留
纳秒精度,而映射到 interval 则会截断至微秒。
chdb_hook 根据 DESCRIBE 返回的 ClickHouse 类型创建表时,会使用下表中的默认 Postgres 类型。额外的读取目标类型仅适用于
显式声明的列,并包含 PostgreSQL 显式类型转换之外的转换。空白单元格表示仍可使用上述类型转换。这些目标类型仅针对读取;
写入遵循另外的转换规则。
输入兼容的类型可以通过其 PostgreSQL input 函数读取字符串。
复合类型的字段必须一一匹配且顺序一致。若要将元组读取为 array,每个字段都必须能够转换为该 array 的元素类型,且任何字段本身都不能是 array。
以 array 形式读取时,
Map 的每个键值对对应一行,Nested 的每个嵌套行对应一行。若要将元组读取为 box,需提供两个点;读取为 circle 时,需提供一个点和半径;读取为 line 时,需提供三个系数。
本表中未列出的所有 chDB 类型都会引发错误,其中包括 Variant、Dynamic 和 AggregateFunction。可使用将它们映射为 String 的结构,从而以文本形式读取。
其中有几种类型,Postgres 支持的取值范围比 chDB 更窄;因此,当 Time 或 Time64 超过 24 小时,或 Date32 超出 Postgres 的日期范围时,复制操作会引发错误。
手动类型映射
列推断会将枚举映射为text,并将 Tuple、Map
和 Nested 值映射为文本 array。如需保留字段类型或限制枚举的取值,请先创建
PostgreSQL 枚举类型和复合类型,再使用这些类型声明列。
可通过 结构 指定 chDB 类型,也可使用 structure 'auto'
基于源数据 (而非 Postgres 表) 推断类型。例如,
可使用这些类型加载事件状态、坐标、标签以及
嵌套条目:
Map 值,先声明一个键字段,再声明一个值字段。每个
Tuple 对应一个复合值;每个 Map 键值对或 Nested 行对应
复合 array 中的一个元素。
如果在 structure 中显式指定 Nested,chDB 会将其拆分为多个
Array 列,每个字段对应一列。可以像上文示例那样使用 Array(Tuple(...)),将嵌套行读取到单个复合
array 列中;如果 chDB 源格式本身包含类型信息,也可以
使用 structure 'auto'。
文本编码
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 中查看版本。