Metadata-Version: 2.5
Name: ddlkit
Version: 0.2.0
Summary: 多方言 DDL 文本解析器：无损保真地提取表、列、约束、索引与方言特性
Project-URL: Homepage, https://github.com/15110244630/ddlkit
Project-URL: Repository, https://github.com/15110244630/ddlkit
Project-URL: Issues, https://github.com/15110244630/ddlkit/issues
Project-URL: Changelog, https://github.com/15110244630/ddlkit/blob/main/CHANGELOG.md
Author: yangyang
License-Expression: MIT
License-File: LICENSE
Keywords: audit,clickhouse,dameng,ddl,governance,hive,oceanbase,parser,sql
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Database
Classifier: Topic :: Software Development :: Quality Assurance
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: sqlglot<31,>=30.18
Description-Content-Type: text/markdown

# ddlkit

多方言 DDL 文本解析器。只做一件事：**DDL 文本 → 结构化数据**，不含规则引擎。

面向的场景是**建表规范审计**：校验表名/列名/索引名的书写形态、长度、注释是否齐全、
类型是否符合规范。这类审计对"保真"的要求极高——解析器**改写**或**丢弃**任何一处，
规则就会判错，而判错是静默的，比报错更危险。

## 核心特征

| 特征 | 说明 |
|---|---|
| **不丢原文** | 每个字段双轨：`*_raw` 保留原文（含引号、原始类型名），归一化字段供比较 |
| **不丢方言** | 方言特性（达梦 `STORAGE`、CK `ENGINE`/`ORDER BY`、Hive `TBLPROPERTIES`、OB `REPLICA_NUM`…）全部结构化进 `extras`，**不做摘除** |
| **不挂死** | 只走 sqlglot 的 tokenizer，不碰 parser。达梦 `NOT CLUSTER PRIMARY KEY` 曾导致 parser 无限回溯 OOM |
| **不改写** | 绕过 parser + generator，因此 `TINYINT` 不会变成 `SMALLINT` |
| **格式自适应** | 自动识别 5 种导出格式（beeline / 双引号包裹逐行 / `\n` 转义逐行 / 无分号锚点 / 常规脚本） |
| **编码自适应** | 逐文件探测 UTF-8 / UTF-8-BOM / GB18030（同一批导出文件里可能混存） |
| **零额外依赖** | 只依赖纯 Python 版 `sqlglot` |

## 安装

```bash
pip install ddlkit
# 或
uv add ddlkit
```

> 依赖声明为 `sqlglot`（纯 Python 版）。**不要同时安装 `sqlglot[c]`**——它会把
> 编译产物覆盖到 `sqlglot/tokenizer_core`，本包未在该形态下验证。

## 快速开始

```python
from ddlkit import parse_file

res = parse_file("ddl/ANMS_ALARM.sql", dialect="dm")

for t in res.tables:
    print(t.qualified_name, len(t.columns), t.comment)
    for c in t.columns:
        # 用 type_raw 判断类型，不要用归一化后的值——那会丢原始写法
        print("   ", c.name_raw, c.type_raw, c.comment)
    for k in t.constraints:
        print("   PK?", k.kind, k.columns, k.clustered)
    print("   方言特性:", t.extras)
```

解析一段文本：

```python
from ddlkit import parse_ddl

res = parse_ddl(
    '''CREATE TABLE `t` (
         `ID` varchar(512) NOT NULL COMMENT '主键',
         PRIMARY KEY (`ID`)
       ) REPLICA_NUM = 3 COMMENT = '示例表';''',
    dialect="ob_mysql",
)
t = res.tables[0]
assert t.constraints[0].kind == "PRIMARY KEY"
assert t.extras["REPLICA_NUM"] == "REPLICA_NUM = 3"
```

## 支持的方言别名

| 业务库 | 可传的 `dialect` | 映射到 sqlglot 方言 |
|---|---|---|
| 达梦 | `dm` / `dameng` / `达梦` | `oracle` |
| ClickHouse | `ck` / `clickhouse` | `clickhouse` |
| OceanBase(MySQL 模式) | `ob` / `ob_mysql` / `oceanbase` | `mysql` |
| Hive | `hive` / `hive2` | `hive` |

其余任意 sqlglot 方言名也可直接传入（如 `postgres`、`snowflake`）。

## 数据模型

```
ParseResult
├── tables: list[Table]
│   ├── name / name_raw / quoted / schema / catalog / temporary
│   ├── columns: list[Column]
│   │   ├── name / name_raw / quoted
│   │   ├── type_name / type_raw / type_args_raw
│   │   ├── nullable / default_raw / comment
│   │   ├── extras      # identity / collate / codec / primary_key …
│   │   └── line / col
│   ├── constraints: list[Constraint]   # PRIMARY KEY / UNIQUE / FOREIGN KEY / CHECK / INDEX
│   ├── indexes: list[Index]            # 独立 CREATE INDEX 语句，已按表名挂接
│   ├── comment
│   ├── extras          # 方言特性，原样保存
│   ├── source          # 文件 / 行号 / 编码 / 格式，供报告定位
│   └── warnings
├── warnings
└── unsupported         # 无法当作建表语句处理的语句（如 CTAS）
```

完整字段语义见 `docs/详细设计.md`。

## 已知限制

* 只解析 DDL，不解析 DML / 存储过程 / PL-SQL 块。
* 只解析 `CREATE TABLE` / `CREATE INDEX` / `COMMENT ON`；其余语句进 `unsupported`/忽略。
* 全角字符长度、`CASE_SENSITIVE` 语义等**库侧语义**不在解析层处理，交由规则层。
* 单条语句内部的极端嵌套（Oracle `q'[...]'` 引号、`$$` 块）未覆盖。

## 开发

```bash
uv sync
uv run pytest -q
uv run ruff check src tests
uv run mypy
```

## 许可

MIT
