GitHub および PGXN にて公開された pg_clickhouse v0.11.0 と chdb extension v0.1.2 は、異種データベース間の互換性に対する私たちの徹底した注力をさらに推し進めるものです。こうした機能強化の多くは、ヘッダーオンリーの C ライブラリである clickhouse-c および pg-clickhouse-c に由来しています。今回のリリースに含まれる変更点から、注目の 3 つをご紹介します。
文字エンコーディングへの対応
まずは文字エンコーディングです。chdb 拡張機能の紹介記事向けのベンチマークを開発している過程で、pg-clickhouse-c がテキストカラムの文字エンコーディングを検証していないことに気付きました。同僚の Philip がすぐさまライブラリにパッチを適用し、テキストベースや JSON ベース1の型にデータベースのエンコーディングに違反するバイトが含まれている場合に例外を発生させるようにしました。
この修正は chdb v0.1.1 でリリースされましたが、不正なエンコーディングのデータを読み込む既存の外部テーブルでエラーが発生しないよう、pg_clickhouse への適用は少し見送っていました。pg_clickhouse v0.11.0 では、エンコーディングのエラーハンドラーを提供する新しい 外部サーバー オプション check_encoding が追加されています。指定できるオプションは次のとおりです。
fail(デフォルト): エラーを発生させますremove: 不正なバイトを削除しますreplace: UTF-8 エンコーディングの場合、不正なバイトを Unicode の置換文字 (``) に置き換えます。その他のエンコーディングではremoveと同じ動作になりますtruncate: 最初の不正なバイトの位置でテキストを切り捨てます
chdb_hook v0.1.2 でも、COPY コマンドと CREATE TABLE コマンドに同様のオプションが用意されています。どちらの拡張機能でも、以下のようなエラーへの対処が可能です。
ERROR: invalid byte sequence for encoding "UTF8": 0x81エラーを解消するには、pg_clickhouse サーバーの設定 check_encoding を変更します。最も可読性が高いのは replace です。
ALTER SERVER ch_server_name OPTIONS (ADD check_encoding 'replace');chdb_hook の場合は、COPY または CREATE TABLE のオプションとして渡します。
CREATE TABLE logs () WITH (
copy_from = 's3://chdb-lakedata-public/logs/logs-2026-08-26.csv',
format = 'CSVWithNames',
check_encoding = 'replace'
);UTF-8 エンコーディングのデータベースでは、不正なバイトが `` に置き換えられます。
try=# SELECT * FROM ch_table ORDER BY id;
id | name
----+---------
1 | Barrack
2 | Ale�y
3 | Leopold
4 | An�n�e他のデータベースエンコーディングでは、問題のある文字は単に削除されます。
try=# SELECT * FROM ch_table ORDER BY id;
id | name
----+---------
1 | Barrack
2 | Aley
3 | Leopold
4 | Ann一方でバイトレベルの互換性を維持する必要がある場合は、該当するカラムを代わりに bytea にマッピングする必要があります。
ALTER FOREIGN TABLE ch_table ALTER name TYPE bytea;これにより、バイナリデータがバイト単位でそのまま保持されます。
try=# SELECT * FROM ch_table ORDER BY id;
id | name
----+------------------
1 | \x4261727261636b
2 | \x416c650079
3 | \x4c656f706f6c64
4 | \x416e006e8165
(4 rows)ただし、テキストへの変換は失敗することにご注意ください。
インターバル型のサポート
ClickHouse は、IntervalNanosecond、IntervalHour、IntervalDay、IntervalYear など、多彩な インターバル型 をサポートしています。以前のリリースでは pg_clickhouse がこれらの型をサポートしておらず、それらを使用している ClickHouse テーブルを インポート しようとするとエラーが返されていました。
今後はその心配はありません。pg_clickhouse v0.11.0 および chdb_hook 0.1.2 では、これらの型が Postgres の interval カラムとしてインポートされます。たとえば、以下の duration カラムのように IntervalMillisecond を使用している ClickHouse テーブルがあるとします。
CREATE TABLE logs (
req_id Int64 NOT NULL,
start_at DateTime64(6, 'UTC') NOT NULL,
duration IntervalMillisecond NOT NULL,
resource Text NOT NULL,
method Enum8('GET' = 1, 'HEAD', 'POST', 'PUT', 'DELETE', 'PATCH') NOT NULL,
node_id Int64 NOT NULL,
response Int32 NOT NULL
) ENGINE = MergeTree
ORDER BY start_at;インポート時、pg_clickhouse は duration interval カラムを持つテーブルを作成します。
| カラム | 型 | Null 許容 |
|---|---|---|
| req_id | bigint | not null |
| start_at | timestamp(6) with time zone | not null |
| duration | interval | not null |
| resource | text | not null |
| method | text | not null |
| node_id | bigint | not null |
| response | integer | not null |
もちろんプッシュダウンも機能します。たとえば、昨日の終わりまでに「完了した」すべてのトランザクションをカウントしたいとしましょう。開始時刻に duration を加算するだけです。
try=# EXPLAIN (VERBOSE, COSTS OFF)
SELECT COUNT(*)
FROM logs
WHERE start_at + duration < date_trunc('day', now());
QUERY PLAN
-----------------------------------------------------------------------------------------------------------
Foreign Scan
Output: (count(*))
Relations: Aggregate on (logs)
Remote SQL: SELECT count(*) FROM "default".logs WHERE (((start_at + duration) < toStartOfDay(now64())))
(4 rows)EXPLAIN (VERBOSE) の出力を見ると、ClickHouse 上で実行されるリモートクエリが表示されており、ClickHouse 側で実行されるよう start_at + duration が明白にプッシュダウンされていることが分かります(当然ながら COUNT() 集約2も同様です)。
同じパターンが chdb_hook v0.1.2 にも適用され、chDB の インターバル型 を Postgres の interval 値としてインポートします。両拡張機能とも、インターバル型を代わりに bigint としてインポートすることも可能です。単に外部テーブルまたはコピー先テーブルを duration bigint で作成するだけで、あとは拡張機能が処理します。
ネスト構造のサポート強化
pg_clickhouse の HTTP ドライバーは v0.1 から、バイナリドライバーは v0.3 から JSON 型 をサポートしています。しかし、以下のように JSON プロパティアクセサーをプッシュダウンすることはできても、
SELECT * FROM things ORDER BY data ->> 'name';ClickHouse 側でエラーが返されていました。
DB::Exception: Data types Variant/Dynamic are not allowed in ORDER BY keys, because it can lead to unexpected results.
Consider using a subcolumn with a specific data type insteadこのエラーは ClickHouse の JSON オブジェクトの実装に起因しています。ClickHouse はソートを実行するために、JSON プロパティが存在しているかを把握しておく必要があります。ClickHouse 25.3 以降のパラメータ化されたサブカラムにより、プロパティの存在が保証されるようになりました。例を見てみましょう。
CREATE TABLE things (
id Int32 NOT NULL,
data JSON(
id UInt32,
name String,
size Enum('small', 'medium', 'large'),
stocked Bool
) NOT NULL
) ENGINE = MergeTree PARTITION BY id ORDER BY (id);以前は pg_clickhouse でパラメータ化された JSON カラムをインポートできませんでしたが、v0.11.0 (および chdb_hook v0.1.2) では単に jsonb (または json) にマッピングされるようになり、プロパティに対する ORDER BY が適切にプッシュダウンされるようになりました。
try=# SELECT * FROM things ORDER BY data ->> 'name';
id | data
----+-----------------------------------------------------------------
4 | {"id": 4, "name": "doodad", "size": "large", "stocked": false}
3 | {"id": 3, "name": "gizmo", "size": "medium", "stocked": true}
2 | {"id": 2, "name": "sprocket", "size": "small", "stocked": true}
1 | {"id": 1, "name": "widget", "size": "large", "stocked": true}
(4 rows)同様に、pg_clickhouse v0.11.0 と chdb_hook v0.1.2 では、次の例のようなフラット化されていない Nested 型 のサポートも改善されています。
CREATE TABLE visits(
visit_id UInt64,
user_id UInt64,
goals Nested(
serial UInt32,
order_id String
)
) ENGINE = MergeTree ORDER BY visit_id SETTINGS flatten_nested = 0;flatten_nested=0 は、(フィールドごとに別々の配列カラムを作成するのではなく)Tuple(serial UInt32, order_id String) の配列としてフォーマットされた単一の goals カラムを作成するよう ClickHouse に指示します。従来はどちらの拡張機能もこの構造をサポートしていませんでした。現在では 2 つのマッピング方法が提供されています。
デフォルトでは、IMPORT FOREIGN SCHEMA ならびに chdb_hook の COPY および CREATE TABLE コマンドは、フラット化されていない Nested カラムを 2 次元のテキスト配列にマッピングします。
| カラム | 型 |
|---|---|
| visit_id | numeric(20,0) |
| user_id | numeric(20,0) |
| goals | text[][] |
これにより、Nested 値の各要素が、各型の文字列表現の配列にマッピングされます。
try=# SELECT * FROM nest_bin.visits WHERE visit_id < 3 ORDER BY visit_id;
visit_id | user_id | goals
----------+---------+-----------------
1 | 1 | {{1,xx},{2,yy}}
(1 row)goals 配列には 2 つのテキスト値を持つ配列が 2 つ含まれており、1 つ目が serial、2 つ目が order_id に対応します。この構造はデータ型を犠牲にしてデータを保持しますが、pg_clickhouse テーブルへの INSERT では、ClickHouse へ挿入する前に型が適切に変換されます。
INSERT INTO visits
VALUES (2, 2, ARRAY[ ['3', 'aa'], ['4', 'bb'] ]);しかし、より良い方法があります。pg_clickhouse v0.11.0 では、順序、型、名前が完全に一致している限り、Nested 値をカスタムの 複合型 (composite type) にマッピングすることも可能です。goals に定義された Nested 型を例にとると、
Tuple(serial UInt32, order_id String)対応する名前と型を持つ複合型を作成し、それを外部テーブルに組み込むことができます。
CREATE TYPE goal_type AS (serial bigint, order_id text);
ALTER FOREIGN TABLE visits ALTER goals TYPE goal_type[];これで、Nested タプルが複合型へと変換されるようになります。
try=# SELECT * FROM nest_bin.visits WHERE visit_id < 3 ORDER BY visit_id;
visit_id | user_id | goals
----------+---------+---------------------
1 | 1 | {"(1,xx)","(2,yy)"}
2 | 2 | {"(3,aa)","(4,bb)"}当然ながら、この形式でデータを INSERT することも可能です。
INSERT INTO visits
VALUES (3, 3, ARRAY[row(5, 'jj'), row(6, 'zz')]::goal_type[]);同じパターンは chdb_hook v0.1.2 にも適用されます。ClickHouse や chDB からエクスポートされたネスト構造のデータを扱う際、Postgres のターゲットテーブルでは多次元の値配列、または適切に構造化された複合型の配列を使用できます。
CREATE TYPE event_status AS ENUM ('new', 'done');
CREATE TYPE event_point AS (x integer, y integer);
CREATE TYPE event_label AS (key text, value bigint);
CREATE TYPE event_item AS (id integer, name text);
CREATE TABLE events (
status event_status,
point event_point,
labels event_label[],
items event_item[]
);あとは、COPY クエリで適切なデータ型定義を使用するか(あるいは *WithNamesAndTypes フォーマットのいずれかに依存して)、データをインポートします。
COPY events FROM 's3://chdb-lakedata-public/examples/events.parquet' (
structure $$
status Enum8('new' = 1, 'done' = 2),
point Tuple(Int32, Int32),
labels Map(String, Int64),
items Array(Tuple(id Int32, name String))
$$
);ここではネスト型に Array() を使用しました。データがフラット化されていない(flatten_nested=0)構造で ClickHouse からエクスポートされている場合は、代わりに Nested を使用できます。
COPY events FROM 's3://chdb-lakedata-public/examples/events.parquet' (
structure $$
status Enum8('new' = 1, 'done' = 2),
point Tuple(Int32, Int32),
labels Map(String, Int64),
items Nested(id Int32, name String)
$$
);その他の更新内容
pg_clickhouse v0.11.0 には、言及しておく価値のある改善がほかにも多数含まれています。
-
目ざとい読者の方ならすでにお気づきのことでしょう。インターバルのマッピング に加え、大きな整数型が適切な Postgres の数値型にマッピングされるようになり、その他多くの ClickHouse データ型も適切な Postgres の対応型にマッピングされるようになりました。
ClickHouse PostgreSQL Int128 numeric(39,0) Int256 numeric(77,0) UInt64 numeric(20,0) UInt128 numeric(39,0) UInt256 numeric(78,0) BFloat16 float4 Time time Time64(P) time Tuple(...) text[] Map(K,V) text[][] LineString path MultiLineString path[] MultiPolygon polygon[][] Point point Ring polygon Polygon polygon[] 同じマッピングが chdb extension v0.1.2 にも適用されます。
-
v0.10.0 で非推奨となっていた従来の
clickhouse_raw_query()関数が削除されました。行を読み込むにはclickhouse_query(server, sql)を、行を返さないステートメントを実行するにはCALL clickhouse_perform(server, sql)を使用するようにコードを更新してください。 -
本リリースでは PostgreSQL 13 のサポートが削除されました。Postgres コミュニティによるサポートは 2025年9月に終了しています。
-
コミュニティからのコントリビューション により、PostgreSQL の
sha224()、sha256()、sha384()、sha512()関数に加え、pgcrypto 拡張機能のdigest()関数のサポート対象となる定数アルゴリズム呼び出しのプッシュダウンが追加されました。
バグ修正を含む詳細については、pg_clickhouse の変更履歴 および chdb の変更履歴 の全容をご確認ください。各拡張機能は以下の通常のリポジトリから入手できます。pg_clickhouse はこちらです。
chdb 拡張機能はこちらから入手できます。
Footnotes
ClickHouse Managed Postgres を今すぐ始める
ClickHouse Managed Postgres を自社のデータで試してみませんか? ClickHouse Cloud は数分で使い始めることができ、300 ドル分の無料クレジットも提供しています。
サインアップ


