Browse Source

HUE-4767 [editor] Limit the autocompleter length before and after the cursor

This puts a hard limit of 150,000 chars before and after the cursor, it will try to cut it at any found statement separator to preserve as many locations as possible.
Johan Ahlen 9 years ago
parent
commit
4aaa92e67b

+ 23 - 0
desktop/core/src/desktop/static/desktop/js/autocomplete/sql.js

@@ -4928,6 +4928,29 @@ parser.parseSql = function (beforeCursor, afterCursor, dialect, sqlFunctions, de
 
   prepareNewStatement();
 
+  var REASONABLE_SURROUNDING_LENGTH = 150000; // About 3000 lines before and after
+
+  if (beforeCursor.length > REASONABLE_SURROUNDING_LENGTH) {
+    if ((beforeCursor.length - beforeCursor.lastIndexOf(';')) > REASONABLE_SURROUNDING_LENGTH) {
+      // Bail out if the last complete statement is more than 150000 chars before
+      return {};
+    }
+    // Cut it at the first statement found within 150000 chars before
+    var lastReasonableChunk = beforeCursor.substring(beforeCursor.length - REASONABLE_SURROUNDING_LENGTH);
+    beforeCursor = lastReasonableChunk.substring(lastReasonableChunk.indexOf(';') + 1);
+  }
+
+  if (afterCursor.length > REASONABLE_SURROUNDING_LENGTH) {
+    if ((afterCursor.length - afterCursor.indexOf(';')) > REASONABLE_SURROUNDING_LENGTH) {
+      // No need to bail out for what's comes after, we can still get keyword completion
+      afterCursor = '';
+    } else {
+      // Cut it at the last statement found within 150000 chars after
+      var firstReasonableChunk = afterCursor.substring(0, REASONABLE_SURROUNDING_LENGTH);
+      afterCursor = firstReasonableChunk.substring(0, firstReasonableChunk.lastIndexOf(';'));
+    }
+  }
+
   parser.yy.partialLengths = parser.identifyPartials(beforeCursor, afterCursor);
 
   if (parser.yy.partialLengths.left > 0) {

+ 23 - 0
desktop/core/src/desktop/static/desktop/js/autocomplete/sql_support.js

@@ -1036,6 +1036,29 @@ parser.parseSql = function (beforeCursor, afterCursor, dialect, sqlFunctions, de
 
   prepareNewStatement();
 
+  var REASONABLE_SURROUNDING_LENGTH = 150000; // About 3000 lines before and after
+
+  if (beforeCursor.length > REASONABLE_SURROUNDING_LENGTH) {
+    if ((beforeCursor.length - beforeCursor.lastIndexOf(';')) > REASONABLE_SURROUNDING_LENGTH) {
+      // Bail out if the last complete statement is more than 150000 chars before
+      return {};
+    }
+    // Cut it at the first statement found within 150000 chars before
+    var lastReasonableChunk = beforeCursor.substring(beforeCursor.length - REASONABLE_SURROUNDING_LENGTH);
+    beforeCursor = lastReasonableChunk.substring(lastReasonableChunk.indexOf(';') + 1);
+  }
+
+  if (afterCursor.length > REASONABLE_SURROUNDING_LENGTH) {
+    if ((afterCursor.length - afterCursor.indexOf(';')) > REASONABLE_SURROUNDING_LENGTH) {
+      // No need to bail out for what's comes after, we can still get keyword completion
+      afterCursor = '';
+    } else {
+      // Cut it at the last statement found within 150000 chars after
+      var firstReasonableChunk = afterCursor.substring(0, REASONABLE_SURROUNDING_LENGTH);
+      afterCursor = firstReasonableChunk.substring(0, firstReasonableChunk.lastIndexOf(';'));
+    }
+  }
+
   parser.yy.partialLengths = parser.identifyPartials(beforeCursor, afterCursor);
 
   if (parser.yy.partialLengths.left > 0) {

+ 55 - 0
desktop/core/src/desktop/static/desktop/spec/autocomplete/sqlSpecSelect.js

@@ -602,6 +602,61 @@ define([
         });
       });
 
+      it('should handle 100k rows before "SELECT * FROM foo WHERE (bar = \'bla\') AND (ble = 1);|"', function() {
+        var beforeCursor = '';
+        for (var i = 0; i < 100000; i++) {
+          beforeCursor += 'SELECT * FROM foo WHERE (bar = \'bla\') AND (ble = 1);\n';
+        }
+        assertAutoComplete({
+          beforeCursor: beforeCursor,
+          afterCursor: ';SELECT * FROM foo WHERE (bar = \'bla\') AND (ble = 1);',
+          dialect: 'hive',
+          hasLocations: true,
+          noErrors: true,
+          containsKeywords: ['SELECT'],
+          expectedResult: {
+            lowerCase: false
+          }
+        });
+      });
+
+      it('should handle 100k rows after "SELECT * FROM foo WHERE (bar = \'bla\') AND (ble = 1);|"', function() {
+        var afterCursor = ';\n';
+        for (var i = 0; i < 100000; i++) {
+          afterCursor += 'SELECT * FROM foo WHERE (bar = \'bla\') AND (ble = 1);\n';
+        }
+        assertAutoComplete({
+          beforeCursor: '',
+          afterCursor: afterCursor,
+          dialect: 'hive',
+          noErrors: true,
+          containsKeywords: ['SELECT'],
+          expectedResult: {
+            lowerCase: false
+          }
+        });
+      });
+
+      it('should handle 100k rows before and after "SELECT * FROM foo WHERE (bar = \'bla\') AND (ble = 1);|"', function() {
+        var beforeCursor = '';
+        var afterCursor = ';\n';
+        for (var i = 0; i < 100000; i++) {
+          beforeCursor += 'SELECT * FROM foo WHERE (bar = \'bla\') AND (ble = 1);\n';
+          afterCursor += 'SELECT * FROM foo WHERE (bar = \'bla\') AND (ble = 1);\n';
+        }
+        assertAutoComplete({
+          beforeCursor: beforeCursor,
+          afterCursor: afterCursor,
+          dialect: 'hive',
+          noErrors: true,
+          hasLocations: true,
+          containsKeywords: ['SELECT'],
+          expectedResult: {
+            lowerCase: false
+          }
+        });
+      });
+
       it('should handle "SELECT * FROM foo WHERE bar IN (SELECT * FROM bla);|"', function() {
         assertAutoComplete({
           beforeCursor: 'SELECT * FROM foo WHERE bar IN (SELECT * FROM bla);',