- 后端
- 数据库
【免费下载链接】sqlglot
Python SQL Parser and Transpiler
SQLGlot 是一个用 Python 编写的 SQL 解析器与转译器(transpiler),支持 20+ 种方言的解析、转译与优化。本文以仓库根目录的 CHANGELOG.md 为骨架,系统梳理 SQLGlot 从 v20 到 v30 的版本演进节奏、变更内容分类体系,并重点深入解读 v30.0.0 这一"里程碑式"大版本中官方公布的 7 条迁移指南——涵盖 mypyc 编译加速、Rust tokenizer 移除、表达式模块包化等直接影响使用者代码的破坏性变更。读完本文,你将掌握如何阅读该变更日志、如何应对 v30 升级带来的 API 变化,以及如何在纯 Python 版与编译加速版sqlglot[c]之间做出选择。
一、CHANGELOG 文档概览:281 个版本、1.5 万行的演进档案
CHANGELOG.md是 SQLGlot 项目最完整、最权威的版本演进档案,全文共 15718 行,按"版本号 + 发布日期"组织章节(如## [v30.18.0] - 2026-09-03),共记录了281 个发布版本,覆盖从 2024 年 1 月的 v20.6.0 到 2026 年 9 月的 v30.18.0 的完整演进过程。
每个版本章节内部,变更被划分为统一的语义化分类(emoji 前缀),统计全文各分类出现的次数,可以直观看出项目各维度的活跃程度:
| 分类(章节标题) | 含义 | 全文出现次数 |
|---|---|---|
### :boom: BREAKING CHANGES | 破坏性变更(可能影响既有使用者代码) | 155 |
### :sparkles: New Features | 新功能 | 194 |
### :bug: Bug Fixes | 缺陷修复 | 231 |
### :recycle: Refactors | 代码重构 | 75 |
### :wrench: Chores | 工程杂项(依赖升级、CI、工具链) | 150 |
### :zap: Performance Improvements | 性能优化 | 11 |
### :white_check_mark: Tests | 测试相关 | 6 |
从统计可以看出,SQLGlot 的迭代以"高频小步快跑"为特征:Bug Fixes 与 New Features 数量领先,说明项目在持续扩展方言支持的同时也在快速修复兼容性问题;BREAKING CHANGES 高达 155 次,提示使用者升级版本时需要留意行为变化,尤其是各 major 版本(v26、v27、v28、v29、v30)。
文档中每条变更以 commit hash 为锚点,注明所属模块(如**executor**、**optimizer**、**parser**、**postgres**、**bigquery**等)、关联 PR 编号与贡献者,部分条目还通过fixes issue #xxxx/addresses issue #xxxx标注其解决的 GitHub Issue。对想要深入追踪某次具体变更的用户而言,这是一种可回溯、可验证的记录方式。
二、版本节奏与最近版本:v30.18.0 带来了什么
CHANGELOG 的开头即最新版本## [v30.18.0] - 2026-09-03。以该版本为例,可以完整看到一份"标准版本章节"的结构:
2.1 破坏性变更(BREAKING CHANGES)
v30.18.0 的破坏性变更全部集中在PostgreSQL 相关类型标注(annotate)与若干解析/生成行为调整上:
- Postgres 函数类型标注:为
decode、Left、Reverse、Overlay、Right、Rpad、SplitPart、To_Hex、Format、Normalize、ToNumber、maketime、regexpreplace、make_timestamp、bit_or、bit_xor、localtimestamp等一系列 Postgres 函数补齐了返回类型标注。这些标注的实现可以在 sqlglot/typing/postgres.py 中找到对应代码。 JSONB_CONTAINS映射为@>运算符:修复了 Postgres 方言下 JSONB 包含关系的表达方式,并新增JSONBContainsTopKey表达式。BTRIM解析为TRIM:Postgres 方言中的BTRIM不再作为独立函数保留,而是统一解析为标准TRIM表达式。- 标识符规范化调整:不再规范化"命名数据而非引用"的标识符,避免在优化过程中误改数据内容。
ANALYZE/DROP支持多表:解析器允许一条语句中列出多张表。MOD改为乘除级优先级解析:MOD运算符的解析优先级被调整到乘除(multiplicative)层级,并同步修正了生成时的括号处理。
2.2 新功能(New Features)
- executor 模块持续扩充:实现了
DPIPE管道操作符(sqlglot/executor/python.py 为核心执行实现)、REVERSE函数加入 ENV、支持OFFSET子句、支持执行优化器拒绝重写的子查询。executor 相关代码位于 sqlglot/executor/(含context.py、env.py、python.py、table.py)。 - 方言能力扩展:Dremio 支持 4 参数
REGEXP_SPLIT;ClickHouse 将trimLeft/trimRight/trimBoth解析进Trim表达式、支持view()表函数;BigQuery 支持数字前缀字段名;Postgres 支持LOCK语句;Teradata 支持mod()函数语法。 explode(map)支持:表值函数explode现在可以作用于 map 类型。
2.3 缺陷修复(Bug Fixes)
v30.18.0 的修复覆盖多个方言,例如:
- Trino:带时区的
TIME字面量解析。 - DuckDB:
JSON_VALUE箭头提取在父表达式需要时正确加括号。 - SQLite:
RegexpLike渲染为REGEXP运算符;CONCAT生成||时保留COALESCE包裹;窗口帧RANGE CURRENT ROW的显式结束边界。 - MySQL:
%x、%r日期格式说明符的映射;CREATE TABLE列定义支持KEY。 - Snowflake:
filter_sql匿名函数处理、位置列引用解析、OBJECT_CONSTRUCT_KEEP_NULL中的限定通配符。 - ClickHouse:VALUES 元组包裹幂等性、保留带引号的参数化关系、生成原生
lag/lead替代lagInFrame/leadInFrame。 - optimizer:不将 WHERE 谓词下推入后续被 RIGHT/FULL JOIN 空值扩展的源;不剪除 GROUP BY/HAVING/QUALIFY 引用的列;
_traverse_union中抛OptimizeError而非破坏作用域图(sqlglot/optimizer/scope.py)。 - parser:
GRANT/REVOKE无权限列表时不再抛ValueError。
这类细节正是 CHANGELOG 的价值所在:升级 SQLGlot 前,扫描目标版本与当前版本之间的 Bug Fixes 列表,即可预判哪些 SQL 行为可能发生变化。
三、v30.0.0 迁移指南详解:性能优先的大版本重构
在整个 CHANGELOG 中,## [v30.0.0] - 2026-03-16(第 1902 行起)是一个特殊的版本章节——它不仅罗列变更,还附带了完整的Migration Guide(迁移指南)。该版本的核心目标是性能与编译:库的多个核心组件开始支持由 mypyc 编译,安装[c]extra 后可获得显著加速,但这要求重构若干内部模块,从而对依赖内部 API、子类化 Parser 或从内部路径导入的用户引入了破坏性变更。
官方同时给出了清晰的适用范围说明:如果只使用公共 API(sqlglot.parse、sqlglot.parse_one、sqlglot.transpile、sqlglot.exp.*、sqlglot.optimizer.*),绝大多数代码无需改动即可升级。
3.1 Rust tokenizer 移除:用[c]替代[rs]
v30 之前项目曾提供 Rust 编写的 tokenizer(sqlglotrs),v29 起被移除,替换为 mypyc 编译的 C 扩展(sqlglotc):
# 之前 pip install "sqlglot[rs]" # 之后 pip install "sqlglot[c]"其中[rs]extra 仍然可以安装,但已退化为废弃的 no-op 桩。被移除的 API 包括:
Tokenizer上的use_rs_tokenizer参数与属性RsTokenizer、RsTokenizerSettings、RsTokenTypeSettings导入tokens.py中的USE_RS_TOKENIZER常量
这一点在当前仓库的 setup.py 中有直接印证:extras_require中"rs"extra 被注释为 "Deprecated: the Rust tokenizer has been replaced by sqlglotc",其内容为["sqlglotrs==0.13.0", f"sqlglotc=={version}; python_version >= '3.10'"];而"c"extra 则为[f"sqlglotc=={version}; python_version >= '3.10'"]。注意:sqlglotc需要在用户机器上从源码编译,且要求 Python 3.10+;在 Python 3.9 上pip install sqlglot[c]是 no-op,只会得到纯 Python 版。独立的编译分发目录见 sqlglotc/(内含 pyproject.toml 与 setup.py)。
3.2expressions.py拆分为包
原来单文件的sqlglot/expressions.py被拆分为sqlglot/expressions/包,按职责划分出 15 个子模块。该拆分在当前仓库的 sqlglot/expressions/ 目录中即可直接验证:
| 模块 | 内容 |
|---|---|
core.py | Expr、Expression、Condition、Func、AggFunc、Column、Literal等 |
datatypes.py | DataType、DType、DataTypeParam、Interval |
query.py | Select、Query、SetOperation、UDTF、Subquery |
ddl.py | Create、Alter、Drop等 DDL 语句 |
dml.py | Insert、Update、Delete、Merge |
properties.py | 所有*Property类、PropertiesLocation |
constraints.py | 所有*ColumnConstraint类 |
math.py | 算术运算符(Add、Sub、Mul、Div等) |
string.py | 字符串函数(Concat、Length、Upper等) |
temporal.py | 日期/时间函数(DateAdd、DateDiff等) |
aggregate.py | 聚合函数(Count、Sum、Avg等) |
array.py | 数组函数(ArrayAgg、Explode等) |
json.py | JSON 函数(JSONExtract等) |
functions.py | 其他函数(Coalesce、If、Case、Cast等) |
builders.py | Builder 辅助函数(select()、from_()、condition()等) |
向后兼容性:from sqlglot.expressions import *与from sqlglot import expressions as exp仍然可用,因为所有符号都从expressions/__init__.py重新导出。但如果你依赖sqlglot.expressions是单文件这一事实(例如检查__file__属性),该行为会被打破。
3.3Parser.expression()不再接受**kwargs
该变更影响所有子类化Parser或在自定义 parse 方法中调用self.expression()的代码。调用方式从"传 kwargs"改为"直接构造表达式实例":
# 之前 self.expression(exp.Select, distinct=True, expressions=cols) # 之后 self.expression(exp.Select(distinct=True, expressions=cols))变更动机是消除**kwargs字典分配的开销——这与 v30 整体的性能优化目标一致。解析器的基类定义位于 sqlglot/parser.py,各方言解析器位于 sqlglot/parsers/。
3.4 作用域遍历:bfs参数移除
Scope相关遍历函数的bfs参数被删除,遍历方式固定为深度优先(DFS):
# 之前 scope.walk(bfs=True) scope.find(exp.Column, bfs=False) walk_in_scope(expr, bfs=True) # 之后 scope.walk() scope.find(exp.Column) walk_in_scope(expr)行为变化:旧版本默认是bfs=True,现在统一为 DFS,因此依赖 BFS 顺序的代码会得到不同顺序的结果。受影响函数包括:Scope.walk()、Scope.find()、Scope.find_all()、walk_in_scope()、find_in_scope()、find_all_in_scope()。作用域分析的核心实现在 sqlglot/optimizer/scope.py。
3.5 Dialect 元类不再修改 Parser token 集合
旧版_Dialect元类会在类创建时根据方言标志(如SUPPORTS_SEMI_ANTI_JOIN)动态修改解析器的 token 集合(ID_VAR_TOKENS、TABLE_ALIAS_TOKENS、NO_PAREN_FUNCTIONS)。这些动态修改已被移除,每个 parser 现在静态声明自己的 token 集合。具体变化:
Dialect.SUPPORTS_SEMI_ANTI_JOIN已删除。SHOW_TRIE/SET_TRIE不再由SHOW_PARSERS/SET_PARSERS自动计算。
方言与解析器的基类分别在 sqlglot/dialects/dialect.py 与 sqlglot/parsers/base.py。
3.6 用Expr替代Expression做通用isinstance检查
Func、Condition、Binary等 trait 基类现在直接继承自Expr而非Expression,因此isinstance(node, exp.Expression)不再能匹配这些 trait 类。若代码需要判断"是否为任意 AST 节点",应改用exp.Expr:
# 之前 isinstance(node, exp.Expression) # 之后 isinstance(node, exp.Expr)3.7 编译类无法被子类化(使用[c]时)
安装sqlglot[c]后,大量核心类经由 mypyc 编译。编译后的类不能在运行时被继承——类定义本身不会报错,但实例化时会抛出TypeError: interpreted classes cannot inherit from compiled。官方给出的受影响清单如下:
被编译(不可子类化):
| 类 | 是否可子类化 |
|---|---|
所有 parser(BigQueryParser、SnowflakeParser等) | 否 |
Parser(基类) | 否 |
Expression、Expr及所有 AST 节点(Select、Column、Func等) | 否 |
MappingSchema、AbstractMappingSchema | 否 |
Scope | 否 |
优化器规则(scope.py、qualify.py、qualify_columns.py等) | 否 |
未被编译(仍可子类化):
| 类 | 是否可子类化 |
|---|---|
Generator及所有方言生成器 | 是 |
Tokenizer及所有方言 tokenizer | 是 |
Dialect及所有方言类 | 是 |
选择建议:如果需要子类化 parser、表达式或 schema 等编译类,请安装纯 Python 版;如果需要更高执行性能且不涉及子类化,则安装编译版:
pip install sqlglot # 纯 Python —— 完整子类化支持 pip install "sqlglot[c]" # 编译版 —— 更快,但不可子类化四、从 CHANGELOG 反推项目架构演进
CHANGELOG 不仅是版本记录,也是理解项目架构演进的线索。结合仓库目录结构,可以交叉验证几个重要结论:
表达式体系包化:v30.0.0 描述的
expressions拆分已完整落地于 sqlglot/expressions/,且从aggregate.py、array.py、json.py、temporal.py等子模块可以看出,表达式按函数族(聚合、数组、JSON、时间)做了职责分离。类型标注成为一等公民:v30 多个版本中反复出现的 "annotate xxx for postgres / mysql / spark" 变更,对应仓库中独立的 sqlglot/typing/ 目录,其中按方言组织了 13 个类型标注模块(
postgres.py、mysql.py、spark.py、bigquery.py、snowflake.py等)。这解释了为何 CHANGELOG 中 annotate 类 PR 如此密集——类型推断能力是 SQLGlot 优化与执行链路的基础。executor 模块快速成长:v30.18.0 中
**executor**前缀的变更(DPIPE、OFFSET、REVERSE、子查询求值、NULL 语义修正)表明 SQLGlot 正在把"解析-优化"链路延伸到"执行"能力,对应 sqlglot/executor/ 的实现。方言覆盖广度:CHANGELOG 中出现的方言模块(trino、duckdb、mysql、clickhouse、bigquery、snowflake、sqlite、postgres、dremio、teradata、starrocks 等)与 sqlglot/dialects/、sqlglot/parsers/、sqlglot/generators/ 三组目录一一对应,每个方言都是"解析器 + 生成器 + 方言定义"三位一体的结构。
优化器规则演进:CHANGELOG 中大量涉及谓词下推、投影剪除、join 优化、作用域修正的变更,都能在 sqlglot/optimizer/ 中找到对应的规则模块(如
pushdown_predicates.py、pushdown_projections.py、optimize_joins.py、qualify.py、eliminate_subqueries.py)。
五、如何在实际工作中用好这份 CHANGELOG
5.1 定位行为变化
升级 SQLGlot 前,重点查看从当前版本到目标版本之间所有### :boom: BREAKING CHANGES章节。从 155 次的出现频率看,任何跨 minor/major 的升级都应检查该列表。同时注意标注了fixes issue #xxxx的条目——这些通常是真实用户报告并修复的边界情况,可能与你的 SQL 场景直接相关。
5.2 按模块筛选关注点
每个条目都带模块前缀,例如**optimizer**、**executor**、**postgres**、**bigquery**。如果你只关心某个方言或某个子系统的行为,可以按前缀聚焦阅读,再结合对应源码目录(如 sqlglot/dialects/postgres.py、sqlglot/optimizer/)验证具体实现。
5.3 验证安装方式与版本前提
阅读 CHANGELOG 中涉及安装方式的内容时,应以当前仓库的 setup.py 为准:devextra 包含 duckdb、pandas、pdoc、pre-commit、ruff 等开发依赖;cextra 安装sqlglotc(需 Python 3.10+);rsextra 已废弃。版本号由 setuptools_scm 从 git 标签生成(version = get_version(local_scheme="no-local-version")),与 CHANGELOG 的版本章节一一对应。
5.4 追踪测试佐证
CHANGELOG 记录的方言级行为变化,大多能在 tests/dialects/ 下的方言测试(如 test_postgres.py、test_clickhouse.py)以及 tests/ 的优化器/执行器测试中找到对应用例。需要深入验证某次修复时,可以沿"CHANGELOG 条目 → 方言测试 → 解析器/生成器实现"的路径层层下钻。
结语
CHANGELOG.md之于 SQLGlot,既是发布日志,也是架构演进史与技术决策文档。它以 281 个版本、155 次破坏性变更和数百次方言级修复,完整记录了项目从纯解析/转译走向"解析 + 优化 + 类型推断 + 执行"一体化平台的过程。其中 v30.0.0 的迁移指南尤其值得细读——它揭示了当前版本在性能(mypyc 编译)与灵活性(子类化能力)之间的明确取舍,也为所有基于 SQLGlot 二次开发的用户提供了升级路径的行动清单。
- 后端
- 数据库
【免费下载链接】sqlglot
Python SQL Parser and Transpiler
相关推荐
mini.nvim 变更日志深度解读:从 0.1.0 到 0.19.0-dev 的演进脉络与升级指南
mini.nvim 变更日志深度解读:从 0.1.0 到 0.19.0 dev 的演进脉络与升级指南 本文基于 CHANGELOG.md https://lin
开发工具编辑器RuboCop 官方变更日志深度解读:从 v1.0 到 v1.91 的演进脉络与升级指南
RuboCop 官方变更日志深度解读:从 v1.0 到 v1.91 的演进脉络与升级指南 CHANGELOG.md 是 RuboCop 项目的权威版本变更记录,
代码质量Lint格式化静态分析开发工具Feast 变更日志深度解读:从 v0.0.1 到 v0.66.0 的八年演进与技术脉络
Feast 变更日志深度解读:从 v0.0.1 到 v0.66.0 的八年演进与技术脉络 本指南以仓库根目录的 CHANGELOG.md https://lin
MLOps后端数据工程
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考