├── .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 | --------------------------------------------------------------------------------