├── .gitignore
├── Cakefile
├── LICENSE
├── README.md
├── browser
├── example.html
└── sql-parser.js
├── index.js
├── lib
├── browser.js
├── compiled_parser.js
├── grammar.js
├── lexer.js
├── nodes.js
├── parser.js
└── sql_parser.js
├── package.json
├── src
├── grammar.coffee
├── lexer.coffee
├── nodes.coffee
├── parser.coffee
└── sql_parser.coffee
└── test
├── grammar.spec.coffee
└── lexer.spec.coffee
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .DS_Store
3 | *.swp
4 |
5 |
--------------------------------------------------------------------------------
/Cakefile:
--------------------------------------------------------------------------------
1 | {spawn, exec} = require 'child_process'
2 | fs = require('fs')
3 | require('coffee-script/register')
4 |
5 | run = (args, cb) ->
6 | proc = spawn './node_modules/.bin/coffee', args
7 | proc.stderr.on 'data', (buffer) -> console.log buffer.toString()
8 | proc.on 'exit', (status) ->
9 | process.exit(1) if status != 0
10 | cb() if typeof cb is 'function'
11 |
12 | build = (cb) ->
13 | files = fs.readdirSync 'src'
14 | files = ('src/' + file for file in files when file.match(/\.coffee$/))
15 | run ['-c', '-o', 'lib'].concat(files), cb
16 |
17 | task 'build', 'Run full build', ->
18 | invoke 'build:compile'
19 | invoke 'build:parser'
20 | setTimeout (-> invoke 'build:browser'), 100
21 |
22 | task 'build:compile', 'Compile all coffee files to js',
23 | build
24 |
25 | task 'build:parser', 'rebuild the Jison parser', ->
26 | parser = require('./src/grammar').parser
27 | fs.writeFileSync 'lib/compiled_parser.js', parser.generate()
28 |
29 | task 'build:browser', 'Build a single JS file suitable for use in the browser', ->
30 | code = ''
31 | for name in ['lexer', 'compiled_parser', 'nodes', 'parser', 'sql_parser']
32 | code += """
33 | require['./#{name}'] = new function() {
34 | var exports = this;
35 | #{fs.readFileSync "lib/#{name}.js"}
36 | };
37 | """
38 | code = """
39 | (function(root) {
40 | var SQLParser = function() {
41 | function require(path){ return require[path]; }
42 | #{code}
43 | return require['./sql_parser']
44 | }();
45 |
46 | if(typeof define === 'function' && define.amd) {
47 | define(function() { return SQLParser });
48 | } else { root.SQLParser = SQLParser }
49 | }(this));
50 | """
51 | fs.writeFileSync './browser/sql-parser.js', code
52 |
53 |
54 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2012 Andrew Kent
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 |
7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | SQL Parser
2 | ==========
3 |
4 | SQL Parser is a lexer, grammar and parser for SQL written in JS. Currently it is only capable of parsing fairly basic SELECT queries but full SQL support will hopefully come in time. See the specs for examples of currently supported queries.
5 |
6 |
7 | Installation
8 | ----------
9 |
10 | The package is distributed on NPM and can be installed with...
11 |
12 | npm install sql-parser
13 |
14 | To build from source you'll need to run the following from the root of the project...
15 |
16 | npm install
17 | cake build
18 |
19 | Tests are written using Mocha and can be run with...
20 |
21 | npm test
22 |
23 |
24 | Lexer
25 | -----
26 |
27 | The lexer takes a SQL query string as input and returns a stream of tokens in the format
28 |
29 | ['NAME', 'value', lineNumber]
30 |
31 | Here is a simple example...
32 |
33 | lexer.tokenize('select * from my_table')
34 |
35 | [
36 | ['SELECT','select',1],
37 | ['STAR','*',1],
38 | ['FROM','from',1],
39 | ['LITERAL','my_table',1]
40 | ]
41 |
42 | The tokenized output is in a format compatible with JISON.
43 |
44 |
45 | Parser
46 | ------
47 |
48 | The parser only currently supports SELECT queries but is able to produce a Select object with properties for where, group, order, limit. See lib/nodes.coffee for more info of the returned object structure. Calling .toString() on a Select object should give you back a well formatted version of the original SQL input.
49 |
50 | tokens = lexer.tokenize('select * from my_table where foo = 'bar')
51 | parser.parse(tokens).toString()
52 |
53 | SELECT *
54 | FROM `my_table`
55 | WHERE `foo` = 'bar'
56 |
57 |
58 | Credits
59 | -------
60 |
61 | A lot of the boilerplate and compilation code in this project is borrowed from the CoffeeScript project as it was the best example of a project using JISON that I could find. Thanks.
62 |
63 |
64 | Contributions
65 | -------------
66 |
67 | Contributions in the form of pull requests that add syntax support are very welcome but should be supported by both Lexer and Parser level tests.
--------------------------------------------------------------------------------
/browser/example.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
--------------------------------------------------------------------------------
/browser/sql-parser.js:
--------------------------------------------------------------------------------
1 | (function(root) {
2 | var SQLParser = function() {
3 | function require(path){ return require[path]; }
4 | require['./lexer'] = new function() {
5 | var exports = this;
6 | // Generated by CoffeeScript 1.8.0
7 | (function() {
8 | var Lexer;
9 |
10 | Lexer = (function() {
11 | var BOOLEAN, DBLSTRING, LITERAL, MATH, MATH_MULTI, NUMBER, PARAMETER, SEPARATOR, SQL_BETWEENS, SQL_CONDITIONALS, SQL_FUNCTIONS, SQL_OPERATORS, SQL_SORT_ORDERS, STAR, STRING, SUB_SELECT_OP, SUB_SELECT_UNARY_OP, WHITESPACE;
12 |
13 | function Lexer(sql, opts) {
14 | var bytesConsumed, i;
15 | if (opts == null) {
16 | opts = {};
17 | }
18 | this.sql = sql;
19 | this.preserveWhitespace = opts.preserveWhitespace || false;
20 | this.tokens = [];
21 | this.currentLine = 1;
22 | i = 0;
23 | while (this.chunk = sql.slice(i)) {
24 | bytesConsumed = this.keywordToken() || this.starToken() || this.booleanToken() || this.functionToken() || this.windowExtension() || this.sortOrderToken() || this.seperatorToken() || this.operatorToken() || this.mathToken() || this.dotToken() || this.conditionalToken() || this.betweenToken() || this.subSelectOpToken() || this.subSelectUnaryOpToken() || this.numberToken() || this.stringToken() || this.parameterToken() || this.parensToken() || this.whitespaceToken() || this.literalToken();
25 | if (bytesConsumed < 1) {
26 | throw new Error("NOTHING CONSUMED: Stopped at - '" + (this.chunk.slice(0, 30)) + "'");
27 | }
28 | i += bytesConsumed;
29 | }
30 | this.token('EOF', '');
31 | this.postProcess();
32 | }
33 |
34 | Lexer.prototype.postProcess = function() {
35 | var i, next_token, token, _i, _len, _ref, _results;
36 | _ref = this.tokens;
37 | _results = [];
38 | for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
39 | token = _ref[i];
40 | if (token[0] === 'STAR') {
41 | next_token = this.tokens[i + 1];
42 | if (!(next_token[0] === 'SEPARATOR' || next_token[0] === 'FROM')) {
43 | _results.push(token[0] = 'MATH_MULTI');
44 | } else {
45 | _results.push(void 0);
46 | }
47 | } else {
48 | _results.push(void 0);
49 | }
50 | }
51 | return _results;
52 | };
53 |
54 | Lexer.prototype.token = function(name, value) {
55 | return this.tokens.push([name, value, this.currentLine]);
56 | };
57 |
58 | Lexer.prototype.tokenizeFromRegex = function(name, regex, part, lengthPart, output) {
59 | var match, partMatch;
60 | if (part == null) {
61 | part = 0;
62 | }
63 | if (lengthPart == null) {
64 | lengthPart = part;
65 | }
66 | if (output == null) {
67 | output = true;
68 | }
69 | if (!(match = regex.exec(this.chunk))) {
70 | return 0;
71 | }
72 | partMatch = match[part];
73 | if (output) {
74 | this.token(name, partMatch);
75 | }
76 | return match[lengthPart].length;
77 | };
78 |
79 | Lexer.prototype.tokenizeFromWord = function(name, word) {
80 | var match, matcher;
81 | if (word == null) {
82 | word = name;
83 | }
84 | word = this.regexEscape(word);
85 | matcher = /^\w+$/.test(word) ? new RegExp("^(" + word + ")\\b", 'ig') : new RegExp("^(" + word + ")", 'ig');
86 | match = matcher.exec(this.chunk);
87 | if (!match) {
88 | return 0;
89 | }
90 | this.token(name, match[1]);
91 | return match[1].length;
92 | };
93 |
94 | Lexer.prototype.tokenizeFromList = function(name, list) {
95 | var entry, ret, _i, _len;
96 | ret = 0;
97 | for (_i = 0, _len = list.length; _i < _len; _i++) {
98 | entry = list[_i];
99 | ret = this.tokenizeFromWord(name, entry);
100 | if (ret > 0) {
101 | break;
102 | }
103 | }
104 | return ret;
105 | };
106 |
107 | Lexer.prototype.keywordToken = function() {
108 | return this.tokenizeFromWord('SELECT') || this.tokenizeFromWord('DISTINCT') || this.tokenizeFromWord('FROM') || this.tokenizeFromWord('WHERE') || this.tokenizeFromWord('GROUP') || this.tokenizeFromWord('ORDER') || this.tokenizeFromWord('BY') || this.tokenizeFromWord('HAVING') || this.tokenizeFromWord('LIMIT') || this.tokenizeFromWord('JOIN') || this.tokenizeFromWord('LEFT') || this.tokenizeFromWord('RIGHT') || this.tokenizeFromWord('INNER') || this.tokenizeFromWord('OUTER') || this.tokenizeFromWord('ON') || this.tokenizeFromWord('AS') || this.tokenizeFromWord('UNION') || this.tokenizeFromWord('ALL') || this.tokenizeFromWord('LIMIT') || this.tokenizeFromWord('OFFSET') || this.tokenizeFromWord('FETCH') || this.tokenizeFromWord('ROW') || this.tokenizeFromWord('ROWS') || this.tokenizeFromWord('ONLY') || this.tokenizeFromWord('NEXT') || this.tokenizeFromWord('FIRST');
109 | };
110 |
111 | Lexer.prototype.dotToken = function() {
112 | return this.tokenizeFromWord('DOT', '.');
113 | };
114 |
115 | Lexer.prototype.operatorToken = function() {
116 | return this.tokenizeFromList('OPERATOR', SQL_OPERATORS);
117 | };
118 |
119 | Lexer.prototype.mathToken = function() {
120 | return this.tokenizeFromList('MATH', MATH) || this.tokenizeFromList('MATH_MULTI', MATH_MULTI);
121 | };
122 |
123 | Lexer.prototype.conditionalToken = function() {
124 | return this.tokenizeFromList('CONDITIONAL', SQL_CONDITIONALS);
125 | };
126 |
127 | Lexer.prototype.betweenToken = function() {
128 | return this.tokenizeFromList('BETWEEN', SQL_BETWEENS);
129 | };
130 |
131 | Lexer.prototype.subSelectOpToken = function() {
132 | return this.tokenizeFromList('SUB_SELECT_OP', SUB_SELECT_OP);
133 | };
134 |
135 | Lexer.prototype.subSelectUnaryOpToken = function() {
136 | return this.tokenizeFromList('SUB_SELECT_UNARY_OP', SUB_SELECT_UNARY_OP);
137 | };
138 |
139 | Lexer.prototype.functionToken = function() {
140 | return this.tokenizeFromList('FUNCTION', SQL_FUNCTIONS);
141 | };
142 |
143 | Lexer.prototype.sortOrderToken = function() {
144 | return this.tokenizeFromList('DIRECTION', SQL_SORT_ORDERS);
145 | };
146 |
147 | Lexer.prototype.booleanToken = function() {
148 | return this.tokenizeFromList('BOOLEAN', BOOLEAN);
149 | };
150 |
151 | Lexer.prototype.starToken = function() {
152 | return this.tokenizeFromRegex('STAR', STAR);
153 | };
154 |
155 | Lexer.prototype.seperatorToken = function() {
156 | return this.tokenizeFromRegex('SEPARATOR', SEPARATOR);
157 | };
158 |
159 | Lexer.prototype.literalToken = function() {
160 | return this.tokenizeFromRegex('LITERAL', LITERAL, 1, 0);
161 | };
162 |
163 | Lexer.prototype.numberToken = function() {
164 | return this.tokenizeFromRegex('NUMBER', NUMBER);
165 | };
166 |
167 | Lexer.prototype.parameterToken = function() {
168 | return this.tokenizeFromRegex('PARAMETER', PARAMETER);
169 | };
170 |
171 | Lexer.prototype.stringToken = function() {
172 | return this.tokenizeFromRegex('STRING', STRING, 1, 0) || this.tokenizeFromRegex('DBLSTRING', DBLSTRING, 1, 0);
173 | };
174 |
175 | Lexer.prototype.parensToken = function() {
176 | return this.tokenizeFromRegex('LEFT_PAREN', /^\(/) || this.tokenizeFromRegex('RIGHT_PAREN', /^\)/);
177 | };
178 |
179 | Lexer.prototype.windowExtension = function() {
180 | var match;
181 | match = /^\.(win):(length|time)/i.exec(this.chunk);
182 | if (!match) {
183 | return 0;
184 | }
185 | this.token('WINDOW', match[1]);
186 | this.token('WINDOW_FUNCTION', match[2]);
187 | return match[0].length;
188 | };
189 |
190 | Lexer.prototype.whitespaceToken = function() {
191 | var match, newlines, partMatch;
192 | if (!(match = WHITESPACE.exec(this.chunk))) {
193 | return 0;
194 | }
195 | partMatch = match[0];
196 | newlines = partMatch.replace(/[^\n]/, '').length;
197 | this.currentLine += newlines;
198 | if (this.preserveWhitespace) {
199 | this.token(name, partMatch);
200 | }
201 | return partMatch.length;
202 | };
203 |
204 | Lexer.prototype.regexEscape = function(str) {
205 | return str.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
206 | };
207 |
208 | SQL_FUNCTIONS = ['AVG', 'COUNT', 'MIN', 'MAX', 'SUM'];
209 |
210 | SQL_SORT_ORDERS = ['ASC', 'DESC'];
211 |
212 | SQL_OPERATORS = ['=', '!=', '>=', '>', '<=', '<>', '<', 'LIKE', 'IS NOT', 'IS'];
213 |
214 | SUB_SELECT_OP = ['IN', 'NOT IN', 'ANY', 'ALL', 'SOME'];
215 |
216 | SUB_SELECT_UNARY_OP = ['EXISTS'];
217 |
218 | SQL_CONDITIONALS = ['AND', 'OR'];
219 |
220 | SQL_BETWEENS = ['BETWEEN', 'NOT BETWEEN'];
221 |
222 | BOOLEAN = ['TRUE', 'FALSE', 'NULL'];
223 |
224 | MATH = ['+', '-'];
225 |
226 | MATH_MULTI = ['/', '*'];
227 |
228 | STAR = /^\*/;
229 |
230 | SEPARATOR = /^,/;
231 |
232 | WHITESPACE = /^[ \n\r]+/;
233 |
234 | LITERAL = /^`?([a-z_][a-z0-9_]{0,})`?/i;
235 |
236 | PARAMETER = /^\$[0-9]+/;
237 |
238 | NUMBER = /^[0-9]+(\.[0-9]+)?/;
239 |
240 | STRING = /^'([^\\']*(?:\\.[^\\']*)*)'/;
241 |
242 | DBLSTRING = /^"([^\\"]*(?:\\.[^\\"]*)*)"/;
243 |
244 | return Lexer;
245 |
246 | })();
247 |
248 | exports.tokenize = function(sql, opts) {
249 | return (new Lexer(sql, opts)).tokens;
250 | };
251 |
252 | }).call(this);
253 |
254 | };require['./compiled_parser'] = new function() {
255 | var exports = this;
256 | /* parser generated by jison 0.4.15 */
257 | /*
258 | Returns a Parser object of the following structure:
259 |
260 | Parser: {
261 | yy: {}
262 | }
263 |
264 | Parser.prototype: {
265 | yy: {},
266 | trace: function(),
267 | symbols_: {associative list: name ==> number},
268 | terminals_: {associative list: number ==> name},
269 | productions_: [...],
270 | performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate, $$, _$),
271 | table: [...],
272 | defaultActions: {...},
273 | parseError: function(str, hash),
274 | parse: function(input),
275 |
276 | lexer: {
277 | EOF: 1,
278 | parseError: function(str, hash),
279 | setInput: function(input),
280 | input: function(),
281 | unput: function(str),
282 | more: function(),
283 | less: function(n),
284 | pastInput: function(),
285 | upcomingInput: function(),
286 | showPosition: function(),
287 | test_match: function(regex_match_array, rule_index),
288 | next: function(),
289 | lex: function(),
290 | begin: function(condition),
291 | popState: function(),
292 | _currentRules: function(),
293 | topState: function(),
294 | pushState: function(condition),
295 |
296 | options: {
297 | ranges: boolean (optional: true ==> token location info will include a .range[] member)
298 | flex: boolean (optional: true ==> flex-like lexing behaviour where the rules are tested exhaustively to find the longest match)
299 | backtrack_lexer: boolean (optional: true ==> lexer regexes are tested in order and for each matching regex the action code is invoked; the lexer terminates the scan when a token is returned by the action code)
300 | },
301 |
302 | performAction: function(yy, yy_, $avoiding_name_collisions, YY_START),
303 | rules: [...],
304 | conditions: {associative list: name ==> set},
305 | }
306 | }
307 |
308 |
309 | token location info (@$, _$, etc.): {
310 | first_line: n,
311 | last_line: n,
312 | first_column: n,
313 | last_column: n,
314 | range: [start_number, end_number] (where the numbers are indexes into the input string, regular zero-based)
315 | }
316 |
317 |
318 | the parseError function receives a 'hash' object with these members for lexer and parser errors: {
319 | text: (matched text)
320 | token: (the produced terminal token, if any)
321 | line: (yylineno)
322 | }
323 | while parser (grammar) errors will also provide these members, i.e. parser errors deliver a superset of attributes: {
324 | loc: (yylloc)
325 | expected: (string describing the set of expected tokens)
326 | recoverable: (boolean: TRUE when the parser has a error recovery rule available for this particular error)
327 | }
328 | */
329 | var parser = (function(){
330 | var o=function(k,v,o,l){for(o=o||{},l=k.length;l--;o[k[l]]=v);return o},$V0=[1,8],$V1=[5,26],$V2=[1,14],$V3=[1,13],$V4=[5,26,31,42],$V5=[1,17],$V6=[5,26,31,42,45,62],$V7=[1,27],$V8=[1,29],$V9=[1,39],$Va=[1,43],$Vb=[1,44],$Vc=[1,40],$Vd=[1,41],$Ve=[1,38],$Vf=[1,42],$Vg=[1,25],$Vh=[5,26,31],$Vi=[5,26,31,42,45],$Vj=[1,56],$Vk=[18,43],$Vl=[1,59],$Vm=[1,60],$Vn=[1,61],$Vo=[1,62],$Vp=[1,63],$Vq=[5,18,23,26,31,34,37,38,41,42,43,45,62,64,65,66,67,68,70],$Vr=[5,18,23,26,31,34,37,38,41,42,43,44,45,51,62,64,65,66,67,68,70,71],$Vs=[1,69],$Vt=[2,83],$Vu=[1,83],$Vv=[1,84],$Vw=[1,102],$Vx=[5,26,31,42,43,44],$Vy=[1,110],$Vz=[5,26,31,42,43,45,64],$VA=[5,26,31,41,42,45,62],$VB=[1,113],$VC=[1,114],$VD=[1,115],$VE=[5,26,31,34,35,37,38,41,42,45,62],$VF=[5,18,23,26,31,34,37,38,41,42,43,45,62,64,70],$VG=[5,26,31,34,37,38,41,42,45,62],$VH=[5,26,31,42,56,58];
331 | var parser = {trace: function trace() { },
332 | yy: {},
333 | symbols_: {"error":2,"Root":3,"Query":4,"EOF":5,"SelectQuery":6,"Unions":7,"SelectWithLimitQuery":8,"BasicSelectQuery":9,"Select":10,"OrderClause":11,"GroupClause":12,"LimitClause":13,"SelectClause":14,"WhereClause":15,"SELECT":16,"Fields":17,"FROM":18,"Table":19,"DISTINCT":20,"Joins":21,"Literal":22,"AS":23,"LEFT_PAREN":24,"List":25,"RIGHT_PAREN":26,"WINDOW":27,"WINDOW_FUNCTION":28,"Number":29,"Union":30,"UNION":31,"ALL":32,"Join":33,"JOIN":34,"ON":35,"Expression":36,"LEFT":37,"RIGHT":38,"INNER":39,"OUTER":40,"WHERE":41,"LIMIT":42,"SEPARATOR":43,"OFFSET":44,"ORDER":45,"BY":46,"OrderArgs":47,"OffsetClause":48,"OrderArg":49,"Value":50,"DIRECTION":51,"OffsetRows":52,"FetchClause":53,"ROW":54,"ROWS":55,"FETCH":56,"FIRST":57,"ONLY":58,"NEXT":59,"GroupBasicClause":60,"HavingClause":61,"GROUP":62,"ArgumentList":63,"HAVING":64,"MATH":65,"MATH_MULTI":66,"OPERATOR":67,"BETWEEN":68,"BetweenExpression":69,"CONDITIONAL":70,"SUB_SELECT_OP":71,"SubSelectExpression":72,"SUB_SELECT_UNARY_OP":73,"String":74,"Function":75,"UserFunction":76,"Boolean":77,"Parameter":78,"NUMBER":79,"BOOLEAN":80,"PARAMETER":81,"STRING":82,"DBLSTRING":83,"LITERAL":84,"DOT":85,"FUNCTION":86,"AggregateArgumentList":87,"Field":88,"STAR":89,"$accept":0,"$end":1},
334 | terminals_: {2:"error",5:"EOF",16:"SELECT",18:"FROM",20:"DISTINCT",23:"AS",24:"LEFT_PAREN",26:"RIGHT_PAREN",27:"WINDOW",28:"WINDOW_FUNCTION",31:"UNION",32:"ALL",34:"JOIN",35:"ON",37:"LEFT",38:"RIGHT",39:"INNER",40:"OUTER",41:"WHERE",42:"LIMIT",43:"SEPARATOR",44:"OFFSET",45:"ORDER",46:"BY",51:"DIRECTION",54:"ROW",55:"ROWS",56:"FETCH",57:"FIRST",58:"ONLY",59:"NEXT",62:"GROUP",64:"HAVING",65:"MATH",66:"MATH_MULTI",67:"OPERATOR",68:"BETWEEN",70:"CONDITIONAL",71:"SUB_SELECT_OP",73:"SUB_SELECT_UNARY_OP",79:"NUMBER",80:"BOOLEAN",81:"PARAMETER",82:"STRING",83:"DBLSTRING",84:"LITERAL",85:"DOT",86:"FUNCTION",89:"STAR"},
335 | productions_: [0,[3,2],[4,1],[4,2],[6,1],[6,1],[9,1],[9,2],[9,2],[9,3],[8,2],[10,1],[10,2],[14,4],[14,5],[14,5],[14,6],[19,1],[19,2],[19,3],[19,3],[19,3],[19,4],[19,6],[7,1],[7,2],[30,2],[30,3],[21,1],[21,2],[33,4],[33,5],[33,5],[33,6],[33,6],[33,6],[33,6],[15,2],[13,2],[13,4],[13,4],[11,3],[11,4],[47,1],[47,3],[49,1],[49,2],[48,2],[48,3],[52,2],[52,2],[53,4],[53,4],[12,1],[12,2],[60,3],[61,2],[36,3],[36,3],[36,3],[36,3],[36,3],[36,3],[36,5],[36,3],[36,2],[36,1],[36,1],[69,3],[72,3],[50,1],[50,1],[50,1],[50,1],[50,1],[50,1],[50,1],[25,1],[29,1],[77,1],[78,1],[74,1],[74,1],[22,1],[22,3],[75,4],[76,3],[76,4],[87,1],[87,2],[63,1],[63,3],[17,1],[17,3],[88,1],[88,1],[88,3]],
336 | performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate /* action[1] */, $$ /* vstack */, _$ /* lstack */) {
337 | /* this == yyval */
338 |
339 | var $0 = $$.length - 1;
340 | switch (yystate) {
341 | case 1:
342 | return this.$ = $$[$0-1];
343 | break;
344 | case 2: case 4: case 5: case 6: case 11: case 53: case 66: case 67: case 70: case 71: case 72: case 73: case 74: case 75: case 76:
345 | this.$ = $$[$0];
346 | break;
347 | case 3:
348 | this.$ = (function () {
349 | $$[$0-1].unions = $$[$0];
350 | return $$[$0-1];
351 | }());
352 | break;
353 | case 7:
354 | this.$ = (function () {
355 | $$[$0-1].order = $$[$0];
356 | return $$[$0-1];
357 | }());
358 | break;
359 | case 8:
360 | this.$ = (function () {
361 | $$[$0-1].group = $$[$0];
362 | return $$[$0-1];
363 | }());
364 | break;
365 | case 9:
366 | this.$ = (function () {
367 | $$[$0-2].group = $$[$0-1];
368 | $$[$0-2].order = $$[$0];
369 | return $$[$0-2];
370 | }());
371 | break;
372 | case 10:
373 | this.$ = (function () {
374 | $$[$0-1].limit = $$[$0];
375 | return $$[$0-1];
376 | }());
377 | break;
378 | case 12:
379 | this.$ = (function () {
380 | $$[$0-1].where = $$[$0];
381 | return $$[$0-1];
382 | }());
383 | break;
384 | case 13:
385 | this.$ = new yy.Select($$[$0-2], $$[$0], false);
386 | break;
387 | case 14:
388 | this.$ = new yy.Select($$[$0-2], $$[$0], true);
389 | break;
390 | case 15:
391 | this.$ = new yy.Select($$[$0-3], $$[$0-1], false, $$[$0]);
392 | break;
393 | case 16:
394 | this.$ = new yy.Select($$[$0-3], $$[$0-1], true, $$[$0]);
395 | break;
396 | case 17:
397 | this.$ = new yy.Table($$[$0]);
398 | break;
399 | case 18:
400 | this.$ = new yy.Table($$[$0-1], $$[$0]);
401 | break;
402 | case 19:
403 | this.$ = new yy.Table($$[$0-2], $$[$0]);
404 | break;
405 | case 20: case 49: case 50: case 51: case 52: case 57:
406 | this.$ = $$[$0-1];
407 | break;
408 | case 21: case 69:
409 | this.$ = new yy.SubSelect($$[$0-1]);
410 | break;
411 | case 22:
412 | this.$ = new yy.SubSelect($$[$0-2], $$[$0]);
413 | break;
414 | case 23:
415 | this.$ = new yy.Table($$[$0-5], null, $$[$0-4], $$[$0-3], $$[$0-1]);
416 | break;
417 | case 24: case 28: case 43: case 90: case 92:
418 | this.$ = [$$[$0]];
419 | break;
420 | case 25:
421 | this.$ = $$[$0-1].concat($$[$01]);
422 | break;
423 | case 26:
424 | this.$ = new yy.Union($$[$0]);
425 | break;
426 | case 27:
427 | this.$ = new yy.Union($$[$0], true);
428 | break;
429 | case 29:
430 | this.$ = $$[$0-1].concat($$[$0]);
431 | break;
432 | case 30:
433 | this.$ = new yy.Join($$[$0-2], $$[$0]);
434 | break;
435 | case 31:
436 | this.$ = new yy.Join($$[$0-2], $$[$0], 'LEFT');
437 | break;
438 | case 32:
439 | this.$ = new yy.Join($$[$0-2], $$[$0], 'RIGHT');
440 | break;
441 | case 33:
442 | this.$ = new yy.Join($$[$0-2], $$[$0], 'LEFT', 'INNER');
443 | break;
444 | case 34:
445 | this.$ = new yy.Join($$[$0-2], $$[$0], 'RIGHT', 'INNER');
446 | break;
447 | case 35:
448 | this.$ = new yy.Join($$[$0-2], $$[$0], 'LEFT', 'OUTER');
449 | break;
450 | case 36:
451 | this.$ = new yy.Join($$[$0-2], $$[$0], 'RIGHT', 'OUTER');
452 | break;
453 | case 37:
454 | this.$ = new yy.Where($$[$0]);
455 | break;
456 | case 38:
457 | this.$ = new yy.Limit($$[$0]);
458 | break;
459 | case 39:
460 | this.$ = new yy.Limit($$[$0], $$[$0-2]);
461 | break;
462 | case 40:
463 | this.$ = new yy.Limit($$[$0-2], $$[$0]);
464 | break;
465 | case 41:
466 | this.$ = new yy.Order($$[$0]);
467 | break;
468 | case 42:
469 | this.$ = new yy.Order($$[$0-1], $$[$0]);
470 | break;
471 | case 44: case 91: case 93:
472 | this.$ = $$[$0-2].concat($$[$0]);
473 | break;
474 | case 45:
475 | this.$ = new yy.OrderArgument($$[$0], 'ASC');
476 | break;
477 | case 46:
478 | this.$ = new yy.OrderArgument($$[$0-1], $$[$0]);
479 | break;
480 | case 47:
481 | this.$ = new yy.Offset($$[$0]);
482 | break;
483 | case 48:
484 | this.$ = new yy.Offset($$[$0-1], $$[$0]);
485 | break;
486 | case 54:
487 | this.$ = (function () {
488 | $$[$0-1].having = $$[$0];
489 | return $$[$0-1];
490 | }());
491 | break;
492 | case 55:
493 | this.$ = new yy.Group($$[$0]);
494 | break;
495 | case 56:
496 | this.$ = new yy.Having($$[$0]);
497 | break;
498 | case 58: case 59: case 60: case 61: case 62: case 64:
499 | this.$ = new yy.Op($$[$0-1], $$[$0-2], $$[$0]);
500 | break;
501 | case 63:
502 | this.$ = new yy.Op($$[$0-3], $$[$0-4], $$[$0-1]);
503 | break;
504 | case 65:
505 | this.$ = new yy.UnaryOp($$[$0-1], $$[$0]);
506 | break;
507 | case 68:
508 | this.$ = new yy.BetweenOp([$$[$0-2], $$[$0]]);
509 | break;
510 | case 77:
511 | this.$ = new yy.ListValue($$[$0]);
512 | break;
513 | case 78:
514 | this.$ = new yy.NumberValue($$[$0]);
515 | break;
516 | case 79:
517 | this.$ = new yy.BooleanValue($$[$0]);
518 | break;
519 | case 80:
520 | this.$ = new yy.ParameterValue($$[$0]);
521 | break;
522 | case 81:
523 | this.$ = new yy.StringValue($$[$0], "'");
524 | break;
525 | case 82:
526 | this.$ = new yy.StringValue($$[$0], '"');
527 | break;
528 | case 83:
529 | this.$ = new yy.LiteralValue($$[$0]);
530 | break;
531 | case 84:
532 | this.$ = new yy.LiteralValue($$[$0-2], $$[$0]);
533 | break;
534 | case 85:
535 | this.$ = new yy.FunctionValue($$[$0-3], $$[$0-1]);
536 | break;
537 | case 86:
538 | this.$ = new yy.FunctionValue($$[$0-2], null, true);
539 | break;
540 | case 87:
541 | this.$ = new yy.FunctionValue($$[$0-3], $$[$0-1], true);
542 | break;
543 | case 88:
544 | this.$ = new yy.ArgumentListValue($$[$0]);
545 | break;
546 | case 89:
547 | this.$ = new yy.ArgumentListValue($$[$0], true);
548 | break;
549 | case 94:
550 | this.$ = new yy.Star();
551 | break;
552 | case 95:
553 | this.$ = new yy.Field($$[$0]);
554 | break;
555 | case 96:
556 | this.$ = new yy.Field($$[$0-2], $$[$0]);
557 | break;
558 | }
559 | },
560 | table: [{3:1,4:2,6:3,8:4,9:5,10:6,14:7,16:$V0},{1:[3]},{5:[1,9]},o($V1,[2,2],{7:10,13:11,30:12,31:$V2,42:$V3}),o($V4,[2,4]),o($V4,[2,5]),o($V4,[2,6],{11:15,12:16,60:18,45:$V5,62:[1,19]}),o($V6,[2,11],{15:20,41:[1,21]}),{17:22,20:[1,23],22:31,24:$V7,29:32,36:26,50:28,72:30,73:$V8,74:33,75:34,76:35,77:36,78:37,79:$V9,80:$Va,81:$Vb,82:$Vc,83:$Vd,84:$Ve,86:$Vf,88:24,89:$Vg},{1:[2,1]},o($V1,[2,3],{30:45,31:$V2}),o($V4,[2,10]),o($Vh,[2,24]),{29:46,79:$V9},{6:47,8:4,9:5,10:6,14:7,16:$V0,32:[1,48]},o($V4,[2,7]),o($V4,[2,8],{11:49,45:$V5}),{46:[1,50]},o($Vi,[2,53],{61:51,64:[1,52]}),{46:[1,53]},o($V6,[2,12]),{22:31,24:$V7,29:32,36:54,50:28,72:30,73:$V8,74:33,75:34,76:35,77:36,78:37,79:$V9,80:$Va,81:$Vb,82:$Vc,83:$Vd,84:$Ve,86:$Vf},{18:[1,55],43:$Vj},{17:57,22:31,24:$V7,29:32,36:26,50:28,72:30,73:$V8,74:33,75:34,76:35,77:36,78:37,79:$V9,80:$Va,81:$Vb,82:$Vc,83:$Vd,84:$Ve,86:$Vf,88:24,89:$Vg},o($Vk,[2,92]),o($Vk,[2,94]),o($Vk,[2,95],{23:[1,58],65:$Vl,66:$Vm,67:$Vn,68:$Vo,70:$Vp}),{4:65,6:3,8:4,9:5,10:6,14:7,16:$V0,22:31,24:$V7,29:32,36:64,50:28,72:30,73:$V8,74:33,75:34,76:35,77:36,78:37,79:$V9,80:$Va,81:$Vb,82:$Vc,83:$Vd,84:$Ve,86:$Vf},o($Vq,[2,67],{71:[1,66]}),{24:[1,68],72:67},o($Vq,[2,66]),o($Vr,[2,70],{85:$Vs}),o($Vr,[2,71]),o($Vr,[2,72]),o($Vr,[2,73]),o($Vr,[2,74]),o($Vr,[2,75]),o($Vr,[2,76]),o([5,18,23,26,31,34,37,38,41,42,43,44,45,51,62,64,65,66,67,68,70,71,85],$Vt,{24:[1,70]}),o([5,18,23,26,31,34,37,38,41,42,43,44,45,51,54,55,62,64,65,66,67,68,70,71],[2,78]),o($Vr,[2,81]),o($Vr,[2,82]),{24:[1,71]},o($Vr,[2,79]),o($Vr,[2,80]),o($Vh,[2,25]),o($V4,[2,38],{43:[1,72],44:[1,73]}),o($Vh,[2,26],{13:11,42:$V3}),{6:74,8:4,9:5,10:6,14:7,16:$V0},o($V4,[2,9]),{22:31,29:32,47:75,49:76,50:77,74:33,75:34,76:35,77:36,78:37,79:$V9,80:$Va,81:$Vb,82:$Vc,83:$Vd,84:$Ve,86:$Vf},o($Vi,[2,54]),{22:31,24:$V7,29:32,36:78,50:28,72:30,73:$V8,74:33,75:34,76:35,77:36,78:37,79:$V9,80:$Va,81:$Vb,82:$Vc,83:$Vd,84:$Ve,86:$Vf},{22:31,24:$V7,29:32,36:80,50:28,63:79,72:30,73:$V8,74:33,75:34,76:35,77:36,78:37,79:$V9,80:$Va,81:$Vb,82:$Vc,83:$Vd,84:$Ve,86:$Vf},o($V6,[2,37],{65:$Vl,66:$Vm,67:$Vn,68:$Vo,70:$Vp}),{19:81,22:82,24:$Vu,84:$Vv},{22:31,24:$V7,29:32,36:26,50:28,72:30,73:$V8,74:33,75:34,76:35,77:36,78:37,79:$V9,80:$Va,81:$Vb,82:$Vc,83:$Vd,84:$Ve,86:$Vf,88:85,89:$Vg},{18:[1,86],43:$Vj},{22:87,84:$Vv},{22:31,24:$V7,29:32,36:88,50:28,72:30,73:$V8,74:33,75:34,76:35,77:36,78:37,79:$V9,80:$Va,81:$Vb,82:$Vc,83:$Vd,84:$Ve,86:$Vf},{22:31,24:$V7,29:32,36:89,50:28,72:30,73:$V8,74:33,75:34,76:35,77:36,78:37,79:$V9,80:$Va,81:$Vb,82:$Vc,83:$Vd,84:$Ve,86:$Vf},{22:31,24:$V7,29:32,36:90,50:28,72:30,73:$V8,74:33,75:34,76:35,77:36,78:37,79:$V9,80:$Va,81:$Vb,82:$Vc,83:$Vd,84:$Ve,86:$Vf},{22:31,24:$V7,29:32,36:92,50:28,69:91,72:30,73:$V8,74:33,75:34,76:35,77:36,78:37,79:$V9,80:$Va,81:$Vb,82:$Vc,83:$Vd,84:$Ve,86:$Vf},{22:31,24:$V7,29:32,36:93,50:28,72:30,73:$V8,74:33,75:34,76:35,77:36,78:37,79:$V9,80:$Va,81:$Vb,82:$Vc,83:$Vd,84:$Ve,86:$Vf},{26:[1,94],65:$Vl,66:$Vm,67:$Vn,68:$Vo,70:$Vp},{26:[1,95]},{24:[1,96],72:97},o($Vq,[2,65]),{4:65,6:3,8:4,9:5,10:6,14:7,16:$V0},{84:[1,98]},{20:$Vw,22:31,24:$V7,26:[1,99],29:32,36:80,50:28,63:101,72:30,73:$V8,74:33,75:34,76:35,77:36,78:37,79:$V9,80:$Va,81:$Vb,82:$Vc,83:$Vd,84:$Ve,86:$Vf,87:100},{20:$Vw,22:31,24:$V7,29:32,36:80,50:28,63:101,72:30,73:$V8,74:33,75:34,76:35,77:36,78:37,79:$V9,80:$Va,81:$Vb,82:$Vc,83:$Vd,84:$Ve,86:$Vf,87:103},{29:104,79:$V9},{29:105,79:$V9},o($Vh,[2,27],{13:11,42:$V3}),o($V4,[2,41],{48:106,43:[1,107],44:[1,108]}),o($Vx,[2,43]),o($Vx,[2,45],{51:[1,109]}),o($Vi,[2,56],{65:$Vl,66:$Vm,67:$Vn,68:$Vo,70:$Vp}),o([5,26,31,42,45,64],[2,55],{43:$Vy}),o($Vz,[2,90],{65:$Vl,66:$Vm,67:$Vn,68:$Vo,70:$Vp}),o($VA,[2,13],{21:111,33:112,34:$VB,37:$VC,38:$VD}),o($VE,[2,17],{22:116,23:[1,117],27:[1,118],84:$Vv,85:$Vs}),{4:120,6:3,8:4,9:5,10:6,14:7,16:$V0,22:31,24:$V7,25:119,29:32,36:80,50:28,63:121,72:30,73:$V8,74:33,75:34,76:35,77:36,78:37,79:$V9,80:$Va,81:$Vb,82:$Vc,83:$Vd,84:$Ve,86:$Vf},o([5,18,23,26,27,31,34,35,37,38,41,42,43,45,62,84,85],$Vt),o($Vk,[2,93]),{19:122,22:82,24:$Vu,84:$Vv},o($Vk,[2,96],{85:$Vs}),o([5,18,23,26,31,34,37,38,41,42,43,45,62,64,65,67,70],[2,58],{66:$Vm,68:$Vo}),o([5,18,23,26,31,34,37,38,41,42,43,45,62,64,65,66,67,70],[2,59],{68:$Vo}),o([5,18,23,26,31,34,37,38,41,42,43,45,62,64,67,70],[2,60],{65:$Vl,66:$Vm,68:$Vo}),o($Vq,[2,61]),{65:$Vl,66:$Vm,67:$Vn,68:$Vo,70:[1,123]},o($VF,[2,62],{65:$Vl,66:$Vm,67:$Vn,68:$Vo}),o($Vq,[2,57]),o($Vq,[2,69]),{4:65,6:3,8:4,9:5,10:6,14:7,16:$V0,22:31,24:$V7,25:124,29:32,36:80,50:28,63:121,72:30,73:$V8,74:33,75:34,76:35,77:36,78:37,79:$V9,80:$Va,81:$Vb,82:$Vc,83:$Vd,84:$Ve,86:$Vf},o($Vq,[2,64]),o([5,18,23,26,27,31,34,35,37,38,41,42,43,44,45,51,62,64,65,66,67,68,70,71,84,85],[2,84]),o($Vr,[2,86]),{26:[1,125]},{26:[2,88],43:$Vy},{22:31,24:$V7,29:32,36:80,50:28,63:126,72:30,73:$V8,74:33,75:34,76:35,77:36,78:37,79:$V9,80:$Va,81:$Vb,82:$Vc,83:$Vd,84:$Ve,86:$Vf},{26:[1,127]},o($V4,[2,39]),o($V4,[2,40]),o($V4,[2,42]),{22:31,29:32,49:128,50:77,74:33,75:34,76:35,77:36,78:37,79:$V9,80:$Va,81:$Vb,82:$Vc,83:$Vd,84:$Ve,86:$Vf},{29:130,52:129,79:$V9},o($Vx,[2,46]),{22:31,29:32,50:131,74:33,75:34,76:35,77:36,78:37,79:$V9,80:$Va,81:$Vb,82:$Vc,83:$Vd,84:$Ve,86:$Vf},o($VA,[2,15],{33:132,34:$VB,37:$VC,38:$VD}),o($VG,[2,28]),{19:133,22:82,24:$Vu,84:$Vv},{34:[1,134],39:[1,135],40:[1,136]},{34:[1,137],39:[1,138],40:[1,139]},o($VE,[2,18],{85:$Vs}),{22:140,84:$Vv},{28:[1,141]},{26:[1,142]},{26:[1,143]},{26:[2,77],43:$Vy},o($VA,[2,14],{33:112,21:144,34:$VB,37:$VC,38:$VD}),{22:31,24:$V7,29:32,36:145,50:28,72:30,73:$V8,74:33,75:34,76:35,77:36,78:37,79:$V9,80:$Va,81:$Vb,82:$Vc,83:$Vd,84:$Ve,86:$Vf},{26:[1,146]},o($Vr,[2,87]),{26:[2,89],43:$Vy},o($Vr,[2,85]),o($Vx,[2,44]),o($V4,[2,47],{53:147,56:[1,148]}),{54:[1,149],55:[1,150]},o($Vz,[2,91]),o($VG,[2,29]),{35:[1,151]},{19:152,22:82,24:$Vu,84:$Vv},{34:[1,153]},{34:[1,154]},{19:155,22:82,24:$Vu,84:$Vv},{34:[1,156]},{34:[1,157]},o($VE,[2,19],{85:$Vs}),{24:[1,158]},o($VE,[2,20]),o($VE,[2,21],{22:159,84:$Vv}),o($VA,[2,16],{33:132,34:$VB,37:$VC,38:$VD}),o($VF,[2,68],{65:$Vl,66:$Vm,67:$Vn,68:$Vo}),o($Vq,[2,63]),o($V4,[2,48]),{57:[1,160],59:[1,161]},o($VH,[2,49]),o($VH,[2,50]),{22:31,24:$V7,29:32,36:162,50:28,72:30,73:$V8,74:33,75:34,76:35,77:36,78:37,79:$V9,80:$Va,81:$Vb,82:$Vc,83:$Vd,84:$Ve,86:$Vf},{35:[1,163]},{19:164,22:82,24:$Vu,84:$Vv},{19:165,22:82,24:$Vu,84:$Vv},{35:[1,166]},{19:167,22:82,24:$Vu,84:$Vv},{19:168,22:82,24:$Vu,84:$Vv},{29:169,79:$V9},o($VE,[2,22],{85:$Vs}),{29:130,52:170,79:$V9},{29:130,52:171,79:$V9},o($VG,[2,30],{65:$Vl,66:$Vm,67:$Vn,68:$Vo,70:$Vp}),{22:31,24:$V7,29:32,36:172,50:28,72:30,73:$V8,74:33,75:34,76:35,77:36,78:37,79:$V9,80:$Va,81:$Vb,82:$Vc,83:$Vd,84:$Ve,86:$Vf},{35:[1,173]},{35:[1,174]},{22:31,24:$V7,29:32,36:175,50:28,72:30,73:$V8,74:33,75:34,76:35,77:36,78:37,79:$V9,80:$Va,81:$Vb,82:$Vc,83:$Vd,84:$Ve,86:$Vf},{35:[1,176]},{35:[1,177]},{26:[1,178]},{58:[1,179]},{58:[1,180]},o($VG,[2,31],{65:$Vl,66:$Vm,67:$Vn,68:$Vo,70:$Vp}),{22:31,24:$V7,29:32,36:181,50:28,72:30,73:$V8,74:33,75:34,76:35,77:36,78:37,79:$V9,80:$Va,81:$Vb,82:$Vc,83:$Vd,84:$Ve,86:$Vf},{22:31,24:$V7,29:32,36:182,50:28,72:30,73:$V8,74:33,75:34,76:35,77:36,78:37,79:$V9,80:$Va,81:$Vb,82:$Vc,83:$Vd,84:$Ve,86:$Vf},o($VG,[2,32],{65:$Vl,66:$Vm,67:$Vn,68:$Vo,70:$Vp}),{22:31,24:$V7,29:32,36:183,50:28,72:30,73:$V8,74:33,75:34,76:35,77:36,78:37,79:$V9,80:$Va,81:$Vb,82:$Vc,83:$Vd,84:$Ve,86:$Vf},{22:31,24:$V7,29:32,36:184,50:28,72:30,73:$V8,74:33,75:34,76:35,77:36,78:37,79:$V9,80:$Va,81:$Vb,82:$Vc,83:$Vd,84:$Ve,86:$Vf},o($VE,[2,23]),o($V4,[2,51]),o($V4,[2,52]),o($VG,[2,33],{65:$Vl,66:$Vm,67:$Vn,68:$Vo,70:$Vp}),o($VG,[2,35],{65:$Vl,66:$Vm,67:$Vn,68:$Vo,70:$Vp}),o($VG,[2,34],{65:$Vl,66:$Vm,67:$Vn,68:$Vo,70:$Vp}),o($VG,[2,36],{65:$Vl,66:$Vm,67:$Vn,68:$Vo,70:$Vp})],
561 | defaultActions: {9:[2,1]},
562 | parseError: function parseError(str, hash) {
563 | if (hash.recoverable) {
564 | this.trace(str);
565 | } else {
566 | throw new Error(str);
567 | }
568 | },
569 | parse: function parse(input) {
570 | var self = this, stack = [0], tstack = [], vstack = [null], lstack = [], table = this.table, yytext = '', yylineno = 0, yyleng = 0, recovering = 0, TERROR = 2, EOF = 1;
571 | var args = lstack.slice.call(arguments, 1);
572 | var lexer = Object.create(this.lexer);
573 | var sharedState = { yy: {} };
574 | for (var k in this.yy) {
575 | if (Object.prototype.hasOwnProperty.call(this.yy, k)) {
576 | sharedState.yy[k] = this.yy[k];
577 | }
578 | }
579 | lexer.setInput(input, sharedState.yy);
580 | sharedState.yy.lexer = lexer;
581 | sharedState.yy.parser = this;
582 | if (typeof lexer.yylloc == 'undefined') {
583 | lexer.yylloc = {};
584 | }
585 | var yyloc = lexer.yylloc;
586 | lstack.push(yyloc);
587 | var ranges = lexer.options && lexer.options.ranges;
588 | if (typeof sharedState.yy.parseError === 'function') {
589 | this.parseError = sharedState.yy.parseError;
590 | } else {
591 | this.parseError = Object.getPrototypeOf(this).parseError;
592 | }
593 | function popStack(n) {
594 | stack.length = stack.length - 2 * n;
595 | vstack.length = vstack.length - n;
596 | lstack.length = lstack.length - n;
597 | }
598 | _token_stack:
599 | function lex() {
600 | var token;
601 | token = lexer.lex() || EOF;
602 | if (typeof token !== 'number') {
603 | token = self.symbols_[token] || token;
604 | }
605 | return token;
606 | }
607 | var symbol, preErrorSymbol, state, action, a, r, yyval = {}, p, len, newState, expected;
608 | while (true) {
609 | state = stack[stack.length - 1];
610 | if (this.defaultActions[state]) {
611 | action = this.defaultActions[state];
612 | } else {
613 | if (symbol === null || typeof symbol == 'undefined') {
614 | symbol = lex();
615 | }
616 | action = table[state] && table[state][symbol];
617 | }
618 | if (typeof action === 'undefined' || !action.length || !action[0]) {
619 | var errStr = '';
620 | expected = [];
621 | for (p in table[state]) {
622 | if (this.terminals_[p] && p > TERROR) {
623 | expected.push('\'' + this.terminals_[p] + '\'');
624 | }
625 | }
626 | if (lexer.showPosition) {
627 | errStr = 'Parse error on line ' + (yylineno + 1) + ':\n' + lexer.showPosition() + '\nExpecting ' + expected.join(', ') + ', got \'' + (this.terminals_[symbol] || symbol) + '\'';
628 | } else {
629 | errStr = 'Parse error on line ' + (yylineno + 1) + ': Unexpected ' + (symbol == EOF ? 'end of input' : '\'' + (this.terminals_[symbol] || symbol) + '\'');
630 | }
631 | this.parseError(errStr, {
632 | text: lexer.match,
633 | token: this.terminals_[symbol] || symbol,
634 | line: lexer.yylineno,
635 | loc: yyloc,
636 | expected: expected
637 | });
638 | }
639 | if (action[0] instanceof Array && action.length > 1) {
640 | throw new Error('Parse Error: multiple actions possible at state: ' + state + ', token: ' + symbol);
641 | }
642 | switch (action[0]) {
643 | case 1:
644 | stack.push(symbol);
645 | vstack.push(lexer.yytext);
646 | lstack.push(lexer.yylloc);
647 | stack.push(action[1]);
648 | symbol = null;
649 | if (!preErrorSymbol) {
650 | yyleng = lexer.yyleng;
651 | yytext = lexer.yytext;
652 | yylineno = lexer.yylineno;
653 | yyloc = lexer.yylloc;
654 | if (recovering > 0) {
655 | recovering--;
656 | }
657 | } else {
658 | symbol = preErrorSymbol;
659 | preErrorSymbol = null;
660 | }
661 | break;
662 | case 2:
663 | len = this.productions_[action[1]][1];
664 | yyval.$ = vstack[vstack.length - len];
665 | yyval._$ = {
666 | first_line: lstack[lstack.length - (len || 1)].first_line,
667 | last_line: lstack[lstack.length - 1].last_line,
668 | first_column: lstack[lstack.length - (len || 1)].first_column,
669 | last_column: lstack[lstack.length - 1].last_column
670 | };
671 | if (ranges) {
672 | yyval._$.range = [
673 | lstack[lstack.length - (len || 1)].range[0],
674 | lstack[lstack.length - 1].range[1]
675 | ];
676 | }
677 | r = this.performAction.apply(yyval, [
678 | yytext,
679 | yyleng,
680 | yylineno,
681 | sharedState.yy,
682 | action[1],
683 | vstack,
684 | lstack
685 | ].concat(args));
686 | if (typeof r !== 'undefined') {
687 | return r;
688 | }
689 | if (len) {
690 | stack = stack.slice(0, -1 * len * 2);
691 | vstack = vstack.slice(0, -1 * len);
692 | lstack = lstack.slice(0, -1 * len);
693 | }
694 | stack.push(this.productions_[action[1]][0]);
695 | vstack.push(yyval.$);
696 | lstack.push(yyval._$);
697 | newState = table[stack[stack.length - 2]][stack[stack.length - 1]];
698 | stack.push(newState);
699 | break;
700 | case 3:
701 | return true;
702 | }
703 | }
704 | return true;
705 | }};
706 |
707 | function Parser () {
708 | this.yy = {};
709 | }
710 | Parser.prototype = parser;parser.Parser = Parser;
711 | return new Parser;
712 | })();
713 |
714 |
715 | if (typeof require !== 'undefined' && typeof exports !== 'undefined') {
716 | exports.parser = parser;
717 | exports.Parser = parser.Parser;
718 | exports.parse = function () { return parser.parse.apply(parser, arguments); };
719 | exports.main = function commonjsMain(args) {
720 | if (!args[1]) {
721 | console.log('Usage: '+args[0]+' FILE');
722 | process.exit(1);
723 | }
724 | var source = require('fs').readFileSync(require('path').normalize(args[1]), "utf8");
725 | return exports.parser.parse(source);
726 | };
727 | if (typeof module !== 'undefined' && require.main === module) {
728 | exports.main(process.argv.slice(1));
729 | }
730 | }
731 | };require['./nodes'] = new function() {
732 | var exports = this;
733 | // Generated by CoffeeScript 1.8.0
734 | (function() {
735 | var ArgumentListValue, BetweenOp, Field, FunctionValue, Group, Having, Join, Limit, ListValue, LiteralValue, Offset, Op, Order, OrderArgument, ParameterValue, Select, Star, StringValue, SubSelect, Table, UnaryOp, Union, Where, indent;
736 |
737 | indent = function(str) {
738 | var line;
739 | return ((function() {
740 | var _i, _len, _ref, _results;
741 | _ref = str.split("\n");
742 | _results = [];
743 | for (_i = 0, _len = _ref.length; _i < _len; _i++) {
744 | line = _ref[_i];
745 | _results.push(" " + line);
746 | }
747 | return _results;
748 | })()).join("\n");
749 | };
750 |
751 | exports.Select = Select = (function() {
752 | function Select(fields, source, distinct, joins, unions) {
753 | this.fields = fields;
754 | this.source = source;
755 | this.distinct = distinct != null ? distinct : false;
756 | this.joins = joins != null ? joins : [];
757 | this.unions = unions != null ? unions : [];
758 | this.order = null;
759 | this.group = null;
760 | this.where = null;
761 | this.limit = null;
762 | }
763 |
764 | Select.prototype.toString = function() {
765 | var join, ret, union, _i, _j, _len, _len1, _ref, _ref1;
766 | ret = ["SELECT " + (this.fields.join(', '))];
767 | ret.push(indent("FROM " + this.source));
768 | _ref = this.joins;
769 | for (_i = 0, _len = _ref.length; _i < _len; _i++) {
770 | join = _ref[_i];
771 | ret.push(indent(join.toString()));
772 | }
773 | if (this.where) {
774 | ret.push(indent(this.where.toString()));
775 | }
776 | if (this.group) {
777 | ret.push(indent(this.group.toString()));
778 | }
779 | if (this.order) {
780 | ret.push(indent(this.order.toString()));
781 | }
782 | if (this.limit) {
783 | ret.push(indent(this.limit.toString()));
784 | }
785 | _ref1 = this.unions;
786 | for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
787 | union = _ref1[_j];
788 | ret.push(union.toString());
789 | }
790 | return ret.join("\n");
791 | };
792 |
793 | return Select;
794 |
795 | })();
796 |
797 | exports.SubSelect = SubSelect = (function() {
798 | function SubSelect(select, name) {
799 | this.select = select;
800 | this.name = name != null ? name : null;
801 | null;
802 | }
803 |
804 | SubSelect.prototype.toString = function() {
805 | var ret;
806 | ret = [];
807 | ret.push('(');
808 | ret.push(indent(this.select.toString()));
809 | ret.push(this.name ? ") " + (this.name.toString()) : ")");
810 | return ret.join("\n");
811 | };
812 |
813 | return SubSelect;
814 |
815 | })();
816 |
817 | exports.Join = Join = (function() {
818 | function Join(right, conditions, side, mode) {
819 | this.right = right;
820 | this.conditions = conditions != null ? conditions : null;
821 | this.side = side != null ? side : null;
822 | this.mode = mode != null ? mode : null;
823 | null;
824 | }
825 |
826 | Join.prototype.toString = function() {
827 | var ret;
828 | ret = '';
829 | if (this.side != null) {
830 | ret += "" + this.side + " ";
831 | }
832 | if (this.mode != null) {
833 | ret += "" + this.mode + " ";
834 | }
835 | return ret + ("JOIN " + this.right + "\n") + indent("ON " + this.conditions);
836 | };
837 |
838 | return Join;
839 |
840 | })();
841 |
842 | exports.Union = Union = (function() {
843 | function Union(query, all) {
844 | this.query = query;
845 | this.all = all != null ? all : false;
846 | null;
847 | }
848 |
849 | Union.prototype.toString = function() {
850 | var all;
851 | all = this.all ? ' ALL' : '';
852 | return "UNION" + all + "\n" + (this.query.toString());
853 | };
854 |
855 | return Union;
856 |
857 | })();
858 |
859 | exports.LiteralValue = LiteralValue = (function() {
860 | function LiteralValue(value, value2) {
861 | this.value = value;
862 | this.value2 = value2 != null ? value2 : null;
863 | if (this.value2) {
864 | this.nested = true;
865 | this.values = this.value.values;
866 | this.values.push(value2);
867 | } else {
868 | this.nested = false;
869 | this.values = [this.value];
870 | }
871 | }
872 |
873 | LiteralValue.prototype.toString = function() {
874 | return "`" + (this.values.join('.')) + "`";
875 | };
876 |
877 | return LiteralValue;
878 |
879 | })();
880 |
881 | exports.StringValue = StringValue = (function() {
882 | function StringValue(value, quoteType) {
883 | this.value = value;
884 | this.quoteType = quoteType != null ? quoteType : "''";
885 | null;
886 | }
887 |
888 | StringValue.prototype.toString = function() {
889 | return "" + this.quoteType + this.value + this.quoteType;
890 | };
891 |
892 | return StringValue;
893 |
894 | })();
895 |
896 | exports.NumberValue = LiteralValue = (function() {
897 | function LiteralValue(value) {
898 | this.value = Number(value);
899 | }
900 |
901 | LiteralValue.prototype.toString = function() {
902 | return this.value.toString();
903 | };
904 |
905 | return LiteralValue;
906 |
907 | })();
908 |
909 | exports.ListValue = ListValue = (function() {
910 | function ListValue(value) {
911 | this.value = value;
912 | }
913 |
914 | ListValue.prototype.toString = function() {
915 | return "(" + (this.value.join(', ')) + ")";
916 | };
917 |
918 | return ListValue;
919 |
920 | })();
921 |
922 | exports.ParameterValue = ParameterValue = (function() {
923 | function ParameterValue(value) {
924 | this.value = value;
925 | this.index = parseInt(value.substr(1), 10) - 1;
926 | }
927 |
928 | ParameterValue.prototype.toString = function() {
929 | return "" + this.value;
930 | };
931 |
932 | return ParameterValue;
933 |
934 | })();
935 |
936 | exports.ArgumentListValue = ArgumentListValue = (function() {
937 | function ArgumentListValue(value, distinct) {
938 | this.value = value;
939 | this.distinct = distinct != null ? distinct : false;
940 | null;
941 | }
942 |
943 | ArgumentListValue.prototype.toString = function() {
944 | if (this.distinct) {
945 | return "DISTINCT " + (this.value.join(', '));
946 | } else {
947 | return "" + (this.value.join(', '));
948 | }
949 | };
950 |
951 | return ArgumentListValue;
952 |
953 | })();
954 |
955 | exports.BooleanValue = LiteralValue = (function() {
956 | function LiteralValue(value) {
957 | this.value = (function() {
958 | switch (value.toLowerCase()) {
959 | case 'true':
960 | return true;
961 | case 'false':
962 | return false;
963 | default:
964 | return null;
965 | }
966 | })();
967 | }
968 |
969 | LiteralValue.prototype.toString = function() {
970 | if (this.value != null) {
971 | return this.value.toString().toUpperCase();
972 | } else {
973 | return 'NULL';
974 | }
975 | };
976 |
977 | return LiteralValue;
978 |
979 | })();
980 |
981 | exports.FunctionValue = FunctionValue = (function() {
982 | function FunctionValue(name, _arguments, udf) {
983 | this.name = name;
984 | this["arguments"] = _arguments != null ? _arguments : null;
985 | this.udf = udf != null ? udf : false;
986 | null;
987 | }
988 |
989 | FunctionValue.prototype.toString = function() {
990 | if (this["arguments"]) {
991 | return "" + (this.name.toUpperCase()) + "(" + (this["arguments"].toString()) + ")";
992 | } else {
993 | return "" + (this.name.toUpperCase()) + "()";
994 | }
995 | };
996 |
997 | return FunctionValue;
998 |
999 | })();
1000 |
1001 | exports.Order = Order = (function() {
1002 | function Order(orderings, offset) {
1003 | this.orderings = orderings;
1004 | this.offset = offset;
1005 | }
1006 |
1007 | Order.prototype.toString = function() {
1008 | return ("ORDER BY " + (this.orderings.join(', '))) + (this.offset ? "\n" + this.offset.toString() : "");
1009 | };
1010 |
1011 | return Order;
1012 |
1013 | })();
1014 |
1015 | exports.OrderArgument = OrderArgument = (function() {
1016 | function OrderArgument(value, direction) {
1017 | this.value = value;
1018 | this.direction = direction != null ? direction : 'ASC';
1019 | null;
1020 | }
1021 |
1022 | OrderArgument.prototype.toString = function() {
1023 | return "" + this.value + " " + this.direction;
1024 | };
1025 |
1026 | return OrderArgument;
1027 |
1028 | })();
1029 |
1030 | exports.Offset = Offset = (function() {
1031 | function Offset(row_count, limit) {
1032 | this.row_count = row_count;
1033 | this.limit = limit;
1034 | null;
1035 | }
1036 |
1037 | Offset.prototype.toString = function() {
1038 | return ("OFFSET " + this.row_count + " ROWS") + (this.limit ? "\nFETCH NEXT " + this.limit + " ROWS ONLY" : "");
1039 | };
1040 |
1041 | return Offset;
1042 |
1043 | })();
1044 |
1045 | exports.Limit = Limit = (function() {
1046 | function Limit(value, offset) {
1047 | this.value = value;
1048 | this.offset = offset;
1049 | null;
1050 | }
1051 |
1052 | Limit.prototype.toString = function() {
1053 | return ("LIMIT " + this.value) + (this.offset ? "\nOFFSET " + this.offset : "");
1054 | };
1055 |
1056 | return Limit;
1057 |
1058 | })();
1059 |
1060 | exports.Table = Table = (function() {
1061 | function Table(name, alias, win, winFn, winArg) {
1062 | this.name = name;
1063 | this.alias = alias != null ? alias : null;
1064 | this.win = win != null ? win : null;
1065 | this.winFn = winFn != null ? winFn : null;
1066 | this.winArg = winArg != null ? winArg : null;
1067 | null;
1068 | }
1069 |
1070 | Table.prototype.toString = function() {
1071 | if (this.win) {
1072 | return "" + this.name + "." + this.win + ":" + this.winFn + "(" + this.winArg + ")";
1073 | } else if (this.alias) {
1074 | return "" + this.name + " AS " + this.alias;
1075 | } else {
1076 | return this.name.toString();
1077 | }
1078 | };
1079 |
1080 | return Table;
1081 |
1082 | })();
1083 |
1084 | exports.Group = Group = (function() {
1085 | function Group(fields) {
1086 | this.fields = fields;
1087 | this.having = null;
1088 | }
1089 |
1090 | Group.prototype.toString = function() {
1091 | var ret;
1092 | ret = ["GROUP BY " + (this.fields.join(', '))];
1093 | if (this.having) {
1094 | ret.push(this.having.toString());
1095 | }
1096 | return ret.join("\n");
1097 | };
1098 |
1099 | return Group;
1100 |
1101 | })();
1102 |
1103 | exports.Where = Where = (function() {
1104 | function Where(conditions) {
1105 | this.conditions = conditions;
1106 | null;
1107 | }
1108 |
1109 | Where.prototype.toString = function() {
1110 | return "WHERE " + this.conditions;
1111 | };
1112 |
1113 | return Where;
1114 |
1115 | })();
1116 |
1117 | exports.Having = Having = (function() {
1118 | function Having(conditions) {
1119 | this.conditions = conditions;
1120 | null;
1121 | }
1122 |
1123 | Having.prototype.toString = function() {
1124 | return "HAVING " + this.conditions;
1125 | };
1126 |
1127 | return Having;
1128 |
1129 | })();
1130 |
1131 | exports.Op = Op = (function() {
1132 | function Op(operation, left, right) {
1133 | this.operation = operation;
1134 | this.left = left;
1135 | this.right = right;
1136 | null;
1137 | }
1138 |
1139 | Op.prototype.toString = function() {
1140 | return "(" + this.left + " " + (this.operation.toUpperCase()) + " " + this.right + ")";
1141 | };
1142 |
1143 | return Op;
1144 |
1145 | })();
1146 |
1147 | exports.UnaryOp = UnaryOp = (function() {
1148 | function UnaryOp(operator, operand) {
1149 | this.operator = operator;
1150 | this.operand = operand;
1151 | null;
1152 | }
1153 |
1154 | UnaryOp.prototype.toString = function() {
1155 | return "(" + (this.operator.toUpperCase()) + " " + this.operand + ")";
1156 | };
1157 |
1158 | return UnaryOp;
1159 |
1160 | })();
1161 |
1162 | exports.BetweenOp = BetweenOp = (function() {
1163 | function BetweenOp(value) {
1164 | this.value = value;
1165 | null;
1166 | }
1167 |
1168 | BetweenOp.prototype.toString = function() {
1169 | return "" + (this.value.join(' AND '));
1170 | };
1171 |
1172 | return BetweenOp;
1173 |
1174 | })();
1175 |
1176 | exports.Field = Field = (function() {
1177 | function Field(field, name) {
1178 | this.field = field;
1179 | this.name = name != null ? name : null;
1180 | null;
1181 | }
1182 |
1183 | Field.prototype.toString = function() {
1184 | if (this.name) {
1185 | return "" + this.field + " AS " + this.name;
1186 | } else {
1187 | return this.field.toString();
1188 | }
1189 | };
1190 |
1191 | return Field;
1192 |
1193 | })();
1194 |
1195 | exports.Star = Star = (function() {
1196 | function Star() {
1197 | null;
1198 | }
1199 |
1200 | Star.prototype.toString = function() {
1201 | return '*';
1202 | };
1203 |
1204 | Star.prototype.star = true;
1205 |
1206 | return Star;
1207 |
1208 | })();
1209 |
1210 | }).call(this);
1211 |
1212 | };require['./parser'] = new function() {
1213 | var exports = this;
1214 | // Generated by CoffeeScript 1.8.0
1215 | (function() {
1216 | var buildParser;
1217 |
1218 | buildParser = function() {
1219 | var parser;
1220 | parser = require('./compiled_parser').parser;
1221 | parser.lexer = {
1222 | lex: function() {
1223 | var tag, _ref;
1224 | _ref = this.tokens[this.pos++] || [''], tag = _ref[0], this.yytext = _ref[1], this.yylineno = _ref[2];
1225 | return tag;
1226 | },
1227 | setInput: function(tokens) {
1228 | this.tokens = tokens;
1229 | return this.pos = 0;
1230 | },
1231 | upcomingInput: function() {
1232 | return "";
1233 | }
1234 | };
1235 | parser.yy = require('./nodes');
1236 | return parser;
1237 | };
1238 |
1239 | exports.parser = buildParser();
1240 |
1241 | exports.parse = function(str) {
1242 | return buildParser().parse(str);
1243 | };
1244 |
1245 | }).call(this);
1246 |
1247 | };require['./sql_parser'] = new function() {
1248 | var exports = this;
1249 | // Generated by CoffeeScript 1.8.0
1250 | (function() {
1251 | exports.lexer = require('./lexer');
1252 |
1253 | exports.parser = require('./parser');
1254 |
1255 | exports.nodes = require('./nodes');
1256 |
1257 | exports.parse = function(sql) {
1258 | return exports.parser.parse(exports.lexer.tokenize(sql));
1259 | };
1260 |
1261 | }).call(this);
1262 |
1263 | };
1264 | return require['./sql_parser']
1265 | }();
1266 |
1267 | if(typeof define === 'function' && define.amd) {
1268 | define(function() { return SQLParser });
1269 | } else { root.SQLParser = SQLParser }
1270 | }(this));
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | sql = require('./lib/sql_parser')
2 |
3 | for(var key in sql) {
4 | exports[key] = sql[key]
5 | }
6 |
7 |
--------------------------------------------------------------------------------
/lib/browser.js:
--------------------------------------------------------------------------------
1 | (function(root) {
2 | var SQLParser = function() {
3 | function require(path){ return require[path]; }
4 | require['./lexer'] = new function() {
5 | var exports = this;
6 | (function() {
7 | var Lexer;
8 |
9 | Lexer = (function() {
10 | var BOOLEAN, DBLSTRING, LITERAL, MATH, MATH_MULTI, NUMBER, SEPARATOR, SQL_CONDITIONALS, SQL_FUNCTIONS, SQL_KEYWORDS, SQL_OPERATORS, SQL_SORT_ORDERS, STAR, STRING, WHITESPACE;
11 |
12 | function Lexer(sql, opts) {
13 | var bytesConsumed, i;
14 | if (opts == null) opts = {};
15 | this.sql = sql;
16 | this.preserveWhitespace = opts.preserveWhitespace || false;
17 | this.tokens = [];
18 | this.currentLine = 1;
19 | i = 0;
20 | while (this.chunk = sql.slice(i)) {
21 | bytesConsumed = this.keywordToken() || this.starToken() || this.booleanToken() || this.functionToken() || this.windowExtension() || this.sortOrderToken() || this.seperatorToken() || this.operatorToken() || this.mathToken() || this.dotToken() || this.conditionalToken() || this.numberToken() || this.stringToken() || this.parensToken() || this.whitespaceToken() || this.literalToken();
22 | if (bytesConsumed < 1) {
23 | throw new Error("NOTHING CONSUMED: Stopped at - '" + (this.chunk.slice(0, 30)) + "'");
24 | }
25 | i += bytesConsumed;
26 | }
27 | this.token('EOF', '');
28 | }
29 |
30 | Lexer.prototype.token = function(name, value) {
31 | return this.tokens.push([name, value, this.currentLine]);
32 | };
33 |
34 | Lexer.prototype.tokenizeFromRegex = function(name, regex, part, lengthPart, output) {
35 | var match, partMatch;
36 | if (part == null) part = 0;
37 | if (lengthPart == null) lengthPart = part;
38 | if (output == null) output = true;
39 | if (!(match = regex.exec(this.chunk))) return 0;
40 | partMatch = match[part];
41 | if (output) this.token(name, partMatch);
42 | return match[lengthPart].length;
43 | };
44 |
45 | Lexer.prototype.tokenizeFromWord = function(name, word) {
46 | var match, matcher;
47 | if (word == null) word = name;
48 | word = this.regexEscape(word);
49 | matcher = /^\w+$/.test(word) ? new RegExp("^(" + word + ")\\b", 'ig') : new RegExp("^(" + word + ")", 'ig');
50 | match = matcher.exec(this.chunk);
51 | if (!match) return 0;
52 | this.token(name, match[1]);
53 | return match[1].length;
54 | };
55 |
56 | Lexer.prototype.tokenizeFromList = function(name, list) {
57 | var entry, ret, _i, _len;
58 | ret = 0;
59 | for (_i = 0, _len = list.length; _i < _len; _i++) {
60 | entry = list[_i];
61 | ret = this.tokenizeFromWord(name, entry);
62 | if (ret > 0) break;
63 | }
64 | return ret;
65 | };
66 |
67 | Lexer.prototype.keywordToken = function() {
68 | return this.tokenizeFromWord('SELECT') || this.tokenizeFromWord('DISTINCT') || this.tokenizeFromWord('FROM') || this.tokenizeFromWord('WHERE') || this.tokenizeFromWord('GROUP') || this.tokenizeFromWord('ORDER') || this.tokenizeFromWord('BY') || this.tokenizeFromWord('HAVING') || this.tokenizeFromWord('LIMIT') || this.tokenizeFromWord('JOIN') || this.tokenizeFromWord('LEFT') || this.tokenizeFromWord('RIGHT') || this.tokenizeFromWord('INNER') || this.tokenizeFromWord('OUTER') || this.tokenizeFromWord('ON') || this.tokenizeFromWord('AS') || this.tokenizeFromWord('UNION') || this.tokenizeFromWord('ALL');
69 | };
70 |
71 | Lexer.prototype.dotToken = function() {
72 | return this.tokenizeFromWord('DOT', '.');
73 | };
74 |
75 | Lexer.prototype.operatorToken = function() {
76 | return this.tokenizeFromList('OPERATOR', SQL_OPERATORS);
77 | };
78 |
79 | Lexer.prototype.mathToken = function() {
80 | return this.tokenizeFromList('MATH', MATH) || this.tokenizeFromList('MATH_MULTI', MATH_MULTI);
81 | };
82 |
83 | Lexer.prototype.conditionalToken = function() {
84 | return this.tokenizeFromList('CONDITIONAL', SQL_CONDITIONALS);
85 | };
86 |
87 | Lexer.prototype.functionToken = function() {
88 | return this.tokenizeFromList('FUNCTION', SQL_FUNCTIONS);
89 | };
90 |
91 | Lexer.prototype.sortOrderToken = function() {
92 | return this.tokenizeFromList('DIRECTION', SQL_SORT_ORDERS);
93 | };
94 |
95 | Lexer.prototype.booleanToken = function() {
96 | return this.tokenizeFromList('BOOLEAN', BOOLEAN);
97 | };
98 |
99 | Lexer.prototype.starToken = function() {
100 | return this.tokenizeFromRegex('STAR', STAR);
101 | };
102 |
103 | Lexer.prototype.seperatorToken = function() {
104 | return this.tokenizeFromRegex('SEPARATOR', SEPARATOR);
105 | };
106 |
107 | Lexer.prototype.literalToken = function() {
108 | return this.tokenizeFromRegex('LITERAL', LITERAL, 1, 0);
109 | };
110 |
111 | Lexer.prototype.numberToken = function() {
112 | return this.tokenizeFromRegex('NUMBER', NUMBER);
113 | };
114 |
115 | Lexer.prototype.stringToken = function() {
116 | return this.tokenizeFromRegex('STRING', STRING, 1, 0) || this.tokenizeFromRegex('DBLSTRING', DBLSTRING, 1, 0);
117 | };
118 |
119 | Lexer.prototype.parensToken = function() {
120 | return this.tokenizeFromRegex('LEFT_PAREN', /^\(/) || this.tokenizeFromRegex('RIGHT_PAREN', /^\)/);
121 | };
122 |
123 | Lexer.prototype.windowExtension = function() {
124 | var match;
125 | match = /^\.(win):(length|time)/i.exec(this.chunk);
126 | if (!match) return 0;
127 | this.token('WINDOW', match[1]);
128 | this.token('WINDOW_FUNCTION', match[2]);
129 | return match[0].length;
130 | };
131 |
132 | Lexer.prototype.whitespaceToken = function() {
133 | var match, newlines, partMatch;
134 | if (!(match = WHITESPACE.exec(this.chunk))) return 0;
135 | partMatch = match[0];
136 | newlines = partMatch.replace(/[^\n]/, '').length;
137 | this.currentLine += newlines;
138 | if (this.preserveWhitespace) this.token(name, partMatch);
139 | return partMatch.length;
140 | };
141 |
142 | Lexer.prototype.regexEscape = function(str) {
143 | return str.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
144 | };
145 |
146 | SQL_KEYWORDS = ['SELECT', 'FROM', 'WHERE', 'GROUP BY', 'ORDER BY', 'HAVING', 'AS'];
147 |
148 | SQL_FUNCTIONS = ['AVG', 'COUNT', 'MIN', 'MAX', 'SUM'];
149 |
150 | SQL_SORT_ORDERS = ['ASC', 'DESC'];
151 |
152 | SQL_OPERATORS = ['=', '>', '<', 'LIKE', 'IS NOT', 'IS'];
153 |
154 | SQL_CONDITIONALS = ['AND', 'OR'];
155 |
156 | BOOLEAN = ['TRUE', 'FALSE', 'NULL'];
157 |
158 | MATH = ['+', '-'];
159 |
160 | MATH_MULTI = ['/', '*'];
161 |
162 | STAR = /^\*/;
163 |
164 | SEPARATOR = /^,/;
165 |
166 | WHITESPACE = /^[ \n\r]+/;
167 |
168 | LITERAL = /^`?([a-z_][a-z0-9_]{0,})`?/i;
169 |
170 | NUMBER = /^[0-9]+(\.[0-9]+)?/;
171 |
172 | STRING = /^'([^\\']*(?:\\.[^\\']*)*)'/;
173 |
174 | DBLSTRING = /^"([^\\"]*(?:\\.[^\\"]*)*)"/;
175 |
176 | return Lexer;
177 |
178 | })();
179 |
180 | exports.tokenize = function(sql, opts) {
181 | return (new Lexer(sql, opts)).tokens;
182 | };
183 |
184 | }).call(this);
185 |
186 | };require['./compiled_parser'] = new function() {
187 | var exports = this;
188 | /* Jison generated parser */
189 | var parser = (function(){
190 | undefined
191 | var parser = {trace: function trace() { },
192 | yy: {},
193 | symbols_: {"error":2,"Root":3,"Query":4,"EOF":5,"SelectQuery":6,"Unions":7,"SelectWithLimitQuery":8,"BasicSelectQuery":9,"Select":10,"OrderClause":11,"GroupClause":12,"LimitClause":13,"SelectClause":14,"WhereClause":15,"SELECT":16,"Fields":17,"FROM":18,"Table":19,"DISTINCT":20,"Joins":21,"Literal":22,"LEFT_PAREN":23,"RIGHT_PAREN":24,"WINDOW":25,"WINDOW_FUNCTION":26,"Number":27,"Union":28,"UNION":29,"ALL":30,"Join":31,"JOIN":32,"ON":33,"Expression":34,"LEFT":35,"RIGHT":36,"INNER":37,"OUTER":38,"WHERE":39,"LIMIT":40,"ORDER":41,"BY":42,"OrderArgs":43,"OrderArg":44,"SEPARATOR":45,"Value":46,"DIRECTION":47,"GroupBasicClause":48,"HavingClause":49,"GROUP":50,"ArgumentList":51,"HAVING":52,"MATH":53,"MATH_MULTI":54,"OPERATOR":55,"CONDITIONAL":56,"String":57,"Function":58,"UserFunction":59,"Boolean":60,"NUMBER":61,"BOOLEAN":62,"STRING":63,"DBLSTRING":64,"LITERAL":65,"DOT":66,"FUNCTION":67,"Field":68,"STAR":69,"AS":70,"$accept":0,"$end":1},
194 | terminals_: {2:"error",5:"EOF",16:"SELECT",18:"FROM",20:"DISTINCT",23:"LEFT_PAREN",24:"RIGHT_PAREN",25:"WINDOW",26:"WINDOW_FUNCTION",29:"UNION",30:"ALL",32:"JOIN",33:"ON",35:"LEFT",36:"RIGHT",37:"INNER",38:"OUTER",39:"WHERE",40:"LIMIT",41:"ORDER",42:"BY",45:"SEPARATOR",47:"DIRECTION",50:"GROUP",52:"HAVING",53:"MATH",54:"MATH_MULTI",55:"OPERATOR",56:"CONDITIONAL",61:"NUMBER",62:"BOOLEAN",63:"STRING",64:"DBLSTRING",65:"LITERAL",66:"DOT",67:"FUNCTION",69:"STAR",70:"AS"},
195 | productions_: [0,[3,2],[4,1],[4,2],[6,1],[6,1],[9,1],[9,2],[9,2],[9,3],[8,2],[10,1],[10,2],[14,4],[14,5],[14,5],[14,6],[19,1],[19,3],[19,4],[19,6],[7,1],[7,2],[28,2],[28,3],[21,1],[21,2],[31,4],[31,5],[31,5],[31,6],[31,6],[31,6],[31,6],[15,2],[13,2],[11,3],[43,1],[43,3],[44,1],[44,2],[12,1],[12,2],[48,3],[49,2],[34,3],[34,3],[34,3],[34,3],[34,3],[34,1],[46,1],[46,1],[46,1],[46,1],[46,1],[46,1],[27,1],[60,1],[57,1],[57,1],[22,1],[22,3],[58,4],[59,4],[51,1],[51,3],[17,1],[17,3],[68,1],[68,1],[68,3]],
196 | performAction: function anonymous(yytext,yyleng,yylineno,yy,yystate,$$,_$) {
197 |
198 | var $0 = $$.length - 1;
199 | switch (yystate) {
200 | case 1:return this.$ = $$[$0-1];
201 | break;
202 | case 2:this.$ = $$[$0];
203 | break;
204 | case 3:this.$ = (function () {
205 | $$[$0-1].unions = $$[$0];
206 | return $$[$0-1];
207 | }());
208 | break;
209 | case 4:this.$ = $$[$0];
210 | break;
211 | case 5:this.$ = $$[$0];
212 | break;
213 | case 6:this.$ = $$[$0];
214 | break;
215 | case 7:this.$ = (function () {
216 | $$[$0-1].order = $$[$0];
217 | return $$[$0-1];
218 | }());
219 | break;
220 | case 8:this.$ = (function () {
221 | $$[$0-1].group = $$[$0];
222 | return $$[$0-1];
223 | }());
224 | break;
225 | case 9:this.$ = (function () {
226 | $$[$0-2].group = $$[$0-1];
227 | $$[$0-2].order = $$[$0];
228 | return $$[$0-2];
229 | }());
230 | break;
231 | case 10:this.$ = (function () {
232 | $$[$0-1].limit = $$[$0];
233 | return $$[$0-1];
234 | }());
235 | break;
236 | case 11:this.$ = $$[$0];
237 | break;
238 | case 12:this.$ = (function () {
239 | $$[$0-1].where = $$[$0];
240 | return $$[$0-1];
241 | }());
242 | break;
243 | case 13:this.$ = new yy.Select($$[$0-2], $$[$0], false);
244 | break;
245 | case 14:this.$ = new yy.Select($$[$0-2], $$[$0], true);
246 | break;
247 | case 15:this.$ = new yy.Select($$[$0-3], $$[$0-1], false, $$[$0]);
248 | break;
249 | case 16:this.$ = new yy.Select($$[$0-3], $$[$0-1], true, $$[$0]);
250 | break;
251 | case 17:this.$ = new yy.Table($$[$0]);
252 | break;
253 | case 18:this.$ = new yy.SubSelect($$[$0-1]);
254 | break;
255 | case 19:this.$ = new yy.SubSelect($$[$0-2], $$[$0]);
256 | break;
257 | case 20:this.$ = new yy.Table($$[$0-5], $$[$0-4], $$[$0-3], $$[$0-1]);
258 | break;
259 | case 21:this.$ = [$$[$0]];
260 | break;
261 | case 22:this.$ = $$[$0-1].concat($$[$01]);
262 | break;
263 | case 23:this.$ = new yy.Union($$[$0]);
264 | break;
265 | case 24:this.$ = new yy.Union($$[$0], true);
266 | break;
267 | case 25:this.$ = [$$[$0]];
268 | break;
269 | case 26:this.$ = $$[$0-1].concat($$[$0]);
270 | break;
271 | case 27:this.$ = new yy.Join($$[$0-2], $$[$0]);
272 | break;
273 | case 28:this.$ = new yy.Join($$[$0-2], $$[$0], 'LEFT');
274 | break;
275 | case 29:this.$ = new yy.Join($$[$0-2], $$[$0], 'RIGHT');
276 | break;
277 | case 30:this.$ = new yy.Join($$[$0-2], $$[$0], 'LEFT', 'INNER');
278 | break;
279 | case 31:this.$ = new yy.Join($$[$0-2], $$[$0], 'RIGHT', 'INNER');
280 | break;
281 | case 32:this.$ = new yy.Join($$[$0-2], $$[$0], 'LEFT', 'OUTER');
282 | break;
283 | case 33:this.$ = new yy.Join($$[$0-2], $$[$0], 'RIGHT', 'OUTER');
284 | break;
285 | case 34:this.$ = new yy.Where($$[$0]);
286 | break;
287 | case 35:this.$ = new yy.Limit($$[$0]);
288 | break;
289 | case 36:this.$ = new yy.Order($$[$0]);
290 | break;
291 | case 37:this.$ = [$$[$0]];
292 | break;
293 | case 38:this.$ = $$[$0-2].concat($$[$0]);
294 | break;
295 | case 39:this.$ = new yy.OrderArgument($$[$0], 'ASC');
296 | break;
297 | case 40:this.$ = new yy.OrderArgument($$[$0-1], $$[$0]);
298 | break;
299 | case 41:this.$ = $$[$0];
300 | break;
301 | case 42:this.$ = (function () {
302 | $$[$0-1].having = $$[$0];
303 | return $$[$0-1];
304 | }());
305 | break;
306 | case 43:this.$ = new yy.Group($$[$0]);
307 | break;
308 | case 44:this.$ = new yy.Having($$[$0]);
309 | break;
310 | case 45:this.$ = $$[$0-1];
311 | break;
312 | case 46:this.$ = new yy.Op($$[$0-1], $$[$0-2], $$[$0]);
313 | break;
314 | case 47:this.$ = new yy.Op($$[$0-1], $$[$0-2], $$[$0]);
315 | break;
316 | case 48:this.$ = new yy.Op($$[$0-1], $$[$0-2], $$[$0]);
317 | break;
318 | case 49:this.$ = new yy.Op($$[$0-1], $$[$0-2], $$[$0]);
319 | break;
320 | case 50:this.$ = $$[$0];
321 | break;
322 | case 51:this.$ = $$[$0];
323 | break;
324 | case 52:this.$ = $$[$0];
325 | break;
326 | case 53:this.$ = $$[$0];
327 | break;
328 | case 54:this.$ = $$[$0];
329 | break;
330 | case 55:this.$ = $$[$0];
331 | break;
332 | case 56:this.$ = $$[$0];
333 | break;
334 | case 57:this.$ = new yy.NumberValue($$[$0]);
335 | break;
336 | case 58:this.$ = new yy.BooleanValue($$[$0]);
337 | break;
338 | case 59:this.$ = new yy.StringValue($$[$0], "'");
339 | break;
340 | case 60:this.$ = new yy.StringValue($$[$0], '"');
341 | break;
342 | case 61:this.$ = new yy.LiteralValue($$[$0]);
343 | break;
344 | case 62:this.$ = new yy.LiteralValue($$[$0-2], $$[$0]);
345 | break;
346 | case 63:this.$ = new yy.FunctionValue($$[$0-3], $$[$0-1]);
347 | break;
348 | case 64:this.$ = new yy.FunctionValue($$[$0-3], $$[$0-1], true);
349 | break;
350 | case 65:this.$ = [$$[$0]];
351 | break;
352 | case 66:this.$ = $$[$0-2].concat($$[$0]);
353 | break;
354 | case 67:this.$ = [$$[$0]];
355 | break;
356 | case 68:this.$ = $$[$0-2].concat($$[$0]);
357 | break;
358 | case 69:this.$ = new yy.Star();
359 | break;
360 | case 70:this.$ = new yy.Field($$[$0]);
361 | break;
362 | case 71:this.$ = new yy.Field($$[$0-2], $$[$0]);
363 | break;
364 | }
365 | },
366 | table: [{3:1,4:2,6:3,8:4,9:5,10:6,14:7,16:[1,8]},{1:[3]},{5:[1,9]},{5:[2,2],7:10,13:11,24:[2,2],28:12,29:[1,14],40:[1,13]},{5:[2,4],24:[2,4],29:[2,4],40:[2,4]},{5:[2,5],24:[2,5],29:[2,5],40:[2,5]},{5:[2,6],11:15,12:16,24:[2,6],29:[2,6],40:[2,6],41:[1,17],48:18,50:[1,19]},{5:[2,11],15:20,24:[2,11],29:[2,11],39:[1,21],40:[2,11],41:[2,11],50:[2,11]},{17:22,20:[1,23],22:29,23:[1,27],27:30,34:26,46:28,57:31,58:32,59:33,60:34,61:[1,36],62:[1,40],63:[1,37],64:[1,38],65:[1,35],67:[1,39],68:24,69:[1,25]},{1:[2,1]},{5:[2,3],24:[2,3],28:41,29:[1,14]},{5:[2,10],24:[2,10],29:[2,10],40:[2,10]},{5:[2,21],24:[2,21],29:[2,21]},{27:42,61:[1,36]},{6:43,8:4,9:5,10:6,14:7,16:[1,8],30:[1,44]},{5:[2,7],24:[2,7],29:[2,7],40:[2,7]},{5:[2,8],11:45,24:[2,8],29:[2,8],40:[2,8],41:[1,17]},{42:[1,46]},{5:[2,41],24:[2,41],29:[2,41],40:[2,41],41:[2,41],49:47,52:[1,48]},{42:[1,49]},{5:[2,12],24:[2,12],29:[2,12],40:[2,12],41:[2,12],50:[2,12]},{22:29,23:[1,27],27:30,34:50,46:28,57:31,58:32,59:33,60:34,61:[1,36],62:[1,40],63:[1,37],64:[1,38],65:[1,35],67:[1,39]},{18:[1,51],45:[1,52]},{17:53,22:29,23:[1,27],27:30,34:26,46:28,57:31,58:32,59:33,60:34,61:[1,36],62:[1,40],63:[1,37],64:[1,38],65:[1,35],67:[1,39],68:24,69:[1,25]},{18:[2,67],45:[2,67]},{18:[2,69],45:[2,69]},{18:[2,70],45:[2,70],53:[1,55],54:[1,56],55:[1,57],56:[1,58],70:[1,54]},{22:29,23:[1,27],27:30,34:59,46:28,57:31,58:32,59:33,60:34,61:[1,36],62:[1,40],63:[1,37],64:[1,38],65:[1,35],67:[1,39]},{5:[2,50],18:[2,50],24:[2,50],29:[2,50],32:[2,50],35:[2,50],36:[2,50],39:[2,50],40:[2,50],41:[2,50],45:[2,50],50:[2,50],52:[2,50],53:[2,50],54:[2,50],55:[2,50],56:[2,50],70:[2,50]},{5:[2,51],18:[2,51],24:[2,51],29:[2,51],32:[2,51],35:[2,51],36:[2,51],39:[2,51],40:[2,51],41:[2,51],45:[2,51],47:[2,51],50:[2,51],52:[2,51],53:[2,51],54:[2,51],55:[2,51],56:[2,51],66:[1,60],70:[2,51]},{5:[2,52],18:[2,52],24:[2,52],29:[2,52],32:[2,52],35:[2,52],36:[2,52],39:[2,52],40:[2,52],41:[2,52],45:[2,52],47:[2,52],50:[2,52],52:[2,52],53:[2,52],54:[2,52],55:[2,52],56:[2,52],70:[2,52]},{5:[2,53],18:[2,53],24:[2,53],29:[2,53],32:[2,53],35:[2,53],36:[2,53],39:[2,53],40:[2,53],41:[2,53],45:[2,53],47:[2,53],50:[2,53],52:[2,53],53:[2,53],54:[2,53],55:[2,53],56:[2,53],70:[2,53]},{5:[2,54],18:[2,54],24:[2,54],29:[2,54],32:[2,54],35:[2,54],36:[2,54],39:[2,54],40:[2,54],41:[2,54],45:[2,54],47:[2,54],50:[2,54],52:[2,54],53:[2,54],54:[2,54],55:[2,54],56:[2,54],70:[2,54]},{5:[2,55],18:[2,55],24:[2,55],29:[2,55],32:[2,55],35:[2,55],36:[2,55],39:[2,55],40:[2,55],41:[2,55],45:[2,55],47:[2,55],50:[2,55],52:[2,55],53:[2,55],54:[2,55],55:[2,55],56:[2,55],70:[2,55]},{5:[2,56],18:[2,56],24:[2,56],29:[2,56],32:[2,56],35:[2,56],36:[2,56],39:[2,56],40:[2,56],41:[2,56],45:[2,56],47:[2,56],50:[2,56],52:[2,56],53:[2,56],54:[2,56],55:[2,56],56:[2,56],70:[2,56]},{5:[2,61],18:[2,61],23:[1,61],24:[2,61],29:[2,61],32:[2,61],35:[2,61],36:[2,61],39:[2,61],40:[2,61],41:[2,61],45:[2,61],47:[2,61],50:[2,61],52:[2,61],53:[2,61],54:[2,61],55:[2,61],56:[2,61],66:[2,61],70:[2,61]},{5:[2,57],18:[2,57],24:[2,57],29:[2,57],32:[2,57],35:[2,57],36:[2,57],39:[2,57],40:[2,57],41:[2,57],45:[2,57],47:[2,57],50:[2,57],52:[2,57],53:[2,57],54:[2,57],55:[2,57],56:[2,57],70:[2,57]},{5:[2,59],18:[2,59],24:[2,59],29:[2,59],32:[2,59],35:[2,59],36:[2,59],39:[2,59],40:[2,59],41:[2,59],45:[2,59],47:[2,59],50:[2,59],52:[2,59],53:[2,59],54:[2,59],55:[2,59],56:[2,59],70:[2,59]},{5:[2,60],18:[2,60],24:[2,60],29:[2,60],32:[2,60],35:[2,60],36:[2,60],39:[2,60],40:[2,60],41:[2,60],45:[2,60],47:[2,60],50:[2,60],52:[2,60],53:[2,60],54:[2,60],55:[2,60],56:[2,60],70:[2,60]},{23:[1,62]},{5:[2,58],18:[2,58],24:[2,58],29:[2,58],32:[2,58],35:[2,58],36:[2,58],39:[2,58],40:[2,58],41:[2,58],45:[2,58],47:[2,58],50:[2,58],52:[2,58],53:[2,58],54:[2,58],55:[2,58],56:[2,58],70:[2,58]},{5:[2,22],24:[2,22],29:[2,22]},{5:[2,35],24:[2,35],29:[2,35],40:[2,35]},{5:[2,23],13:11,24:[2,23],29:[2,23],40:[1,13]},{6:63,8:4,9:5,10:6,14:7,16:[1,8]},{5:[2,9],24:[2,9],29:[2,9],40:[2,9]},{22:29,27:30,43:64,44:65,46:66,57:31,58:32,59:33,60:34,61:[1,36],62:[1,40],63:[1,37],64:[1,38],65:[1,35],67:[1,39]},{5:[2,42],24:[2,42],29:[2,42],40:[2,42],41:[2,42]},{22:29,23:[1,27],27:30,34:67,46:28,57:31,58:32,59:33,60:34,61:[1,36],62:[1,40],63:[1,37],64:[1,38],65:[1,35],67:[1,39]},{22:29,23:[1,27],27:30,34:69,46:28,51:68,57:31,58:32,59:33,60:34,61:[1,36],62:[1,40],63:[1,37],64:[1,38],65:[1,35],67:[1,39]},{5:[2,34],24:[2,34],29:[2,34],40:[2,34],41:[2,34],50:[2,34],53:[1,55],54:[1,56],55:[1,57],56:[1,58]},{19:70,22:71,23:[1,72],65:[1,73]},{22:29,23:[1,27],27:30,34:26,46:28,57:31,58:32,59:33,60:34,61:[1,36],62:[1,40],63:[1,37],64:[1,38],65:[1,35],67:[1,39],68:74,69:[1,25]},{18:[1,75],45:[1,52]},{22:76,65:[1,73]},{22:29,23:[1,27],27:30,34:77,46:28,57:31,58:32,59:33,60:34,61:[1,36],62:[1,40],63:[1,37],64:[1,38],65:[1,35],67:[1,39]},{22:29,23:[1,27],27:30,34:78,46:28,57:31,58:32,59:33,60:34,61:[1,36],62:[1,40],63:[1,37],64:[1,38],65:[1,35],67:[1,39]},{22:29,23:[1,27],27:30,34:79,46:28,57:31,58:32,59:33,60:34,61:[1,36],62:[1,40],63:[1,37],64:[1,38],65:[1,35],67:[1,39]},{22:29,23:[1,27],27:30,34:80,46:28,57:31,58:32,59:33,60:34,61:[1,36],62:[1,40],63:[1,37],64:[1,38],65:[1,35],67:[1,39]},{24:[1,81],53:[1,55],54:[1,56],55:[1,57],56:[1,58]},{65:[1,82]},{22:29,23:[1,27],27:30,34:69,46:28,51:83,57:31,58:32,59:33,60:34,61:[1,36],62:[1,40],63:[1,37],64:[1,38],65:[1,35],67:[1,39]},{22:29,23:[1,27],27:30,34:69,46:28,51:84,57:31,58:32,59:33,60:34,61:[1,36],62:[1,40],63:[1,37],64:[1,38],65:[1,35],67:[1,39]},{5:[2,24],13:11,24:[2,24],29:[2,24],40:[1,13]},{5:[2,36],24:[2,36],29:[2,36],40:[2,36],45:[1,85]},{5:[2,37],24:[2,37],29:[2,37],40:[2,37],45:[2,37]},{5:[2,39],24:[2,39],29:[2,39],40:[2,39],45:[2,39],47:[1,86]},{5:[2,44],24:[2,44],29:[2,44],40:[2,44],41:[2,44],53:[1,55],54:[1,56],55:[1,57],56:[1,58]},{5:[2,43],24:[2,43],29:[2,43],40:[2,43],41:[2,43],45:[1,87],52:[2,43]},{5:[2,65],24:[2,65],29:[2,65],40:[2,65],41:[2,65],45:[2,65],52:[2,65],53:[1,55],54:[1,56],55:[1,57],56:[1,58]},{5:[2,13],21:88,24:[2,13],29:[2,13],31:89,32:[1,90],35:[1,91],36:[1,92],39:[2,13],40:[2,13],41:[2,13],50:[2,13]},{5:[2,17],24:[2,17],25:[1,93],29:[2,17],32:[2,17],33:[2,17],35:[2,17],36:[2,17],39:[2,17],40:[2,17],41:[2,17],50:[2,17],66:[1,60]},{4:94,6:3,8:4,9:5,10:6,14:7,16:[1,8]},{5:[2,61],18:[2,61],24:[2,61],25:[2,61],29:[2,61],32:[2,61],33:[2,61],35:[2,61],36:[2,61],39:[2,61],40:[2,61],41:[2,61],45:[2,61],50:[2,61],66:[2,61]},{18:[2,68],45:[2,68]},{19:95,22:71,23:[1,72],65:[1,73]},{18:[2,71],45:[2,71],66:[1,60]},{5:[2,46],18:[2,46],24:[2,46],29:[2,46],32:[2,46],35:[2,46],36:[2,46],39:[2,46],40:[2,46],41:[2,46],45:[2,46],50:[2,46],52:[2,46],53:[2,46],54:[1,56],55:[2,46],56:[2,46],70:[2,46]},{5:[2,47],18:[2,47],24:[2,47],29:[2,47],32:[2,47],35:[2,47],36:[2,47],39:[2,47],40:[2,47],41:[2,47],45:[2,47],50:[2,47],52:[2,47],53:[2,47],54:[2,47],55:[2,47],56:[2,47],70:[2,47]},{5:[2,48],18:[2,48],24:[2,48],29:[2,48],32:[2,48],35:[2,48],36:[2,48],39:[2,48],40:[2,48],41:[2,48],45:[2,48],50:[2,48],52:[2,48],53:[1,55],54:[1,56],55:[2,48],56:[2,48],70:[2,48]},{5:[2,49],18:[2,49],24:[2,49],29:[2,49],32:[2,49],35:[2,49],36:[2,49],39:[2,49],40:[2,49],41:[2,49],45:[2,49],50:[2,49],52:[2,49],53:[1,55],54:[1,56],55:[1,57],56:[2,49],70:[2,49]},{5:[2,45],18:[2,45],24:[2,45],29:[2,45],32:[2,45],35:[2,45],36:[2,45],39:[2,45],40:[2,45],41:[2,45],45:[2,45],50:[2,45],52:[2,45],53:[2,45],54:[2,45],55:[2,45],56:[2,45],70:[2,45]},{5:[2,62],18:[2,62],24:[2,62],25:[2,62],29:[2,62],32:[2,62],33:[2,62],35:[2,62],36:[2,62],39:[2,62],40:[2,62],41:[2,62],45:[2,62],47:[2,62],50:[2,62],52:[2,62],53:[2,62],54:[2,62],55:[2,62],56:[2,62],66:[2,62],70:[2,62]},{24:[1,96],45:[1,87]},{24:[1,97],45:[1,87]},{22:29,27:30,44:98,46:66,57:31,58:32,59:33,60:34,61:[1,36],62:[1,40],63:[1,37],64:[1,38],65:[1,35],67:[1,39]},{5:[2,40],24:[2,40],29:[2,40],40:[2,40],45:[2,40]},{22:29,27:30,46:99,57:31,58:32,59:33,60:34,61:[1,36],62:[1,40],63:[1,37],64:[1,38],65:[1,35],67:[1,39]},{5:[2,15],24:[2,15],29:[2,15],31:100,32:[1,90],35:[1,91],36:[1,92],39:[2,15],40:[2,15],41:[2,15],50:[2,15]},{5:[2,25],24:[2,25],29:[2,25],32:[2,25],35:[2,25],36:[2,25],39:[2,25],40:[2,25],41:[2,25],50:[2,25]},{19:101,22:71,23:[1,72],65:[1,73]},{32:[1,102],37:[1,103],38:[1,104]},{32:[1,105],37:[1,106],38:[1,107]},{26:[1,108]},{24:[1,109]},{5:[2,14],21:110,24:[2,14],29:[2,14],31:89,32:[1,90],35:[1,91],36:[1,92],39:[2,14],40:[2,14],41:[2,14],50:[2,14]},{5:[2,64],18:[2,64],24:[2,64],29:[2,64],32:[2,64],35:[2,64],36:[2,64],39:[2,64],40:[2,64],41:[2,64],45:[2,64],47:[2,64],50:[2,64],52:[2,64],53:[2,64],54:[2,64],55:[2,64],56:[2,64],70:[2,64]},{5:[2,63],18:[2,63],24:[2,63],29:[2,63],32:[2,63],35:[2,63],36:[2,63],39:[2,63],40:[2,63],41:[2,63],45:[2,63],47:[2,63],50:[2,63],52:[2,63],53:[2,63],54:[2,63],55:[2,63],56:[2,63],70:[2,63]},{5:[2,38],24:[2,38],29:[2,38],40:[2,38],45:[2,38]},{5:[2,66],24:[2,66],29:[2,66],40:[2,66],41:[2,66],45:[2,66],52:[2,66]},{5:[2,26],24:[2,26],29:[2,26],32:[2,26],35:[2,26],36:[2,26],39:[2,26],40:[2,26],41:[2,26],50:[2,26]},{33:[1,111]},{19:112,22:71,23:[1,72],65:[1,73]},{32:[1,113]},{32:[1,114]},{19:115,22:71,23:[1,72],65:[1,73]},{32:[1,116]},{32:[1,117]},{23:[1,118]},{5:[2,18],22:119,24:[2,18],29:[2,18],32:[2,18],33:[2,18],35:[2,18],36:[2,18],39:[2,18],40:[2,18],41:[2,18],50:[2,18],65:[1,73]},{5:[2,16],24:[2,16],29:[2,16],31:100,32:[1,90],35:[1,91],36:[1,92],39:[2,16],40:[2,16],41:[2,16],50:[2,16]},{22:29,23:[1,27],27:30,34:120,46:28,57:31,58:32,59:33,60:34,61:[1,36],62:[1,40],63:[1,37],64:[1,38],65:[1,35],67:[1,39]},{33:[1,121]},{19:122,22:71,23:[1,72],65:[1,73]},{19:123,22:71,23:[1,72],65:[1,73]},{33:[1,124]},{19:125,22:71,23:[1,72],65:[1,73]},{19:126,22:71,23:[1,72],65:[1,73]},{27:127,61:[1,36]},{5:[2,19],24:[2,19],29:[2,19],32:[2,19],33:[2,19],35:[2,19],36:[2,19],39:[2,19],40:[2,19],41:[2,19],50:[2,19],66:[1,60]},{5:[2,27],24:[2,27],29:[2,27],32:[2,27],35:[2,27],36:[2,27],39:[2,27],40:[2,27],41:[2,27],50:[2,27],53:[1,55],54:[1,56],55:[1,57],56:[1,58]},{22:29,23:[1,27],27:30,34:128,46:28,57:31,58:32,59:33,60:34,61:[1,36],62:[1,40],63:[1,37],64:[1,38],65:[1,35],67:[1,39]},{33:[1,129]},{33:[1,130]},{22:29,23:[1,27],27:30,34:131,46:28,57:31,58:32,59:33,60:34,61:[1,36],62:[1,40],63:[1,37],64:[1,38],65:[1,35],67:[1,39]},{33:[1,132]},{33:[1,133]},{24:[1,134]},{5:[2,28],24:[2,28],29:[2,28],32:[2,28],35:[2,28],36:[2,28],39:[2,28],40:[2,28],41:[2,28],50:[2,28],53:[1,55],54:[1,56],55:[1,57],56:[1,58]},{22:29,23:[1,27],27:30,34:135,46:28,57:31,58:32,59:33,60:34,61:[1,36],62:[1,40],63:[1,37],64:[1,38],65:[1,35],67:[1,39]},{22:29,23:[1,27],27:30,34:136,46:28,57:31,58:32,59:33,60:34,61:[1,36],62:[1,40],63:[1,37],64:[1,38],65:[1,35],67:[1,39]},{5:[2,29],24:[2,29],29:[2,29],32:[2,29],35:[2,29],36:[2,29],39:[2,29],40:[2,29],41:[2,29],50:[2,29],53:[1,55],54:[1,56],55:[1,57],56:[1,58]},{22:29,23:[1,27],27:30,34:137,46:28,57:31,58:32,59:33,60:34,61:[1,36],62:[1,40],63:[1,37],64:[1,38],65:[1,35],67:[1,39]},{22:29,23:[1,27],27:30,34:138,46:28,57:31,58:32,59:33,60:34,61:[1,36],62:[1,40],63:[1,37],64:[1,38],65:[1,35],67:[1,39]},{5:[2,20],24:[2,20],29:[2,20],32:[2,20],33:[2,20],35:[2,20],36:[2,20],39:[2,20],40:[2,20],41:[2,20],50:[2,20]},{5:[2,30],24:[2,30],29:[2,30],32:[2,30],35:[2,30],36:[2,30],39:[2,30],40:[2,30],41:[2,30],50:[2,30],53:[1,55],54:[1,56],55:[1,57],56:[1,58]},{5:[2,32],24:[2,32],29:[2,32],32:[2,32],35:[2,32],36:[2,32],39:[2,32],40:[2,32],41:[2,32],50:[2,32],53:[1,55],54:[1,56],55:[1,57],56:[1,58]},{5:[2,31],24:[2,31],29:[2,31],32:[2,31],35:[2,31],36:[2,31],39:[2,31],40:[2,31],41:[2,31],50:[2,31],53:[1,55],54:[1,56],55:[1,57],56:[1,58]},{5:[2,33],24:[2,33],29:[2,33],32:[2,33],35:[2,33],36:[2,33],39:[2,33],40:[2,33],41:[2,33],50:[2,33],53:[1,55],54:[1,56],55:[1,57],56:[1,58]}],
367 | defaultActions: {9:[2,1]},
368 | parseError: function parseError(str, hash) {
369 | throw new Error(str);
370 | },
371 | parse: function parse(input) {
372 | var self = this,
373 | stack = [0],
374 | vstack = [null], // semantic value stack
375 | lstack = [], // location stack
376 | table = this.table,
377 | yytext = '',
378 | yylineno = 0,
379 | yyleng = 0,
380 | recovering = 0,
381 | TERROR = 2,
382 | EOF = 1;
383 |
384 | //this.reductionCount = this.shiftCount = 0;
385 |
386 | this.lexer.setInput(input);
387 | this.lexer.yy = this.yy;
388 | this.yy.lexer = this.lexer;
389 | if (typeof this.lexer.yylloc == 'undefined')
390 | this.lexer.yylloc = {};
391 | var yyloc = this.lexer.yylloc;
392 | lstack.push(yyloc);
393 |
394 | if (typeof this.yy.parseError === 'function')
395 | this.parseError = this.yy.parseError;
396 |
397 | function popStack (n) {
398 | stack.length = stack.length - 2*n;
399 | vstack.length = vstack.length - n;
400 | lstack.length = lstack.length - n;
401 | }
402 |
403 | function lex() {
404 | var token;
405 | token = self.lexer.lex() || 1; // $end = 1
406 | // if token isn't its numeric value, convert
407 | if (typeof token !== 'number') {
408 | token = self.symbols_[token] || token;
409 | }
410 | return token;
411 | };
412 |
413 | var symbol, preErrorSymbol, state, action, a, r, yyval={},p,len,newState, expected;
414 | while (true) {
415 | // retreive state number from top of stack
416 | state = stack[stack.length-1];
417 |
418 | // use default actions if available
419 | if (this.defaultActions[state]) {
420 | action = this.defaultActions[state];
421 | } else {
422 | if (symbol == null)
423 | symbol = lex();
424 | // read action for current state and first input
425 | action = table[state] && table[state][symbol];
426 | }
427 |
428 | // handle parse error
429 | if (typeof action === 'undefined' || !action.length || !action[0]) {
430 |
431 | if (!recovering) {
432 | // Report error
433 | expected = [];
434 | for (p in table[state]) if (this.terminals_[p] && p > 2) {
435 | expected.push("'"+this.terminals_[p]+"'");
436 | }
437 | var errStr = '';
438 | if (this.lexer.showPosition) {
439 | errStr = 'Parse error on line '+(yylineno+1)+":\n"+this.lexer.showPosition()+'\nExpecting '+expected.join(', ') + ", got '" + this.terminals_[symbol]+ "'";
440 | } else {
441 | errStr = 'Parse error on line '+(yylineno+1)+": Unexpected " +
442 | (symbol == 1 /*EOF*/ ? "end of input" :
443 | ("'"+(this.terminals_[symbol] || symbol)+"'"));
444 | }
445 | this.parseError(errStr,
446 | {text: this.lexer.match, token: this.terminals_[symbol] || symbol, line: this.lexer.yylineno, loc: yyloc, expected: expected});
447 | }
448 |
449 | // just recovered from another error
450 | if (recovering == 3) {
451 | if (symbol == EOF) {
452 | throw new Error(errStr || 'Parsing halted.');
453 | }
454 |
455 | // discard current lookahead and grab another
456 | yyleng = this.lexer.yyleng;
457 | yytext = this.lexer.yytext;
458 | yylineno = this.lexer.yylineno;
459 | yyloc = this.lexer.yylloc;
460 | symbol = lex();
461 | }
462 |
463 | // try to recover from error
464 | while (1) {
465 | // check for error recovery rule in this state
466 | if ((TERROR.toString()) in table[state]) {
467 | break;
468 | }
469 | if (state == 0) {
470 | throw new Error(errStr || 'Parsing halted.');
471 | }
472 | popStack(1);
473 | state = stack[stack.length-1];
474 | }
475 |
476 | preErrorSymbol = symbol; // save the lookahead token
477 | symbol = TERROR; // insert generic error symbol as new lookahead
478 | state = stack[stack.length-1];
479 | action = table[state] && table[state][TERROR];
480 | recovering = 3; // allow 3 real symbols to be shifted before reporting a new error
481 | }
482 |
483 | // this shouldn't happen, unless resolve defaults are off
484 | if (action[0] instanceof Array && action.length > 1) {
485 | throw new Error('Parse Error: multiple actions possible at state: '+state+', token: '+symbol);
486 | }
487 |
488 | switch (action[0]) {
489 |
490 | case 1: // shift
491 | //this.shiftCount++;
492 |
493 | stack.push(symbol);
494 | vstack.push(this.lexer.yytext);
495 | lstack.push(this.lexer.yylloc);
496 | stack.push(action[1]); // push state
497 | symbol = null;
498 | if (!preErrorSymbol) { // normal execution/no error
499 | yyleng = this.lexer.yyleng;
500 | yytext = this.lexer.yytext;
501 | yylineno = this.lexer.yylineno;
502 | yyloc = this.lexer.yylloc;
503 | if (recovering > 0)
504 | recovering--;
505 | } else { // error just occurred, resume old lookahead f/ before error
506 | symbol = preErrorSymbol;
507 | preErrorSymbol = null;
508 | }
509 | break;
510 |
511 | case 2: // reduce
512 | //this.reductionCount++;
513 |
514 | len = this.productions_[action[1]][1];
515 |
516 | // perform semantic action
517 | yyval.$ = vstack[vstack.length-len]; // default to $$ = $1
518 | // default location, uses first token for firsts, last for lasts
519 | yyval._$ = {
520 | first_line: lstack[lstack.length-(len||1)].first_line,
521 | last_line: lstack[lstack.length-1].last_line,
522 | first_column: lstack[lstack.length-(len||1)].first_column,
523 | last_column: lstack[lstack.length-1].last_column
524 | };
525 | r = this.performAction.call(yyval, yytext, yyleng, yylineno, this.yy, action[1], vstack, lstack);
526 |
527 | if (typeof r !== 'undefined') {
528 | return r;
529 | }
530 |
531 | // pop off stack
532 | if (len) {
533 | stack = stack.slice(0,-1*len*2);
534 | vstack = vstack.slice(0, -1*len);
535 | lstack = lstack.slice(0, -1*len);
536 | }
537 |
538 | stack.push(this.productions_[action[1]][0]); // push nonterminal (reduce)
539 | vstack.push(yyval.$);
540 | lstack.push(yyval._$);
541 | // goto new state = table[STATE][NONTERMINAL]
542 | newState = table[stack[stack.length-2]][stack[stack.length-1]];
543 | stack.push(newState);
544 | break;
545 |
546 | case 3: // accept
547 | return true;
548 | }
549 |
550 | }
551 |
552 | return true;
553 | }};
554 | return parser;
555 | })();
556 | if (typeof require !== 'undefined' && typeof exports !== 'undefined') {
557 | exports.parser = parser;
558 | exports.parse = function () { return parser.parse.apply(parser, arguments); }
559 | exports.main = function commonjsMain(args) {
560 | if (!args[1])
561 | throw new Error('Usage: '+args[0]+' FILE');
562 | if (typeof process !== 'undefined') {
563 | var source = require('fs').readFileSync(require('path').join(process.cwd(), args[1]), "utf8");
564 | } else {
565 | var cwd = require("file").path(require("file").cwd());
566 | var source = cwd.join(args[1]).read({charset: "utf-8"});
567 | }
568 | return exports.parser.parse(source);
569 | }
570 | if (typeof module !== 'undefined' && require.main === module) {
571 | exports.main(typeof process !== 'undefined' ? process.argv.slice(1) : require("system").args);
572 | }
573 | }
574 | };require['./nodes'] = new function() {
575 | var exports = this;
576 | (function() {
577 | var Field, FunctionValue, Group, Having, Join, Limit, LiteralValue, Op, Order, OrderArgument, Select, Star, StringValue, SubSelect, Table, Union, Where, indent;
578 |
579 | indent = function(str) {
580 | var line;
581 | return ((function() {
582 | var _i, _len, _ref, _results;
583 | _ref = str.split("\n");
584 | _results = [];
585 | for (_i = 0, _len = _ref.length; _i < _len; _i++) {
586 | line = _ref[_i];
587 | _results.push(" " + line);
588 | }
589 | return _results;
590 | })()).join("\n");
591 | };
592 |
593 | exports.Select = Select = (function() {
594 |
595 | function Select(fields, source, distinct, joins, unions) {
596 | this.fields = fields;
597 | this.source = source;
598 | this.distinct = distinct != null ? distinct : false;
599 | this.joins = joins != null ? joins : [];
600 | this.unions = unions != null ? unions : [];
601 | this.order = null;
602 | this.group = null;
603 | this.where = null;
604 | this.limit = null;
605 | }
606 |
607 | Select.prototype.toString = function() {
608 | var join, ret, union, _i, _j, _len, _len2, _ref, _ref2;
609 | ret = ["SELECT " + (this.fields.join(', '))];
610 | ret.push(indent("FROM " + this.source));
611 | _ref = this.joins;
612 | for (_i = 0, _len = _ref.length; _i < _len; _i++) {
613 | join = _ref[_i];
614 | ret.push(indent(join.toString()));
615 | }
616 | if (this.where) ret.push(indent(this.where.toString()));
617 | if (this.group) ret.push(indent(this.group.toString()));
618 | if (this.order) ret.push(indent(this.order.toString()));
619 | if (this.limit) ret.push(indent(this.limit.toString()));
620 | _ref2 = this.unions;
621 | for (_j = 0, _len2 = _ref2.length; _j < _len2; _j++) {
622 | union = _ref2[_j];
623 | ret.push(union.toString());
624 | }
625 | return ret.join("\n");
626 | };
627 |
628 | return Select;
629 |
630 | })();
631 |
632 | exports.SubSelect = SubSelect = (function() {
633 |
634 | function SubSelect(select, name) {
635 | this.select = select;
636 | this.name = name != null ? name : null;
637 | null;
638 | }
639 |
640 | SubSelect.prototype.toString = function() {
641 | var ret;
642 | ret = [];
643 | ret.push('(');
644 | ret.push(indent(this.select.toString()));
645 | ret.push(this.name ? ") " + (this.name.toString()) : ")");
646 | return ret.join("\n");
647 | };
648 |
649 | return SubSelect;
650 |
651 | })();
652 |
653 | exports.Join = Join = (function() {
654 |
655 | function Join(right, conditions, side, mode) {
656 | this.right = right;
657 | this.conditions = conditions != null ? conditions : null;
658 | this.side = side != null ? side : null;
659 | this.mode = mode != null ? mode : null;
660 | null;
661 | }
662 |
663 | Join.prototype.toString = function() {
664 | var ret;
665 | ret = '';
666 | if (this.side != null) ret += "" + this.side + " ";
667 | if (this.mode != null) ret += "" + this.mode + " ";
668 | return ret + ("JOIN " + this.right + "\n") + indent("ON " + this.conditions);
669 | };
670 |
671 | return Join;
672 |
673 | })();
674 |
675 | exports.Union = Union = (function() {
676 |
677 | function Union(query, all) {
678 | this.query = query;
679 | this.all = all != null ? all : false;
680 | null;
681 | }
682 |
683 | Union.prototype.toString = function() {
684 | var all;
685 | all = this.all ? ' ALL' : '';
686 | return "UNION" + all + "\n" + (this.query.toString());
687 | };
688 |
689 | return Union;
690 |
691 | })();
692 |
693 | exports.LiteralValue = LiteralValue = (function() {
694 |
695 | function LiteralValue(value, value2) {
696 | this.value = value;
697 | this.value2 = value2 != null ? value2 : null;
698 | if (this.value2) {
699 | this.nested = true;
700 | this.values = this.value.values;
701 | this.values.push(value2);
702 | } else {
703 | this.nested = false;
704 | this.values = [this.value];
705 | }
706 | }
707 |
708 | LiteralValue.prototype.toString = function() {
709 | return "`" + (this.values.join('.')) + "`";
710 | };
711 |
712 | return LiteralValue;
713 |
714 | })();
715 |
716 | exports.StringValue = StringValue = (function() {
717 |
718 | function StringValue(value, quoteType) {
719 | this.value = value;
720 | this.quoteType = quoteType != null ? quoteType : "''";
721 | null;
722 | }
723 |
724 | StringValue.prototype.toString = function() {
725 | return "" + this.quoteType + this.value + this.quoteType;
726 | };
727 |
728 | return StringValue;
729 |
730 | })();
731 |
732 | exports.NumberValue = LiteralValue = (function() {
733 |
734 | function LiteralValue(value) {
735 | this.value = Number(value);
736 | }
737 |
738 | LiteralValue.prototype.toString = function() {
739 | return this.value.toString();
740 | };
741 |
742 | return LiteralValue;
743 |
744 | })();
745 |
746 | exports.BooleanValue = LiteralValue = (function() {
747 |
748 | function LiteralValue(value) {
749 | this.value = (function() {
750 | switch (value.toLowerCase()) {
751 | case 'true':
752 | return true;
753 | case 'false':
754 | return false;
755 | default:
756 | return null;
757 | }
758 | })();
759 | }
760 |
761 | LiteralValue.prototype.toString = function() {
762 | if (this.value != null) {
763 | return this.value.toString().toUpperCase();
764 | } else {
765 | return 'NULL';
766 | }
767 | };
768 |
769 | return LiteralValue;
770 |
771 | })();
772 |
773 | exports.FunctionValue = FunctionValue = (function() {
774 |
775 | function FunctionValue(name, _arguments, udf) {
776 | this.name = name;
777 | this.arguments = _arguments != null ? _arguments : [];
778 | this.udf = udf != null ? udf : false;
779 | null;
780 | }
781 |
782 | FunctionValue.prototype.toString = function() {
783 | return "" + this.name + "(" + (this.arguments.join(', ')) + ")";
784 | };
785 |
786 | return FunctionValue;
787 |
788 | })();
789 |
790 | exports.Order = Order = (function() {
791 |
792 | function Order(orderings) {
793 | this.orderings = orderings;
794 | }
795 |
796 | Order.prototype.toString = function() {
797 | return "ORDER BY " + (this.orderings.join(', '));
798 | };
799 |
800 | return Order;
801 |
802 | })();
803 |
804 | exports.OrderArgument = OrderArgument = (function() {
805 |
806 | function OrderArgument(value, direction) {
807 | this.value = value;
808 | this.direction = direction != null ? direction : 'ASC';
809 | null;
810 | }
811 |
812 | OrderArgument.prototype.toString = function() {
813 | return "" + this.value + " " + this.direction;
814 | };
815 |
816 | return OrderArgument;
817 |
818 | })();
819 |
820 | exports.Limit = Limit = (function() {
821 |
822 | function Limit(value) {
823 | this.value = value;
824 | null;
825 | }
826 |
827 | Limit.prototype.toString = function() {
828 | return "LIMIT " + this.value;
829 | };
830 |
831 | return Limit;
832 |
833 | })();
834 |
835 | exports.Table = Table = (function() {
836 |
837 | function Table(name, win, winFn, winArg) {
838 | this.name = name;
839 | this.win = win != null ? win : null;
840 | this.winFn = winFn != null ? winFn : null;
841 | this.winArg = winArg != null ? winArg : null;
842 | null;
843 | }
844 |
845 | Table.prototype.toString = function() {
846 | if (this.win) {
847 | return "" + this.name + "." + this.win + ":" + this.winFn + "(" + this.winArg + ")";
848 | } else {
849 | return this.name.toString();
850 | }
851 | };
852 |
853 | return Table;
854 |
855 | })();
856 |
857 | exports.Group = Group = (function() {
858 |
859 | function Group(fields) {
860 | this.fields = fields;
861 | this.having = null;
862 | }
863 |
864 | Group.prototype.toString = function() {
865 | var ret;
866 | ret = ["GROUP BY " + (this.fields.join(', '))];
867 | if (this.having) ret.push(this.having.toString());
868 | return ret.join("\n");
869 | };
870 |
871 | return Group;
872 |
873 | })();
874 |
875 | exports.Where = Where = (function() {
876 |
877 | function Where(conditions) {
878 | this.conditions = conditions;
879 | null;
880 | }
881 |
882 | Where.prototype.toString = function() {
883 | return "WHERE " + this.conditions;
884 | };
885 |
886 | return Where;
887 |
888 | })();
889 |
890 | exports.Having = Having = (function() {
891 |
892 | function Having(conditions) {
893 | this.conditions = conditions;
894 | null;
895 | }
896 |
897 | Having.prototype.toString = function() {
898 | return "HAVING " + this.conditions;
899 | };
900 |
901 | return Having;
902 |
903 | })();
904 |
905 | exports.Op = Op = (function() {
906 |
907 | function Op(operation, left, right) {
908 | this.operation = operation;
909 | this.left = left;
910 | this.right = right;
911 | null;
912 | }
913 |
914 | Op.prototype.toString = function() {
915 | return "(" + this.left + " " + this.operation + " " + this.right + ")";
916 | };
917 |
918 | return Op;
919 |
920 | })();
921 |
922 | exports.Field = Field = (function() {
923 |
924 | function Field(field, name) {
925 | this.field = field;
926 | this.name = name != null ? name : null;
927 | null;
928 | }
929 |
930 | Field.prototype.toString = function() {
931 | if (this.name) {
932 | return "" + this.field + " AS " + this.name;
933 | } else {
934 | return this.field.toString();
935 | }
936 | };
937 |
938 | return Field;
939 |
940 | })();
941 |
942 | exports.Star = Star = (function() {
943 |
944 | function Star() {
945 | null;
946 | }
947 |
948 | Star.prototype.toString = function() {
949 | return '*';
950 | };
951 |
952 | Star.prototype.star = true;
953 |
954 | return Star;
955 |
956 | })();
957 |
958 | }).call(this);
959 |
960 | };require['./parser'] = new function() {
961 | var exports = this;
962 | (function() {
963 | var buildParser;
964 |
965 | buildParser = function() {
966 | var parser;
967 | parser = require('./compiled_parser').parser;
968 | parser.lexer = {
969 | lex: function() {
970 | var tag, _ref;
971 | _ref = this.tokens[this.pos++] || [''], tag = _ref[0], this.yytext = _ref[1], this.yylineno = _ref[2];
972 | return tag;
973 | },
974 | setInput: function(tokens) {
975 | this.tokens = tokens;
976 | return this.pos = 0;
977 | },
978 | upcomingInput: function() {
979 | return "";
980 | }
981 | };
982 | parser.yy = require('./nodes');
983 | return parser;
984 | };
985 |
986 | exports.parser = buildParser();
987 |
988 | exports.parse = function(str) {
989 | return buildParser().parse(str);
990 | };
991 |
992 | }).call(this);
993 |
994 | };require['./sql_parser'] = new function() {
995 | var exports = this;
996 | (function() {
997 |
998 | exports.lexer = require('./lexer');
999 |
1000 | exports.parser = require('./parser');
1001 |
1002 | exports.nodes = require('./nodes');
1003 |
1004 | exports.parse = function(sql) {
1005 | return exports.parser.parse(exports.lexer.tokenize(sql));
1006 | };
1007 |
1008 | }).call(this);
1009 |
1010 | };
1011 | return require['./sql_parser']
1012 | }();
1013 |
1014 | if(typeof define === 'function' && define.amd) {
1015 | define(function() { return SQLParser });
1016 | } else { root.SQLParser = SQLParser }
1017 | }(this));
--------------------------------------------------------------------------------
/lib/compiled_parser.js:
--------------------------------------------------------------------------------
1 | /* parser generated by jison 0.4.15 */
2 | /*
3 | Returns a Parser object of the following structure:
4 |
5 | Parser: {
6 | yy: {}
7 | }
8 |
9 | Parser.prototype: {
10 | yy: {},
11 | trace: function(),
12 | symbols_: {associative list: name ==> number},
13 | terminals_: {associative list: number ==> name},
14 | productions_: [...],
15 | performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate, $$, _$),
16 | table: [...],
17 | defaultActions: {...},
18 | parseError: function(str, hash),
19 | parse: function(input),
20 |
21 | lexer: {
22 | EOF: 1,
23 | parseError: function(str, hash),
24 | setInput: function(input),
25 | input: function(),
26 | unput: function(str),
27 | more: function(),
28 | less: function(n),
29 | pastInput: function(),
30 | upcomingInput: function(),
31 | showPosition: function(),
32 | test_match: function(regex_match_array, rule_index),
33 | next: function(),
34 | lex: function(),
35 | begin: function(condition),
36 | popState: function(),
37 | _currentRules: function(),
38 | topState: function(),
39 | pushState: function(condition),
40 |
41 | options: {
42 | ranges: boolean (optional: true ==> token location info will include a .range[] member)
43 | flex: boolean (optional: true ==> flex-like lexing behaviour where the rules are tested exhaustively to find the longest match)
44 | backtrack_lexer: boolean (optional: true ==> lexer regexes are tested in order and for each matching regex the action code is invoked; the lexer terminates the scan when a token is returned by the action code)
45 | },
46 |
47 | performAction: function(yy, yy_, $avoiding_name_collisions, YY_START),
48 | rules: [...],
49 | conditions: {associative list: name ==> set},
50 | }
51 | }
52 |
53 |
54 | token location info (@$, _$, etc.): {
55 | first_line: n,
56 | last_line: n,
57 | first_column: n,
58 | last_column: n,
59 | range: [start_number, end_number] (where the numbers are indexes into the input string, regular zero-based)
60 | }
61 |
62 |
63 | the parseError function receives a 'hash' object with these members for lexer and parser errors: {
64 | text: (matched text)
65 | token: (the produced terminal token, if any)
66 | line: (yylineno)
67 | }
68 | while parser (grammar) errors will also provide these members, i.e. parser errors deliver a superset of attributes: {
69 | loc: (yylloc)
70 | expected: (string describing the set of expected tokens)
71 | recoverable: (boolean: TRUE when the parser has a error recovery rule available for this particular error)
72 | }
73 | */
74 | var parser = (function(){
75 | var o=function(k,v,o,l){for(o=o||{},l=k.length;l--;o[k[l]]=v);return o},$V0=[1,8],$V1=[5,26],$V2=[1,14],$V3=[1,13],$V4=[5,26,31,42],$V5=[1,17],$V6=[5,26,31,42,45,62],$V7=[1,27],$V8=[1,29],$V9=[1,39],$Va=[1,43],$Vb=[1,44],$Vc=[1,40],$Vd=[1,41],$Ve=[1,38],$Vf=[1,42],$Vg=[1,25],$Vh=[5,26,31],$Vi=[5,26,31,42,45],$Vj=[1,56],$Vk=[18,43],$Vl=[1,59],$Vm=[1,60],$Vn=[1,61],$Vo=[1,62],$Vp=[1,63],$Vq=[5,18,23,26,31,34,37,38,41,42,43,45,62,64,65,66,67,68,70],$Vr=[5,18,23,26,31,34,37,38,41,42,43,44,45,51,62,64,65,66,67,68,70,71],$Vs=[1,69],$Vt=[2,83],$Vu=[1,83],$Vv=[1,84],$Vw=[1,102],$Vx=[5,26,31,42,43,44],$Vy=[1,110],$Vz=[5,26,31,42,43,45,64],$VA=[5,26,31,41,42,45,62],$VB=[1,113],$VC=[1,114],$VD=[1,115],$VE=[5,26,31,34,35,37,38,41,42,45,62],$VF=[5,18,23,26,31,34,37,38,41,42,43,45,62,64,70],$VG=[5,26,31,34,37,38,41,42,45,62],$VH=[5,26,31,42,56,58];
76 | var parser = {trace: function trace() { },
77 | yy: {},
78 | symbols_: {"error":2,"Root":3,"Query":4,"EOF":5,"SelectQuery":6,"Unions":7,"SelectWithLimitQuery":8,"BasicSelectQuery":9,"Select":10,"OrderClause":11,"GroupClause":12,"LimitClause":13,"SelectClause":14,"WhereClause":15,"SELECT":16,"Fields":17,"FROM":18,"Table":19,"DISTINCT":20,"Joins":21,"Literal":22,"AS":23,"LEFT_PAREN":24,"List":25,"RIGHT_PAREN":26,"WINDOW":27,"WINDOW_FUNCTION":28,"Number":29,"Union":30,"UNION":31,"ALL":32,"Join":33,"JOIN":34,"ON":35,"Expression":36,"LEFT":37,"RIGHT":38,"INNER":39,"OUTER":40,"WHERE":41,"LIMIT":42,"SEPARATOR":43,"OFFSET":44,"ORDER":45,"BY":46,"OrderArgs":47,"OffsetClause":48,"OrderArg":49,"Value":50,"DIRECTION":51,"OffsetRows":52,"FetchClause":53,"ROW":54,"ROWS":55,"FETCH":56,"FIRST":57,"ONLY":58,"NEXT":59,"GroupBasicClause":60,"HavingClause":61,"GROUP":62,"ArgumentList":63,"HAVING":64,"MATH":65,"MATH_MULTI":66,"OPERATOR":67,"BETWEEN":68,"BetweenExpression":69,"CONDITIONAL":70,"SUB_SELECT_OP":71,"SubSelectExpression":72,"SUB_SELECT_UNARY_OP":73,"String":74,"Function":75,"UserFunction":76,"Boolean":77,"Parameter":78,"NUMBER":79,"BOOLEAN":80,"PARAMETER":81,"STRING":82,"DBLSTRING":83,"LITERAL":84,"DOT":85,"FUNCTION":86,"AggregateArgumentList":87,"Field":88,"STAR":89,"$accept":0,"$end":1},
79 | terminals_: {2:"error",5:"EOF",16:"SELECT",18:"FROM",20:"DISTINCT",23:"AS",24:"LEFT_PAREN",26:"RIGHT_PAREN",27:"WINDOW",28:"WINDOW_FUNCTION",31:"UNION",32:"ALL",34:"JOIN",35:"ON",37:"LEFT",38:"RIGHT",39:"INNER",40:"OUTER",41:"WHERE",42:"LIMIT",43:"SEPARATOR",44:"OFFSET",45:"ORDER",46:"BY",51:"DIRECTION",54:"ROW",55:"ROWS",56:"FETCH",57:"FIRST",58:"ONLY",59:"NEXT",62:"GROUP",64:"HAVING",65:"MATH",66:"MATH_MULTI",67:"OPERATOR",68:"BETWEEN",70:"CONDITIONAL",71:"SUB_SELECT_OP",73:"SUB_SELECT_UNARY_OP",79:"NUMBER",80:"BOOLEAN",81:"PARAMETER",82:"STRING",83:"DBLSTRING",84:"LITERAL",85:"DOT",86:"FUNCTION",89:"STAR"},
80 | productions_: [0,[3,2],[4,1],[4,2],[6,1],[6,1],[9,1],[9,2],[9,2],[9,3],[8,2],[10,1],[10,2],[14,4],[14,5],[14,5],[14,6],[19,1],[19,2],[19,3],[19,3],[19,3],[19,4],[19,6],[7,1],[7,2],[30,2],[30,3],[21,1],[21,2],[33,4],[33,5],[33,5],[33,6],[33,6],[33,6],[33,6],[15,2],[13,2],[13,4],[13,4],[11,3],[11,4],[47,1],[47,3],[49,1],[49,2],[48,2],[48,3],[52,2],[52,2],[53,4],[53,4],[12,1],[12,2],[60,3],[61,2],[36,3],[36,3],[36,3],[36,3],[36,3],[36,3],[36,5],[36,3],[36,2],[36,1],[36,1],[69,3],[72,3],[50,1],[50,1],[50,1],[50,1],[50,1],[50,1],[50,1],[25,1],[29,1],[77,1],[78,1],[74,1],[74,1],[22,1],[22,3],[75,4],[76,3],[76,4],[87,1],[87,2],[63,1],[63,3],[17,1],[17,3],[88,1],[88,1],[88,3]],
81 | performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate /* action[1] */, $$ /* vstack */, _$ /* lstack */) {
82 | /* this == yyval */
83 |
84 | var $0 = $$.length - 1;
85 | switch (yystate) {
86 | case 1:
87 | return this.$ = $$[$0-1];
88 | break;
89 | case 2: case 4: case 5: case 6: case 11: case 53: case 66: case 67: case 70: case 71: case 72: case 73: case 74: case 75: case 76:
90 | this.$ = $$[$0];
91 | break;
92 | case 3:
93 | this.$ = (function () {
94 | $$[$0-1].unions = $$[$0];
95 | return $$[$0-1];
96 | }());
97 | break;
98 | case 7:
99 | this.$ = (function () {
100 | $$[$0-1].order = $$[$0];
101 | return $$[$0-1];
102 | }());
103 | break;
104 | case 8:
105 | this.$ = (function () {
106 | $$[$0-1].group = $$[$0];
107 | return $$[$0-1];
108 | }());
109 | break;
110 | case 9:
111 | this.$ = (function () {
112 | $$[$0-2].group = $$[$0-1];
113 | $$[$0-2].order = $$[$0];
114 | return $$[$0-2];
115 | }());
116 | break;
117 | case 10:
118 | this.$ = (function () {
119 | $$[$0-1].limit = $$[$0];
120 | return $$[$0-1];
121 | }());
122 | break;
123 | case 12:
124 | this.$ = (function () {
125 | $$[$0-1].where = $$[$0];
126 | return $$[$0-1];
127 | }());
128 | break;
129 | case 13:
130 | this.$ = new yy.Select($$[$0-2], $$[$0], false);
131 | break;
132 | case 14:
133 | this.$ = new yy.Select($$[$0-2], $$[$0], true);
134 | break;
135 | case 15:
136 | this.$ = new yy.Select($$[$0-3], $$[$0-1], false, $$[$0]);
137 | break;
138 | case 16:
139 | this.$ = new yy.Select($$[$0-3], $$[$0-1], true, $$[$0]);
140 | break;
141 | case 17:
142 | this.$ = new yy.Table($$[$0]);
143 | break;
144 | case 18:
145 | this.$ = new yy.Table($$[$0-1], $$[$0]);
146 | break;
147 | case 19:
148 | this.$ = new yy.Table($$[$0-2], $$[$0]);
149 | break;
150 | case 20: case 49: case 50: case 51: case 52: case 57:
151 | this.$ = $$[$0-1];
152 | break;
153 | case 21: case 69:
154 | this.$ = new yy.SubSelect($$[$0-1]);
155 | break;
156 | case 22:
157 | this.$ = new yy.SubSelect($$[$0-2], $$[$0]);
158 | break;
159 | case 23:
160 | this.$ = new yy.Table($$[$0-5], null, $$[$0-4], $$[$0-3], $$[$0-1]);
161 | break;
162 | case 24: case 28: case 43: case 90: case 92:
163 | this.$ = [$$[$0]];
164 | break;
165 | case 25:
166 | this.$ = $$[$0-1].concat($$[$01]);
167 | break;
168 | case 26:
169 | this.$ = new yy.Union($$[$0]);
170 | break;
171 | case 27:
172 | this.$ = new yy.Union($$[$0], true);
173 | break;
174 | case 29:
175 | this.$ = $$[$0-1].concat($$[$0]);
176 | break;
177 | case 30:
178 | this.$ = new yy.Join($$[$0-2], $$[$0]);
179 | break;
180 | case 31:
181 | this.$ = new yy.Join($$[$0-2], $$[$0], 'LEFT');
182 | break;
183 | case 32:
184 | this.$ = new yy.Join($$[$0-2], $$[$0], 'RIGHT');
185 | break;
186 | case 33:
187 | this.$ = new yy.Join($$[$0-2], $$[$0], 'LEFT', 'INNER');
188 | break;
189 | case 34:
190 | this.$ = new yy.Join($$[$0-2], $$[$0], 'RIGHT', 'INNER');
191 | break;
192 | case 35:
193 | this.$ = new yy.Join($$[$0-2], $$[$0], 'LEFT', 'OUTER');
194 | break;
195 | case 36:
196 | this.$ = new yy.Join($$[$0-2], $$[$0], 'RIGHT', 'OUTER');
197 | break;
198 | case 37:
199 | this.$ = new yy.Where($$[$0]);
200 | break;
201 | case 38:
202 | this.$ = new yy.Limit($$[$0]);
203 | break;
204 | case 39:
205 | this.$ = new yy.Limit($$[$0], $$[$0-2]);
206 | break;
207 | case 40:
208 | this.$ = new yy.Limit($$[$0-2], $$[$0]);
209 | break;
210 | case 41:
211 | this.$ = new yy.Order($$[$0]);
212 | break;
213 | case 42:
214 | this.$ = new yy.Order($$[$0-1], $$[$0]);
215 | break;
216 | case 44: case 91: case 93:
217 | this.$ = $$[$0-2].concat($$[$0]);
218 | break;
219 | case 45:
220 | this.$ = new yy.OrderArgument($$[$0], 'ASC');
221 | break;
222 | case 46:
223 | this.$ = new yy.OrderArgument($$[$0-1], $$[$0]);
224 | break;
225 | case 47:
226 | this.$ = new yy.Offset($$[$0]);
227 | break;
228 | case 48:
229 | this.$ = new yy.Offset($$[$0-1], $$[$0]);
230 | break;
231 | case 54:
232 | this.$ = (function () {
233 | $$[$0-1].having = $$[$0];
234 | return $$[$0-1];
235 | }());
236 | break;
237 | case 55:
238 | this.$ = new yy.Group($$[$0]);
239 | break;
240 | case 56:
241 | this.$ = new yy.Having($$[$0]);
242 | break;
243 | case 58: case 59: case 60: case 61: case 62: case 64:
244 | this.$ = new yy.Op($$[$0-1], $$[$0-2], $$[$0]);
245 | break;
246 | case 63:
247 | this.$ = new yy.Op($$[$0-3], $$[$0-4], $$[$0-1]);
248 | break;
249 | case 65:
250 | this.$ = new yy.UnaryOp($$[$0-1], $$[$0]);
251 | break;
252 | case 68:
253 | this.$ = new yy.BetweenOp([$$[$0-2], $$[$0]]);
254 | break;
255 | case 77:
256 | this.$ = new yy.ListValue($$[$0]);
257 | break;
258 | case 78:
259 | this.$ = new yy.NumberValue($$[$0]);
260 | break;
261 | case 79:
262 | this.$ = new yy.BooleanValue($$[$0]);
263 | break;
264 | case 80:
265 | this.$ = new yy.ParameterValue($$[$0]);
266 | break;
267 | case 81:
268 | this.$ = new yy.StringValue($$[$0], "'");
269 | break;
270 | case 82:
271 | this.$ = new yy.StringValue($$[$0], '"');
272 | break;
273 | case 83:
274 | this.$ = new yy.LiteralValue($$[$0]);
275 | break;
276 | case 84:
277 | this.$ = new yy.LiteralValue($$[$0-2], $$[$0]);
278 | break;
279 | case 85:
280 | this.$ = new yy.FunctionValue($$[$0-3], $$[$0-1]);
281 | break;
282 | case 86:
283 | this.$ = new yy.FunctionValue($$[$0-2], null, true);
284 | break;
285 | case 87:
286 | this.$ = new yy.FunctionValue($$[$0-3], $$[$0-1], true);
287 | break;
288 | case 88:
289 | this.$ = new yy.ArgumentListValue($$[$0]);
290 | break;
291 | case 89:
292 | this.$ = new yy.ArgumentListValue($$[$0], true);
293 | break;
294 | case 94:
295 | this.$ = new yy.Star();
296 | break;
297 | case 95:
298 | this.$ = new yy.Field($$[$0]);
299 | break;
300 | case 96:
301 | this.$ = new yy.Field($$[$0-2], $$[$0]);
302 | break;
303 | }
304 | },
305 | table: [{3:1,4:2,6:3,8:4,9:5,10:6,14:7,16:$V0},{1:[3]},{5:[1,9]},o($V1,[2,2],{7:10,13:11,30:12,31:$V2,42:$V3}),o($V4,[2,4]),o($V4,[2,5]),o($V4,[2,6],{11:15,12:16,60:18,45:$V5,62:[1,19]}),o($V6,[2,11],{15:20,41:[1,21]}),{17:22,20:[1,23],22:31,24:$V7,29:32,36:26,50:28,72:30,73:$V8,74:33,75:34,76:35,77:36,78:37,79:$V9,80:$Va,81:$Vb,82:$Vc,83:$Vd,84:$Ve,86:$Vf,88:24,89:$Vg},{1:[2,1]},o($V1,[2,3],{30:45,31:$V2}),o($V4,[2,10]),o($Vh,[2,24]),{29:46,79:$V9},{6:47,8:4,9:5,10:6,14:7,16:$V0,32:[1,48]},o($V4,[2,7]),o($V4,[2,8],{11:49,45:$V5}),{46:[1,50]},o($Vi,[2,53],{61:51,64:[1,52]}),{46:[1,53]},o($V6,[2,12]),{22:31,24:$V7,29:32,36:54,50:28,72:30,73:$V8,74:33,75:34,76:35,77:36,78:37,79:$V9,80:$Va,81:$Vb,82:$Vc,83:$Vd,84:$Ve,86:$Vf},{18:[1,55],43:$Vj},{17:57,22:31,24:$V7,29:32,36:26,50:28,72:30,73:$V8,74:33,75:34,76:35,77:36,78:37,79:$V9,80:$Va,81:$Vb,82:$Vc,83:$Vd,84:$Ve,86:$Vf,88:24,89:$Vg},o($Vk,[2,92]),o($Vk,[2,94]),o($Vk,[2,95],{23:[1,58],65:$Vl,66:$Vm,67:$Vn,68:$Vo,70:$Vp}),{4:65,6:3,8:4,9:5,10:6,14:7,16:$V0,22:31,24:$V7,29:32,36:64,50:28,72:30,73:$V8,74:33,75:34,76:35,77:36,78:37,79:$V9,80:$Va,81:$Vb,82:$Vc,83:$Vd,84:$Ve,86:$Vf},o($Vq,[2,67],{71:[1,66]}),{24:[1,68],72:67},o($Vq,[2,66]),o($Vr,[2,70],{85:$Vs}),o($Vr,[2,71]),o($Vr,[2,72]),o($Vr,[2,73]),o($Vr,[2,74]),o($Vr,[2,75]),o($Vr,[2,76]),o([5,18,23,26,31,34,37,38,41,42,43,44,45,51,62,64,65,66,67,68,70,71,85],$Vt,{24:[1,70]}),o([5,18,23,26,31,34,37,38,41,42,43,44,45,51,54,55,62,64,65,66,67,68,70,71],[2,78]),o($Vr,[2,81]),o($Vr,[2,82]),{24:[1,71]},o($Vr,[2,79]),o($Vr,[2,80]),o($Vh,[2,25]),o($V4,[2,38],{43:[1,72],44:[1,73]}),o($Vh,[2,26],{13:11,42:$V3}),{6:74,8:4,9:5,10:6,14:7,16:$V0},o($V4,[2,9]),{22:31,29:32,47:75,49:76,50:77,74:33,75:34,76:35,77:36,78:37,79:$V9,80:$Va,81:$Vb,82:$Vc,83:$Vd,84:$Ve,86:$Vf},o($Vi,[2,54]),{22:31,24:$V7,29:32,36:78,50:28,72:30,73:$V8,74:33,75:34,76:35,77:36,78:37,79:$V9,80:$Va,81:$Vb,82:$Vc,83:$Vd,84:$Ve,86:$Vf},{22:31,24:$V7,29:32,36:80,50:28,63:79,72:30,73:$V8,74:33,75:34,76:35,77:36,78:37,79:$V9,80:$Va,81:$Vb,82:$Vc,83:$Vd,84:$Ve,86:$Vf},o($V6,[2,37],{65:$Vl,66:$Vm,67:$Vn,68:$Vo,70:$Vp}),{19:81,22:82,24:$Vu,84:$Vv},{22:31,24:$V7,29:32,36:26,50:28,72:30,73:$V8,74:33,75:34,76:35,77:36,78:37,79:$V9,80:$Va,81:$Vb,82:$Vc,83:$Vd,84:$Ve,86:$Vf,88:85,89:$Vg},{18:[1,86],43:$Vj},{22:87,84:$Vv},{22:31,24:$V7,29:32,36:88,50:28,72:30,73:$V8,74:33,75:34,76:35,77:36,78:37,79:$V9,80:$Va,81:$Vb,82:$Vc,83:$Vd,84:$Ve,86:$Vf},{22:31,24:$V7,29:32,36:89,50:28,72:30,73:$V8,74:33,75:34,76:35,77:36,78:37,79:$V9,80:$Va,81:$Vb,82:$Vc,83:$Vd,84:$Ve,86:$Vf},{22:31,24:$V7,29:32,36:90,50:28,72:30,73:$V8,74:33,75:34,76:35,77:36,78:37,79:$V9,80:$Va,81:$Vb,82:$Vc,83:$Vd,84:$Ve,86:$Vf},{22:31,24:$V7,29:32,36:92,50:28,69:91,72:30,73:$V8,74:33,75:34,76:35,77:36,78:37,79:$V9,80:$Va,81:$Vb,82:$Vc,83:$Vd,84:$Ve,86:$Vf},{22:31,24:$V7,29:32,36:93,50:28,72:30,73:$V8,74:33,75:34,76:35,77:36,78:37,79:$V9,80:$Va,81:$Vb,82:$Vc,83:$Vd,84:$Ve,86:$Vf},{26:[1,94],65:$Vl,66:$Vm,67:$Vn,68:$Vo,70:$Vp},{26:[1,95]},{24:[1,96],72:97},o($Vq,[2,65]),{4:65,6:3,8:4,9:5,10:6,14:7,16:$V0},{84:[1,98]},{20:$Vw,22:31,24:$V7,26:[1,99],29:32,36:80,50:28,63:101,72:30,73:$V8,74:33,75:34,76:35,77:36,78:37,79:$V9,80:$Va,81:$Vb,82:$Vc,83:$Vd,84:$Ve,86:$Vf,87:100},{20:$Vw,22:31,24:$V7,29:32,36:80,50:28,63:101,72:30,73:$V8,74:33,75:34,76:35,77:36,78:37,79:$V9,80:$Va,81:$Vb,82:$Vc,83:$Vd,84:$Ve,86:$Vf,87:103},{29:104,79:$V9},{29:105,79:$V9},o($Vh,[2,27],{13:11,42:$V3}),o($V4,[2,41],{48:106,43:[1,107],44:[1,108]}),o($Vx,[2,43]),o($Vx,[2,45],{51:[1,109]}),o($Vi,[2,56],{65:$Vl,66:$Vm,67:$Vn,68:$Vo,70:$Vp}),o([5,26,31,42,45,64],[2,55],{43:$Vy}),o($Vz,[2,90],{65:$Vl,66:$Vm,67:$Vn,68:$Vo,70:$Vp}),o($VA,[2,13],{21:111,33:112,34:$VB,37:$VC,38:$VD}),o($VE,[2,17],{22:116,23:[1,117],27:[1,118],84:$Vv,85:$Vs}),{4:120,6:3,8:4,9:5,10:6,14:7,16:$V0,22:31,24:$V7,25:119,29:32,36:80,50:28,63:121,72:30,73:$V8,74:33,75:34,76:35,77:36,78:37,79:$V9,80:$Va,81:$Vb,82:$Vc,83:$Vd,84:$Ve,86:$Vf},o([5,18,23,26,27,31,34,35,37,38,41,42,43,45,62,84,85],$Vt),o($Vk,[2,93]),{19:122,22:82,24:$Vu,84:$Vv},o($Vk,[2,96],{85:$Vs}),o([5,18,23,26,31,34,37,38,41,42,43,45,62,64,65,67,70],[2,58],{66:$Vm,68:$Vo}),o([5,18,23,26,31,34,37,38,41,42,43,45,62,64,65,66,67,70],[2,59],{68:$Vo}),o([5,18,23,26,31,34,37,38,41,42,43,45,62,64,67,70],[2,60],{65:$Vl,66:$Vm,68:$Vo}),o($Vq,[2,61]),{65:$Vl,66:$Vm,67:$Vn,68:$Vo,70:[1,123]},o($VF,[2,62],{65:$Vl,66:$Vm,67:$Vn,68:$Vo}),o($Vq,[2,57]),o($Vq,[2,69]),{4:65,6:3,8:4,9:5,10:6,14:7,16:$V0,22:31,24:$V7,25:124,29:32,36:80,50:28,63:121,72:30,73:$V8,74:33,75:34,76:35,77:36,78:37,79:$V9,80:$Va,81:$Vb,82:$Vc,83:$Vd,84:$Ve,86:$Vf},o($Vq,[2,64]),o([5,18,23,26,27,31,34,35,37,38,41,42,43,44,45,51,62,64,65,66,67,68,70,71,84,85],[2,84]),o($Vr,[2,86]),{26:[1,125]},{26:[2,88],43:$Vy},{22:31,24:$V7,29:32,36:80,50:28,63:126,72:30,73:$V8,74:33,75:34,76:35,77:36,78:37,79:$V9,80:$Va,81:$Vb,82:$Vc,83:$Vd,84:$Ve,86:$Vf},{26:[1,127]},o($V4,[2,39]),o($V4,[2,40]),o($V4,[2,42]),{22:31,29:32,49:128,50:77,74:33,75:34,76:35,77:36,78:37,79:$V9,80:$Va,81:$Vb,82:$Vc,83:$Vd,84:$Ve,86:$Vf},{29:130,52:129,79:$V9},o($Vx,[2,46]),{22:31,29:32,50:131,74:33,75:34,76:35,77:36,78:37,79:$V9,80:$Va,81:$Vb,82:$Vc,83:$Vd,84:$Ve,86:$Vf},o($VA,[2,15],{33:132,34:$VB,37:$VC,38:$VD}),o($VG,[2,28]),{19:133,22:82,24:$Vu,84:$Vv},{34:[1,134],39:[1,135],40:[1,136]},{34:[1,137],39:[1,138],40:[1,139]},o($VE,[2,18],{85:$Vs}),{22:140,84:$Vv},{28:[1,141]},{26:[1,142]},{26:[1,143]},{26:[2,77],43:$Vy},o($VA,[2,14],{33:112,21:144,34:$VB,37:$VC,38:$VD}),{22:31,24:$V7,29:32,36:145,50:28,72:30,73:$V8,74:33,75:34,76:35,77:36,78:37,79:$V9,80:$Va,81:$Vb,82:$Vc,83:$Vd,84:$Ve,86:$Vf},{26:[1,146]},o($Vr,[2,87]),{26:[2,89],43:$Vy},o($Vr,[2,85]),o($Vx,[2,44]),o($V4,[2,47],{53:147,56:[1,148]}),{54:[1,149],55:[1,150]},o($Vz,[2,91]),o($VG,[2,29]),{35:[1,151]},{19:152,22:82,24:$Vu,84:$Vv},{34:[1,153]},{34:[1,154]},{19:155,22:82,24:$Vu,84:$Vv},{34:[1,156]},{34:[1,157]},o($VE,[2,19],{85:$Vs}),{24:[1,158]},o($VE,[2,20]),o($VE,[2,21],{22:159,84:$Vv}),o($VA,[2,16],{33:132,34:$VB,37:$VC,38:$VD}),o($VF,[2,68],{65:$Vl,66:$Vm,67:$Vn,68:$Vo}),o($Vq,[2,63]),o($V4,[2,48]),{57:[1,160],59:[1,161]},o($VH,[2,49]),o($VH,[2,50]),{22:31,24:$V7,29:32,36:162,50:28,72:30,73:$V8,74:33,75:34,76:35,77:36,78:37,79:$V9,80:$Va,81:$Vb,82:$Vc,83:$Vd,84:$Ve,86:$Vf},{35:[1,163]},{19:164,22:82,24:$Vu,84:$Vv},{19:165,22:82,24:$Vu,84:$Vv},{35:[1,166]},{19:167,22:82,24:$Vu,84:$Vv},{19:168,22:82,24:$Vu,84:$Vv},{29:169,79:$V9},o($VE,[2,22],{85:$Vs}),{29:130,52:170,79:$V9},{29:130,52:171,79:$V9},o($VG,[2,30],{65:$Vl,66:$Vm,67:$Vn,68:$Vo,70:$Vp}),{22:31,24:$V7,29:32,36:172,50:28,72:30,73:$V8,74:33,75:34,76:35,77:36,78:37,79:$V9,80:$Va,81:$Vb,82:$Vc,83:$Vd,84:$Ve,86:$Vf},{35:[1,173]},{35:[1,174]},{22:31,24:$V7,29:32,36:175,50:28,72:30,73:$V8,74:33,75:34,76:35,77:36,78:37,79:$V9,80:$Va,81:$Vb,82:$Vc,83:$Vd,84:$Ve,86:$Vf},{35:[1,176]},{35:[1,177]},{26:[1,178]},{58:[1,179]},{58:[1,180]},o($VG,[2,31],{65:$Vl,66:$Vm,67:$Vn,68:$Vo,70:$Vp}),{22:31,24:$V7,29:32,36:181,50:28,72:30,73:$V8,74:33,75:34,76:35,77:36,78:37,79:$V9,80:$Va,81:$Vb,82:$Vc,83:$Vd,84:$Ve,86:$Vf},{22:31,24:$V7,29:32,36:182,50:28,72:30,73:$V8,74:33,75:34,76:35,77:36,78:37,79:$V9,80:$Va,81:$Vb,82:$Vc,83:$Vd,84:$Ve,86:$Vf},o($VG,[2,32],{65:$Vl,66:$Vm,67:$Vn,68:$Vo,70:$Vp}),{22:31,24:$V7,29:32,36:183,50:28,72:30,73:$V8,74:33,75:34,76:35,77:36,78:37,79:$V9,80:$Va,81:$Vb,82:$Vc,83:$Vd,84:$Ve,86:$Vf},{22:31,24:$V7,29:32,36:184,50:28,72:30,73:$V8,74:33,75:34,76:35,77:36,78:37,79:$V9,80:$Va,81:$Vb,82:$Vc,83:$Vd,84:$Ve,86:$Vf},o($VE,[2,23]),o($V4,[2,51]),o($V4,[2,52]),o($VG,[2,33],{65:$Vl,66:$Vm,67:$Vn,68:$Vo,70:$Vp}),o($VG,[2,35],{65:$Vl,66:$Vm,67:$Vn,68:$Vo,70:$Vp}),o($VG,[2,34],{65:$Vl,66:$Vm,67:$Vn,68:$Vo,70:$Vp}),o($VG,[2,36],{65:$Vl,66:$Vm,67:$Vn,68:$Vo,70:$Vp})],
306 | defaultActions: {9:[2,1]},
307 | parseError: function parseError(str, hash) {
308 | if (hash.recoverable) {
309 | this.trace(str);
310 | } else {
311 | throw new Error(str);
312 | }
313 | },
314 | parse: function parse(input) {
315 | var self = this, stack = [0], tstack = [], vstack = [null], lstack = [], table = this.table, yytext = '', yylineno = 0, yyleng = 0, recovering = 0, TERROR = 2, EOF = 1;
316 | var args = lstack.slice.call(arguments, 1);
317 | var lexer = Object.create(this.lexer);
318 | var sharedState = { yy: {} };
319 | for (var k in this.yy) {
320 | if (Object.prototype.hasOwnProperty.call(this.yy, k)) {
321 | sharedState.yy[k] = this.yy[k];
322 | }
323 | }
324 | lexer.setInput(input, sharedState.yy);
325 | sharedState.yy.lexer = lexer;
326 | sharedState.yy.parser = this;
327 | if (typeof lexer.yylloc == 'undefined') {
328 | lexer.yylloc = {};
329 | }
330 | var yyloc = lexer.yylloc;
331 | lstack.push(yyloc);
332 | var ranges = lexer.options && lexer.options.ranges;
333 | if (typeof sharedState.yy.parseError === 'function') {
334 | this.parseError = sharedState.yy.parseError;
335 | } else {
336 | this.parseError = Object.getPrototypeOf(this).parseError;
337 | }
338 | function popStack(n) {
339 | stack.length = stack.length - 2 * n;
340 | vstack.length = vstack.length - n;
341 | lstack.length = lstack.length - n;
342 | }
343 | _token_stack:
344 | function lex() {
345 | var token;
346 | token = lexer.lex() || EOF;
347 | if (typeof token !== 'number') {
348 | token = self.symbols_[token] || token;
349 | }
350 | return token;
351 | }
352 | var symbol, preErrorSymbol, state, action, a, r, yyval = {}, p, len, newState, expected;
353 | while (true) {
354 | state = stack[stack.length - 1];
355 | if (this.defaultActions[state]) {
356 | action = this.defaultActions[state];
357 | } else {
358 | if (symbol === null || typeof symbol == 'undefined') {
359 | symbol = lex();
360 | }
361 | action = table[state] && table[state][symbol];
362 | }
363 | if (typeof action === 'undefined' || !action.length || !action[0]) {
364 | var errStr = '';
365 | expected = [];
366 | for (p in table[state]) {
367 | if (this.terminals_[p] && p > TERROR) {
368 | expected.push('\'' + this.terminals_[p] + '\'');
369 | }
370 | }
371 | if (lexer.showPosition) {
372 | errStr = 'Parse error on line ' + (yylineno + 1) + ':\n' + lexer.showPosition() + '\nExpecting ' + expected.join(', ') + ', got \'' + (this.terminals_[symbol] || symbol) + '\'';
373 | } else {
374 | errStr = 'Parse error on line ' + (yylineno + 1) + ': Unexpected ' + (symbol == EOF ? 'end of input' : '\'' + (this.terminals_[symbol] || symbol) + '\'');
375 | }
376 | this.parseError(errStr, {
377 | text: lexer.match,
378 | token: this.terminals_[symbol] || symbol,
379 | line: lexer.yylineno,
380 | loc: yyloc,
381 | expected: expected
382 | });
383 | }
384 | if (action[0] instanceof Array && action.length > 1) {
385 | throw new Error('Parse Error: multiple actions possible at state: ' + state + ', token: ' + symbol);
386 | }
387 | switch (action[0]) {
388 | case 1:
389 | stack.push(symbol);
390 | vstack.push(lexer.yytext);
391 | lstack.push(lexer.yylloc);
392 | stack.push(action[1]);
393 | symbol = null;
394 | if (!preErrorSymbol) {
395 | yyleng = lexer.yyleng;
396 | yytext = lexer.yytext;
397 | yylineno = lexer.yylineno;
398 | yyloc = lexer.yylloc;
399 | if (recovering > 0) {
400 | recovering--;
401 | }
402 | } else {
403 | symbol = preErrorSymbol;
404 | preErrorSymbol = null;
405 | }
406 | break;
407 | case 2:
408 | len = this.productions_[action[1]][1];
409 | yyval.$ = vstack[vstack.length - len];
410 | yyval._$ = {
411 | first_line: lstack[lstack.length - (len || 1)].first_line,
412 | last_line: lstack[lstack.length - 1].last_line,
413 | first_column: lstack[lstack.length - (len || 1)].first_column,
414 | last_column: lstack[lstack.length - 1].last_column
415 | };
416 | if (ranges) {
417 | yyval._$.range = [
418 | lstack[lstack.length - (len || 1)].range[0],
419 | lstack[lstack.length - 1].range[1]
420 | ];
421 | }
422 | r = this.performAction.apply(yyval, [
423 | yytext,
424 | yyleng,
425 | yylineno,
426 | sharedState.yy,
427 | action[1],
428 | vstack,
429 | lstack
430 | ].concat(args));
431 | if (typeof r !== 'undefined') {
432 | return r;
433 | }
434 | if (len) {
435 | stack = stack.slice(0, -1 * len * 2);
436 | vstack = vstack.slice(0, -1 * len);
437 | lstack = lstack.slice(0, -1 * len);
438 | }
439 | stack.push(this.productions_[action[1]][0]);
440 | vstack.push(yyval.$);
441 | lstack.push(yyval._$);
442 | newState = table[stack[stack.length - 2]][stack[stack.length - 1]];
443 | stack.push(newState);
444 | break;
445 | case 3:
446 | return true;
447 | }
448 | }
449 | return true;
450 | }};
451 |
452 | function Parser () {
453 | this.yy = {};
454 | }
455 | Parser.prototype = parser;parser.Parser = Parser;
456 | return new Parser;
457 | })();
458 |
459 |
460 | if (typeof require !== 'undefined' && typeof exports !== 'undefined') {
461 | exports.parser = parser;
462 | exports.Parser = parser.Parser;
463 | exports.parse = function () { return parser.parse.apply(parser, arguments); };
464 | exports.main = function commonjsMain(args) {
465 | if (!args[1]) {
466 | console.log('Usage: '+args[0]+' FILE');
467 | process.exit(1);
468 | }
469 | var source = require('fs').readFileSync(require('path').normalize(args[1]), "utf8");
470 | return exports.parser.parse(source);
471 | };
472 | if (typeof module !== 'undefined' && require.main === module) {
473 | exports.main(process.argv.slice(1));
474 | }
475 | }
--------------------------------------------------------------------------------
/lib/grammar.js:
--------------------------------------------------------------------------------
1 | // Generated by CoffeeScript 1.8.0
2 | (function() {
3 | var Parser, alt, alternatives, grammar, name, o, operators, token, tokens, unwrap;
4 |
5 | Parser = require('jison').Parser;
6 |
7 | unwrap = /^function\s*\(\)\s*\{\s*return\s*([\s\S]*);\s*\}/;
8 |
9 | o = function(patternString, action, options) {
10 | var match;
11 | patternString = patternString.replace(/\s{2,}/g, ' ');
12 | if (!action) {
13 | return [patternString, '$$ = $1;', options];
14 | }
15 | action = (match = unwrap.exec(action)) ? match[1] : "(" + action + "())";
16 | action = action.replace(/\bnew /g, '$&yy.');
17 | return [patternString, "$$ = " + action + ";", options];
18 | };
19 |
20 | grammar = {
21 | Root: [o('Query EOF')],
22 | Query: [
23 | o("SelectQuery"), o("SelectQuery Unions", function() {
24 | $1.unions = $2;
25 | return $1;
26 | })
27 | ],
28 | SelectQuery: [o("SelectWithLimitQuery"), o("BasicSelectQuery")],
29 | BasicSelectQuery: [
30 | o('Select'), o('Select OrderClause', function() {
31 | $1.order = $2;
32 | return $1;
33 | }), o('Select GroupClause', function() {
34 | $1.group = $2;
35 | return $1;
36 | }), o('Select GroupClause OrderClause', function() {
37 | $1.group = $2;
38 | $1.order = $3;
39 | return $1;
40 | })
41 | ],
42 | SelectWithLimitQuery: [
43 | o('SelectQuery LimitClause', function() {
44 | $1.limit = $2;
45 | return $1;
46 | })
47 | ],
48 | Select: [
49 | o('SelectClause'), o('SelectClause WhereClause', function() {
50 | $1.where = $2;
51 | return $1;
52 | })
53 | ],
54 | SelectClause: [
55 | o('SELECT Fields FROM Table', function() {
56 | return new Select($2, $4, false);
57 | }), o('SELECT DISTINCT Fields FROM Table', function() {
58 | return new Select($3, $5, true);
59 | }), o('SELECT Fields FROM Table Joins', function() {
60 | return new Select($2, $4, false, $5);
61 | }), o('SELECT DISTINCT Fields FROM Table Joins', function() {
62 | return new Select($3, $5, true, $6);
63 | })
64 | ],
65 | Table: [
66 | o('Literal', function() {
67 | return new Table($1);
68 | }), o('Literal Literal', function() {
69 | return new Table($1, $2);
70 | }), o('Literal AS Literal', function() {
71 | return new Table($1, $3);
72 | }), o('LEFT_PAREN List RIGHT_PAREN', function() {
73 | return $2;
74 | }), o('LEFT_PAREN Query RIGHT_PAREN', function() {
75 | return new SubSelect($2);
76 | }), o('LEFT_PAREN Query RIGHT_PAREN Literal', function() {
77 | return new SubSelect($2, $4);
78 | }), o('Literal WINDOW WINDOW_FUNCTION LEFT_PAREN Number RIGHT_PAREN', function() {
79 | return new Table($1, null, $2, $3, $5);
80 | })
81 | ],
82 | Unions: [
83 | o('Union', function() {
84 | return [$1];
85 | }), o('Unions Union', function() {
86 | return $1.concat($3);
87 | })
88 | ],
89 | Union: [
90 | o('UNION SelectQuery', function() {
91 | return new Union($2);
92 | }), o('UNION ALL SelectQuery', function() {
93 | return new Union($3, true);
94 | })
95 | ],
96 | Joins: [
97 | o('Join', function() {
98 | return [$1];
99 | }), o('Joins Join', function() {
100 | return $1.concat($2);
101 | })
102 | ],
103 | Join: [
104 | o('JOIN Table ON Expression', function() {
105 | return new Join($2, $4);
106 | }), o('LEFT JOIN Table ON Expression', function() {
107 | return new Join($3, $5, 'LEFT');
108 | }), o('RIGHT JOIN Table ON Expression', function() {
109 | return new Join($3, $5, 'RIGHT');
110 | }), o('LEFT INNER JOIN Table ON Expression', function() {
111 | return new Join($4, $6, 'LEFT', 'INNER');
112 | }), o('RIGHT INNER JOIN Table ON Expression', function() {
113 | return new Join($4, $6, 'RIGHT', 'INNER');
114 | }), o('LEFT OUTER JOIN Table ON Expression', function() {
115 | return new Join($4, $6, 'LEFT', 'OUTER');
116 | }), o('RIGHT OUTER JOIN Table ON Expression', function() {
117 | return new Join($4, $6, 'RIGHT', 'OUTER');
118 | })
119 | ],
120 | WhereClause: [
121 | o('WHERE Expression', function() {
122 | return new Where($2);
123 | })
124 | ],
125 | LimitClause: [
126 | o('LIMIT Number', function() {
127 | return new Limit($2);
128 | }), o('LIMIT Number SEPARATOR Number', function() {
129 | return new Limit($4, $2);
130 | }), o('LIMIT Number OFFSET Number', function() {
131 | return new Limit($2, $4);
132 | })
133 | ],
134 | OrderClause: [
135 | o('ORDER BY OrderArgs', function() {
136 | return new Order($3);
137 | }), o('ORDER BY OrderArgs OffsetClause', function() {
138 | return new Order($3, $4);
139 | })
140 | ],
141 | OrderArgs: [
142 | o('OrderArg', function() {
143 | return [$1];
144 | }), o('OrderArgs SEPARATOR OrderArg', function() {
145 | return $1.concat($3);
146 | })
147 | ],
148 | OrderArg: [
149 | o('Value', function() {
150 | return new OrderArgument($1, 'ASC');
151 | }), o('Value DIRECTION', function() {
152 | return new OrderArgument($1, $2);
153 | })
154 | ],
155 | OffsetClause: [
156 | o('OFFSET OffsetRows', function() {
157 | return new Offset($2);
158 | }), o('OFFSET OffsetRows FetchClause', function() {
159 | return new Offset($2, $3);
160 | })
161 | ],
162 | OffsetRows: [
163 | o('Number ROW', function() {
164 | return $1;
165 | }), o('Number ROWS', function() {
166 | return $1;
167 | })
168 | ],
169 | FetchClause: [
170 | o('FETCH FIRST OffsetRows ONLY', function() {
171 | return $3;
172 | }), o('FETCH NEXT OffsetRows ONLY', function() {
173 | return $3;
174 | })
175 | ],
176 | GroupClause: [
177 | o('GroupBasicClause'), o('GroupBasicClause HavingClause', function() {
178 | $1.having = $2;
179 | return $1;
180 | })
181 | ],
182 | GroupBasicClause: [
183 | o('GROUP BY ArgumentList', function() {
184 | return new Group($3);
185 | })
186 | ],
187 | HavingClause: [
188 | o('HAVING Expression', function() {
189 | return new Having($2);
190 | })
191 | ],
192 | Expression: [
193 | o('LEFT_PAREN Expression RIGHT_PAREN', function() {
194 | return $2;
195 | }), o('Expression MATH Expression', function() {
196 | return new Op($2, $1, $3);
197 | }), o('Expression MATH_MULTI Expression', function() {
198 | return new Op($2, $1, $3);
199 | }), o('Expression OPERATOR Expression', function() {
200 | return new Op($2, $1, $3);
201 | }), o('Expression BETWEEN BetweenExpression', function() {
202 | return new Op($2, $1, $3);
203 | }), o('Expression CONDITIONAL Expression', function() {
204 | return new Op($2, $1, $3);
205 | }), o('Value SUB_SELECT_OP LEFT_PAREN List RIGHT_PAREN', function() {
206 | return new Op($2, $1, $4);
207 | }), o('Value SUB_SELECT_OP SubSelectExpression', function() {
208 | return new Op($2, $1, $3);
209 | }), o('SUB_SELECT_UNARY_OP SubSelectExpression', function() {
210 | return new UnaryOp($1, $2);
211 | }), o('SubSelectExpression'), o('Value')
212 | ],
213 | BetweenExpression: [
214 | o('Expression CONDITIONAL Expression', function() {
215 | return new BetweenOp([$1, $3]);
216 | })
217 | ],
218 | SubSelectExpression: [
219 | o('LEFT_PAREN Query RIGHT_PAREN', function() {
220 | return new SubSelect($2);
221 | })
222 | ],
223 | Value: [o('Literal'), o('Number'), o('String'), o('Function'), o('UserFunction'), o('Boolean'), o('Parameter')],
224 | List: [
225 | o('ArgumentList', function() {
226 | return new ListValue($1);
227 | })
228 | ],
229 | Number: [
230 | o('NUMBER', function() {
231 | return new NumberValue($1);
232 | })
233 | ],
234 | Boolean: [
235 | o('BOOLEAN', function() {
236 | return new BooleanValue($1);
237 | })
238 | ],
239 | Parameter: [
240 | o('PARAMETER', function() {
241 | return new ParameterValue($1);
242 | })
243 | ],
244 | String: [
245 | o('STRING', function() {
246 | return new StringValue($1, "'");
247 | }), o('DBLSTRING', function() {
248 | return new StringValue($1, '"');
249 | })
250 | ],
251 | Literal: [
252 | o('LITERAL', function() {
253 | return new LiteralValue($1);
254 | }), o('Literal DOT LITERAL', function() {
255 | return new LiteralValue($1, $3);
256 | })
257 | ],
258 | Function: [
259 | o("FUNCTION LEFT_PAREN AggregateArgumentList RIGHT_PAREN", function() {
260 | return new FunctionValue($1, $3);
261 | })
262 | ],
263 | UserFunction: [
264 | o("LITERAL LEFT_PAREN RIGHT_PAREN", function() {
265 | return new FunctionValue($1, null, true);
266 | }), o("LITERAL LEFT_PAREN AggregateArgumentList RIGHT_PAREN", function() {
267 | return new FunctionValue($1, $3, true);
268 | })
269 | ],
270 | AggregateArgumentList: [
271 | o('ArgumentList', function() {
272 | return new ArgumentListValue($1);
273 | }), o('DISTINCT ArgumentList', function() {
274 | return new ArgumentListValue($2, true);
275 | })
276 | ],
277 | ArgumentList: [
278 | o('Expression', function() {
279 | return [$1];
280 | }), o('ArgumentList SEPARATOR Value', function() {
281 | return $1.concat($3);
282 | })
283 | ],
284 | Fields: [
285 | o('Field', function() {
286 | return [$1];
287 | }), o('Fields SEPARATOR Field', function() {
288 | return $1.concat($3);
289 | })
290 | ],
291 | Field: [
292 | o('STAR', function() {
293 | return new Star();
294 | }), o('Expression', function() {
295 | return new Field($1);
296 | }), o('Expression AS Literal', function() {
297 | return new Field($1, $3);
298 | })
299 | ]
300 | };
301 |
302 | tokens = [];
303 |
304 | operators = [['left', 'Op'], ['left', 'MATH_MULTI'], ['left', 'MATH'], ['left', 'OPERATOR'], ['left', 'CONDITIONAL']];
305 |
306 | for (name in grammar) {
307 | alternatives = grammar[name];
308 | grammar[name] = (function() {
309 | var _i, _j, _len, _len1, _ref, _results;
310 | _results = [];
311 | for (_i = 0, _len = alternatives.length; _i < _len; _i++) {
312 | alt = alternatives[_i];
313 | _ref = alt[0].split(' ');
314 | for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) {
315 | token = _ref[_j];
316 | if (!grammar[token]) {
317 | tokens.push(token);
318 | }
319 | }
320 | if (name === 'Root') {
321 | alt[1] = "return " + alt[1];
322 | }
323 | _results.push(alt);
324 | }
325 | return _results;
326 | })();
327 | }
328 |
329 | exports.parser = new Parser({
330 | tokens: tokens.join(' '),
331 | bnf: grammar,
332 | operators: operators.reverse(),
333 | startSymbol: 'Root'
334 | });
335 |
336 | }).call(this);
337 |
--------------------------------------------------------------------------------
/lib/lexer.js:
--------------------------------------------------------------------------------
1 | // Generated by CoffeeScript 1.8.0
2 | (function() {
3 | var Lexer;
4 |
5 | Lexer = (function() {
6 | var BOOLEAN, DBLSTRING, LITERAL, MATH, MATH_MULTI, NUMBER, PARAMETER, SEPARATOR, SQL_BETWEENS, SQL_CONDITIONALS, SQL_FUNCTIONS, SQL_OPERATORS, SQL_SORT_ORDERS, STAR, STRING, SUB_SELECT_OP, SUB_SELECT_UNARY_OP, WHITESPACE;
7 |
8 | function Lexer(sql, opts) {
9 | var bytesConsumed, i;
10 | if (opts == null) {
11 | opts = {};
12 | }
13 | this.sql = sql;
14 | this.preserveWhitespace = opts.preserveWhitespace || false;
15 | this.tokens = [];
16 | this.currentLine = 1;
17 | i = 0;
18 | while (this.chunk = sql.slice(i)) {
19 | bytesConsumed = this.keywordToken() || this.starToken() || this.booleanToken() || this.functionToken() || this.windowExtension() || this.sortOrderToken() || this.seperatorToken() || this.operatorToken() || this.mathToken() || this.dotToken() || this.conditionalToken() || this.betweenToken() || this.subSelectOpToken() || this.subSelectUnaryOpToken() || this.numberToken() || this.stringToken() || this.parameterToken() || this.parensToken() || this.whitespaceToken() || this.literalToken();
20 | if (bytesConsumed < 1) {
21 | throw new Error("NOTHING CONSUMED: Stopped at - '" + (this.chunk.slice(0, 30)) + "'");
22 | }
23 | i += bytesConsumed;
24 | }
25 | this.token('EOF', '');
26 | this.postProcess();
27 | }
28 |
29 | Lexer.prototype.postProcess = function() {
30 | var i, next_token, token, _i, _len, _ref, _results;
31 | _ref = this.tokens;
32 | _results = [];
33 | for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
34 | token = _ref[i];
35 | if (token[0] === 'STAR') {
36 | next_token = this.tokens[i + 1];
37 | if (!(next_token[0] === 'SEPARATOR' || next_token[0] === 'FROM')) {
38 | _results.push(token[0] = 'MATH_MULTI');
39 | } else {
40 | _results.push(void 0);
41 | }
42 | } else {
43 | _results.push(void 0);
44 | }
45 | }
46 | return _results;
47 | };
48 |
49 | Lexer.prototype.token = function(name, value) {
50 | return this.tokens.push([name, value, this.currentLine]);
51 | };
52 |
53 | Lexer.prototype.tokenizeFromRegex = function(name, regex, part, lengthPart, output) {
54 | var match, partMatch;
55 | if (part == null) {
56 | part = 0;
57 | }
58 | if (lengthPart == null) {
59 | lengthPart = part;
60 | }
61 | if (output == null) {
62 | output = true;
63 | }
64 | if (!(match = regex.exec(this.chunk))) {
65 | return 0;
66 | }
67 | partMatch = match[part];
68 | if (output) {
69 | this.token(name, partMatch);
70 | }
71 | return match[lengthPart].length;
72 | };
73 |
74 | Lexer.prototype.tokenizeFromWord = function(name, word) {
75 | var match, matcher;
76 | if (word == null) {
77 | word = name;
78 | }
79 | word = this.regexEscape(word);
80 | matcher = /^\w+$/.test(word) ? new RegExp("^(" + word + ")\\b", 'ig') : new RegExp("^(" + word + ")", 'ig');
81 | match = matcher.exec(this.chunk);
82 | if (!match) {
83 | return 0;
84 | }
85 | this.token(name, match[1]);
86 | return match[1].length;
87 | };
88 |
89 | Lexer.prototype.tokenizeFromList = function(name, list) {
90 | var entry, ret, _i, _len;
91 | ret = 0;
92 | for (_i = 0, _len = list.length; _i < _len; _i++) {
93 | entry = list[_i];
94 | ret = this.tokenizeFromWord(name, entry);
95 | if (ret > 0) {
96 | break;
97 | }
98 | }
99 | return ret;
100 | };
101 |
102 | Lexer.prototype.keywordToken = function() {
103 | return this.tokenizeFromWord('SELECT') || this.tokenizeFromWord('DISTINCT') || this.tokenizeFromWord('FROM') || this.tokenizeFromWord('WHERE') || this.tokenizeFromWord('GROUP') || this.tokenizeFromWord('ORDER') || this.tokenizeFromWord('BY') || this.tokenizeFromWord('HAVING') || this.tokenizeFromWord('LIMIT') || this.tokenizeFromWord('JOIN') || this.tokenizeFromWord('LEFT') || this.tokenizeFromWord('RIGHT') || this.tokenizeFromWord('INNER') || this.tokenizeFromWord('OUTER') || this.tokenizeFromWord('ON') || this.tokenizeFromWord('AS') || this.tokenizeFromWord('UNION') || this.tokenizeFromWord('ALL') || this.tokenizeFromWord('LIMIT') || this.tokenizeFromWord('OFFSET') || this.tokenizeFromWord('FETCH') || this.tokenizeFromWord('ROW') || this.tokenizeFromWord('ROWS') || this.tokenizeFromWord('ONLY') || this.tokenizeFromWord('NEXT') || this.tokenizeFromWord('FIRST');
104 | };
105 |
106 | Lexer.prototype.dotToken = function() {
107 | return this.tokenizeFromWord('DOT', '.');
108 | };
109 |
110 | Lexer.prototype.operatorToken = function() {
111 | return this.tokenizeFromList('OPERATOR', SQL_OPERATORS);
112 | };
113 |
114 | Lexer.prototype.mathToken = function() {
115 | return this.tokenizeFromList('MATH', MATH) || this.tokenizeFromList('MATH_MULTI', MATH_MULTI);
116 | };
117 |
118 | Lexer.prototype.conditionalToken = function() {
119 | return this.tokenizeFromList('CONDITIONAL', SQL_CONDITIONALS);
120 | };
121 |
122 | Lexer.prototype.betweenToken = function() {
123 | return this.tokenizeFromList('BETWEEN', SQL_BETWEENS);
124 | };
125 |
126 | Lexer.prototype.subSelectOpToken = function() {
127 | return this.tokenizeFromList('SUB_SELECT_OP', SUB_SELECT_OP);
128 | };
129 |
130 | Lexer.prototype.subSelectUnaryOpToken = function() {
131 | return this.tokenizeFromList('SUB_SELECT_UNARY_OP', SUB_SELECT_UNARY_OP);
132 | };
133 |
134 | Lexer.prototype.functionToken = function() {
135 | return this.tokenizeFromList('FUNCTION', SQL_FUNCTIONS);
136 | };
137 |
138 | Lexer.prototype.sortOrderToken = function() {
139 | return this.tokenizeFromList('DIRECTION', SQL_SORT_ORDERS);
140 | };
141 |
142 | Lexer.prototype.booleanToken = function() {
143 | return this.tokenizeFromList('BOOLEAN', BOOLEAN);
144 | };
145 |
146 | Lexer.prototype.starToken = function() {
147 | return this.tokenizeFromRegex('STAR', STAR);
148 | };
149 |
150 | Lexer.prototype.seperatorToken = function() {
151 | return this.tokenizeFromRegex('SEPARATOR', SEPARATOR);
152 | };
153 |
154 | Lexer.prototype.literalToken = function() {
155 | return this.tokenizeFromRegex('LITERAL', LITERAL, 1, 0);
156 | };
157 |
158 | Lexer.prototype.numberToken = function() {
159 | return this.tokenizeFromRegex('NUMBER', NUMBER);
160 | };
161 |
162 | Lexer.prototype.parameterToken = function() {
163 | return this.tokenizeFromRegex('PARAMETER', PARAMETER);
164 | };
165 |
166 | Lexer.prototype.stringToken = function() {
167 | return this.tokenizeFromRegex('STRING', STRING, 1, 0) || this.tokenizeFromRegex('DBLSTRING', DBLSTRING, 1, 0);
168 | };
169 |
170 | Lexer.prototype.parensToken = function() {
171 | return this.tokenizeFromRegex('LEFT_PAREN', /^\(/) || this.tokenizeFromRegex('RIGHT_PAREN', /^\)/);
172 | };
173 |
174 | Lexer.prototype.windowExtension = function() {
175 | var match;
176 | match = /^\.(win):(length|time)/i.exec(this.chunk);
177 | if (!match) {
178 | return 0;
179 | }
180 | this.token('WINDOW', match[1]);
181 | this.token('WINDOW_FUNCTION', match[2]);
182 | return match[0].length;
183 | };
184 |
185 | Lexer.prototype.whitespaceToken = function() {
186 | var match, newlines, partMatch;
187 | if (!(match = WHITESPACE.exec(this.chunk))) {
188 | return 0;
189 | }
190 | partMatch = match[0];
191 | newlines = partMatch.replace(/[^\n]/, '').length;
192 | this.currentLine += newlines;
193 | if (this.preserveWhitespace) {
194 | this.token(name, partMatch);
195 | }
196 | return partMatch.length;
197 | };
198 |
199 | Lexer.prototype.regexEscape = function(str) {
200 | return str.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
201 | };
202 |
203 | SQL_FUNCTIONS = ['AVG', 'COUNT', 'MIN', 'MAX', 'SUM'];
204 |
205 | SQL_SORT_ORDERS = ['ASC', 'DESC'];
206 |
207 | SQL_OPERATORS = ['=', '!=', '>=', '>', '<=', '<>', '<', 'LIKE', 'IS NOT', 'IS'];
208 |
209 | SUB_SELECT_OP = ['IN', 'NOT IN', 'ANY', 'ALL', 'SOME'];
210 |
211 | SUB_SELECT_UNARY_OP = ['EXISTS'];
212 |
213 | SQL_CONDITIONALS = ['AND', 'OR'];
214 |
215 | SQL_BETWEENS = ['BETWEEN', 'NOT BETWEEN'];
216 |
217 | BOOLEAN = ['TRUE', 'FALSE', 'NULL'];
218 |
219 | MATH = ['+', '-'];
220 |
221 | MATH_MULTI = ['/', '*'];
222 |
223 | STAR = /^\*/;
224 |
225 | SEPARATOR = /^,/;
226 |
227 | WHITESPACE = /^[ \n\r]+/;
228 |
229 | LITERAL = /^`?([a-z_][a-z0-9_]{0,})`?/i;
230 |
231 | PARAMETER = /^\$[0-9]+/;
232 |
233 | NUMBER = /^[0-9]+(\.[0-9]+)?/;
234 |
235 | STRING = /^'([^\\']*(?:\\.[^\\']*)*)'/;
236 |
237 | DBLSTRING = /^"([^\\"]*(?:\\.[^\\"]*)*)"/;
238 |
239 | return Lexer;
240 |
241 | })();
242 |
243 | exports.tokenize = function(sql, opts) {
244 | return (new Lexer(sql, opts)).tokens;
245 | };
246 |
247 | }).call(this);
248 |
--------------------------------------------------------------------------------
/lib/nodes.js:
--------------------------------------------------------------------------------
1 | // Generated by CoffeeScript 1.8.0
2 | (function() {
3 | var ArgumentListValue, BetweenOp, Field, FunctionValue, Group, Having, Join, Limit, ListValue, LiteralValue, Offset, Op, Order, OrderArgument, ParameterValue, Select, Star, StringValue, SubSelect, Table, UnaryOp, Union, Where, indent;
4 |
5 | indent = function(str) {
6 | var line;
7 | return ((function() {
8 | var _i, _len, _ref, _results;
9 | _ref = str.split("\n");
10 | _results = [];
11 | for (_i = 0, _len = _ref.length; _i < _len; _i++) {
12 | line = _ref[_i];
13 | _results.push(" " + line);
14 | }
15 | return _results;
16 | })()).join("\n");
17 | };
18 |
19 | exports.Select = Select = (function() {
20 | function Select(fields, source, distinct, joins, unions) {
21 | this.fields = fields;
22 | this.source = source;
23 | this.distinct = distinct != null ? distinct : false;
24 | this.joins = joins != null ? joins : [];
25 | this.unions = unions != null ? unions : [];
26 | this.order = null;
27 | this.group = null;
28 | this.where = null;
29 | this.limit = null;
30 | }
31 |
32 | Select.prototype.toString = function() {
33 | var join, ret, union, _i, _j, _len, _len1, _ref, _ref1;
34 | ret = ["SELECT " + (this.fields.join(', '))];
35 | ret.push(indent("FROM " + this.source));
36 | _ref = this.joins;
37 | for (_i = 0, _len = _ref.length; _i < _len; _i++) {
38 | join = _ref[_i];
39 | ret.push(indent(join.toString()));
40 | }
41 | if (this.where) {
42 | ret.push(indent(this.where.toString()));
43 | }
44 | if (this.group) {
45 | ret.push(indent(this.group.toString()));
46 | }
47 | if (this.order) {
48 | ret.push(indent(this.order.toString()));
49 | }
50 | if (this.limit) {
51 | ret.push(indent(this.limit.toString()));
52 | }
53 | _ref1 = this.unions;
54 | for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
55 | union = _ref1[_j];
56 | ret.push(union.toString());
57 | }
58 | return ret.join("\n");
59 | };
60 |
61 | return Select;
62 |
63 | })();
64 |
65 | exports.SubSelect = SubSelect = (function() {
66 | function SubSelect(select, name) {
67 | this.select = select;
68 | this.name = name != null ? name : null;
69 | null;
70 | }
71 |
72 | SubSelect.prototype.toString = function() {
73 | var ret;
74 | ret = [];
75 | ret.push('(');
76 | ret.push(indent(this.select.toString()));
77 | ret.push(this.name ? ") " + (this.name.toString()) : ")");
78 | return ret.join("\n");
79 | };
80 |
81 | return SubSelect;
82 |
83 | })();
84 |
85 | exports.Join = Join = (function() {
86 | function Join(right, conditions, side, mode) {
87 | this.right = right;
88 | this.conditions = conditions != null ? conditions : null;
89 | this.side = side != null ? side : null;
90 | this.mode = mode != null ? mode : null;
91 | null;
92 | }
93 |
94 | Join.prototype.toString = function() {
95 | var ret;
96 | ret = '';
97 | if (this.side != null) {
98 | ret += "" + this.side + " ";
99 | }
100 | if (this.mode != null) {
101 | ret += "" + this.mode + " ";
102 | }
103 | return ret + ("JOIN " + this.right + "\n") + indent("ON " + this.conditions);
104 | };
105 |
106 | return Join;
107 |
108 | })();
109 |
110 | exports.Union = Union = (function() {
111 | function Union(query, all) {
112 | this.query = query;
113 | this.all = all != null ? all : false;
114 | null;
115 | }
116 |
117 | Union.prototype.toString = function() {
118 | var all;
119 | all = this.all ? ' ALL' : '';
120 | return "UNION" + all + "\n" + (this.query.toString());
121 | };
122 |
123 | return Union;
124 |
125 | })();
126 |
127 | exports.LiteralValue = LiteralValue = (function() {
128 | function LiteralValue(value, value2) {
129 | this.value = value;
130 | this.value2 = value2 != null ? value2 : null;
131 | if (this.value2) {
132 | this.nested = true;
133 | this.values = this.value.values;
134 | this.values.push(value2);
135 | } else {
136 | this.nested = false;
137 | this.values = [this.value];
138 | }
139 | }
140 |
141 | LiteralValue.prototype.toString = function() {
142 | return "`" + (this.values.join('.')) + "`";
143 | };
144 |
145 | return LiteralValue;
146 |
147 | })();
148 |
149 | exports.StringValue = StringValue = (function() {
150 | function StringValue(value, quoteType) {
151 | this.value = value;
152 | this.quoteType = quoteType != null ? quoteType : "''";
153 | null;
154 | }
155 |
156 | StringValue.prototype.toString = function() {
157 | return "" + this.quoteType + this.value + this.quoteType;
158 | };
159 |
160 | return StringValue;
161 |
162 | })();
163 |
164 | exports.NumberValue = LiteralValue = (function() {
165 | function LiteralValue(value) {
166 | this.value = Number(value);
167 | }
168 |
169 | LiteralValue.prototype.toString = function() {
170 | return this.value.toString();
171 | };
172 |
173 | return LiteralValue;
174 |
175 | })();
176 |
177 | exports.ListValue = ListValue = (function() {
178 | function ListValue(value) {
179 | this.value = value;
180 | }
181 |
182 | ListValue.prototype.toString = function() {
183 | return "(" + (this.value.join(', ')) + ")";
184 | };
185 |
186 | return ListValue;
187 |
188 | })();
189 |
190 | exports.ParameterValue = ParameterValue = (function() {
191 | function ParameterValue(value) {
192 | this.value = value;
193 | this.index = parseInt(value.substr(1), 10) - 1;
194 | }
195 |
196 | ParameterValue.prototype.toString = function() {
197 | return "" + this.value;
198 | };
199 |
200 | return ParameterValue;
201 |
202 | })();
203 |
204 | exports.ArgumentListValue = ArgumentListValue = (function() {
205 | function ArgumentListValue(value, distinct) {
206 | this.value = value;
207 | this.distinct = distinct != null ? distinct : false;
208 | null;
209 | }
210 |
211 | ArgumentListValue.prototype.toString = function() {
212 | if (this.distinct) {
213 | return "DISTINCT " + (this.value.join(', '));
214 | } else {
215 | return "" + (this.value.join(', '));
216 | }
217 | };
218 |
219 | return ArgumentListValue;
220 |
221 | })();
222 |
223 | exports.BooleanValue = LiteralValue = (function() {
224 | function LiteralValue(value) {
225 | this.value = (function() {
226 | switch (value.toLowerCase()) {
227 | case 'true':
228 | return true;
229 | case 'false':
230 | return false;
231 | default:
232 | return null;
233 | }
234 | })();
235 | }
236 |
237 | LiteralValue.prototype.toString = function() {
238 | if (this.value != null) {
239 | return this.value.toString().toUpperCase();
240 | } else {
241 | return 'NULL';
242 | }
243 | };
244 |
245 | return LiteralValue;
246 |
247 | })();
248 |
249 | exports.FunctionValue = FunctionValue = (function() {
250 | function FunctionValue(name, _arguments, udf) {
251 | this.name = name;
252 | this["arguments"] = _arguments != null ? _arguments : null;
253 | this.udf = udf != null ? udf : false;
254 | null;
255 | }
256 |
257 | FunctionValue.prototype.toString = function() {
258 | if (this["arguments"]) {
259 | return "" + (this.name.toUpperCase()) + "(" + (this["arguments"].toString()) + ")";
260 | } else {
261 | return "" + (this.name.toUpperCase()) + "()";
262 | }
263 | };
264 |
265 | return FunctionValue;
266 |
267 | })();
268 |
269 | exports.Order = Order = (function() {
270 | function Order(orderings, offset) {
271 | this.orderings = orderings;
272 | this.offset = offset;
273 | }
274 |
275 | Order.prototype.toString = function() {
276 | return ("ORDER BY " + (this.orderings.join(', '))) + (this.offset ? "\n" + this.offset.toString() : "");
277 | };
278 |
279 | return Order;
280 |
281 | })();
282 |
283 | exports.OrderArgument = OrderArgument = (function() {
284 | function OrderArgument(value, direction) {
285 | this.value = value;
286 | this.direction = direction != null ? direction : 'ASC';
287 | null;
288 | }
289 |
290 | OrderArgument.prototype.toString = function() {
291 | return "" + this.value + " " + this.direction;
292 | };
293 |
294 | return OrderArgument;
295 |
296 | })();
297 |
298 | exports.Offset = Offset = (function() {
299 | function Offset(row_count, limit) {
300 | this.row_count = row_count;
301 | this.limit = limit;
302 | null;
303 | }
304 |
305 | Offset.prototype.toString = function() {
306 | return ("OFFSET " + this.row_count + " ROWS") + (this.limit ? "\nFETCH NEXT " + this.limit + " ROWS ONLY" : "");
307 | };
308 |
309 | return Offset;
310 |
311 | })();
312 |
313 | exports.Limit = Limit = (function() {
314 | function Limit(value, offset) {
315 | this.value = value;
316 | this.offset = offset;
317 | null;
318 | }
319 |
320 | Limit.prototype.toString = function() {
321 | return ("LIMIT " + this.value) + (this.offset ? "\nOFFSET " + this.offset : "");
322 | };
323 |
324 | return Limit;
325 |
326 | })();
327 |
328 | exports.Table = Table = (function() {
329 | function Table(name, alias, win, winFn, winArg) {
330 | this.name = name;
331 | this.alias = alias != null ? alias : null;
332 | this.win = win != null ? win : null;
333 | this.winFn = winFn != null ? winFn : null;
334 | this.winArg = winArg != null ? winArg : null;
335 | null;
336 | }
337 |
338 | Table.prototype.toString = function() {
339 | if (this.win) {
340 | return "" + this.name + "." + this.win + ":" + this.winFn + "(" + this.winArg + ")";
341 | } else if (this.alias) {
342 | return "" + this.name + " AS " + this.alias;
343 | } else {
344 | return this.name.toString();
345 | }
346 | };
347 |
348 | return Table;
349 |
350 | })();
351 |
352 | exports.Group = Group = (function() {
353 | function Group(fields) {
354 | this.fields = fields;
355 | this.having = null;
356 | }
357 |
358 | Group.prototype.toString = function() {
359 | var ret;
360 | ret = ["GROUP BY " + (this.fields.join(', '))];
361 | if (this.having) {
362 | ret.push(this.having.toString());
363 | }
364 | return ret.join("\n");
365 | };
366 |
367 | return Group;
368 |
369 | })();
370 |
371 | exports.Where = Where = (function() {
372 | function Where(conditions) {
373 | this.conditions = conditions;
374 | null;
375 | }
376 |
377 | Where.prototype.toString = function() {
378 | return "WHERE " + this.conditions;
379 | };
380 |
381 | return Where;
382 |
383 | })();
384 |
385 | exports.Having = Having = (function() {
386 | function Having(conditions) {
387 | this.conditions = conditions;
388 | null;
389 | }
390 |
391 | Having.prototype.toString = function() {
392 | return "HAVING " + this.conditions;
393 | };
394 |
395 | return Having;
396 |
397 | })();
398 |
399 | exports.Op = Op = (function() {
400 | function Op(operation, left, right) {
401 | this.operation = operation;
402 | this.left = left;
403 | this.right = right;
404 | null;
405 | }
406 |
407 | Op.prototype.toString = function() {
408 | return "(" + this.left + " " + (this.operation.toUpperCase()) + " " + this.right + ")";
409 | };
410 |
411 | return Op;
412 |
413 | })();
414 |
415 | exports.UnaryOp = UnaryOp = (function() {
416 | function UnaryOp(operator, operand) {
417 | this.operator = operator;
418 | this.operand = operand;
419 | null;
420 | }
421 |
422 | UnaryOp.prototype.toString = function() {
423 | return "(" + (this.operator.toUpperCase()) + " " + this.operand + ")";
424 | };
425 |
426 | return UnaryOp;
427 |
428 | })();
429 |
430 | exports.BetweenOp = BetweenOp = (function() {
431 | function BetweenOp(value) {
432 | this.value = value;
433 | null;
434 | }
435 |
436 | BetweenOp.prototype.toString = function() {
437 | return "" + (this.value.join(' AND '));
438 | };
439 |
440 | return BetweenOp;
441 |
442 | })();
443 |
444 | exports.Field = Field = (function() {
445 | function Field(field, name) {
446 | this.field = field;
447 | this.name = name != null ? name : null;
448 | null;
449 | }
450 |
451 | Field.prototype.toString = function() {
452 | if (this.name) {
453 | return "" + this.field + " AS " + this.name;
454 | } else {
455 | return this.field.toString();
456 | }
457 | };
458 |
459 | return Field;
460 |
461 | })();
462 |
463 | exports.Star = Star = (function() {
464 | function Star() {
465 | null;
466 | }
467 |
468 | Star.prototype.toString = function() {
469 | return '*';
470 | };
471 |
472 | Star.prototype.star = true;
473 |
474 | return Star;
475 |
476 | })();
477 |
478 | }).call(this);
479 |
--------------------------------------------------------------------------------
/lib/parser.js:
--------------------------------------------------------------------------------
1 | // Generated by CoffeeScript 1.8.0
2 | (function() {
3 | var buildParser;
4 |
5 | buildParser = function() {
6 | var parser;
7 | parser = require('./compiled_parser').parser;
8 | parser.lexer = {
9 | lex: function() {
10 | var tag, _ref;
11 | _ref = this.tokens[this.pos++] || [''], tag = _ref[0], this.yytext = _ref[1], this.yylineno = _ref[2];
12 | return tag;
13 | },
14 | setInput: function(tokens) {
15 | this.tokens = tokens;
16 | return this.pos = 0;
17 | },
18 | upcomingInput: function() {
19 | return "";
20 | }
21 | };
22 | parser.yy = require('./nodes');
23 | return parser;
24 | };
25 |
26 | exports.parser = buildParser();
27 |
28 | exports.parse = function(str) {
29 | return buildParser().parse(str);
30 | };
31 |
32 | }).call(this);
33 |
--------------------------------------------------------------------------------
/lib/sql_parser.js:
--------------------------------------------------------------------------------
1 | // Generated by CoffeeScript 1.8.0
2 | (function() {
3 | exports.lexer = require('./lexer');
4 |
5 | exports.parser = require('./parser');
6 |
7 | exports.nodes = require('./nodes');
8 |
9 | exports.parse = function(sql) {
10 | return exports.parser.parse(exports.lexer.tokenize(sql));
11 | };
12 |
13 | }).call(this);
14 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "sql-parser",
3 | "description": "Lexer and Parser for SQL Syntax",
4 | "version": "0.5.0",
5 | "scripts": {
6 | "test": "./node_modules/.bin/cake build && ./node_modules/.bin/mocha --require should --compilers coffee:coffee-script/register"
7 | },
8 | "author": {
9 | "name": "Andy Kent",
10 | "email": "andy@forward.co.uk"
11 | },
12 | "directories": {
13 | "lib" : "./lib"
14 | },
15 | "dependencies": {
16 | },
17 | "devDependencies": {
18 | "jison": "0.4.15",
19 | "coffee-script": "1.8.0",
20 | "mocha" : "2.0.1",
21 | "should" : "4.1.0"
22 | },
23 | "engines": [
24 | "node"
25 | ],
26 | "repository": {
27 | "type": "git",
28 | "url": "http://github.com/forward/sql-parser.git"
29 | }
30 | }
--------------------------------------------------------------------------------
/src/grammar.coffee:
--------------------------------------------------------------------------------
1 | {Parser} = require 'jison'
2 |
3 | unwrap = /^function\s*\(\)\s*\{\s*return\s*([\s\S]*);\s*\}/
4 |
5 | o = (patternString, action, options) ->
6 | patternString = patternString.replace /\s{2,}/g, ' '
7 | return [patternString, '$$ = $1;', options] unless action
8 | action = if match = unwrap.exec action then match[1] else "(#{action}())"
9 | action = action.replace /\bnew /g, '$&yy.'
10 | [patternString, "$$ = #{action};", options]
11 |
12 | grammar =
13 |
14 | Root: [
15 | o 'Query EOF'
16 | ]
17 |
18 | Query: [
19 | o "SelectQuery"
20 | o "SelectQuery Unions", -> $1.unions = $2; $1
21 | ]
22 |
23 | SelectQuery: [
24 | o "SelectWithLimitQuery"
25 | o "BasicSelectQuery"
26 | ]
27 |
28 | BasicSelectQuery: [
29 | o 'Select'
30 | o 'Select OrderClause', -> $1.order = $2; $1
31 | o 'Select GroupClause', -> $1.group = $2; $1
32 | o 'Select GroupClause OrderClause', -> $1.group = $2; $1.order = $3; $1
33 | ]
34 |
35 | SelectWithLimitQuery: [
36 | o 'SelectQuery LimitClause', -> $1.limit = $2; $1
37 | ]
38 |
39 | Select: [
40 | o 'SelectClause'
41 | o 'SelectClause WhereClause', -> $1.where = $2; $1
42 | ]
43 |
44 | SelectClause: [
45 | o 'SELECT Fields FROM Table', -> new Select($2, $4, false)
46 | o 'SELECT DISTINCT Fields FROM Table', -> new Select($3, $5, true)
47 | o 'SELECT Fields FROM Table Joins', -> new Select($2, $4, false, $5)
48 | o 'SELECT DISTINCT Fields FROM Table Joins', -> new Select($3, $5, true, $6)
49 | ]
50 |
51 | Table: [
52 | o 'Literal', -> new Table($1)
53 | o 'Literal Literal', -> new Table($1, $2)
54 | o 'Literal AS Literal', -> new Table($1, $3)
55 | o 'LEFT_PAREN List RIGHT_PAREN', -> $2
56 | o 'LEFT_PAREN Query RIGHT_PAREN', -> new SubSelect($2)
57 | o 'LEFT_PAREN Query RIGHT_PAREN Literal', -> new SubSelect($2, $4)
58 | o 'Literal WINDOW WINDOW_FUNCTION LEFT_PAREN Number RIGHT_PAREN',
59 | -> new Table($1, null, $2, $3, $5)
60 | ]
61 |
62 | Unions: [
63 | o 'Union', -> [$1]
64 | o 'Unions Union', -> $1.concat($3)
65 | ]
66 |
67 | Union: [
68 | o 'UNION SelectQuery', -> new Union($2)
69 | o 'UNION ALL SelectQuery', -> new Union($3, true)
70 | ]
71 |
72 | Joins: [
73 | o 'Join', -> [$1]
74 | o 'Joins Join', -> $1.concat($2)
75 | ]
76 |
77 | Join: [
78 | o 'JOIN Table ON Expression', -> new Join($2, $4)
79 | o 'LEFT JOIN Table ON Expression', -> new Join($3, $5, 'LEFT')
80 | o 'RIGHT JOIN Table ON Expression', -> new Join($3, $5, 'RIGHT')
81 | o 'LEFT INNER JOIN Table ON Expression', -> new Join($4, $6, 'LEFT', 'INNER')
82 | o 'RIGHT INNER JOIN Table ON Expression', -> new Join($4, $6, 'RIGHT', 'INNER')
83 | o 'LEFT OUTER JOIN Table ON Expression', -> new Join($4, $6, 'LEFT', 'OUTER')
84 | o 'RIGHT OUTER JOIN Table ON Expression', -> new Join($4, $6, 'RIGHT', 'OUTER')
85 | ]
86 |
87 | WhereClause: [
88 | o 'WHERE Expression', -> new Where($2)
89 | ]
90 |
91 | LimitClause: [
92 | o 'LIMIT Number', -> new Limit($2)
93 | o 'LIMIT Number SEPARATOR Number', -> new Limit($4, $2)
94 | o 'LIMIT Number OFFSET Number', -> new Limit($2, $4)
95 | ]
96 |
97 | OrderClause: [
98 | o 'ORDER BY OrderArgs', -> new Order($3)
99 | o 'ORDER BY OrderArgs OffsetClause', -> new Order($3, $4)
100 | ]
101 |
102 | OrderArgs: [
103 | o 'OrderArg', -> [$1]
104 | o 'OrderArgs SEPARATOR OrderArg', -> $1.concat($3)
105 | ]
106 |
107 | OrderArg: [
108 | o 'Value', -> new OrderArgument($1, 'ASC')
109 | o 'Value DIRECTION', -> new OrderArgument($1, $2)
110 | ]
111 |
112 | OffsetClause: [
113 | # MS SQL Server 2012+
114 | o 'OFFSET OffsetRows', -> new Offset($2)
115 | o 'OFFSET OffsetRows FetchClause', -> new Offset($2, $3)
116 | ]
117 |
118 | OffsetRows: [
119 | o 'Number ROW', -> $1
120 | o 'Number ROWS', -> $1
121 | ]
122 |
123 | FetchClause: [
124 | o 'FETCH FIRST OffsetRows ONLY', -> $3
125 | o 'FETCH NEXT OffsetRows ONLY', -> $3
126 | ]
127 |
128 | GroupClause: [
129 | o 'GroupBasicClause'
130 | o 'GroupBasicClause HavingClause', -> $1.having = $2; $1
131 | ]
132 |
133 | GroupBasicClause: [
134 | o 'GROUP BY ArgumentList', -> new Group($3)
135 | ]
136 |
137 | HavingClause: [
138 | o 'HAVING Expression', -> new Having($2)
139 | ]
140 |
141 |
142 | Expression: [
143 | o 'LEFT_PAREN Expression RIGHT_PAREN', -> $2
144 | o 'Expression MATH Expression', -> new Op($2, $1, $3)
145 | o 'Expression MATH_MULTI Expression', -> new Op($2, $1, $3)
146 | o 'Expression OPERATOR Expression', -> new Op($2, $1, $3)
147 | o 'Expression BETWEEN BetweenExpression', -> new Op($2, $1, $3)
148 | o 'Expression CONDITIONAL Expression', -> new Op($2, $1, $3)
149 | o 'Value SUB_SELECT_OP LEFT_PAREN List RIGHT_PAREN', -> new Op($2, $1, $4)
150 | o 'Value SUB_SELECT_OP SubSelectExpression', -> new Op($2, $1, $3)
151 | o 'SUB_SELECT_UNARY_OP SubSelectExpression', -> new UnaryOp($1, $2)
152 | o 'SubSelectExpression'
153 | o 'Value'
154 | ]
155 |
156 | BetweenExpression: [
157 | o 'Expression CONDITIONAL Expression', -> new BetweenOp([$1, $3])
158 | ]
159 |
160 | SubSelectExpression: [
161 | o 'LEFT_PAREN Query RIGHT_PAREN', -> new SubSelect($2)
162 | ]
163 |
164 | Value: [
165 | o 'Literal'
166 | o 'Number'
167 | o 'String'
168 | o 'Function'
169 | o 'UserFunction'
170 | o 'Boolean'
171 | o 'Parameter'
172 | ]
173 |
174 | List: [
175 | o 'ArgumentList', -> new ListValue($1)
176 | ]
177 |
178 | Number: [
179 | o 'NUMBER', -> new NumberValue($1)
180 | ]
181 |
182 | Boolean: [
183 | o 'BOOLEAN', -> new BooleanValue($1)
184 | ]
185 |
186 | Parameter: [
187 | o 'PARAMETER', -> new ParameterValue($1)
188 | ]
189 |
190 | String: [
191 | o 'STRING', -> new StringValue($1, "'")
192 | o 'DBLSTRING', -> new StringValue($1, '"')
193 | ]
194 |
195 | Literal: [
196 | o 'LITERAL', -> new LiteralValue($1)
197 | o 'Literal DOT LITERAL', -> new LiteralValue($1, $3)
198 | ]
199 |
200 | Function: [
201 | o "FUNCTION LEFT_PAREN AggregateArgumentList RIGHT_PAREN", -> new FunctionValue($1, $3)
202 | ]
203 |
204 | UserFunction: [
205 | o "LITERAL LEFT_PAREN RIGHT_PAREN", -> new FunctionValue($1, null, true)
206 | o "LITERAL LEFT_PAREN AggregateArgumentList RIGHT_PAREN", -> new FunctionValue($1, $3, true)
207 | ]
208 |
209 | AggregateArgumentList: [
210 | o 'ArgumentList', -> new ArgumentListValue($1)
211 | o 'DISTINCT ArgumentList', -> new ArgumentListValue($2, true)
212 | ]
213 |
214 | ArgumentList: [
215 | o 'Expression', -> [$1]
216 | o 'ArgumentList SEPARATOR Value', -> $1.concat($3)
217 | ]
218 |
219 | Fields: [
220 | o 'Field', -> [$1]
221 | o 'Fields SEPARATOR Field', -> $1.concat($3)
222 | ]
223 |
224 | Field: [
225 | o 'STAR', -> new Star()
226 | o 'Expression', -> new Field($1)
227 | o 'Expression AS Literal', -> new Field($1, $3)
228 | ]
229 |
230 | tokens = []
231 | operators = [
232 | ['left', 'Op']
233 | ['left', 'MATH_MULTI']
234 | ['left', 'MATH']
235 | ['left', 'OPERATOR']
236 | ['left', 'CONDITIONAL']
237 | ]
238 |
239 | for name, alternatives of grammar
240 | grammar[name] = for alt in alternatives
241 | for token in alt[0].split ' '
242 | tokens.push token unless grammar[token]
243 | alt[1] = "return #{alt[1]}" if name is 'Root'
244 | alt
245 |
246 | exports.parser = new Parser
247 | tokens : tokens.join ' '
248 | bnf : grammar
249 | operators : operators.reverse()
250 | startSymbol : 'Root'
251 |
--------------------------------------------------------------------------------
/src/lexer.coffee:
--------------------------------------------------------------------------------
1 | class Lexer
2 | constructor: (sql, opts={}) ->
3 | @sql = sql
4 | @preserveWhitespace = opts.preserveWhitespace || false
5 | @tokens = []
6 | @currentLine = 1
7 | i = 0
8 | while @chunk = sql.slice(i)
9 | bytesConsumed = @keywordToken() or
10 | @starToken() or
11 | @booleanToken() or
12 | @functionToken() or
13 | @windowExtension() or
14 | @sortOrderToken() or
15 | @seperatorToken() or
16 | @operatorToken() or
17 | @mathToken() or
18 | @dotToken() or
19 | @conditionalToken() or
20 | @betweenToken() or
21 | @subSelectOpToken() or
22 | @subSelectUnaryOpToken() or
23 | @numberToken() or
24 | @stringToken() or
25 | @parameterToken() or
26 | @parensToken() or
27 | @whitespaceToken() or
28 | @literalToken()
29 | throw new Error("NOTHING CONSUMED: Stopped at - '#{@chunk.slice(0,30)}'") if bytesConsumed < 1
30 | i += bytesConsumed
31 | @token('EOF', '')
32 | @postProcess()
33 |
34 | postProcess: ->
35 | for token, i in @tokens
36 | if token[0] is 'STAR'
37 | next_token = @tokens[i+1]
38 | unless next_token[0] is 'SEPARATOR' or next_token[0] is 'FROM'
39 | token[0] = 'MATH_MULTI'
40 |
41 | token: (name, value) ->
42 | @tokens.push([name, value, @currentLine])
43 |
44 | tokenizeFromRegex: (name, regex, part=0, lengthPart=part, output=true) ->
45 | return 0 unless match = regex.exec(@chunk)
46 | partMatch = match[part]
47 | @token(name, partMatch) if output
48 | return match[lengthPart].length
49 |
50 | tokenizeFromWord: (name, word=name) ->
51 | word = @regexEscape(word)
52 | matcher = if (/^\w+$/).test(word)
53 | new RegExp("^(#{word})\\b",'ig')
54 | else
55 | new RegExp("^(#{word})",'ig')
56 | match = matcher.exec(@chunk)
57 | return 0 unless match
58 | @token(name, match[1])
59 | return match[1].length
60 |
61 | tokenizeFromList: (name, list) ->
62 | ret = 0
63 | for entry in list
64 | ret = @tokenizeFromWord(name, entry)
65 | break if ret > 0
66 | ret
67 |
68 | keywordToken: ->
69 | @tokenizeFromWord('SELECT') or
70 | @tokenizeFromWord('DISTINCT') or
71 | @tokenizeFromWord('FROM') or
72 | @tokenizeFromWord('WHERE') or
73 | @tokenizeFromWord('GROUP') or
74 | @tokenizeFromWord('ORDER') or
75 | @tokenizeFromWord('BY') or
76 | @tokenizeFromWord('HAVING') or
77 | @tokenizeFromWord('LIMIT') or
78 | @tokenizeFromWord('JOIN') or
79 | @tokenizeFromWord('LEFT') or
80 | @tokenizeFromWord('RIGHT') or
81 | @tokenizeFromWord('INNER') or
82 | @tokenizeFromWord('OUTER') or
83 | @tokenizeFromWord('ON') or
84 | @tokenizeFromWord('AS') or
85 | @tokenizeFromWord('UNION') or
86 | @tokenizeFromWord('ALL') or
87 | @tokenizeFromWord('LIMIT') or
88 | @tokenizeFromWord('OFFSET') or
89 | @tokenizeFromWord('FETCH') or
90 | @tokenizeFromWord('ROW') or
91 | @tokenizeFromWord('ROWS') or
92 | @tokenizeFromWord('ONLY') or
93 | @tokenizeFromWord('NEXT') or
94 | @tokenizeFromWord('FIRST')
95 |
96 | dotToken: -> @tokenizeFromWord('DOT', '.')
97 | operatorToken: -> @tokenizeFromList('OPERATOR', SQL_OPERATORS)
98 | mathToken: ->
99 | @tokenizeFromList('MATH', MATH) or
100 | @tokenizeFromList('MATH_MULTI', MATH_MULTI)
101 | conditionalToken: -> @tokenizeFromList('CONDITIONAL', SQL_CONDITIONALS)
102 | betweenToken: -> @tokenizeFromList('BETWEEN', SQL_BETWEENS)
103 | subSelectOpToken: -> @tokenizeFromList('SUB_SELECT_OP', SUB_SELECT_OP)
104 | subSelectUnaryOpToken: -> @tokenizeFromList('SUB_SELECT_UNARY_OP', SUB_SELECT_UNARY_OP)
105 | functionToken: -> @tokenizeFromList('FUNCTION', SQL_FUNCTIONS)
106 | sortOrderToken: -> @tokenizeFromList('DIRECTION', SQL_SORT_ORDERS)
107 | booleanToken: -> @tokenizeFromList('BOOLEAN', BOOLEAN)
108 |
109 | starToken: -> @tokenizeFromRegex('STAR', STAR)
110 | seperatorToken: -> @tokenizeFromRegex('SEPARATOR', SEPARATOR)
111 | literalToken: -> @tokenizeFromRegex('LITERAL', LITERAL, 1, 0)
112 | numberToken: -> @tokenizeFromRegex('NUMBER', NUMBER)
113 | parameterToken: -> @tokenizeFromRegex('PARAMETER', PARAMETER)
114 | stringToken: ->
115 | @tokenizeFromRegex('STRING', STRING, 1, 0) ||
116 | @tokenizeFromRegex('DBLSTRING', DBLSTRING, 1, 0)
117 |
118 |
119 | parensToken: ->
120 | @tokenizeFromRegex('LEFT_PAREN', /^\(/,) or
121 | @tokenizeFromRegex('RIGHT_PAREN', /^\)/,)
122 |
123 | windowExtension: ->
124 | match = (/^\.(win):(length|time)/i).exec(@chunk)
125 | return 0 unless match
126 | @token('WINDOW', match[1])
127 | @token('WINDOW_FUNCTION', match[2])
128 | match[0].length
129 |
130 | whitespaceToken: ->
131 | return 0 unless match = WHITESPACE.exec(@chunk)
132 | partMatch = match[0]
133 | newlines = partMatch.replace(/[^\n]/, '').length
134 | @currentLine += newlines
135 | @token(name, partMatch) if @preserveWhitespace
136 | return partMatch.length
137 |
138 | regexEscape: (str) ->
139 | str.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&")
140 |
141 | SQL_FUNCTIONS = ['AVG', 'COUNT', 'MIN', 'MAX', 'SUM']
142 | SQL_SORT_ORDERS = ['ASC', 'DESC']
143 | SQL_OPERATORS = ['=', '!=', '>=', '>', '<=', '<>', '<', 'LIKE', 'IS NOT', 'IS']
144 | SUB_SELECT_OP = ['IN', 'NOT IN', 'ANY', 'ALL', 'SOME']
145 | SUB_SELECT_UNARY_OP = ['EXISTS']
146 | SQL_CONDITIONALS = ['AND', 'OR']
147 | SQL_BETWEENS = ['BETWEEN', 'NOT BETWEEN']
148 | BOOLEAN = ['TRUE', 'FALSE', 'NULL']
149 | MATH = ['+', '-']
150 | MATH_MULTI = ['/', '*']
151 | STAR = /^\*/
152 | SEPARATOR = /^,/
153 | WHITESPACE = /^[ \n\r]+/
154 | LITERAL = /^`?([a-z_][a-z0-9_]{0,})`?/i
155 | PARAMETER = /^\$[0-9]+/
156 | NUMBER = /^[0-9]+(\.[0-9]+)?/
157 | STRING = /^'([^\\']*(?:\\.[^\\']*)*)'/
158 | DBLSTRING = /^"([^\\"]*(?:\\.[^\\"]*)*)"/
159 |
160 |
161 |
162 | exports.tokenize = (sql, opts) -> (new Lexer(sql, opts)).tokens
163 |
164 |
--------------------------------------------------------------------------------
/src/nodes.coffee:
--------------------------------------------------------------------------------
1 | indent = (str) ->
2 | (" #{line}" for line in str.split("\n")).join("\n")
3 |
4 | exports.Select = class Select
5 | constructor: (@fields, @source, @distinct=false, @joins=[], @unions=[]) ->
6 | @order = null
7 | @group = null
8 | @where = null
9 | @limit = null
10 | toString: ->
11 | ret = ["SELECT #{@fields.join(', ')}"]
12 | ret.push indent("FROM #{@source}")
13 | ret.push indent(join.toString()) for join in @joins
14 | ret.push indent(@where.toString()) if @where
15 | ret.push indent(@group.toString()) if @group
16 | ret.push indent(@order.toString()) if @order
17 | ret.push indent(@limit.toString()) if @limit
18 | ret.push union.toString() for union in @unions
19 | ret.join("\n")
20 |
21 | exports.SubSelect = class SubSelect
22 | constructor: (@select, @name=null) -> null
23 | toString: ->
24 | ret = []
25 | ret.push '('
26 | ret.push indent(@select.toString())
27 | ret.push if @name then ") #{@name.toString()}" else ")"
28 | ret.join("\n")
29 |
30 | exports.Join = class Join
31 | constructor: (@right, @conditions=null, @side=null, @mode=null) -> null
32 | toString: ->
33 | ret = ''
34 | ret += "#{@side} " if @side?
35 | ret += "#{@mode} " if @mode?
36 | ret + "JOIN #{@right}\n" + indent("ON #{@conditions}")
37 |
38 | exports.Union = class Union
39 | constructor: (@query, @all=false) -> null
40 | toString: ->
41 | all = if @all then ' ALL' else ''
42 | "UNION#{all}\n#{@query.toString()}"
43 |
44 | exports.LiteralValue = class LiteralValue
45 | constructor: (@value, @value2=null) ->
46 | if @value2
47 | @nested = true
48 | @values = @value.values
49 | @values.push(value2)
50 | else
51 | @nested = false
52 | @values = [@value]
53 | # TODO: Backtick quotes only supports MySQL, Postgres uses double-quotes
54 | toString: -> "`#{@values.join('.')}`"
55 |
56 | exports.StringValue = class StringValue
57 | constructor: (@value, @quoteType="''") -> null
58 | toString: -> "#{@quoteType}#{@value}#{@quoteType}"
59 |
60 | exports.NumberValue = class LiteralValue
61 | constructor: (value) -> @value = Number(value)
62 | toString: -> @value.toString()
63 |
64 | exports.ListValue = class ListValue
65 | constructor: (value) -> @value = value
66 | toString: -> "(#{@value.join(', ')})"
67 |
68 | exports.ParameterValue = class ParameterValue
69 | constructor: (value) ->
70 | @value = value
71 | @index = parseInt(value.substr(1), 10) - 1
72 | toString: -> "#{@value}"
73 |
74 | exports.ArgumentListValue = class ArgumentListValue
75 | constructor: (@value, @distinct=false) -> null
76 | toString: ->
77 | if @distinct
78 | "DISTINCT #{@value.join(', ')}"
79 | else
80 | "#{@value.join(', ')}"
81 |
82 | exports.BooleanValue = class LiteralValue
83 | constructor: (value) ->
84 | @value = switch value.toLowerCase()
85 | when 'true'
86 | true
87 | when 'false'
88 | false
89 | else
90 | null
91 | toString: -> if @value? then @value.toString().toUpperCase() else 'NULL'
92 |
93 | exports.FunctionValue = class FunctionValue
94 | constructor: (@name, @arguments=null, @udf=false) -> null
95 | toString: ->
96 | if @arguments
97 | "#{@name.toUpperCase()}(#{@arguments.toString()})"
98 | else
99 | "#{@name.toUpperCase()}()"
100 |
101 | exports.Order = class Order
102 | constructor: (@orderings, @offset) ->
103 | toString: -> "ORDER BY #{@orderings.join(', ')}" +
104 | (if @offset then "\n" + @offset.toString() else "")
105 |
106 | exports.OrderArgument = class OrderArgument
107 | constructor: (@value, @direction='ASC') -> null
108 | toString: -> "#{@value} #{@direction}"
109 |
110 | exports.Offset = class Offset
111 | constructor: (@row_count, @limit) -> null
112 | toString: -> "OFFSET #{@row_count} ROWS" +
113 | (if @limit then "\nFETCH NEXT #{@limit} ROWS ONLY" else "")
114 |
115 | exports.Limit = class Limit
116 | constructor: (@value, @offset) -> null
117 | toString: -> "LIMIT #{@value}" + (if @offset then "\nOFFSET #{@offset}" else "")
118 |
119 | exports.Table = class Table
120 | constructor: (@name, @alias=null, @win=null, @winFn=null, @winArg=null) -> null
121 | toString: ->
122 | if @win
123 | "#{@name}.#{@win}:#{@winFn}(#{@winArg})"
124 | else if @alias
125 | "#{@name} AS #{@alias}"
126 | else
127 | @name.toString()
128 |
129 | exports.Group = class Group
130 | constructor: (@fields) ->
131 | @having = null
132 | toString: ->
133 | ret = ["GROUP BY #{@fields.join(', ')}"]
134 | ret.push @having.toString() if @having
135 | ret.join("\n")
136 |
137 | exports.Where = class Where
138 | constructor: (@conditions) -> null
139 | toString: -> "WHERE #{@conditions}"
140 |
141 | exports.Having = class Having
142 | constructor: (@conditions) -> null
143 | toString: -> "HAVING #{@conditions}"
144 |
145 | exports.Op = class Op
146 | constructor: (@operation, @left, @right) -> null
147 | toString: -> "(#{@left} #{@operation.toUpperCase()} #{@right})"
148 |
149 | exports.UnaryOp = class UnaryOp
150 | constructor: (@operator, @operand) -> null
151 | toString: -> "(#{@operator.toUpperCase()} #{@operand})"
152 |
153 | exports.BetweenOp = class BetweenOp
154 | constructor: (@value) -> null
155 | toString: -> "#{@value.join(' AND ')}"
156 |
157 | exports.Field = class Field
158 | constructor: (@field, @name=null) -> null
159 | toString: -> if @name then "#{@field} AS #{@name}" else @field.toString()
160 |
161 | exports.Star = class Star
162 | constructor: () -> null
163 | toString: -> '*'
164 | star: true
165 |
--------------------------------------------------------------------------------
/src/parser.coffee:
--------------------------------------------------------------------------------
1 | buildParser = ->
2 |
3 | parser = require('./compiled_parser').parser
4 |
5 | parser.lexer =
6 | lex: ->
7 | [tag, @yytext, @yylineno] = @tokens[@pos++] or ['']
8 | tag
9 | setInput: (@tokens) -> @pos = 0
10 | upcomingInput: -> ""
11 |
12 | parser.yy = require('./nodes')
13 |
14 | return parser
15 |
16 | exports.parser = buildParser()
17 |
18 | exports.parse = (str) -> buildParser().parse(str)
--------------------------------------------------------------------------------
/src/sql_parser.coffee:
--------------------------------------------------------------------------------
1 | exports.lexer = require('./lexer')
2 | exports.parser = require('./parser')
3 | exports.nodes = require('./nodes')
4 |
5 | exports.parse = (sql) -> exports.parser.parse(exports.lexer.tokenize(sql))
--------------------------------------------------------------------------------
/test/grammar.spec.coffee:
--------------------------------------------------------------------------------
1 | lexer = require('../lib/lexer')
2 | parser = require("../lib/parser")
3 |
4 | parse = (query) ->
5 | parser.parse(lexer.tokenize(query))
6 |
7 | describe "SQL Grammar", ->
8 | describe "SELECT Queries", ->
9 |
10 | it "parses ORDER BY clauses", ->
11 | parse("SELECT * FROM my_table ORDER BY x DESC").toString().should.eql """
12 | SELECT *
13 | FROM `my_table`
14 | ORDER BY `x` DESC
15 | """
16 |
17 | it "parses ORDER BY clauses with OFFSET n ROWS", ->
18 | parse("SELECT * FROM my_table ORDER BY x DESC OFFSET 10 ROWS").toString().should.eql """
19 | SELECT *
20 | FROM `my_table`
21 | ORDER BY `x` DESC
22 | OFFSET 10 ROWS
23 | """
24 |
25 | it "parses ORDER BY clauses with OFFSET n ROW", ->
26 | parse("SELECT * FROM my_table ORDER BY x DESC OFFSET 10 ROW").toString().should.eql """
27 | SELECT *
28 | FROM `my_table`
29 | ORDER BY `x` DESC
30 | OFFSET 10 ROWS
31 | """
32 |
33 | it "parses ORDER BY clauses with OFFSET n ROW FETCH FIRST n ONLY", ->
34 | parse("SELECT * FROM my_table ORDER BY x DESC OFFSET 10 ROW FETCH FIRST 15 ROW ONLY").toString().should.eql """
35 | SELECT *
36 | FROM `my_table`
37 | ORDER BY `x` DESC
38 | OFFSET 10 ROWS
39 | FETCH NEXT 15 ROWS ONLY
40 | """
41 |
42 | it "parses ORDER BY clauses with OFFSET n ROW FETCH NEXT n ONLY", ->
43 | parse("SELECT * FROM my_table ORDER BY x DESC OFFSET 10 ROW FETCH NEXT 15 ROWS ONLY").toString().should.eql """
44 | SELECT *
45 | FROM `my_table`
46 | ORDER BY `x` DESC
47 | OFFSET 10 ROWS
48 | FETCH NEXT 15 ROWS ONLY
49 | """
50 |
51 | it "parses GROUP BY clauses", ->
52 | parse("SELECT * FROM my_table GROUP BY x, y").toString().should.eql """
53 | SELECT *
54 | FROM `my_table`
55 | GROUP BY `x`, `y`
56 | """
57 |
58 | it "parses LIMIT clauses", ->
59 | parse("SELECT * FROM my_table LIMIT 10").toString().should.eql """
60 | SELECT *
61 | FROM `my_table`
62 | LIMIT 10
63 | """
64 |
65 | it "parses LIMIT clauses after ORDER BY", ->
66 | parse("SELECT * FROM my_table ORDER BY cat DESC LIMIT 10").toString().should.eql """
67 | SELECT *
68 | FROM `my_table`
69 | ORDER BY `cat` DESC
70 | LIMIT 10
71 | """
72 |
73 | it "parses LIMIT clauses with comma separated offset", ->
74 | parse("SELECT * FROM my_table LIMIT 30, 10").toString().should.eql """
75 | SELECT *
76 | FROM `my_table`
77 | LIMIT 10
78 | OFFSET 30
79 | """
80 |
81 | it "parses LIMIT clauses with OFFSET keyword", ->
82 | parse("SELECT * FROM my_table LIMIT 10 OFFSET 30").toString().should.eql """
83 | SELECT *
84 | FROM `my_table`
85 | LIMIT 10
86 | OFFSET 30
87 | """
88 |
89 | it "parses SELECTs with FUNCTIONs without arguments", ->
90 | parse("SELECT X(Y(Z())) FROM X").toString().should.eql """
91 | SELECT X(Y(Z()))
92 | FROM `X`
93 | """
94 |
95 | it "parses SELECTs with FUNCTIONs", ->
96 | parse("SELECT a, COUNT(1, b) FROM my_table LIMIT 10").toString().should.eql """
97 | SELECT `a`, COUNT(1, `b`)
98 | FROM `my_table`
99 | LIMIT 10
100 | """
101 |
102 | it "parses COUNT(DISTINCT field)", ->
103 | parse("select a, count(distinct b) FROM my_table limit 10").toString().should.eql """
104 | SELECT `a`, COUNT(DISTINCT `b`)
105 | FROM `my_table`
106 | LIMIT 10
107 | """
108 |
109 | it "parses WHERE clauses", ->
110 | parse("SELECT * FROM my_table WHERE x > 1 AND y = 'foo'").toString().should.eql """
111 | SELECT *
112 | FROM `my_table`
113 | WHERE ((`x` > 1) AND (`y` = 'foo'))
114 | """
115 |
116 | it "parses complex WHERE clauses", ->
117 | parse("SELECT * FROM my_table WHERE a > 10 AND (a < 30 OR b = 'c')").toString().should.eql """
118 | SELECT *
119 | FROM `my_table`
120 | WHERE ((`a` > 10) AND ((`a` < 30) OR (`b` = 'c')))
121 | """
122 |
123 | it "parses WHERE clauses with BETWEEN operator", ->
124 | parse("SELECT * FROM my_table WHERE a > 10 AND b BETWEEN 4 AND 6 AND c = 4").toString().should.eql """
125 | SELECT *
126 | FROM `my_table`
127 | WHERE (((`a` > 10) AND (`b` BETWEEN 4 AND 6)) AND (`c` = 4))
128 | """
129 |
130 | it "parses WHERE with ORDER BY clauses", ->
131 | parse("SELECT * FROM my_table WHERE x > 1 ORDER BY y").toString().should.eql """
132 | SELECT *
133 | FROM `my_table`
134 | WHERE (`x` > 1)
135 | ORDER BY `y` ASC
136 | """
137 |
138 | it "parses WHERE with multiple ORDER BY clauses", ->
139 | parse("SELECT * FROM my_table WHERE x > 1 ORDER BY x, y DESC").toString().should.eql """
140 | SELECT *
141 | FROM `my_table`
142 | WHERE (`x` > 1)
143 | ORDER BY `x` ASC, `y` DESC
144 | """
145 |
146 | it "parses WHERE with ORDER BY clauses with direction", ->
147 | parse("SELECT * FROM my_table WHERE x > 1 ORDER BY y ASC").toString().should.eql """
148 | SELECT *
149 | FROM `my_table`
150 | WHERE (`x` > 1)
151 | ORDER BY `y` ASC
152 | """
153 |
154 | it "parses WHERE with GROUP BY clauses", ->
155 | parse("SELECT * FROM my_table WHERE x > 1 GROUP BY x, y").toString().should.eql """
156 | SELECT *
157 | FROM `my_table`
158 | WHERE (`x` > 1)
159 | GROUP BY `x`, `y`
160 | """
161 |
162 | it "parses WHERE with GROUP BY and ORDER BY clauses", ->
163 | parse("SELECT * FROM my_table WHERE x > 1 GROUP BY x, y ORDER BY COUNT(y) ASC").toString().should.eql """
164 | SELECT *
165 | FROM `my_table`
166 | WHERE (`x` > 1)
167 | GROUP BY `x`, `y`
168 | ORDER BY COUNT(`y`) ASC
169 | """
170 |
171 | it "parses GROUP BY and HAVING clauses", ->
172 | parse("SELECT * FROM my_table GROUP BY x, y HAVING COUNT(`y`) > 1").toString().should.eql """
173 | SELECT *
174 | FROM `my_table`
175 | GROUP BY `x`, `y`
176 | HAVING (COUNT(`y`) > 1)
177 | """
178 |
179 | it "parses UDFs", ->
180 | parse("SELECT LENGTH(a) FROM my_table").toString().should.eql """
181 | SELECT LENGTH(`a`)
182 | FROM `my_table`
183 | """
184 |
185 | it "parses expressions in place of fields", ->
186 | parse("SELECT f+LENGTH(f)/3 AS f1 FROM my_table").toString().should.eql """
187 | SELECT (`f` + (LENGTH(`f`) / 3)) AS `f1`
188 | FROM `my_table`
189 | """
190 |
191 | it "supports booleans", ->
192 | parse("SELECT null FROM my_table WHERE a = true").toString().should.eql """
193 | SELECT NULL
194 | FROM `my_table`
195 | WHERE (`a` = TRUE)
196 | """
197 |
198 | it "supports IS and IS NOT", ->
199 | parse("SELECT * FROM my_table WHERE a IS NULL AND b IS NOT NULL").toString().should.eql """
200 | SELECT *
201 | FROM `my_table`
202 | WHERE ((`a` IS NULL) AND (`b` IS NOT NULL))
203 | """
204 |
205 | it "supports nested expressions", ->
206 | parse("SELECT * FROM my_table WHERE MOD(LENGTH(a) + LENGTH(b), c)").toString().should.eql """
207 | SELECT *
208 | FROM `my_table`
209 | WHERE MOD((LENGTH(`a`) + LENGTH(`b`)), `c`)
210 | """
211 |
212 | it "supports nested fields using dot syntax", ->
213 | parse("SELECT a.b.c FROM my_table WHERE a.b > 2").toString().should.eql """
214 | SELECT `a.b.c`
215 | FROM `my_table`
216 | WHERE (`a.b` > 2)
217 | """
218 |
219 | it "supports time window extensions", ->
220 | parse("SELECT * FROM my_table.win:length(123)").toString().should.eql """
221 | SELECT *
222 | FROM `my_table`.win:length(123)
223 | """
224 |
225 | it "parses sub selects", ->
226 | parse("select * from (select * from my_table)").toString().should.eql """
227 | SELECT *
228 | FROM (
229 | SELECT *
230 | FROM `my_table`
231 | )
232 | """
233 |
234 | it "parses named sub selects", ->
235 | parse("select * from (select * from my_table) t").toString().should.eql """
236 | SELECT *
237 | FROM (
238 | SELECT *
239 | FROM `my_table`
240 | ) `t`
241 | """
242 |
243 | it "parses single joins", ->
244 | parse("select * from a join b on a.id = b.id").toString().should.eql """
245 | SELECT *
246 | FROM `a`
247 | JOIN `b`
248 | ON (`a.id` = `b.id`)
249 | """
250 |
251 | it "parses right outer joins", ->
252 | parse("select * from a right outer join b on a.id = b.id").toString().should.eql """
253 | SELECT *
254 | FROM `a`
255 | RIGHT OUTER JOIN `b`
256 | ON (`a.id` = `b.id`)
257 | """
258 |
259 | it "parses multiple joins", ->
260 | parse("select * from a join b on a.id = b.id join c on a.id = c.id").toString().should.eql """
261 | SELECT *
262 | FROM `a`
263 | JOIN `b`
264 | ON (`a.id` = `b.id`)
265 | JOIN `c`
266 | ON (`a.id` = `c.id`)
267 | """
268 |
269 | it "parses UNIONs", ->
270 | parse("select * from a union select * from b").toString().should.eql """
271 | SELECT *
272 | FROM `a`
273 | UNION
274 | SELECT *
275 | FROM `b`
276 | """
277 |
278 | it "parses UNION ALL", ->
279 | parse("select * from a union all select * from b").toString().should.eql """
280 | SELECT *
281 | FROM `a`
282 | UNION ALL
283 | SELECT *
284 | FROM `b`
285 | """
286 |
287 | describe "string quoting", ->
288 | it "doesn't choke on escaped quotes", ->
289 | parse("select * from a where foo = 'I\\'m'").toString().should.eql """
290 | SELECT *
291 | FROM `a`
292 | WHERE (`foo` = 'I\\'m')
293 | """
294 |
295 | it "allows using double quotes", ->
296 | parse('select * from a where foo = "a"').toString().should.eql """
297 | SELECT *
298 | FROM `a`
299 | WHERE (`foo` = "a")
300 | """
301 |
302 | it "allows nesting different quote styles", ->
303 | parse("""select * from a where foo = "I'm" """).toString().should.eql """
304 | SELECT *
305 | FROM `a`
306 | WHERE (`foo` = "I'm")
307 | """
308 |
309 | describe "subselect clauses", ->
310 | it "parses a subselect field", ->
311 | parse("""select (select x from y) from a""").toString().should.eql """
312 | SELECT (
313 | SELECT `x`
314 | FROM `y`
315 | )
316 | FROM `a`
317 | """
318 |
319 | it "parses an IN clause containing a list", ->
320 | parse("""select * from a where x in (1,2,3)""").toString().should.eql """
321 | SELECT *
322 | FROM `a`
323 | WHERE (`x` IN (1, 2, 3))
324 | """
325 |
326 | it "parses an IN clause containing a query", ->
327 | parse("""select * from a where x in (select foo from bar)""").toString().should.eql """
328 | SELECT *
329 | FROM `a`
330 | WHERE (`x` IN (
331 | SELECT `foo`
332 | FROM `bar`
333 | ))
334 | """
335 |
336 | it "parses a NOT IN clause containing a query", ->
337 | parse("""select * from a where x not in (select foo from bar)""").toString().should.eql """
338 | SELECT *
339 | FROM `a`
340 | WHERE (`x` NOT IN (
341 | SELECT `foo`
342 | FROM `bar`
343 | ))
344 | """
345 |
346 | it "parses an EXISTS clause containing a query", ->
347 | parse("""select * from a where exists (select foo from bar)""").toString().should.eql """
348 | SELECT *
349 | FROM `a`
350 | WHERE (EXISTS (
351 | SELECT `foo`
352 | FROM `bar`
353 | ))
354 | """
355 |
356 | describe "aliases", ->
357 | it "parses aliased table names", ->
358 | parse("""select * from a b""").toString().should.eql """
359 | SELECT *
360 | FROM `a` AS `b`
361 | """
362 |
363 | it "parses aliased table names with as", ->
364 | parse("""select * from a as b""").toString().should.eql """
365 | SELECT *
366 | FROM `a` AS `b`
367 | """
368 |
369 | describe "STARS", ->
370 | it "parses stars as multiplication", ->
371 | parse('SELECT * FROM foo WHERE a = 1*2').toString().should.eql """
372 | SELECT *
373 | FROM `foo`
374 | WHERE (`a` = (1 * 2))
375 | """
376 |
377 | describe "Parameters", ->
378 | it "parses query parameters", ->
379 | parse('select * from foo where bar = $12').toString().should.eql """
380 | SELECT *
381 | FROM `foo`
382 | WHERE (`bar` = $12)
383 | """
384 |
385 |
--------------------------------------------------------------------------------
/test/lexer.spec.coffee:
--------------------------------------------------------------------------------
1 | lexer = require('../lib/lexer')
2 |
3 | describe "SQL Lexer", ->
4 | it "eats select queries", ->
5 | tokens = lexer.tokenize("select * from my_table")
6 | tokens.should.eql [
7 | ["SELECT", "select", 1]
8 | ["STAR", "*", 1]
9 | ["FROM", "from", 1]
10 | ["LITERAL", "my_table", 1]
11 | ["EOF", "", 1]
12 | ]
13 |
14 | it "eats select queries with stars and multiplication", ->
15 | tokens = lexer.tokenize("select * from my_table where foo = 1 * 2")
16 | tokens.should.eql [
17 | ["SELECT", "select", 1]
18 | ["STAR", "*", 1]
19 | ["FROM", "from", 1]
20 | ["LITERAL", "my_table", 1]
21 | ["WHERE", "where", 1]
22 | ["LITERAL", "foo", 1]
23 | ["OPERATOR", "=", 1]
24 | ["NUMBER", "1", 1]
25 | ["MATH_MULTI", "*", 1]
26 | ["NUMBER", "2", 1]
27 | ["EOF", "", 1]
28 | ]
29 |
30 |
31 | it "eats sub selects", ->
32 | tokens = lexer.tokenize("select * from (select * from my_table) t")
33 | tokens.should.eql [
34 | ["SELECT", "select", 1]
35 | ["STAR", "*", 1]
36 | ["FROM", "from", 1]
37 | [ 'LEFT_PAREN', '(', 1 ]
38 | [ 'SELECT', 'select', 1 ]
39 | [ 'STAR', '*', 1 ]
40 | [ 'FROM', 'from', 1 ]
41 | [ 'LITERAL', 'my_table', 1 ]
42 | [ 'RIGHT_PAREN', ')', 1 ]
43 | ["LITERAL", "t", 1]
44 | ["EOF", "", 1]
45 | ]
46 |
47 | it "eats joins", ->
48 | tokens = lexer.tokenize("select * from a join b on a.id = b.id")
49 | tokens.should.eql [
50 | ["SELECT", "select", 1]
51 | ["STAR", "*", 1]
52 | ["FROM", "from", 1]
53 | [ 'LITERAL', 'a', 1 ]
54 | [ 'JOIN', 'join', 1 ]
55 | [ 'LITERAL', 'b', 1 ]
56 | [ 'ON', 'on', 1 ]
57 | [ 'LITERAL', 'a', 1 ]
58 | [ 'DOT', '.', 1 ]
59 | [ 'LITERAL', 'id', 1 ]
60 | [ 'OPERATOR', '=', 1 ]
61 | [ 'LITERAL', 'b', 1 ]
62 | [ 'DOT', '.', 1 ]
63 | [ 'LITERAL', 'id', 1 ]
64 | ["EOF", "", 1]
65 | ]
66 |
--------------------------------------------------------------------------------