73 个版本 (破坏性更新)
0.50.0 | 2024 年 8 月 16 日 |
---|---|
0.49.0 | 2024 年 7 月 23 日 |
0.48.0 | 2024 年 7 月 9 日 |
0.44.0 | 2024 年 3 月 3 日 |
0.1.8 | 2018 年 10 月 14 日 |
#7 在 解析器实现 中排名第七
1,143,587 每月下载量
在 421 个 crate 中使用(其中 106 个直接使用)
1MB
27K SLoC
Rust 的可扩展 SQL 词汇和解析器
这个 crate 包含了一个符合 ANSI/ISO SQL 标准 和其他方言的 SQL 词汇和解析器。这个 crate 被用作 SQL 查询引擎、特定供应商的解析器和各种 SQL 分析的基础。
示例
解析简单的 SELECT
语句
use sqlparser::dialect::GenericDialect;
use sqlparser::parser::Parser;
let sql = "SELECT a, b, 123, myfunc(b) \
FROM table_1 \
WHERE a > b AND b < 100 \
ORDER BY a DESC, b";
let dialect = GenericDialect {}; // or AnsiDialect, or your own dialect ...
let ast = Parser::parse_sql(&dialect, sql).unwrap();
println!("AST: {:?}", ast);
输出结果如下
AST: [Query(Query { ctes: [], body: Select(Select { distinct: false, projection: [UnnamedExpr(Identifier("a")), UnnamedExpr(Identifier("b")), UnnamedExpr(Value(Long(123))), UnnamedExpr(Function(Function { name: ObjectName(["myfunc"]), args: [Identifier("b")], filter: None, over: None, distinct: false }))], from: [TableWithJoins { relation: Table { name: ObjectName(["table_1"]), alias: None, args: [], with_hints: [] }, joins: [] }], selection: Some(BinaryOp { left: BinaryOp { left: Identifier("a"), op: Gt, right: Identifier("b") }, op: And, right: BinaryOp { left: Identifier("b"), op: Lt, right: Value(Long(100)) } }), group_by: [], having: None }), order_by: [OrderByExpr { expr: Identifier("a"), asc: Some(false) }, OrderByExpr { expr: Identifier("b"), asc: None }], limit: None, offset: None, fetch: None })]
特性
以下为可选的 crate 功能
serde
:通过实现所有 AST 节点的Serialize
和Deserialize
来添加 Serde 支持。visitor
:添加一个能够递归遍历 AST 树的Visitor
。
语法与语义
这个 crate 只提供了一个语法解析器,并试图避免应用任何 SQL 语义,接受特定数据库会拒绝的查询,即使在使用该数据库特定的 Dialect
的情况下。例如,CREATE TABLE(x int, x int)
在这个 crate 中被接受,尽管大多数 SQL 引擎会因为这个重复的列名 x
而拒绝这个语句。
这个 crate 避免了语义分析,因为语义在不同方言和实现之间差异很大。如果你想要进行语义分析,可以自由地使用这个项目作为基础。
保留语法往返
这个软件包允许用户恢复原始的SQL文本(注释被移除,空白字符被规范化,关键字首字母大写),这对于分析和操作SQL的工具非常有用。
这意味着除了注释、空白和关键字的大小写外,以下所有SQL都应该成立:
// Parse SQL
let ast = Parser::parse_sql(&GenericDialect, sql).unwrap();
// The original SQL text can be generated from the AST
assert_eq!(ast[0].to_string(), sql);
在这个软件包中,仍有某些情况下,具有类似语义的不同SQL使用相同的AST表示。我们欢迎提交PR来修复这些问题,并在AST中区分不同的语法。
SQL兼容性
SQL首次于1987年标准化,并且自那时以来,标准的修订版已经定期发布。大多数修订都添加了语言的重要新功能,因此没有数据库声称支持所有功能。这个解析器目前支持SQL-92的大部分语法,以及一些新版本的语法,这些语法已被明确请求,以及一些MSSQL、PostgreSQL和其他特定方言的语法。尽可能情况下,使用在线SQL:2016语法来指导接受哪些语法。
遗憾的是,关于兼容性的具体说明很难。没有公开可用的测试套件可以自动评估兼容性,手动评估会消耗项目有限的资源。尽管如此,我们最终支持完整的SQL方言,我们正在缓慢地构建自己的测试套件。
如果您正在评估该项目是否适合您的需求,您可能需要通过实验来验证它是否支持您需要的SQL子集。请提交您发现的任何不受支持的查询的问题。这样做有助于我们优先支持标准中实际使用的部分。请注意,如果您迫切需要支持某个功能,您可能需要自己编写实现。有关详细信息,请参阅贡献部分。
命令行
该软件包包含一个CLI程序,可以解析文件并将结果以JSON格式输出。
$ cargo run --features json_example --example cli FILENAME.sql [--dialectname]
用户
该解析器目前正在被以下项目使用:DataFusion查询引擎,LocustDB,Ballista,GlueSQL,Opteryx,Polars,PRQL,Qrlew,JumpWire,以及ParadeDB。
如果您正在使用sqlparser-rs,请随时提交PR将其添加到该列表中。
设计
核心表达式解析器使用Pratt解析器设计,这是一种自顶向下的操作符优先级(TDOP)解析器,而周围的SQL语句解析器是一个传统的、手写的递归下降解析器。Eli Bendersky有一个很好的TDOP解析器教程,如果您想了解更多关于这项技术的话。
我们喜欢这种设计模式而不是解析器生成器,原因如下:
- 代码易于编写,可以简洁而优雅。
- 性能通常优于解析器生成器生成的代码。
- 使用手写代码进行调试更容易。
- 与使用解析器生成器相比,扩展和创建特定方言的扩展要容易得多。
支持自定义SQL方言
这是一项正在进行中的工作,但我们有一些关于编写自定义SQL解析器的笔记。
贡献
非常鼓励贡献!然而,我们维护这个crate的带宽有限。请仔细阅读以下部分。
新语法
最常见的PR是添加对SQL标准中或流行RDBMS(如Microsoft SQL Server或PostgreSQL)中功能的支持或修复一个bug。经过简短审查后,这些PR可能会被接受。任何特定方言的SQL功能都应该由相关的两个 Dialect
以及GenericDialect
来解析。
主要API更改
当前维护者不计划对crate的API进行任何重大更改。提议进行重大重构的PR可能不会被接受。
测试
虽然我们希望以合理的时间审查PR,但可能需要一周或更长时间。为了加快流程,请确保PR通过了所有CI检查,并包含演示您的代码按预期工作的测试(以及避免回归)。记得也要测试错误路径。
没有测试的PR将不会被审查或合并。由于CI确保了cargo test
、cargo fmt
和cargo clippy
通过,您在提交PR之前应该本地运行这三个命令。
提交问题
如果您无法提交补丁,请随意提交一个问题。请尽量包括以下内容:
- 一些代表您希望支持或修复的语法的示例;
- 如果该语法是SQL:2016的一部分,请提供相关的SQL语法片段;以及
- 支持此功能的几个最流行数据库的文档链接。
不幸的是,如果您需要支持某个功能,您可能需要自己实现它,或提交一个足够详细的问题单,以便社区的其他成员可以这样做。我们作为维护者的目标是促进各种贡献者贡献的各种功能的集成,而不是自己提供实现,因为我们没有这样的资源。
许可
本存储库中的所有代码均受Apache Software License 2.0许可。
除非您明确声明,否则您根据Apache-2.0许可证定义的,有意提交以包含在作品中的任何贡献,都应按上述方式许可,不附加任何额外条款或条件。
依赖项
~46–590KB
~13K SLoC