Explorar el Código

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 hace 9 años
padre
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);',