Browse Source

HUE-6615 [editor] Fix comment related issues with the statement parser

Johan Ahlen 8 years ago
parent
commit
c9d8c70

+ 107 - 12
desktop/core/src/desktop/static/desktop/js/autocomplete/jison/sqlStatementsParser.jison

@@ -16,16 +16,40 @@
 
 %lex
 %options flex
+%x multiLineComment inLineComment singleQuote doubleQuote backTick
 %%
 
-\s                                                                    { /* skip whitespace */ }
-'--'.*                                                                { /* skip comments */ }
-[/][*][^*]*[*]+([^/*][^*]*[*]+)*[/]                                   { /* skip comments */ }
+'/*'                                                                  { this.begin("multiLineComment"); return 'PART_OF_STATEMENT'; }
+<multiLineComment>^(?![*][/])*                                        { return 'PART_OF_STATEMENT'; }
+<multiLineComment><<EOF>>                                             { this.popState(); return 'PART_OF_STATEMENT'; }
+<multiLineComment>'*/'                                                { this.popState(); return 'PART_OF_STATEMENT'; }
 
-<<EOF>>                                                               { return 'EOF'; }
-([^;"'`]|(["][^"]*["])|(['][^']*['])|([`][^`]*[`]))*[;]?              { return 'STATEMENT'; }
+'--'                                                                  { this.begin("inLineComment"); return 'PART_OF_STATEMENT'; }
+<inLineComment>[^\n]+                                                 { return 'PART_OF_STATEMENT'; }
+<inLineComment><<EOF>>                                                { this.popState(); return 'EOF'; }
+<inLineComment>[\n]                                                   { this.popState(); return 'PART_OF_STATEMENT'; }
+
+'"'                                                                   { this.begin("doubleQuote"); return 'PART_OF_STATEMENT'; }
+<doubleQuote>(?:\\["]|[^"])+                                          { return 'PART_OF_STATEMENT'; }
+<doubleQuote><<EOF>>                                                  { this.popState(); return 'EOF'; }
+<doubleQuote>'"'                                                      { this.popState(); return 'PART_OF_STATEMENT'; }
+
+'\''                                                                  { this.begin("singleQuote"); return 'PART_OF_STATEMENT'; }
+<singleQuote>(?:\\[']|[^'])+                                          { return 'PART_OF_STATEMENT'; }
+<singleQuote><<EOF>>                                                  { this.popState(); return 'EOF'; }
+<singleQuote>'\''                                                     { this.popState(); return 'PART_OF_STATEMENT'; }
+
+'`'                                                                   { this.begin("backTick"); return 'PART_OF_STATEMENT'; }
+<backTick>[^`]+                                                       { return 'PART_OF_STATEMENT'; }
+<backTick><<EOF>>                                                     { this.popState(); return 'PART_OF_STATEMENT'; }
+<backTick>'`'                                                         { this.popState(); return 'PART_OF_STATEMENT'; }
 
-.                                                                     { /* skip unknown chars */ }
+[^"\\;'`-]+                                                           { return 'PART_OF_STATEMENT'; }
+[-][^;-]                                                              { return 'PART_OF_STATEMENT'; }
+[/][^;*]                                                              { return 'PART_OF_STATEMENT'; }
+';'                                                                   { return ';'; }
+
+<<EOF>>                                                               { return 'EOF'; }
 
 /lex
 
@@ -34,20 +58,91 @@
 %%
 
 SqlStatementsParser
- : Statements EOF
+ : Statements 'EOF'
+   {
+     parser.removeTrailingWhiteSpace($1);
+     return $1;
+   }
+ | OneOrMoreSeparators Statements 'EOF'
+   {
+     parser.handleLeadingStatements($1, $2);
+     parser.removeTrailingWhiteSpace($2);
+     return $2;
+   }
+ | OneOrMoreSeparators Statements OneOrMoreSeparators 'EOF'
    {
+     parser.handleLeadingStatements($1, $2);
+     parser.handleTrailingStatements($2, $3);
+     parser.removeTrailingWhiteSpace($2);
+     return $2;
+   }
+ | Statements OneOrMoreSeparators 'EOF'
+   {
+     parser.handleTrailingStatements($1, $2);
+     parser.removeTrailingWhiteSpace($1);
      return $1;
    }
- | EOF
+ | OneOrMoreSeparators 'EOF'
+   {
+     var result = [];
+     parser.handleLeadingStatements($1, result);
+     return result;
+   }
+ | 'EOF'
    {
      return [];
    }
  ;
 
 Statements
- : 'STATEMENT'                                                        --> [{ type: 'statement', statement: $1, location: @1 }]
- | Statements 'STATEMENT'
+ : StatementParts                                                  -> [{ type: 'statement', statement: $1, location: @1 }]
+ | Statements OneOrMoreSeparators StatementParts
+   {
+     parser.handleTrailingStatements($1, $2);
+     $1.push({ type: 'statement', statement: $3, location: @3 });
+   }
+ ;
+
+StatementParts
+ : 'PART_OF_STATEMENT'
+ | StatementParts 'PART_OF_STATEMENT'                              -> $1 + $2;
+ ;
+
+OneOrMoreSeparators
+ : ';'                                                             -> [@1]
+ | OneOrMoreSeparators ';'
    {
-     $1.push({ type: 'statement', statement: $2, location: @2 });
+     $1.push(@2);
    }
- ;
+ ;
+
+%%
+
+parser.handleLeadingStatements = function (emptyStatements, result) {
+  for (var i = emptyStatements.length - 1; i >= 0; i--) {
+    result.unshift({ type: 'statement', statement: ';', location: emptyStatements[i] });
+  }
+}
+
+parser.handleTrailingStatements = function (result, emptyStatements) {
+  var lastStatement = result[result.length - 1];
+  lastStatement.statement += ';'
+  lastStatement.location = {
+    first_line: lastStatement.location.first_line,
+    first_column: lastStatement.location.first_column,
+    last_line: emptyStatements[0].last_line,
+    last_column: emptyStatements[0].last_column
+  }
+  if (emptyStatements.length > 1) {
+    for (var i = 1; i < emptyStatements.length; i++) {
+      result.push({ type: 'statement', statement: ';', location: emptyStatements[i] });
+    }
+  }
+}
+
+parser.removeTrailingWhiteSpace = function (result) {
+  var lastStatement = result[result.length - 1];
+  if (/^\s+$/.test(lastStatement.statement)) {
+    result.pop()
+  }
+}

+ 128 - 19
desktop/core/src/desktop/static/desktop/js/autocomplete/sqlStatementsParser.js

@@ -86,12 +86,12 @@
   }
 */
 var sqlStatementsParser = (function(){
-var o=function(k,v,o,l){for(o=o||{},l=k.length;l--;o[k[l]]=v);return o},$V0=[5,6];
+var o=function(k,v,o,l){for(o=o||{},l=k.length;l--;o[k[l]]=v);return o},$V0=[1,7],$V1=[1,6],$V2=[1,12],$V3=[5,9],$V4=[1,13],$V5=[5,8,9];
 var parser = {trace: function trace() { },
 yy: {},
-symbols_: {"error":2,"SqlStatementsParser":3,"Statements":4,"EOF":5,"STATEMENT":6,"$accept":0,"$end":1},
-terminals_: {2:"error",5:"EOF",6:"STATEMENT"},
-productions_: [0,[3,2],[3,1],[4,1],[4,2]],
+symbols_: {"error":2,"SqlStatementsParser":3,"Statements":4,"EOF":5,"OneOrMoreSeparators":6,"StatementParts":7,"PART_OF_STATEMENT":8,";":9,"$accept":0,"$end":1},
+terminals_: {2:"error",5:"EOF",8:"PART_OF_STATEMENT",9:";"},
+productions_: [0,[3,2],[3,3],[3,4],[3,3],[3,2],[3,1],[4,1],[4,3],[7,1],[7,2],[6,1],[6,2]],
 performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate /* action[1] */, $$ /* vstack */, _$ /* lstack */) {
 /* this == yyval */
 
@@ -99,26 +99,68 @@ var $0 = $$.length - 1;
 switch (yystate) {
 case 1:
 
+     parser.removeTrailingWhiteSpace($$[$0-1]);
      return $$[$0-1];
    
 break;
 case 2:
 
-     return [];
+     parser.handleLeadingStatements($$[$0-2], $$[$0-1]);
+     parser.removeTrailingWhiteSpace($$[$0-1]);
+     return $$[$0-1];
    
 break;
 case 3:
-this.$ = [{ type: 'statement', statement: $$[$0], location: _$[$0] }];
+
+     parser.handleLeadingStatements($$[$0-3], $$[$0-2]);
+     parser.handleTrailingStatements($$[$0-2], $$[$0-1]);
+     parser.removeTrailingWhiteSpace($$[$0-2]);
+     return $$[$0-2];
+   
 break;
 case 4:
 
-     $$[$0-1].push({ type: 'statement', statement: $$[$0], location: _$[$0] });
+     parser.handleTrailingStatements($$[$0-2], $$[$0-1]);
+     parser.removeTrailingWhiteSpace($$[$0-2]);
+     return $$[$0-2];
+   
+break;
+case 5:
+
+     var result = [];
+     parser.handleLeadingStatements($$[$0-1], result);
+     return result;
+   
+break;
+case 6:
+
+     return [];
+   
+break;
+case 7:
+this.$ = [{ type: 'statement', statement: $$[$0], location: _$[$0] }];
+break;
+case 8:
+
+     parser.handleTrailingStatements($$[$0-2], $$[$0-1]);
+     $$[$0-2].push({ type: 'statement', statement: $$[$0], location: _$[$0] });
+   
+break;
+case 10:
+this.$ = $$[$0-1] + $$[$0];;
+break;
+case 11:
+this.$ = [_$[$0]];
+break;
+case 12:
+
+     $$[$0-1].push(_$[$0]);
    
 break;
 }
 },
-table: [{3:1,4:2,5:[1,3],6:[1,4]},{1:[3]},{5:[1,5],6:[1,6]},{1:[2,2]},o($V0,[2,3]),{1:[2,1]},o($V0,[2,4])],
-defaultActions: {3:[2,2],5:[2,1]},
+table: [{3:1,4:2,5:[1,4],6:3,7:5,8:$V0,9:$V1},{1:[3]},{5:[1,8],6:9,9:$V1},{4:10,5:[1,11],7:5,8:$V0,9:$V2},{1:[2,6]},o($V3,[2,7],{8:$V4}),o($V5,[2,11]),o($V5,[2,9]),{1:[2,1]},{5:[1,14],7:15,8:$V0,9:$V2},{5:[1,16],6:17,9:$V1},{1:[2,5]},o($V5,[2,12]),o($V5,[2,10]),{1:[2,4]},o($V3,[2,8],{8:$V4}),{1:[2,2]},{5:[1,18],7:15,8:$V0,9:$V2},{1:[2,3]}],
+defaultActions: {4:[2,6],8:[2,1],11:[2,5],14:[2,4],16:[2,2],18:[2,3]},
 parseError: function parseError(str, hash) {
     if (hash.recoverable) {
         this.trace(str);
@@ -269,7 +311,36 @@ parse: function parse(input) {
     }
     return true;
 }};
-/* generated by jison-lex 0.3.4 */
+
+
+parser.handleLeadingStatements = function (emptyStatements, result) {
+  for (var i = emptyStatements.length - 1; i >= 0; i--) {
+    result.unshift({ type: 'statement', statement: ';', location: emptyStatements[i] });
+  }
+}
+
+parser.handleTrailingStatements = function (result, emptyStatements) {
+  var lastStatement = result[result.length - 1];
+  lastStatement.statement += ';'
+  lastStatement.location = {
+    first_line: lastStatement.location.first_line,
+    first_column: lastStatement.location.first_column,
+    last_line: emptyStatements[0].last_line,
+    last_column: emptyStatements[0].last_column
+  }
+  if (emptyStatements.length > 1) {
+    for (var i = 1; i < emptyStatements.length; i++) {
+      result.push({ type: 'statement', statement: ';', location: emptyStatements[i] });
+    }
+  }
+}
+
+parser.removeTrailingWhiteSpace = function (result) {
+  var lastStatement = result[result.length - 1];
+  if (/^\s+$/.test(lastStatement.statement)) {
+    result.pop()
+  }
+}/* generated by jison-lex 0.3.4 */
 var lexer = (function(){
 var lexer = ({
 
@@ -597,24 +668,62 @@ options: {"flex":true},
 performAction: function anonymous(yy,yy_,$avoiding_name_collisions,YY_START) {
 var YYSTATE=YY_START;
 switch($avoiding_name_collisions) {
-case 0: /* skip whitespace */ 
+case 0: this.begin("multiLineComment"); return 8; 
+break;
+case 1: return 8; 
+break;
+case 2: this.popState(); return 8; 
+break;
+case 3: this.popState(); return 8; 
+break;
+case 4: this.begin("inLineComment"); return 8; 
+break;
+case 5: return 8; 
+break;
+case 6: this.popState(); return 5; 
+break;
+case 7: this.popState(); return 8; 
+break;
+case 8: this.begin("doubleQuote"); return 8; 
+break;
+case 9: return 8; 
+break;
+case 10: this.popState(); return 5; 
+break;
+case 11: this.popState(); return 8; 
+break;
+case 12: this.begin("singleQuote"); return 8; 
+break;
+case 13: return 8; 
+break;
+case 14: this.popState(); return 5; 
+break;
+case 15: this.popState(); return 8; 
+break;
+case 16: this.begin("backTick"); return 8; 
+break;
+case 17: return 8; 
+break;
+case 18: this.popState(); return 8; 
+break;
+case 19: this.popState(); return 8; 
 break;
-case 1: /* skip comments */ 
+case 20: return 8; 
 break;
-case 2: /* skip comments */ 
+case 21: return 8; 
 break;
-case 3: return 5; 
+case 22: return 8; 
 break;
-case 4: return 6; 
+case 23: return 9; 
 break;
-case 5: /* skip unknown chars */ 
+case 24: return 5; 
 break;
-case 6:console.log(yy_.yytext);
+case 25:console.log(yy_.yytext);
 break;
 }
 },
-rules: [/^(?:\s)/,/^(?:--.*)/,/^(?:[\/][*][^*]*[*]+([^\/*][^*]*[*]+)*[\/])/,/^(?:$)/,/^(?:([^;"'`]|(["][^"]*["])|(['][^']*['])|([`][^`]*[`]))*[;]?)/,/^(?:.)/,/^(?:.)/],
-conditions: {"INITIAL":{"rules":[0,1,2,3,4,5,6],"inclusive":true}}
+rules: [/^(?:\/\*)/,/^(?:^(?![*][\/])*)/,/^(?:$)/,/^(?:\*\/)/,/^(?:--)/,/^(?:[^\n]+)/,/^(?:$)/,/^(?:[\n])/,/^(?:")/,/^(?:(?:\\["]|[^"])+)/,/^(?:$)/,/^(?:")/,/^(?:')/,/^(?:(?:\\[']|[^'])+)/,/^(?:$)/,/^(?:')/,/^(?:`)/,/^(?:[^`]+)/,/^(?:$)/,/^(?:`)/,/^(?:[^"\\;'`-]+)/,/^(?:[-][^;-])/,/^(?:[\/][^;*])/,/^(?:;)/,/^(?:$)/,/^(?:.)/],
+conditions: {"multiLineComment":{"rules":[1,2,3],"inclusive":false},"inLineComment":{"rules":[5,6,7],"inclusive":false},"singleQuote":{"rules":[13,14,15],"inclusive":false},"doubleQuote":{"rules":[9,10,11],"inclusive":false},"backTick":{"rules":[17,18,19],"inclusive":false},"INITIAL":{"rules":[0,4,8,12,16,20,21,22,23,24,25],"inclusive":true}}
 });
 return lexer;
 })();

+ 3 - 0
desktop/core/src/desktop/static/desktop/js/ko.hue-bindings.js

@@ -3475,6 +3475,9 @@
       var parseForStatements = function () {
         try {
           lastKnownStatements = sqlStatementsParser.parse(self.editor.getValue());
+          if (typeof hueDebug !== 'undefined' && hueDebug.logStatementLocations) {
+            console.log(lastKnownStatements);
+          }
         } catch (error) {
           console.warn('Could not parse statements!');
           console.warn(error);

+ 175 - 90
desktop/core/src/desktop/static/desktop/spec/autocomplete/sqlStatementsParserSpec.js

@@ -16,105 +16,190 @@
 (function () {
   describe('sqlStatementsParser.js', function () {
 
-    var splitTests = [
-      {
-        id: 1,
-        statements: '',
-        expectedResult: []
-      }, {
-        id: 2,
-        statements: 'select * from bla',
-        expectedResult: [
-          { type: 'statement', statement: 'select * from bla', location: { first_line: 1, last_line: 1, first_column: 0,  last_column: 17 } }
-        ]
-      }, {
-        id: 3,
-        statements: 'select * from bla;',
-        expectedResult: [
-          { type: 'statement', statement: 'select * from bla;', location: { first_line: 1, last_line: 1, first_column: 0,  last_column: 18 } }
-        ]
-      }, {
-        id: 4,
-        statements: 'select * from bla;select * from ble',
-        expectedResult: [
-          { type: 'statement', statement: 'select * from bla;', location: { first_line: 1, last_line: 1, first_column: 0,  last_column: 18 } },
-          { type: 'statement', statement: 'select * from ble', location: { first_line: 1, last_line: 1, first_column: 18,  last_column: 35 } }
-        ]
+    var stringifySplitResult = function (result) {
+      var s = '[';
+      var first = true;
+      result.forEach(function (entry) {
+        s += first ? '{\n' : ', {\n';
+        s += '  statement: \'' + entry.statement.replace(/\n/g, '\\n') + '\',\n';
+        s += '  location: { first_line: ' + entry.location.first_line + ', first_column: ' + entry.location.first_column + ', last_line: ' + entry.location.last_line + ', last_column: ' + entry.location.last_column + ' }'
+        s += '\n}';
+        first = false;
+      });
+      s += ']';
+      return s;
+    };
+
+    var testParser = function (input, expectedOutput) {
+      try {
+        expectedOutput.forEach(function (entry) {
+          entry.type = 'statement';
+        });
+        var result = sqlStatementsParser.parse(input);
+        var because = '\n\nParser output: ' + stringifySplitResult(result) + '\nExpected output: ' + stringifySplitResult(expectedOutput);
+        expect(result).toEqual(expectedOutput, because);
+      } catch (error) {
+        console.error(error);
+        console.log(error.message);
+
+        fail('Got error');
+      }
+    };
+
+    it('should split "" correctly', function () {
+      testParser('', []);
+    });
+
+    it('should split ";" correctly', function () {
+      testParser(';', [{
+        statement: ';',
+        location: { first_line: 1, first_column: 0, last_line: 1, last_column: 1 }
+      }]);
+    });
+
+    it('should split ";   \\n;   \\r\\n;" correctly', function () {
+      testParser(';   \n;   \r\n;', [{
+        statement: ';',
+        location: { first_line: 1, first_column: 0, last_line: 1, last_column: 1 }
       }, {
-        id: 5,
-        statements: 'select * from bla;;select * from ble',
-        expectedResult: [
-          { type: 'statement', statement: 'select * from bla;', location: { first_line: 1, last_line: 1, first_column: 0,  last_column: 18 } },
-          { type: 'statement', statement: ';', location: { first_line: 1, last_line: 1, first_column: 18,  last_column: 19 } },
-          { type: 'statement', statement: 'select * from ble', location: { first_line: 1, last_line: 1, first_column: 19,  last_column: 36 } }
-        ]
+        statement: '   \n;',
+        location: { first_line: 1, first_column: 1, last_line: 2, last_column: 1 }
       }, {
-        id: 6,
-        statements: 'select * from bla;\n;select * from ble',
-        expectedResult: [
-          { type: 'statement', statement: 'select * from bla;', location: { first_line: 1, last_line: 1, first_column: 0,  last_column: 18 } },
-          { type: 'statement', statement: '\n;', location: { first_line: 1, last_line: 2, first_column: 18,  last_column: 1 } },
-          { type: 'statement', statement: 'select * from ble', location: { first_line: 2, last_line: 2, first_column: 1,  last_column: 18 } }
-        ]
+        statement: '   \r\n;',
+        location: { first_line: 2, first_column: 1, last_line: 3, last_column: 1 }
+      }]);
+    });
+
+    it('should split "select * from bla" correctly', function () {
+      testParser('select * from bla', [{
+        statement: 'select * from bla',
+        location: { first_line: 1, first_column: 0, last_line: 1, last_column: 17 }
+      }]);
+    });
+
+    it('should split ";;select * from bla" correctly', function () {
+      testParser(';;select * from bla', [{
+        statement: ';',
+        location: { first_line: 1, first_column: 0, last_line: 1, last_column: 1 }
       }, {
-        id: 5,
-        statements: 'select * \nfrom bla;\r\nselect * from ble;\n',
-        expectedResult: [
-          { type: 'statement', statement: 'select * \nfrom bla;', location: { first_line: 1, last_line: 2, first_column: 0,  last_column: 9 } },
-          { type: 'statement', statement: '\r\nselect * from ble;', location: { first_line: 2, last_line: 3, first_column: 9,  last_column: 18 } }
-        ]
+        statement: ';',
+        location: { first_line: 1, first_column: 1, last_line: 1, last_column: 2 }
       }, {
-        id: 7,
-        statements: 'select * from bla where x = ";";',
-        expectedResult: [
-          { type: 'statement', statement: 'select * from bla where x = ";";', location: { first_line: 1, last_line: 1, first_column: 0,  last_column: 32 } }
-        ]
+        statement: 'select * from bla',
+        location: { first_line: 1, first_column: 2, last_line: 1, last_column: 19 }
+      }]);
+    });
+
+    it('should split "select * from bla;" correctly', function () {
+      testParser('select * from bla;', [{
+        statement: 'select * from bla;',
+        location: { first_line: 1, first_column: 0, last_line: 1, last_column: 18 }
+      }]);
+    });
+
+    it('should split "select * from bla;select * from ble" correctly', function () {
+      testParser('select * from bla;select * from ble', [{
+        statement: 'select * from bla;',
+        location: { first_line: 1, first_column: 0, last_line: 1, last_column: 18 }
       }, {
-        id: 8,
-        statements: 'select * from bla where x = \';\';\n\nSELECT bla FROM foo WHERE y = `;` AND true = false;',
-        expectedResult: [
-          { type: 'statement', statement: 'select * from bla where x = \';\';', location: { first_line: 1, last_line: 1, first_column: 0,  last_column: 32 } },
-          { type: 'statement', statement: '\n\nSELECT bla FROM foo WHERE y = `;` AND true = false;', location: { first_line: 1, last_line: 3, first_column: 32,  last_column: 51 } }
-        ]
+        statement: 'select * from ble',
+        location: { first_line: 1, first_column: 18, last_line: 1, last_column: 35 }
+      }]);
+    });
+
+    it('should split "select * from bla;;select * from ble" correctly', function () {
+      testParser('select * from bla;;select * from ble', [{
+        statement: 'select * from bla;',
+        location: { first_line: 1, first_column: 0, last_line: 1, last_column: 18 }
       }, {
-        id: 9,
-        statements: 'select * from bla where x = "; AND boo = 1;\n\nUSE db',
-        expectedResult: [
-          { type: 'statement', statement: 'select * from bla where x = ', location: { first_line: 1, last_line: 1, first_column: 0,  last_column: 28 } },
-          { type: 'statement', statement: ';', location: { first_line: 1, last_line: 1, first_column: 29,  last_column: 30 } },
-          { type: 'statement', statement: ' AND boo = 1;', location: { first_line: 1, last_line: 1, first_column: 30,  last_column: 43 } },
-          { type: 'statement', statement: '\n\nUSE db', location: { first_line: 1, last_line: 3, first_column: 43,  last_column: 6 } }
-        ]
+        statement: ';',
+        location: { first_line: 1, first_column: 18, last_line: 1, last_column: 19 }
+      },{
+        statement: 'select * from ble',
+        location: { first_line: 1, first_column: 19, last_line: 1, last_column: 36 }
+      }]);
+    });
+
+    it('should split "select * from bla;\\n;select * from ble" correctly', function () {
+      testParser('select * from bla;\n;select * from ble', [{
+        statement: 'select * from bla;',
+        location: { first_line: 1, first_column: 0, last_line: 1, last_column: 18 }
       }, {
-        id: 10,
-        statements: '--- Some comment with ; ; \nselect * from bla where x = ";";',
-        expectedResult: [
-          { type: 'statement', statement: '\nselect * from bla where x = ";";', location: { first_line: 1, last_line: 2, first_column: 26,  last_column: 32 } }
-        ]
+        statement: '\n;',
+        location: { first_line: 1, first_column: 18, last_line: 2, last_column: 1 }
+      },{
+        statement: 'select * from ble',
+        location: { first_line: 2, first_column: 1, last_line: 2, last_column: 18 }
+      }]);
+    });
+
+    it('should split "select * \\nfrom bla;\\r\\nselect * from ble;\\n" correctly', function () {
+      testParser('select * \nfrom bla;\r\nselect * from ble;\n', [{
+        statement: 'select * \nfrom bla;',
+        location: { first_line: 1, first_column: 0, last_line: 2, last_column: 9 }
       }, {
-        id: 11,
-        statements: 'select *\n-- bla\n from bla;',
-        expectedResult: [
-          { type: 'statement', statement: 'select *\n-- bla\n from bla;', location: { first_line: 1, last_line: 3, first_column: 0,  last_column: 10 } }
-        ]
+        statement: '\r\nselect * from ble;',
+        location: { first_line: 2, first_column: 9, last_line: 3, last_column: 18 }
+      }]);
+    });
+
+    it('should split "select * from bla where x = ";";" correctly', function () {
+      testParser('select * from bla where x = ";";', [{
+        statement: 'select * from bla where x = ";";',
+        location: { first_line: 1, first_column: 0, last_line: 1, last_column: 32 }
+      }]);
+    });
+
+    it('should split "select * from bla where x = \';\';\\n\\nSELECT bla FROM foo WHERE y = `;` AND true = false;" correctly', function () {
+      testParser('select * from bla where x = \';\';\n\nSELECT bla FROM foo WHERE y = `;` AND true = false;', [{
+        statement: 'select * from bla where x = \';\';',
+        location: { first_line: 1, first_column: 0, last_line: 1, last_column: 32 }
       }, {
-        id: 12,
-        statements: 'select *\n/* bla \n\n*/\n from bla;',
-        expectedResult: [
-          { type: 'statement', statement: 'select *\n/* bla \n\n*/\n from bla;', location: { first_line: 1, last_line: 5, first_column: 0,  last_column: 10 } }
-        ]
-      }
-    ];
-
-    splitTests.forEach(function (splitTest) {
-      it('should split correctly, test ' + splitTest.id, function () {
-        try {
-          var result = sqlStatementsParser.parse(splitTest.statements);
-          expect(result).toEqual(splitTest.expectedResult);
-        } catch (error) {
-          fail('Got error');
-        }
-      });
+        statement: '\n\nSELECT bla FROM foo WHERE y = `;` AND true = false;',
+        location: { first_line: 1, first_column: 32, last_line: 3, last_column: 51 }
+      }]);
+    });
+
+    it('should split "select * from bla where x = "; AND boo = 1;\\n\\nUSE db" correctly', function () {
+      testParser('select * from bla where x = "; AND boo = 1;\n\nUSE db', [{
+        statement: 'select * from bla where x = "; AND boo = 1;\n\nUSE db',
+        location: { first_line: 1, first_column: 0, last_line: 3, last_column: 6 }
+      }]);
+    });
+
+    it('should split "--- Some comment with ; ; \\nselect * from bla where x = ";";" correctly', function () {
+      testParser('--- Some comment with ; ; \nselect * from bla where x = ";";', [{
+        statement: '--- Some comment with ; ; \nselect * from bla where x = ";";',
+        location: { first_line: 1, first_column: 0, last_line: 2, last_column: 32 }
+      }]);
+    });
+
+    it('should split "select *\n-- bla\n from bla;" correctly', function () {
+      testParser('select *\n-- bla\n from bla;', [{
+        statement: 'select *\n-- bla\n from bla;',
+        location: { first_line: 1, first_column: 0, last_line: 3, last_column: 10 }
+      }]);
+    });
+
+    it('should split "select *\\n/* bla \\n\\n*/\\n from bla;" correctly', function () {
+      testParser('select *\n/* bla \n\n*/\n from bla;', [{
+        statement: 'select *\n/* bla \n\n*/\n from bla;',
+        location: { first_line: 1, first_column: 0, last_line: 5, last_column: 10 }
+      }]);
+    });
+
+    it('should split "SELECT\\n id -- some ID\\n FROM customers;" correctly', function () {
+      testParser('SELECT\n id -- some ID\n FROM customers;', [{
+        statement: 'SELECT\n id -- some ID\n FROM customers;',
+        location: { first_line: 1, first_column: 0, last_line: 3, last_column: 16 }
+      }]);
+    });
+
+    it('should split "SELECT\n id -- some ID;\n FROM customers;" correctly', function () {
+      testParser('SELECT\n id -- some ID;\n FROM customers;', [{
+        statement: 'SELECT\n id -- some ID;\n FROM customers;',
+        location: { first_line: 1, first_column: 0, last_line: 3, last_column: 16 }
+      }]);
     });
   });
 })();