dbx OceanBase Oracle 分区 DDL 验证指南:从自动化重放脚本到 UI 存储属性偏好
【免费下载链接】dbx15MB,轻量级跨平台数据库客户端、数据库管理工具。支持 MySQL、PostgreSQL、SQLite、Redis、MongoDB、DuckDB、ClickHouse、SQL Server 等。15MB, lightweight, cross-platform database client. Supports MySQL, PostgreSQL, SQLite, Redis, MongoDB, DuckDB, ClickHouse, SQL Server and more.项目地址: https://gitcode.com/t8y2/dbx
本指南围绕开源数据库客户端 dbx 中 OceanBase Oracle 模式(Oracle 兼容租户)的分区表 DDL 验证方案展开,涵盖构建与运行自动化验证脚本、JSON-RPC 驱动下的分区元数据重放与语义检查、以及桌面端 "Omit storage attributes"(省略存储属性)偏好的 UI 验证。读完本文,你将掌握如何完整复现分区 DDL 的端到端验证流程,理解 dbx 底层如何生成分区 DDL 与读取分区信息,并能自行扩展验证用例。
一、为什么要验证 OceanBase Oracle 分区 DDL
OceanBase 的 Oracle 兼容模式在语法上与原生 Oracle 高度一致,但分区表的存储选项、元数据视图与DBMS_METADATA支持程度存在版本差异。dbx 作为数据库客户端,需要保证:
- 在对象树中正确展示分区表的 Partitions / Subpartitions 分组;
- 生成可再次执行的分区 DDL(含分区子句、约束、LOCAL 索引、默认值与注释);
- 提供 "省略存储属性" 选项,导出的 DDL 可跨环境重放,而不丢失语义。
agents/drivers/oceanbase-oracle/scripts/README.md描述了一套针对以上目标的验证方案,其配套脚本与实现源码位于:
- 验证脚本
- Agent 实现
- DDL 存储属性偏好实现
二、构建 OceanBase Oracle Agent(JDK 21)
验证脚本通过 JSON-RPC 启动一个已构建的 Agent 进程,因此第一步是从仓库根目录用 JDK 21 构建并打包。官方命令如下:
./agents/gradlew -p agents :common:test :oceanbase-oracle:test :oceanbase-oracle:shadowJar该命令依次执行:
| 任务 | 作用 |
|---|---|
:common:test | 构建并测试 Agent 公共模块(agents/common/src) |
:oceanbase-oracle:test | 运行 OceanBase Oracle Agent 的 JUnit 单元测试(OceanBaseOracleAgentTest.java) |
:oceanbase-oracle:shadowJar | 打出包含全部依赖的 fat jar,产物为agents/drivers/oceanbase-oracle/build/libs/dbx-agent-oceanbase-oracle.jar |
单元测试层已经覆盖了若干关键行为,例如 JDBC URL 构造(默认追加compatibleOjdbcVersion=8)、查询超时到 OceanBase 会话变量ob_query_timeout(微秒)的换算,以及分区键顺序与字典序保持等,可作为构建期的事实基线。
三、环境变量与一次性 Oracle 租户准备
运行脚本前需要设置以下环境变量:
| 环境变量 | 含义 | 默认值/要求 |
|---|---|---|
OB_HOST | OceanBase 主机地址 | 必填 |
OB_PORT | 连接端口 | 默认2881(脚本内process.env.OB_PORT ?? 2881) |
OB_TENANT | 租户名 | 必填 |
OB_PASSWORD | 一次性 Oracle 租户中SYS用户的密码 | 必填 |
注意事项:
OB_PASSWORD必须属于一个一次性(disposable)Oracle 租户——脚本会在该租户下创建、重放和删除测试对象,切勿使用生产租户;- 脚本以
user@tenant形式构造连接用户名(见 verify-partition-ddl.ts),user分别为SYS与三个测试用户; - Agent 内置 profile 的默认端口为 2883(对应 OceanBase 常部署的 OBProxy 端口,见 OceanBaseOracleAgent.java),而验证脚本显式覆盖为 2881(observer 直连默认端口),两种端口均可根据实际拓扑调整。
四、运行分区 DDL 验证脚本
构建完成后,在仓库根目录执行:
pnpm exec tsx --tsconfig apps/desktop/tsconfig.json agents/drivers/oceanbase-oracle/scripts/verify-partition-ddl.ts命令拆解:
pnpm exec tsx:以 tsx 运行时直接执行 TypeScript 脚本,无需单独编译;--tsconfig apps/desktop/tsconfig.json:复用桌面端 TypeScript 配置,使脚本能够解析对apps/desktop/src前端源码的导入(见下文);- 脚本入口为 verify-partition-ddl.ts。
脚本通过子进程启动 Agent jar,并基于 stdio 之上的 JSON-RPC 2.0 协议与其通信({"jsonrpc":"2.0","id":...,"method":...,"params":...}每行一条),单次请求超时为 60 秒(verify-partition-ddl.ts)。
4.1 隔离 Schema 与测试夹具
脚本会创建三个相互隔离、以随机后缀命名的 Schema(避免并行运行时互相污染):
DBX7055_S<8位随机大写>:源 Schema,用于建表并采集 DDL/分区元数据;DBX7055_L<8位随机大写>:逻辑重放目标,重放"省略存储属性"后的简化 DDL;DBX7055_P<8位随机大写>:物理重放目标,重放包含存储属性的完整 DDL。
测试夹具共8 张表,覆盖了分区 DDL 的主要形态:
| 表名 | 形态 | 覆盖点 |
|---|---|---|
PARENT | 普通表 + 主键 | 外键引用目标 |
RANGE_LIST | RANGE 分区 + LIST 子分区 | 复合分区、默认值含存储关键字文本、PK/CHECK 约束 |
RANGE_T | RANGE 复合分区键(ID,D) | 多列分区键、多列 MAXVALUE 边界 |
LIST_T | LIST 分区 | 列表值中含'PCTFREE = 20'文本 |
HASH_T | HASH 分区PARTITIONS 4 | 分区数量断言 |
CHILD | 普通表 + 外键 | 外键语义重放验证 |
Mixed Table | 带引号标识符 | 列名恰为"PCTFREE"、默认值含引号转义 |
TEMP_T | 全局临时表(ON COMMIT PRESERVE ROWS) | 内部会话索引不得被导出 |
除此之外,源 Schema 还创建了一个 LOCAL 索引C_LOCAL ON RANGE_LIST(NOTE) LOCAL,以及表注释table's PCTFREE = 20和列注释note ; ) COMPRESS FOR ARCHIVE——这些文本刻意包含与存储选项关键字相似的子串,用于验证"清理存储选项"不会误伤字符串字面量与注释。
4.2 采集、重放与逐项断言
对每张表,脚本执行以下流程:
- 以
source会话调用get_table_ddl获取完整 DDL,调用list_partitions、list_subpartitions获取分区/子分区元数据(verify-partition-ddl.ts); - 用
applyDdlStoragePreference(ddl, "oceanbase-oracle")生成简化 DDL,并断言applyDdlStoragePreference(ddl, "oceanbase-oracle", false) === ddl(关闭选项时原样返回)、简化结果不含REPLICA_NUM =; - 分别把简化 DDL 重放到
logical会话、完整 DDL 重放到physical会话:先将源 Schema 限定名替换为目标 Schema,再用splitSqlStatementRanges(sqlStatementRanges.ts)切分语句逐条执行; - 重放后断言
list_partitions、list_subpartitions、get_columns结果与源 Schema 完全一致(assert.deepEqual),从而证明"省略存储属性"不影响分区结构与列元数据。
分区/子分区数量断言如下([分区数, 子分区数]):
| 表 | 断言 |
|---|---|
RANGE_LIST | [2, 4](2 个分区 × 各 2 个子分区) |
RANGE_T | [2, 0] |
LIST_T | [2, 0] |
HASH_T | [4, 0] |
随后,三个会话还会执行一组语义检查(verify-partition-ddl.ts):
- 向
RANGE_LIST插入落在P1/PM分区内的合法行成功,插入分区边界外(ID = -1)的行被拒绝; - 插入主键重复行被拒绝(PK 强制);
- 向
PARENT插入父行后,CHILD可插入合法外键行,插入指向不存在父行的孤儿行((2, 999))被拒绝(FK 强制); - 查询
USER_TAB_COMMENTS确认注释原样保留(table's PCTFREE = 20); - 查询
USER_PART_INDEXES确认 LOCAL 索引C_LOCAL的LOCALITY为LOCAL。
4.3 证据产物与清理
每个 DDL 文件名(去除引号后)对应两个文件,加上汇总报告,全部写入:
agents/drivers/oceanbase-oracle/build/partition-ddl-evidence/ ├── <Table>.full.sql # 完整 DDL(含存储属性) ├── <Table>.logical.sql # 省略存储属性后的逻辑 DDL └── verification.json # 汇总报告(schema 名、逐表断言、语义检查说明)可通过OB_TEST_OUTPUT环境变量覆盖输出目录。verification.json记录了三个 Schema 的确切名称、每张表的partitions/subpartitions数量与重放结果,方便人工在 dbx 中打开这些 Schema 做界面复核。
清理方式:断开这些测试 Schema 的会话后,使用报告中的确切名称执行
DROP USER "<reported name>" CASCADE需要注意:任何证据文件中都不会写入连接凭据,可放心归档或提交。
五、源码级原理:分区元数据与 DDL 生成
5.1 分区信息读取
Agent 的listPartitions/listSubpartitions最终都进入queryPartitions(OceanBaseOracleAgent.java),数据来源为 Oracle 兼容字典视图:
| 信息 | 数据源 |
|---|---|
| 分区键列 | ALL_PART_KEY_COLUMNS/ALL_SUBPART_KEY_COLUMNS(按COLUMN_POSITION排序) |
| 分区名、位置、边界值、分区类型 | ALL_TAB_PARTITIONS/ALL_TAB_SUBPARTITIONSJOINALL_PART_TABLES |
分区键列会以双引号括起并转义内嵌引号(如测试中的"A""B"),边界值HIGH_VALUE原样保留(如100, 'East'、MAXVALUE, MAXVALUE),HASH 子分区的边界值为空。单元测试 OceanBaseOracleAgentTest.java 明确验证了分区按字典序返回、复合键顺序保持以及 NULL HASH 边界不抛错。
5.2 分区 DDL 的拼装策略
getTableDdl(OceanBaseOracleAgent.java)的组装过程如下:
- 调用
DBMS_METADATA.GET_DDL('TABLE', name, owner)获取基础 DDL——约束与分区子句已包含在内; - OceanBase 4.2.5 在跨 Schema 场景下会省略 CREATE TABLE 的属主,Agent 通过正则将
CREATE [GLOBAL TEMPORARY] TABLE "name"修正为CREATE ... "owner"."name"; - 查询
ALL_INDEXES找出非约束索引,逐一追加GET_DDL('INDEX', ...)结果。查询同时排除两类索引:- 与
ALL_CONSTRAINTS中P/U约束关联的索引(已随约束输出); - 全局临时表内部的会话索引(
IDX_FOR_HEAP_GTT_<表名>且包含SYS_SESSION_ID列)——这正是 README 强调的 "internal session index must not be exported" 的源码依据;
- 与
- 追加表注释
COMMENT ON TABLE与非空列注释COMMENT ON COLUMN(单引号做''转义); - 尽力追加对象授权(
GRANT ... ON ... TO ...),无权限时静默跳过。
其中索引追加使用的是DdlBuilder.appendTrailingSql,保证多个语句以分号正确分隔。
5.3 DBMS_METADATA 的版本依赖与回退
README 明确说明验证基于DBMS_METADATA.GET_DDL,而该函数在 OceanBase 4.2.5 中TABLE 结果不包含独立索引与注释,因此 Agent 采用"单独追加"策略。此外,不同 OceanBase 版本与租户权限对DBMS_METADATA的覆盖度不一,getObjectSource在DBMS_METADATA不可用时(如视图、过程、函数、包等对象)会回退到ALL_VIEWS/ALL_SOURCE字典视图拼装可编辑源码(OceanBaseOracleAgent.java)。
六、UI 验证:Omit storage attributes(省略存储属性)
构建并安装 Agent(安装方式见仓库根目录 CONTRIBUTING.md)后,使用当前前端按以下步骤做界面验证:
- 展开一张分区表的Partitions与Subpartitions分组,确认分组数据正常加载;
- 打开该表的 DDL 视图,确认Omit storage attributes开关默认启用;
- 复制并导出脚本,关闭开关后再次复制/导出,对比两份输出;
- 两次输出都必须保留:分区子句、约束(PK/CHECK/FK)、LOCAL 索引、默认值与注释;
- 切换该开关不会重新请求数据库,也不会覆盖缓存的原始 DDL——它只是对已缓存原始 DDL 的纯文本后处理;
- 在结构编辑器中,当 DDL 存在未保存的编辑时,该开关处于禁用状态(防止基于过期/未落盘的文本做清理)。
6.1 偏好生效范围与清理清单
该偏好仅对 OceanBase Oracle(oceanbase-oracle)生效,其他数据库类型(包括原生 Oracle)不受影响。开启后移除的已知表级存储选项为:
| 选项 | 说明 |
|---|---|
COMPRESS FOR ARCHIVE [HIGH\|LOW] | 归档压缩,可选 HIGH/LOW 级别 |
NOCOMPRESS | 关闭压缩 |
REPLICA_NUM = <n> | 副本数(OceanBase 特有) |
BLOCK_SIZE = <n> | 数据块大小 |
TABLET_SIZE = <n> | 分区单元(tablet)大小 |
PCTFREE = <n> | 块内预留空间比例 |
USE_BLOOM_FILTER = TRUE/FALSE | 布隆过滤器开关(OceanBase 特有) |
未知选项与所有分区子句都会被保留——这是刻意设计:清理只针对白名单内的已知表选项,避免误删无法识别的新特性参数或分区边界表达式。
6.2 前端实现细节
前端实现位于 ddlStorage.ts 的applyDdlStoragePreference(sql, databaseType, excludeStorage = true):
- 非
oceanbase-oracle或excludeStorage = false时原样返回; - 使用 SQL 语义分词器(
tokenizeSqlSemantic(sql, "oracle"))做词法级处理,而非正则替换——从而能区分字符串字面量、注释与真实关键字; - 仅在
CREATE [GLOBAL TEMPORARY] TABLE ... )闭合括号之后的表选项区做匹配;一旦遇到PARTITION关键字即停止(分区子句永不触碰); - 对每个命中选项校验其取值合法性(
REPLICA_NUM等要求整数、USE_BLOOM_FILTER要求TRUE/FALSE),非法取值宁可跳过也不误删; - 若 SQL 存在未闭合 token(分词不完整),直接返回原文本,不做破坏性清理。
配套测试 ddlStorage.spec.ts 覆盖了关键边界:默认值DEFAULT 'PCTFREE = 20'与注释文本'COMPRESS FOR ARCHIVE'不被误删、Oracle 替代字符串q'[can't ) PCTFREE=42]'保留、/* ... */注释保留、同一脚本内多张表各自独立清理、ALTER TABLE语句不受影响、未知属性TABLE_MODE='QUEUING'保留。
七、已验证环境与适用前提
- 验证版本:脚本已针对 OceanBase4.2.5.7(Oracle 模式)通过;
- 覆盖形态:RANGE、LIST、HASH 以及 RANGE/LIST 复合分区表,复合分区键,约束,默认值/注释,临时表;
- DDL 获取:依赖
DBMS_METADATA.GET_DDL(OceanBase 4.2.5 文档支持该函数),并因该版本 TABLE 结果省略索引与注释而单独追加原生索引 DDL 与 COMMENT 语句; - 适用限制:若目标 OceanBase 版本的
DBMS_METADATA行为或字典视图字段有差异,需以实际版本为准调整断言;脚本要求一次性租户,测试 Schema 需按报告清理。
八、扩展建议
- 新增分区形态(如
PARTITION BY HASH多分区、RANGE-COMPOSITE其他子分区策略)时,在fixtures数组追加表定义并在expected中补充数量断言即可; - 若需要验证更多存储选项,可在源表 DDL 中追加选项并在脚本中增加"简化结果不含该选项"的断言,同时同步维护 ddlStorage.ts 的白名单与 ddlStorage.spec.ts 的用例;
- 将
OB_TEST_OUTPUT指向 CI 临时目录,即可把verification.json作为分区 DDL 回归检查的机器可读结果。
通过自动化脚本与 UI 双通道验证,dbx 保证 OceanBase Oracle 分区表在任何时候都能以"语义完整、格式干净"的 DDL 被浏览、复制与跨环境重放。
【免费下载链接】dbx15MB,轻量级跨平台数据库客户端、数据库管理工具。支持 MySQL、PostgreSQL、SQLite、Redis、MongoDB、DuckDB、ClickHouse、SQL Server 等。15MB, lightweight, cross-platform database client. Supports MySQL, PostgreSQL, SQLite, Redis, MongoDB, DuckDB, ClickHouse, SQL Server and more.项目地址: https://gitcode.com/t8y2/dbx
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考