#lexer #sql-parser #sql-query #sql #parser #ansi #query-parser

无std sqlparser-patched

支持ANSI SQL:2011的可扩展SQL词法分析和解析器

2个不稳定版本

0.43.1 2024年2月1日
0.41.0 2024年1月24日

1011数据库接口

Apache-2.0

1MB
21K 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避免语义分析,因为不同方言和实现之间的差异很大。如果您想进行语义分析,请随时使用此项目作为基础。

保留语法往返

此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);

在此crate中,仍有少数情况,其中看似具有相似语义的不同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查询引擎、LocustDBBallistaGlueSQLOpteryxPRQLQrlewJumpWire 等项目使用。

如果您的项目正在使用 sqlparser-rs,请随意将其添加到此列表中。

设计

核心表达式解析器使用的是Pratt 解析器设计,这是一个自顶向下的操作符优先(TDOP)解析器,而周围的 SQL 语句解析器则是一个传统的、手写的递归下降解析器。Eli Bendersky 有一个关于 TDOP 解析器的教程,如果您想了解更多关于这项技术的信息。

我们之所以喜欢这种设计模式,是因为

  • 代码简单易写,可以简洁而优雅
  • 性能通常比由解析器生成器的代码更好
  • 使用手写代码进行调试更容易
  • 与使用解析器生成器相比,扩展和创建特定方言的扩展更容易

支持自定义 SQL 方言

这是一个正在进行中的工作,但我们有一些关于编写自定义 SQL 解析器的笔记。

贡献

鼓励贡献!然而,维护此软件包的带宽是有限的。请仔细阅读以下部分。

新语法

最常用的 PR 添加了对 SQL 标准中或流行的 RDBMS(如 Microsoft SQL Server 或 PostgreSQL)中功能的支持或修复,这些 PR 可能会在简短审查后被接受。任何特定方言的 SQL 功能都应该由相关的 DialectGenericDialect 解析。

主要 API 变更

当前维护者不计划对此crate的API进行任何重大更改。提出重大重构的PR不太可能被接受。

测试

虽然我们希望以合理的时间及时审查PR,但可能需要一周或更长时间。为了加快流程,请确保PR通过所有CI检查,并包含测试以证明您的代码按预期工作(并避免回归)。请记住还要测试错误路径。

没有测试的PR将不会被审查或合并。由于CI确保cargo testcargo fmtcargo clippy通过,您在提交PR之前可能需要在本地运行所有三个命令。

提交问题

如果您无法提交补丁,请随时提交问题。请尽量包含

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

不幸的是,如果您需要支持某个功能,您可能需要自己实现它,或者提交一个描述得当的ticket,以便社区的其他成员可以这样做。作为维护者,我们的目标是促进从各种贡献者那里整合各种功能,但我们不提供实现,因为我们没有资源。

许可

此存储库中的所有代码均根据Apache软件许可协议2.0进行许可。

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

依赖项

~46–600KB
~13K SLoC