From 89bd5b172d2472bf9edde7a5f50d60f0e0ea95b6 Mon Sep 17 00:00:00 2001 From: xigua Date: Tue, 15 Dec 2020 15:04:46 +0800 Subject: [PATCH] update README.md, add README-zh_CN.md --- README-zh_CN.md | 216 +++++++++++++++++++++++++++++++++++++++++ README.md | 249 ++++++++++++++++++++++++++++++++++-------------- 2 files changed, 392 insertions(+), 73 deletions(-) create mode 100644 README-zh_CN.md diff --git a/README-zh_CN.md b/README-zh_CN.md new file mode 100644 index 0000000..487c28a --- /dev/null +++ b/README-zh_CN.md @@ -0,0 +1,216 @@ +# dt-sql-parser + +[![NPM version][npm-image]][npm-url] + +[npm-image]: https://img.shields.io/npm/v/dt-sql-parser.svg?style=flat-square +[npm-url]: https://www.npmjs.com/package/dt-sql-parser + +此项目是基于 [ANTLR4](https://github.com/antlr/antlr4) 开发的 SQL 语言解析器。主要用于大数据开发中,对各类 SQL 的解析。目前支持的 SQL: + +- MySQL +- Flink SQL +- Spark SQL +- Hive SQL +- PL/SQL + +每种 SQL 都提供了对应基础类、Visitor 类和 Listener 类,包含了生成 token、生成 AST、语法校验、visitor 和 listener 模式遍历 AST 指定节点等功能。 + +此外,为了方便解析,还提供了几个辅助方法可以在解析前对 SQL 进行格式处理。主要作用是清除 SQL 语句中的 '--' 和 '/**/' 两种类型的注释,以及拆分大段 SQL。 + +提示:项目中的 grammar 文件也可以通过 [ANTLR4](https://github.com/antlr/antlr4) 编译成其他语言 + +[English](./README.md) | 简体中文 + +## 安装 + +``` +// use npm +npm i dt-sql-parser --save + +// use yarn +yarn add dt-sql-parser +``` + +## 示例 + +### Clean + +清除注释和前后空格 + +```javascript +import { cleanSql } from 'dt-sql-parser'; + +const sql = `-- comment comment +select id,name from user1; ` +const cleanedSql = cleanSql(sql) +console.log(cleanedSql) + +/* +select id,name from user1; +*/ +``` + +### Split + +分割 sql + +```javascript +import { splitSql } from 'dt-sql-parser'; + +const sql = `select id,name from user1; +select id,name from user2;` +const sqlList = splitSql(sql) +console.log(sqlList) + +/* +["select id,name from user1;", "\nselect id,name from user2;"] +*/ +``` + +### Tokens + +对 sql 语句进行词法分析,生成 token + +```javascript +import { GenericSQL } from 'dt-sql-parser'; + +const parser = new GenericSQL() +const sql = 'select id,name,sex from user1;' +const tokens = parser.getAllTokens(sql) +console.log(tokens) +/* +[ + { + channel: 0 + column: 0 + line: 1 + source: [SqlLexer, InputStream] + start: 0 + stop: 5 + tokenIndex: -1 + type: 137 + _text: null + text: "SELECT" + }, + ... +] +*/ +``` + +### Syntax validation + +validate 方法对 sql 语句的语法正确性进行校验,返回一个由 error 组成的数组 + +```javascript +import { GenericSQL } from 'dt-sql-parser'; + +const validate = (sql) => { + const parser = new GenericSQL() + const errors = parser.validate(sql) + console.log(errors) +} +``` +语法正确的 sql: +```javascript +const correctSql = 'select id,name from user1;' +validate(correctSql) +/* +[] +*/ +``` +包含错误语法的 sql: +```javascript +const incorrectSql = 'selec id,name from user1;' +validate(incorrectSql) +/* +[ + { + endCol: 5, + endLine: 1, + startCol: 0, + startLine: 1, + message: "mismatched input 'SELEC' expecting {, 'ALTER', 'ANALYZE', 'CALL', 'CHANGE', 'CHECK', 'CREATE', 'DELETE', 'DESC', 'DESCRIBE', 'DROP', 'EXPLAIN', 'GET', 'GRANT', 'INSERT', 'KILL', 'LOAD', 'LOCK', 'OPTIMIZE', 'PURGE', 'RELEASE', 'RENAME', 'REPLACE', 'RESIGNAL', 'REVOKE', 'SELECT', 'SET', 'SHOW', 'SIGNAL', 'UNLOCK', 'UPDATE', 'USE', 'BEGIN', 'BINLOG', 'CACHE', 'CHECKSUM', 'COMMIT', 'DEALLOCATE', 'DO', 'FLUSH', 'HANDLER', 'HELP', 'INSTALL', 'PREPARE', 'REPAIR', 'RESET', 'ROLLBACK', 'SAVEPOINT', 'START', 'STOP', 'TRUNCATE', 'UNINSTALL', 'XA', 'EXECUTE', 'SHUTDOWN', '--', '(', ';'}" + } +] +*/ +``` + +### Visitor + +使用 visitor 模式访问 AST 中的指定节点 + +```javascript +import { GenericSQL, SqlParserVisitor } from 'dt-sql-parser'; + +const parser = new GenericSQL() +const sql = `select id,name from user1;` +// parseTree +const tree = parser.parse(sql) +class MyVisitor extends SqlParserVisitor { + // 重写 visitTableName 方法 + visitTableName(ctx) { + let tableName = ctx.getText().toLowerCase() + console.log('TableName', tableName) + } + // 重写 visitSelectElements 方法 + visitSelectElements(ctx) { + let selectElements = ctx.getText().toLowerCase() + console.log('SelectElements', selectElements) + } +} +const visitor = new MyVisitor() +visitor.visit(tree) + +/* +SelectElements id,name +TableName user1 +*/ + +``` +提示:使用 Visitor 模式时,节点的方法名称可以在对应 SQL 目录下的 Visitor 文件中查找 + +### Listener + +listener 模式,利用 [ANTLR4](https://github.com/antlr/antlr4) 提供的 ParseTreeWalker 对象遍历 AST,进入各个节点时调用对应的方法。 + +```javascript +import { GenericSQL, SqlParserListener } from 'dt-sql-parser'; + +const parser = new GenericSQL(); +const sql = 'select id,name from user1;' +// parseTree +const tree = parser.parse(sql) +class MyListener extends SqlParserListener { + enterTableName(ctx) { + let tableName = ctx.getText().toLowerCase() + console.log('TableName', tableName) + } + enterSelectElements(ctx) { + let selectElements = ctx.getText().toLowerCase() + log('SelectElements', selectElements) + } +} +const listenTableName = new MyListener(); +parser.listen(listenTableName, tree); + +/* +SelectElements id,name +TableName user1 +*/ + +``` + +提示:使用 Listener 模式时,节点的方法名称可以在对应 SQL 目录下的 Listener 文件中查找 + +### 其他 + +- parserTreeToString 将 SQL 解析成 AST,再转成 string 形式 + +## 路线图 + +- Auto-complete +- Impala SQL + +## 许可证 + +[MIT](./LICENSE) \ No newline at end of file diff --git a/README.md b/README.md index 9212497..487c28a 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,3 @@ -> 如果你只想单纯的解析(SQL/SparkSQL),请使用 [cuopyue](https://github.com/HSunboy/cuopyue) - # dt-sql-parser [![NPM version][npm-image]][npm-url] @@ -7,107 +5,212 @@ [npm-image]: https://img.shields.io/npm/v/dt-sql-parser.svg?style=flat-square [npm-url]: https://www.npmjs.com/package/dt-sql-parser -本项目用于处理SQL,目前含有功能 +此项目是基于 [ANTLR4](https://github.com/antlr/antlr4) 开发的 SQL 语言解析器。主要用于大数据开发中,对各类 SQL 的解析。目前支持的 SQL: -1. 校验SQL,hive SQL,impala SQL,flinkSQL 等语法,并给予错误信息与建议提示 -2. SQL分割,根据`;`将sql分割为数组 -3. 去除SQL中的的注释(目前支持`--`,`/**/`类型注释) +- MySQL +- Flink SQL +- Spark SQL +- Hive SQL +- PL/SQL -## 用法 +每种 SQL 都提供了对应基础类、Visitor 类和 Listener 类,包含了生成 token、生成 AST、语法校验、visitor 和 listener 模式遍历 AST 指定节点等功能。 -### 过滤注释 / SQL分割 +此外,为了方便解析,还提供了几个辅助方法可以在解析前对 SQL 进行格式处理。主要作用是清除 SQL 语句中的 '--' 和 '/**/' 两种类型的注释,以及拆分大段 SQL。 -``` javascript -const dtFilter=require("dt-sql-parser").filter; -const sql=` -/*sttttttttart*/create table /*hhhhhhhh -hhhhhh -aaaaaa*/ sql_task_comment_test(id int comment 'id') comment 'sql test'; - --eeeeeeeend -` -console.log(dtFilter.filterComments(sql))//过滤注释 -console.log(dtFilter.splitSql(sql));//分割sql +提示:项目中的 grammar 文件也可以通过 [ANTLR4](https://github.com/antlr/antlr4) 编译成其他语言 + +[English](./README.md) | 简体中文 + +## 安装 + +``` +// use npm +npm i dt-sql-parser --save + +// use yarn +yarn add dt-sql-parser ``` -### 校验hive sql语法 +## 示例 -``` javascript -const dtSqlParser=require("dt-sql-parser").parser; +### Clean -console.log(dtSqlParser.parseSyntax("selet * form",'hive')); +清除注释和前后空格 + +```javascript +import { cleanSql } from 'dt-sql-parser'; + +const sql = `-- comment comment +select id,name from user1; ` +const cleanedSql = cleanSql(sql) +console.log(cleanedSql) /* -{ - "text": "selet",//错误部分 - "token": "REGULAR_IDENTIFIER",//类型 - "line": 0, - "loc": {//错误位置信息 - "first_line": 1, - "last_line": 1, - "first_column": 0, - "last_column": 5 - }, - "ruleId": "0", - "expected": [//建议输入内容 - { - "text": "select",//建议内容 - "distance": 1//建议优先级 - }, - { - "text": "delete", - "distance": 2 - } - ], - "recoverable": false, - "incompleteStatement": true -} +select id,name from user1; */ ``` -## API +### Split -### filter +分割 sql -#### function filterComments(sql:string):string +```javascript +import { splitSql } from 'dt-sql-parser'; -过滤 `sql` 注释(支持`/*`和`--`) +const sql = `select id,name from user1; +select id,name from user2;` +const sqlList = splitSql(sql) +console.log(sqlList) -#### function splitSql(sql:string):Array +/* +["select id,name from user1;", "\nselect id,name from user2;"] +*/ +``` -自动去除注释,并且提取出各个 `sql` +### Tokens -### parser +对 sql 语句进行词法分析,生成 token -#### function parseSyntax(sql:string|Array, type?:string):Object|boolean +```javascript +import { GenericSQL } from 'dt-sql-parser'; -校验 `sql` 语法,如果没错误,则返回 `false`,否则返回错误详细信息 +const parser = new GenericSQL() +const sql = 'select id,name,sex from user1;' +const tokens = parser.getAllTokens(sql) +console.log(tokens) +/* +[ + { + channel: 0 + column: 0 + line: 1 + source: [SqlLexer, InputStream] + start: 0 + stop: 5 + tokenIndex: -1 + type: 137 + _text: null + text: "SELECT" + }, + ... +] +*/ +``` -可以提供一个含有两个字符串的数组,代表被光标分割的两个 `sql片段` +### Syntax validation -#### function parserSql(sql:string|Array, type?:string):Object +validate 方法对 sql 语句的语法正确性进行校验,返回一个由 error 组成的数组 -解析 `sql` 语法,根据上下文提示补全字段与其它辅助信息 +```javascript +import { GenericSQL } from 'dt-sql-parser'; -可以提供一个含有两个字符串的数组,代表被光标分割的两个sql片段 +const validate = (sql) => { + const parser = new GenericSQL() + const errors = parser.validate(sql) + console.log(errors) +} +``` +语法正确的 sql: +```javascript +const correctSql = 'select id,name from user1;' +validate(correctSql) +/* +[] +*/ +``` +包含错误语法的 sql: +```javascript +const incorrectSql = 'selec id,name from user1;' +validate(incorrectSql) +/* +[ + { + endCol: 5, + endLine: 1, + startCol: 0, + startLine: 1, + message: "mismatched input 'SELEC' expecting {, 'ALTER', 'ANALYZE', 'CALL', 'CHANGE', 'CHECK', 'CREATE', 'DELETE', 'DESC', 'DESCRIBE', 'DROP', 'EXPLAIN', 'GET', 'GRANT', 'INSERT', 'KILL', 'LOAD', 'LOCK', 'OPTIMIZE', 'PURGE', 'RELEASE', 'RENAME', 'REPLACE', 'RESIGNAL', 'REVOKE', 'SELECT', 'SET', 'SHOW', 'SIGNAL', 'UNLOCK', 'UPDATE', 'USE', 'BEGIN', 'BINLOG', 'CACHE', 'CHECKSUM', 'COMMIT', 'DEALLOCATE', 'DO', 'FLUSH', 'HANDLER', 'HELP', 'INSTALL', 'PREPARE', 'REPAIR', 'RESET', 'ROLLBACK', 'SAVEPOINT', 'START', 'STOP', 'TRUNCATE', 'UNINSTALL', 'XA', 'EXECUTE', 'SHUTDOWN', '--', '(', ';'}" + } +] +*/ +``` -### flinksqlParser +### Visitor -#### function flinksqlParser (sql: sql): SyntaxError +使用 visitor 模式访问 AST 中的指定节点 -校验 `flinksql` 语法。 +```javascript +import { GenericSQL, SqlParserVisitor } from 'dt-sql-parser'; ->本项目文档不是很详细,也不准确(暂时没精力写),项目功能可以满足 hivesql,sql,impala,flinksql 的语法检查和提示功能。 -具体使用方式可以参照代码中的 ts 类型。 ----- +const parser = new GenericSQL() +const sql = `select id,name from user1;` +// parseTree +const tree = parser.parse(sql) +class MyVisitor extends SqlParserVisitor { + // 重写 visitTableName 方法 + visitTableName(ctx) { + let tableName = ctx.getText().toLowerCase() + console.log('TableName', tableName) + } + // 重写 visitSelectElements 方法 + visitSelectElements(ctx) { + let selectElements = ctx.getText().toLowerCase() + console.log('SelectElements', selectElements) + } +} +const visitor = new MyVisitor() +visitor.visit(tree) -hive,impala语法解析文件来自[Hue](https://github.com/cloudera/hue) +/* +SelectElements id,name +TableName user1 +*/ ----- +``` +提示:使用 Visitor 模式时,节点的方法名称可以在对应 SQL 目录下的 Visitor 文件中查找 -### ChangeLog +### Listener -- 1.1.8 添加转义字符支持 -- 1.1.9 添加函数的中括号语法支持[ split(nameList](0) ) -- 1.2.0 添加 ts,添加测试 -- 2.0.0 添加flinksql语法检查 -- 3.0.0 拆分hive,impala,集成最新 `HUE` 方案 +listener 模式,利用 [ANTLR4](https://github.com/antlr/antlr4) 提供的 ParseTreeWalker 对象遍历 AST,进入各个节点时调用对应的方法。 + +```javascript +import { GenericSQL, SqlParserListener } from 'dt-sql-parser'; + +const parser = new GenericSQL(); +const sql = 'select id,name from user1;' +// parseTree +const tree = parser.parse(sql) +class MyListener extends SqlParserListener { + enterTableName(ctx) { + let tableName = ctx.getText().toLowerCase() + console.log('TableName', tableName) + } + enterSelectElements(ctx) { + let selectElements = ctx.getText().toLowerCase() + log('SelectElements', selectElements) + } +} +const listenTableName = new MyListener(); +parser.listen(listenTableName, tree); + +/* +SelectElements id,name +TableName user1 +*/ + +``` + +提示:使用 Listener 模式时,节点的方法名称可以在对应 SQL 目录下的 Listener 文件中查找 + +### 其他 + +- parserTreeToString 将 SQL 解析成 AST,再转成 string 形式 + +## 路线图 + +- Auto-complete +- Impala SQL + +## 许可证 + +[MIT](./LICENSE) \ No newline at end of file