---
title: "pg_clickhouse と chdb のアップデート: エンコーディング、ネスト、データ型"
date: "2026-10-01T03:03:55.259Z"
author: "David Wheeler"
category: "Product"
excerpt: "pg_clickhouse と chdb 拡張機能の最新リリースでは、文字エンコーディング、interval の処理、ネストされたデータ、JSON、ClickHouse と Postgres 間の型マッピングが改善されました。"
---

# pg_clickhouse と chdb のアップデート: エンコーディング、ネスト、データ型

GitHub および PGXN にて公開された [pg_clickhouse](https://clickhouse.com/docs/ja/products/managed-postgres/extensions/pg_clickhouse/introduction) v0.11.0 と [chdb extension](https://clickhouse.com/docs/ja/products/managed-postgres/extensions/chdb/introduction) v0.1.2 は、異種データベース間の互換性に対する私たちの徹底した注力をさらに推し進めるものです。こうした機能強化の多くは、ヘッダーオンリーの C ライブラリである [clickhouse-c](https://github.com/serprex/clickhouse-c) および [pg-clickhouse-c](https://github.com/ClickHouse/pg-clickhouse-c/) に由来しています。今回のリリースに含まれる変更点から、注目の 3 つをご紹介します。

## 文字エンコーディングへの対応 {#what_a_character}

まずは文字エンコーディングです。[chdb 拡張機能の紹介記事](https://clickhouse.com/ja/blog/introducing-chdb-postgres-jp)向けのベンチマークを開発している過程で、[pg-clickhouse-c](https://github.com/ClickHouse/pg-clickhouse-c/) がテキストカラムの文字エンコーディングを検証していないことに気付きました。同僚の [Philip](https://clickhouse.com/authors/philip-dube) がすぐさまライブラリにパッチを適用し、テキストベースや JSON ベース[^json]の型にデータベースのエンコーディングに違反するバイトが含まれている場合に例外を発生させるようにしました。

この修正は [chdb v0.1.1](https://pgxn.org/dist/chdb/0.1.1/) でリリースされましたが、不正なエンコーディングのデータを読み込む既存の外部テーブルでエラーが発生しないよう、pg_clickhouse への適用は少し見送っていました。[pg_clickhouse](https://clickhouse.com/docs/ja/products/managed-postgres/extensions/pg_clickhouse/introduction) v0.11.0 では、エンコーディングのエラーハンドラーを提供する新しい [外部サーバー](https://clickhouse.com/docs/ja/products/managed-postgres/extensions/pg_clickhouse/reference#create-server) オプション `check_encoding` が追加されています。指定できるオプションは次のとおりです。

*   `fail` (デフォルト): エラーを発生させます
*   `remove`: 不正なバイトを削除します
*   `replace`: UTF-8 エンコーディングの場合、不正なバイトを Unicode の置換文字 (``) に置き換えます。その他のエンコーディングでは `remove` と同じ動作になります
*   `truncate`: 最初の不正なバイトの位置でテキストを切り捨てます

[chdb_hook](https://clickhouse.com/docs/ja/products/managed-postgres/extensions/chdb/chdb_hook) v0.1.2 でも、[COPY](https://clickhouse.com/docs/ja/products/managed-postgres/extensions/chdb/chdb_hook#copy-overloading) コマンドと [CREATE TABLE](https://clickhouse.com/docs/ja/products/managed-postgres/extensions/chdb/chdb_hook#create-table-overloading) コマンドに同様のオプションが用意されています。どちらの拡張機能でも、以下のようなエラーへの対処が可能です。

```shell
ERROR:  invalid byte sequence for encoding "UTF8": 0x81
```

エラーを解消するには、pg_clickhouse サーバーの設定 `check_encoding` を変更します。最も可読性が高いのは `replace` です。

<pre><code type='click-ui' language='sql'>
ALTER SERVER ch_server_name OPTIONS (ADD check_encoding 'replace');
</code></pre>

chdb_hook の場合は、[COPY](https://clickhouse.com/docs/ja/products/managed-postgres/extensions/chdb/chdb_hook#copy-overloading) または [CREATE TABLE](https://clickhouse.com/docs/ja/products/managed-postgres/extensions/chdb/chdb_hook#create-table-overloading) のオプションとして渡します。

<pre><code type='click-ui' language='sql'>
CREATE TABLE logs () WITH (
    copy_from      = 's3://chdb-lakedata-public/logs/logs-2026-08-26.csv',
    format         = 'CSVWithNames',
    check_encoding = 'replace'
);
</code></pre>

UTF-8 エンコーディングのデータベースでは、不正なバイトが `` に置き換えられます。

```shell
try=# SELECT * FROM ch_table ORDER BY id;
 id |   name
----+---------
  1 | Barrack
  2 | Ale�y
  3 | Leopold
  4 | An�n�e
```

他のデータベースエンコーディングでは、問題のある文字は単に削除されます。

```shell
try=# SELECT * FROM ch_table ORDER BY id;
 id |   name
----+---------
  1 | Barrack
  2 | Aley
  3 | Leopold
  4 | Ann
```

一方でバイトレベルの互換性を維持する必要がある場合は、該当するカラムを代わりに `bytea` にマッピングする必要があります。

<pre><code type='click-ui' language='sql'>
ALTER FOREIGN TABLE ch_table ALTER name TYPE bytea;
</code></pre>

これにより、バイナリデータがバイト単位でそのまま保持されます。

```shell
try=# SELECT * FROM ch_table ORDER BY id;
id |      name
----+------------------
  1 | \x4261727261636b
  2 | \x416c650079
  3 | \x4c656f706f6c64
  4 | \x416e006e8165
(4 rows)
```

ただし、テキストへの変換は失敗することにご注意ください。

## インターバル型のサポート {#intervalid}

ClickHouse は、`IntervalNanosecond`、`IntervalHour`、`IntervalDay`、`IntervalYear` など、多彩な [インターバル型](https://clickhouse.com/docs/ja/reference/data-types/special-data-types/interval) をサポートしています。以前のリリースでは pg_clickhouse がこれらの型をサポートしておらず、それらを使用している ClickHouse テーブルを [インポート](https://clickhouse.com/docs/ja/products/managed-postgres/extensions/pg_clickhouse/reference#import-foreign-schema) しようとするとエラーが返されていました。

今後はその心配はありません。[pg_clickhouse](https://clickhouse.com/docs/ja/products/managed-postgres/extensions/pg_clickhouse/introduction) v0.11.0 および [chdb_hook](https://clickhouse.com/docs/ja/products/managed-postgres/extensions/chdb/chdb_hook) 0.1.2 では、これらの型が Postgres の `interval` カラムとしてインポートされます。たとえば、以下の `duration` カラムのように `IntervalMillisecond` を使用している ClickHouse テーブルがあるとします。

<pre><code type='click-ui' language='sql'>
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;
</code></pre>

インポート時、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 を加算するだけです。

```shell
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()` 集約[^ival_agg]も同様です)。

同じパターンが [chdb_hook](https://clickhouse.com/docs/ja/products/managed-postgres/extensions/chdb/chdb_hook) v0.1.2 にも適用され、chDB の [インターバル型](https://clickhouse.com/docs/ja/reference/data-types/special-data-types/interval) を Postgres の `interval` 値としてインポートします。両拡張機能とも、インターバル型を代わりに `bigint` としてインポートすることも可能です。単に外部テーブルまたはコピー先テーブルを `duration bigint` で作成するだけで、あとは拡張機能が処理します。

## ネスト構造のサポート強化 {#nesting_instinct}

pg_clickhouse の HTTP ドライバーは v0.1 から、バイナリドライバーは v0.3 から [JSON 型](https://clickhouse.com/docs/ja/reference/data-types/newjson) をサポートしています。しかし、以下のように JSON プロパティアクセサーをプッシュダウンすることはできても、

<pre><code type='click-ui' language='sql'>
SELECT * FROM things ORDER BY data -&gt;&gt; 'name';
</code></pre>

ClickHouse 側でエラーが返されていました。

```shell
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 以降のパラメータ化されたサブカラムにより、プロパティの存在が保証されるようになりました。例を見てみましょう。

<pre><code type='click-ui' language='sql'>
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);
</code></pre>

以前は [pg_clickhouse](https://clickhouse.com/docs/ja/products/managed-postgres/extensions/pg_clickhouse/introduction) でパラメータ化された JSON カラムをインポートできませんでしたが、v0.11.0 (および [chdb_hook](https://clickhouse.com/docs/ja/products/managed-postgres/extensions/chdb/chdb_hook) v0.1.2) では単に jsonb (または json) にマッピングされるようになり、プロパティに対する `ORDER BY` が適切にプッシュダウンされるようになりました。

```shell
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](https://clickhouse.com/docs/ja/products/managed-postgres/extensions/pg_clickhouse/introduction) v0.11.0 と [chdb_hook](https://clickhouse.com/docs/ja/products/managed-postgres/extensions/chdb/chdb_hook) v0.1.2 では、次の例のようなフラット化されていない [Nested 型](https://clickhouse.com/docs/ja/reference/data-types/nested-data-structures) のサポートも改善されています。

<pre><code type='click-ui' language='sql'>
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;
</code></pre>

[`flatten_nested=0`](https://clickhouse.com/docs/ja/reference/settings/session-settings/other#flatten_nested) は、(フィールドごとに別々の配列カラムを作成するのではなく)`Tuple(serial UInt32, order_id String)` の配列としてフォーマットされた単一の `goals` カラムを作成するよう ClickHouse に指示します。従来はどちらの拡張機能もこの構造をサポートしていませんでした。現在では 2 つのマッピング方法が提供されています。

デフォルトでは、[IMPORT FOREIGN SCHEMA](https://clickhouse.com/docs/ja/products/managed-postgres/extensions/pg_clickhouse/reference#import-foreign-schema) ならびに chdb_hook の [COPY](https://clickhouse.com/docs/ja/products/managed-postgres/extensions/chdb/chdb_hook#copy-overloading) および [CREATE TABLE](https://clickhouse.com/docs/ja/products/managed-postgres/extensions/chdb/chdb_hook#create-table-overloading) コマンドは、フラット化されていない Nested カラムを 2 次元のテキスト配列にマッピングします。

|  カラム  |     型      |
| -------- | ------------- |
| visit_id | numeric(20,0) |
| user_id  | numeric(20,0) |
| goals    | text[][]      |

これにより、Nested 値の各要素が、各型の文字列表現の配列にマッピングされます。

```shell
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 へ挿入する前に型が適切に変換されます。

<pre><code type='click-ui' language='sql'>
INSERT INTO visits
VALUES (2, 2, ARRAY[ ['3', 'aa'], ['4', 'bb'] ]);
</code></pre>

しかし、より良い方法があります。[pg_clickhouse](https://clickhouse.com/docs/ja/products/managed-postgres/extensions/pg_clickhouse/introduction) v0.11.0 では、順序、型、名前が完全に一致している限り、Nested 値をカスタムの [複合型 (composite type)](https://www.postgresql.org/docs/current/rowtypes.html) にマッピングすることも可能です。`goals` に定義された Nested 型を例にとると、

```shell
Tuple(serial UInt32, order_id String)
```

対応する名前と型を持つ複合型を作成し、それを外部テーブルに組み込むことができます。

<pre><code type='click-ui' language='sql'>
CREATE TYPE goal_type AS (serial bigint, order_id text);
ALTER FOREIGN TABLE visits ALTER goals TYPE goal_type[];
</code></pre>

これで、Nested タプルが複合型へと変換されるようになります。

```shell
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 することも可能です。

<pre><code type='click-ui' language='sql'>
INSERT INTO visits
VALUES (3, 3, ARRAY[row(5, 'jj'), row(6, 'zz')]::goal_type[]);
</code></pre>

同じパターンは [chdb_hook](https://clickhouse.com/docs/ja/products/managed-postgres/extensions/chdb/chdb_hook) v0.1.2 にも適用されます。ClickHouse や chDB からエクスポートされたネスト構造のデータを扱う際、Postgres のターゲットテーブルでは多次元の値配列、または適切に構造化された複合型の配列を使用できます。

<pre><code type='click-ui' language='sql'>
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[]
);
</code></pre>

あとは、`COPY` クエリで適切なデータ型定義を使用するか(あるいは `*WithNamesAndTypes` フォーマットのいずれかに依存して)、データをインポートします。

<pre><code type='click-ui' language='sql'>
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))
    $$
);
</code></pre>

ここではネスト型に `Array()` を使用しました。データがフラット化されていない([`flatten_nested=0`](https://clickhouse.com/docs/ja/reference/settings/session-settings/other#flatten_nested))構造で ClickHouse からエクスポートされている場合は、代わりに `Nested` を使用できます。

<pre><code type='click-ui' language='sql'>
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)
    $$
);
</code></pre>

## その他の更新内容 {#odds_and_ends}

[pg_clickhouse](https://clickhouse.com/docs/ja/products/managed-postgres/extensions/pg_clickhouse/introduction) v0.11.0 には、言及しておく価値のある改善がほかにも多数含まれています。

*   目ざとい読者の方ならすでにお気づきのことでしょう。[インターバルのマッピング](#intervalid) に加え、大きな整数型が適切な 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](https://clickhouse.com/docs/ja/products/managed-postgres/extensions/chdb/introduction) v0.1.2 にも適用されます。

*   v0.10.0 で非推奨となっていた従来の `clickhouse_raw_query()` 関数が削除されました。行を読み込むには `clickhouse_query(server, sql)` を、行を返さないステートメントを実行するには `CALL clickhouse_perform(server, sql)` を使用するようにコードを更新してください。

*   本リリースでは PostgreSQL 13 のサポートが削除されました。Postgres コミュニティによるサポートは 2025年9月に終了しています。

*   [コミュニティからのコントリビューション](https://github.com/ClickHouse/pg_clickhouse/pull/360) により、PostgreSQL の `sha224()`、`sha256()`、`sha384()`、`sha512()` 関数に加え、[pgcrypto](https://www.postgresql.org/docs/current/pgcrypto.html) 拡張機能の `digest()` 関数のサポート対象となる定数アルゴリズム呼び出しのプッシュダウンが追加されました。

バグ修正を含む詳細については、[pg_clickhouse の変更履歴](https://github.com/ClickHouse/pg_clickhouse/releases/tag/v0.11.0) および [chdb の変更履歴](https://github.com/ClickHouse/pg_chdb/releases/tag/v0.1.2) の全容をご確認ください。各拡張機能は以下の通常のリポジトリから入手できます。pg_clickhouse はこちらです。

*   [PGXN](https://pgxn.org/dist/pg_clickhouse/)
*   [GitHub](https://github.com/ClickHouse/pg_clickhouse/releases/tag/v0.11.0)
*   [Docker](https://github.com/ClickHouse/pg_clickhouse/pkgs/container/pg_clickhouse)

chdb 拡張機能はこちらから入手できます。

*   [PGXN](https://pgxn.org/dist/chdb/)
*   [GitHub](https://github.com/ClickHouse/pg_chdb/releases/tag/v0.1.2)

[^json]: もちろん、JSON は定義上 [UTF-8 が推奨](https://www.rfc-editor.org/info/rfc7159/#section-8.1) されますが、例外もあります。[Postgres 内の JSON データ](https://www.postgresql.org/docs/current/datatype-json.html) は、常にデータベースのエンコーディングを使用しなければなりません。
[^ival_agg]: 残念ながら、ClickHouse のインターバル型自体はまだ集約をサポートしていないため、たとえば `avg(duration)` は失敗します。しかし、26.10 における [`avg`](https://github.com/ClickHouse/ClickHouse/pull/121458) および [`sum`](https://github.com/ClickHouse/ClickHouse/pull/121600) のサポートにご期待ください。

---

## ClickHouse Managed Postgres を今すぐ始める

ClickHouse Managed Postgres を自社のデータで試してみませんか？ ClickHouse Cloud は数分で使い始めることができ、300 ドル分の無料クレジットも提供しています。

[サインアップ](https://console.clickhouse.cloud/signUp?intent=pg&loc=blog-cta-2475-clickhouse-managed-postgres&utm_blogctaid=2475)

---