> ## Documentation Index
> Fetch the complete documentation index at: https://clickhouse.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Snowflake Horizon catalog

> 通过 ClickHouse DataLakeCatalog 使用 Snowflake Horizon Catalog 查询和写入 Snowflake 托管的 Iceberg 表。

export const BetaBadge = ({link, galaxyTrack, galaxyEvent}) => {
  if (link) {
    return <a href={link} target="_blank" rel="noopener noreferrer" className="betaBadge" onClick={galaxyTrack && galaxyEvent ? galaxyOnClick(galaxyEvent) : undefined}>
                <span>Beta</span>
            </a>;
  }
  return <a href="https://clickhouse.com/docs/reference/settings/beta-and-experimental-features#beta-features" className="betaBadge">
            <span>Beta 版功能</span>
        </a>;
};

<BetaBadge />

ClickHouse 可通过 Horizon 提供的 Iceberg REST API (基于 Apache Polaris) 连接到 [Snowflake Horizon Catalog](https://docs.snowflake.com/en/user-guide/tables-iceberg-access-using-external-query-engine-snowflake-horizon)。
借助 `DataLakeCatalog` 数据库引擎以及 `catalog_type = 'horizon'`，您可以从 ClickHouse **读取和写入**由 Snowflake 管理的 Iceberg 表。

Horizon 与 Snowflake Open Catalog / 自托管 Polaris 相关，但并不相同：

|        | Open Catalog / Polaris (`catalog_type = 'rest'`) | Horizon (`catalog_type = 'horizon'`)                                                          |
| ------ | ------------------------------------------------ | --------------------------------------------------------------------------------------------- |
| 端点     | Open Catalog 或自托管 Polaris URI                    | `https://<org>-<account>.snowflakecomputing.com/polaris/api/catalog`                          |
| 仓库     | Polaris 目录 / 仓库名称                                | Snowflake **数据库**名称 (通常为大写)                                                                   |
| 身份验证范围 | `PRINCIPAL_ROLE:ALL` (通常使用)                      | `session:role:<ROLE>`                                                                         |
| 凭据     | `client_id:client_secret`                        | PAT 或密钥对 JWT (作为 `catalog_credential`；OAuth client\_secret 不按 ':' 拆分) ，或 Bearer `auth_header` |

<Note>
  此功能目前处于 Beta 阶段，请通过以下命令启用：
  `SET allow_experimental_database_iceberg = 1;`
  (或者，根据您的 ClickHouse 版本，使用 `SET allow_database_iceberg = 1;`。)
</Note>

<div id="prerequisites">
  ## 前置条件
</div>

* 拥有 Snowflake 托管的 Iceberg 表的 Snowflake 账户
* Horizon Iceberg REST 端点：
  `https://<organization>-<account>.snowflakecomputing.com/polaris/api/catalog`
* 对 Iceberg 表具有相应特权的 Snowflake 角色 (如需执行 INSERT，还应具有写入特权)
* 采用以下任一方式进行身份验证：
  * 编程访问令牌 (PAT)
  * 用于换取访问令牌的密钥对 JWT
  * 外部 OAuth 访问令牌 (作为 Bearer `auth_header`)
* 可供 ClickHouse 访问的对象存储 (建议使用下发的凭据)
* 支持 DataLakeCatalog Iceberg 的 ClickHouse

<div id="connecting">
  ## 创建连接
</div>

<div id="option-a-programmatic-access-token-recommended">
  ### 选项 A：程序化访问令牌 (推荐)
</div>

```sql theme={null}
SET allow_experimental_database_iceberg = 1;

CREATE DATABASE horizon_catalog
ENGINE = DataLakeCatalog('https://<org>-<account>.snowflakecomputing.com/polaris/api/catalog')
SETTINGS
    catalog_type = 'horizon',
    warehouse = 'ICEBERG_TEST_DB',
    catalog_credential = '<PAT>',
    auth_scope = 'session:role:DATA_ENGINEER',
    oauth_server_uri = 'https://<org>-<account>.snowflakecomputing.com/polaris/api/catalog/v1/oauth/tokens',
    vended_credentials = 1;
```

`warehouse` 必须是 Snowflake **数据库**名称 (而不是 Snowflake 虚拟仓库) 。
未加引号的 Snowflake 标识符均为大写。

<div id="option-b-pre-exchanged-bearer-access-token">
  ### 选项 B：预先换取的 Bearer 访问令牌
</div>

```sql theme={null}
CREATE DATABASE horizon_catalog
ENGINE = DataLakeCatalog('https://<org>-<account>.snowflakecomputing.com/polaris/api/catalog')
SETTINGS
    catalog_type = 'horizon',
    warehouse = 'ICEBERG_TEST_DB',
    auth_header = 'Authorization: Bearer <ACCESS_TOKEN>',
    vended_credentials = 1;
```

<div id="query">
  ## 查询 Iceberg 表
</div>

```sql theme={null}
USE horizon_catalog;
SHOW TABLES;

SELECT count(*) FROM `PUBLIC.test_table`;
SHOW CREATE TABLE `PUBLIC.test_table`;
```

<Note>
  命名空间 (schema) 和表通常以 `` `SCHEMA.table` `` 的形式引用，除非
  已启用 Experimental 表命名空间。
</Note>

<div id="write">
  ## 写入路径
</div>

拥有 INSERT/UPDATE/DELETE 权限 (创建表时还需 CREATE ICEBERG TABLE 权限) 的角色
可以让 ClickHouse 通过同一目录写入：

```sql theme={null}
-- Insert into an existing Snowflake-managed Iceberg table
INSERT INTO horizon_catalog.`PUBLIC.test_table`
SELECT
    number AS id,
    concat('name_', toString(number)) AS name
FROM numbers(100);

-- Create a new Iceberg table in the Horizon catalog (requires CREATE ICEBERG TABLE)
CREATE TABLE horizon_catalog.`PUBLIC.clickhouse_written`
(
    id Int64,
    name String
)
ENGINE = Iceberg;
```

具体的 `CREATE TABLE` 语法取决于您所用版本中 ClickHouse Iceberg / DataLakeCatalog 对 REST 目录写入的支持；Snowflake 的权限问题会表现为目录 HTTP 错误。

<div id="loading">
  ## 加载到 MergeTree
</div>

```sql theme={null}
CREATE TABLE my_clickhouse_table
(
    id Int64,
    name String
)
ENGINE = MergeTree
ORDER BY id;

INSERT INTO my_clickhouse_table
SELECT * FROM horizon_catalog.`PUBLIC.test_table`;
```
