Skip to content

Commit 3f406d2

Browse files
authored
Merge pull request #21 from JavaScriptor/feat-union-support
Feat union support
2 parents c2decc0 + 2bbd726 commit 3f406d2

File tree

3 files changed

+64
-7
lines changed

3 files changed

+64
-7
lines changed

src/sqlParser.jison

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ SHARE return 'SHARE'
8989
MODE return 'MODE'
9090
OJ return 'OJ'
9191
LIMIT return 'LIMIT'
92+
UNION return 'UNION'
9293

9394
"," return ','
9495
"=" return '='
@@ -159,8 +160,32 @@ LIMIT return 'LIMIT'
159160
%% /* language grammar */
160161

161162
main
162-
: selectClause EOF { return {nodeType: 'Main', value: $1}; }
163-
| selectClause ';' EOF { return {nodeType: 'Main', value: $1, hasSemicolon: true}; }
163+
: selectClause semicolonOpt EOF { return {nodeType: 'Main', value: $1, hasSemicolon: $2}; }
164+
| unionClause semicolonOpt EOF { return {nodeType: 'Main', value: $1, hasSemicolon: $2}; }
165+
;
166+
167+
semicolonOpt
168+
: ';' { $$ = true }
169+
| { $$ = false }
170+
;
171+
172+
unionClause
173+
: unionClauseNotParenthesized { $$ = $1 }
174+
| unionClauseParenthesized order_by_opt limit_opt { $$ = $1, $$.orderBy = $2, $$.limit = $3; }
175+
;
176+
177+
unionClauseParenthesized
178+
: selectClauseParenthesized UNION distinctOpt selectClauseParenthesized { $$ = { type: 'Union', left: $1, distinctOpt: $3, right: $4 }; }
179+
| selectClauseParenthesized UNION distinctOpt unionClauseParenthesized { $$ = { type: 'Union', left: $1, distinctOpt: $3, right: $4 }; }
180+
;
181+
182+
selectClauseParenthesized
183+
: '(' selectClause ')' { $$ = { type: 'SelectParenthesized', value: $2 }; }
184+
;
185+
186+
unionClauseNotParenthesized
187+
: selectClause UNION distinctOpt selectClause { $$ = { type: 'Union', left: $1, distinctOpt: $3, right: $4 } }
188+
| selectClause UNION distinctOpt unionClauseNotParenthesized { $$ = { type: 'Union', left: $1, distinctOpt: $3, right: $4 } }
164189
;
165190

166191
selectClause

src/stringify.js

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { timingSafeEqual } from "crypto";
2+
13
if (!sqlParser) {
24
sqlParser = {};
35
}
@@ -55,13 +57,13 @@ Sql.prototype.append = function(word, noPrefix, noSuffix) {
5557
}
5658
}
5759
Sql.prototype.travelMain = function(ast) {
58-
this.travelSelect(ast.value);
60+
this.travel(ast.value);
5961
if (ast.hasSemicolon) {
6062
this.append(';', true);
6163
}
6264
}
6365
Sql.prototype.travelSelect = function(ast) {
64-
this.appendKeyword('select', true);
66+
this.appendKeyword('select');
6567
if (ast.distinctOpt) {
6668
this.appendKeyword(ast.distinctOpt);
6769
}
@@ -537,3 +539,16 @@ Sql.prototype.travelTableFactor = function (ast) {
537539
this.travel(ast.indexHintOpt);
538540
}
539541
}
542+
Sql.prototype.travelUnion = function (ast) {
543+
this.travel(ast.left);
544+
this.appendKeyword('UNION');
545+
if (ast.distinctOpt) {
546+
this.appendKeyword(ast.distinctOpt)
547+
}
548+
this.travel(ast.right);
549+
}
550+
Sql.prototype.travelSelectParenthesized = function (ast) {
551+
this.appendKeyword('(');
552+
this.travel(ast.value);
553+
this.appendKeyword(')');
554+
}

test/main.test.js

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,20 @@ const parser = require('../');
55

66
const testParser = function (sql) {
77
let firstAst = parser.parse(sql);
8+
debug(JSON.stringify(firstAst, null, 2));
89
let firstSql = parser.stringify(firstAst);
10+
debug(firstSql);
911
let secondAst = parser.parse(firstSql);
12+
debug(parser.stringify(secondAst));
1013
let secondSql = parser.stringify(secondAst);
14+
debug(JSON.stringify(secondAst, null, 2));
1115

1216
if (firstSql !== secondSql) {
1317
console.log('firstSql', firstSql);
1418
console.log('secondSql', secondSql);
1519
throw 'err firstSql don\'t equals secondSql. ';
1620
}
1721

18-
debug(JSON.stringify(secondAst, null, 2));
19-
debug(parser.stringify(secondAst));
20-
2122
return secondAst;
2223
}
2324

@@ -360,5 +361,21 @@ describe('select grammar support', function () {
360361
testParser('SELECT COUNT(*) AS total, a b, b as c, c/2 d, d & e an FROM b');
361362
});
362363

364+
it ('union support, https://dev.mysql.com/doc/refman/8.0/en/union.html', function () {
365+
testParser('select a from dual union select a from foo;');
366+
});
367+
368+
it ('union Parenthesized support, https://dev.mysql.com/doc/refman/8.0/en/union.html', function () {
369+
testParser('(select a from dual) union (select a from foo) order by a desc limit 100, 100;');
370+
});
371+
372+
it ('union all support, https://dev.mysql.com/doc/refman/8.0/en/union.html', function () {
373+
testParser('(select a from dual) union all (select a from foo) order by a limit 100');
374+
});
375+
376+
it ('union distinct support, https://dev.mysql.com/doc/refman/8.0/en/union.html', function () {
377+
testParser('select a from dual order by a desc limit 1, 1 union distinct select a from foo order by a limit 1');
378+
});
379+
363380
});
364381

0 commit comments

Comments
 (0)