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解析器实现 中排名第七

Download history 149249/week @ 2024-05-03 164375/week @ 2024-05-10 161378/week @ 2024-05-17 160958/week @ 2024-05-24 236396/week @ 2024-05-31 255121/week @ 2024-06-07 219857/week @ 2024-06-14 271010/week @ 2024-06-21 271746/week @ 2024-06-28 260094/week @ 2024-07-05 254155/week @ 2024-07-12 255142/week @ 2024-07-19 265297/week @ 2024-07-26 267974/week @ 2024-08-02 269903/week @ 2024-08-09 286457/week @ 2024-08-16

1,143,587 每月下载量
421 crate 中使用(其中 106 个直接使用)

Apache-2.0 协议

1MB
27K SLoC

Rust 的可扩展 SQL 词汇和解析器

License Version Build Status Coverage Status Gitter Chat

这个 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 节点的 SerializeDeserialize 来添加 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查询引擎,LocustDBBallistaGlueSQLOpteryxPolarsPRQLQrlewJumpWire,以及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 testcargo fmtcargo clippy通过,您在提交PR之前应该本地运行这三个命令。

提交问题

如果您无法提交补丁,请随意提交一个问题。请尽量包括以下内容:

  • 一些代表您希望支持或修复的语法的示例;
  • 如果该语法是SQL:2016的一部分,请提供相关的SQL语法片段;以及
  • 支持此功能的几个最流行数据库的文档链接。

不幸的是,如果您需要支持某个功能,您可能需要自己实现它,或提交一个足够详细的问题单,以便社区的其他成员可以这样做。我们作为维护者的目标是促进各种贡献者贡献的各种功能的集成,而不是自己提供实现,因为我们没有这样的资源。

许可

本存储库中的所有代码均受Apache Software License 2.0许可。

除非您明确声明,否则您根据Apache-2.0许可证定义的,有意提交以包含在作品中的任何贡献,都应按上述方式许可,不附加任何额外条款或条件。

依赖项

~46–590KB
~13K SLoC