Prechádzať zdrojové kódy

[editor] Improved autocompletion around partial backticked identifiers

Johan Åhlén 4 rokov pred
rodič
commit
4181c09c15
38 zmenil súbory, kde vykonal 301 pridanie a 1119 odobranie
  1. 3 10
      desktop/core/src/desktop/js/parse/sql/calcite/sqlParseSupport.js
  2. 2 1
      desktop/core/src/desktop/js/parse/sql/calcite/test/calciteAutocompleteParser.Select.test.js
  3. 2 92
      desktop/core/src/desktop/js/parse/sql/calcite/test/calciteAutocompleteParser.test.js
  4. 3 10
      desktop/core/src/desktop/js/parse/sql/dasksql/sqlParseSupport.js
  5. 2 1
      desktop/core/src/desktop/js/parse/sql/dasksql/test/dasksqlAutocompleteParser.Select.test.js
  6. 2 92
      desktop/core/src/desktop/js/parse/sql/dasksql/test/dasksqlAutocompleteParser.test.js
  7. 3 10
      desktop/core/src/desktop/js/parse/sql/druid/sqlParseSupport.js
  8. 2 1
      desktop/core/src/desktop/js/parse/sql/druid/test/druidAutocompleteParser.Select.test.js
  9. 2 88
      desktop/core/src/desktop/js/parse/sql/druid/test/druidAutocompleteParser.test.js
  10. 3 10
      desktop/core/src/desktop/js/parse/sql/elasticsearch/sqlParseSupport.js
  11. 2 1
      desktop/core/src/desktop/js/parse/sql/elasticsearch/test/elasticsearchAutocompleteParser.Select.test.js
  12. 2 112
      desktop/core/src/desktop/js/parse/sql/elasticsearch/test/elasticsearchAutocompleteParser.test.js
  13. 3 10
      desktop/core/src/desktop/js/parse/sql/flink/sqlParseSupport.js
  14. 2 1
      desktop/core/src/desktop/js/parse/sql/flink/test/flinkAutocompleteParser.Select.test.js
  15. 2 88
      desktop/core/src/desktop/js/parse/sql/flink/test/flinkAutocompleteParser.test.js
  16. 3 10
      desktop/core/src/desktop/js/parse/sql/generic/sqlParseSupport.js
  17. 2 1
      desktop/core/src/desktop/js/parse/sql/generic/test/genericAutocompleteParser.Select.test.js
  18. 2 92
      desktop/core/src/desktop/js/parse/sql/generic/test/genericAutocompleteParser.test.js
  19. 3 10
      desktop/core/src/desktop/js/parse/sql/hive/sqlParseSupport.js
  20. 2 1
      desktop/core/src/desktop/js/parse/sql/hive/test/hiveAutocompleteParser.Select.test.js
  21. 2 73
      desktop/core/src/desktop/js/parse/sql/hive/test/hiveAutocompleteParser.test.js
  22. 3 10
      desktop/core/src/desktop/js/parse/sql/impala/sqlParseSupport.js
  23. 2 1
      desktop/core/src/desktop/js/parse/sql/impala/test/impalaAutocompleteParser.Select.test.js
  24. 2 86
      desktop/core/src/desktop/js/parse/sql/impala/test/impalaAutocompleteParser.test.js
  25. 3 10
      desktop/core/src/desktop/js/parse/sql/ksql/sqlParseSupport.js
  26. 2 1
      desktop/core/src/desktop/js/parse/sql/ksql/test/ksqlAutocompleteParser.Select.test.js
  27. 2 88
      desktop/core/src/desktop/js/parse/sql/ksql/test/ksqlAutocompleteParser.test.js
  28. 3 10
      desktop/core/src/desktop/js/parse/sql/phoenix/sqlParseSupport.js
  29. 2 1
      desktop/core/src/desktop/js/parse/sql/phoenix/test/phoenixAutocompleteParser.Select.test.js
  30. 2 92
      desktop/core/src/desktop/js/parse/sql/phoenix/test/phoenixAutocompleteParser.test.js
  31. 3 10
      desktop/core/src/desktop/js/parse/sql/presto/sqlParseSupport.js
  32. 2 1
      desktop/core/src/desktop/js/parse/sql/presto/test/prestoAutocompleteParser.Select.test.js
  33. 2 87
      desktop/core/src/desktop/js/parse/sql/presto/test/prestoAutocompleteParser.test.js
  34. 146 0
      desktop/core/src/desktop/js/parse/sql/sharedParserTests.ts
  35. 32 0
      desktop/core/src/desktop/js/parse/sql/sqlParseUtils.js
  36. 4 0
      desktop/core/src/desktop/js/parse/types.ts
  37. 37 7
      desktop/core/src/desktop/js/sql/autocompleteResults.js
  38. 5 1
      desktop/core/src/desktop/js/sql/sqlUtils.ts

+ 3 - 10
desktop/core/src/desktop/js/parse/sql/calcite/sqlParseSupport.js

@@ -20,7 +20,8 @@ import {
   initSyntaxParser,
   identifierEquals,
   equalIgnoreCase,
-  SIMPLE_TABLE_REF_SUGGESTIONS
+  SIMPLE_TABLE_REF_SUGGESTIONS,
+  adjustForPartialBackticks
 } from 'parse/sql/sqlParseUtils';
 
 const initSqlParser = function (parser) {
@@ -651,15 +652,6 @@ const initSqlParser = function (parser) {
     }
   };
 
-  parser.identifyPartials = function (beforeCursor, afterCursor) {
-    const beforeMatch = beforeCursor.match(/[0-9a-zA-Z_]*$/);
-    const afterMatch = afterCursor.match(/^[0-9a-zA-Z_]*(?:\((?:[^)]*\))?)?/);
-    return {
-      left: beforeMatch ? beforeMatch[0].length : 0,
-      right: afterMatch ? afterMatch[0].length : 0
-    };
-  };
-
   const addCleanTablePrimary = function (tables, tablePrimary) {
     if (tablePrimary.alias) {
       tables.push({ alias: tablePrimary.alias, identifierChain: tablePrimary.identifierChain });
@@ -1395,6 +1387,7 @@ const initSqlParser = function (parser) {
       linkTablePrimaries();
       parser.commitLocations();
       // Clean up and prioritize
+      adjustForPartialBackticks(parser);
       prioritizeSuggestions();
     } catch (err) {
       if (debug) {

+ 2 - 1
desktop/core/src/desktop/js/parse/sql/calcite/test/calciteAutocompleteParser.Select.test.js

@@ -232,8 +232,9 @@ describe('calciteAutocompleteParser.js SELECT statements', () => {
       afterCursor: '',
       expectedResult: {
         lowerCase: false,
-        suggestTables: {},
+        suggestTables: { appendBacktick: true },
         suggestDatabases: {
+          appendBacktick: true,
           appendDot: true
         }
       }

+ 2 - 92
desktop/core/src/desktop/js/parse/sql/calcite/test/calciteAutocompleteParser.test.js

@@ -14,6 +14,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+import { assertPartials } from 'parse/sql/sharedParserTests';
 import calciteAutocompleteParser from '../calciteAutocompleteParser';
 
 describe('calciteAutocompleteParser.js', () => {
@@ -277,98 +278,7 @@ describe('calciteAutocompleteParser.js', () => {
 
   describe('partial removal', () => {
     it('should identify part lengths', () => {
-      const limitChars = [
-        ' ',
-        '\n',
-        '\t',
-        '&',
-        '~',
-        '%',
-        '!',
-        '.',
-        ',',
-        '+',
-        '-',
-        '*',
-        '/',
-        '=',
-        '<',
-        '>',
-        ')',
-        '[',
-        ']',
-        ';'
-      ];
-
-      expect(calciteAutocompleteParser.identifyPartials('', '')).toEqual({ left: 0, right: 0 });
-      expect(calciteAutocompleteParser.identifyPartials('foo', '')).toEqual({ left: 3, right: 0 });
-      expect(calciteAutocompleteParser.identifyPartials(' foo', '')).toEqual({ left: 3, right: 0 });
-      expect(calciteAutocompleteParser.identifyPartials('asdf 1234', '')).toEqual({
-        left: 4,
-        right: 0
-      });
-
-      expect(calciteAutocompleteParser.identifyPartials('foo', 'bar')).toEqual({
-        left: 3,
-        right: 3
-      });
-
-      expect(calciteAutocompleteParser.identifyPartials('fo', 'o()')).toEqual({
-        left: 2,
-        right: 3
-      });
-
-      expect(calciteAutocompleteParser.identifyPartials('fo', 'o(')).toEqual({ left: 2, right: 2 });
-      expect(calciteAutocompleteParser.identifyPartials('fo', 'o(bla bla)')).toEqual({
-        left: 2,
-        right: 10
-      });
-
-      expect(calciteAutocompleteParser.identifyPartials('foo ', '')).toEqual({ left: 0, right: 0 });
-      expect(calciteAutocompleteParser.identifyPartials("foo '", "'")).toEqual({
-        left: 0,
-        right: 0
-      });
-
-      expect(calciteAutocompleteParser.identifyPartials('foo "', '"')).toEqual({
-        left: 0,
-        right: 0
-      });
-      limitChars.forEach(char => {
-        expect(calciteAutocompleteParser.identifyPartials('bar foo' + char, '')).toEqual({
-          left: 0,
-          right: 0
-        });
-
-        expect(calciteAutocompleteParser.identifyPartials('bar foo' + char + 'foofoo', '')).toEqual(
-          {
-            left: 6,
-            right: 0
-          }
-        );
-
-        expect(
-          calciteAutocompleteParser.identifyPartials('bar foo' + char + 'foofoo ', '')
-        ).toEqual({
-          left: 0,
-          right: 0
-        });
-
-        expect(calciteAutocompleteParser.identifyPartials('', char + 'foo bar')).toEqual({
-          left: 0,
-          right: 0
-        });
-
-        expect(calciteAutocompleteParser.identifyPartials('', 'foofoo' + char)).toEqual({
-          left: 0,
-          right: 6
-        });
-
-        expect(calciteAutocompleteParser.identifyPartials('', ' foofoo' + char)).toEqual({
-          left: 0,
-          right: 0
-        });
-      });
+      assertPartials(calciteAutocompleteParser);
     });
   });
 });

+ 3 - 10
desktop/core/src/desktop/js/parse/sql/dasksql/sqlParseSupport.js

@@ -20,7 +20,8 @@ import {
   initSyntaxParser,
   identifierEquals,
   equalIgnoreCase,
-  SIMPLE_TABLE_REF_SUGGESTIONS
+  SIMPLE_TABLE_REF_SUGGESTIONS,
+  adjustForPartialBackticks
 } from 'parse/sql/sqlParseUtils';
 
 const initSqlParser = function (parser) {
@@ -645,15 +646,6 @@ const initSqlParser = function (parser) {
     }
   };
 
-  parser.identifyPartials = function (beforeCursor, afterCursor) {
-    const beforeMatch = beforeCursor.match(/[0-9a-zA-Z_]*$/);
-    const afterMatch = afterCursor.match(/^[0-9a-zA-Z_]*(?:\((?:[^)]*\))?)?/);
-    return {
-      left: beforeMatch ? beforeMatch[0].length : 0,
-      right: afterMatch ? afterMatch[0].length : 0
-    };
-  };
-
   const addCleanTablePrimary = function (tables, tablePrimary) {
     if (tablePrimary.alias) {
       tables.push({ alias: tablePrimary.alias, identifierChain: tablePrimary.identifierChain });
@@ -1374,6 +1366,7 @@ const initSqlParser = function (parser) {
       linkTablePrimaries();
       parser.commitLocations();
       // Clean up and prioritize
+      adjustForPartialBackticks(parser);
       prioritizeSuggestions();
     } catch (err) {
       if (debug) {

+ 2 - 1
desktop/core/src/desktop/js/parse/sql/dasksql/test/dasksqlAutocompleteParser.Select.test.js

@@ -232,8 +232,9 @@ describe('dasksqlAutocompleteParser.js SELECT statements', () => {
       afterCursor: '',
       expectedResult: {
         lowerCase: false,
-        suggestTables: {},
+        suggestTables: { appendBacktick: true },
         suggestDatabases: {
+          appendBacktick: true,
           appendDot: true
         }
       }

+ 2 - 92
desktop/core/src/desktop/js/parse/sql/dasksql/test/dasksqlAutocompleteParser.test.js

@@ -14,6 +14,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+import { assertPartials } from 'parse/sql/sharedParserTests';
 import dasksqlAutocompleteParser from '../dasksqlAutocompleteParser';
 
 describe('dasksqlAutocompleteParser.js', () => {
@@ -215,98 +216,7 @@ describe('dasksqlAutocompleteParser.js', () => {
 
   describe('partial removal', () => {
     it('should identify part lengths', () => {
-      const limitChars = [
-        ' ',
-        '\n',
-        '\t',
-        '&',
-        '~',
-        '%',
-        '!',
-        '.',
-        ',',
-        '+',
-        '-',
-        '*',
-        '/',
-        '=',
-        '<',
-        '>',
-        ')',
-        '[',
-        ']',
-        ';'
-      ];
-
-      expect(dasksqlAutocompleteParser.identifyPartials('', '')).toEqual({ left: 0, right: 0 });
-      expect(dasksqlAutocompleteParser.identifyPartials('foo', '')).toEqual({ left: 3, right: 0 });
-      expect(dasksqlAutocompleteParser.identifyPartials(' foo', '')).toEqual({ left: 3, right: 0 });
-      expect(dasksqlAutocompleteParser.identifyPartials('asdf 1234', '')).toEqual({
-        left: 4,
-        right: 0
-      });
-
-      expect(dasksqlAutocompleteParser.identifyPartials('foo', 'bar')).toEqual({
-        left: 3,
-        right: 3
-      });
-
-      expect(dasksqlAutocompleteParser.identifyPartials('fo', 'o()')).toEqual({
-        left: 2,
-        right: 3
-      });
-
-      expect(dasksqlAutocompleteParser.identifyPartials('fo', 'o(')).toEqual({ left: 2, right: 2 });
-      expect(dasksqlAutocompleteParser.identifyPartials('fo', 'o(bla bla)')).toEqual({
-        left: 2,
-        right: 10
-      });
-
-      expect(dasksqlAutocompleteParser.identifyPartials('foo ', '')).toEqual({ left: 0, right: 0 });
-      expect(dasksqlAutocompleteParser.identifyPartials("foo '", "'")).toEqual({
-        left: 0,
-        right: 0
-      });
-
-      expect(dasksqlAutocompleteParser.identifyPartials('foo "', '"')).toEqual({
-        left: 0,
-        right: 0
-      });
-      limitChars.forEach(char => {
-        expect(dasksqlAutocompleteParser.identifyPartials('bar foo' + char, '')).toEqual({
-          left: 0,
-          right: 0
-        });
-
-        expect(dasksqlAutocompleteParser.identifyPartials('bar foo' + char + 'foofoo', '')).toEqual(
-          {
-            left: 6,
-            right: 0
-          }
-        );
-
-        expect(
-          dasksqlAutocompleteParser.identifyPartials('bar foo' + char + 'foofoo ', '')
-        ).toEqual({
-          left: 0,
-          right: 0
-        });
-
-        expect(dasksqlAutocompleteParser.identifyPartials('', char + 'foo bar')).toEqual({
-          left: 0,
-          right: 0
-        });
-
-        expect(dasksqlAutocompleteParser.identifyPartials('', 'foofoo' + char)).toEqual({
-          left: 0,
-          right: 6
-        });
-
-        expect(dasksqlAutocompleteParser.identifyPartials('', ' foofoo' + char)).toEqual({
-          left: 0,
-          right: 0
-        });
-      });
+      assertPartials(dasksqlAutocompleteParser);
     });
   });
 });

+ 3 - 10
desktop/core/src/desktop/js/parse/sql/druid/sqlParseSupport.js

@@ -20,7 +20,8 @@ import {
   initSyntaxParser,
   identifierEquals,
   equalIgnoreCase,
-  SIMPLE_TABLE_REF_SUGGESTIONS
+  SIMPLE_TABLE_REF_SUGGESTIONS,
+  adjustForPartialBackticks
 } from 'parse/sql/sqlParseUtils';
 
 const initSqlParser = function (parser) {
@@ -645,15 +646,6 @@ const initSqlParser = function (parser) {
     }
   };
 
-  parser.identifyPartials = function (beforeCursor, afterCursor) {
-    const beforeMatch = beforeCursor.match(/[0-9a-zA-Z_]*$/);
-    const afterMatch = afterCursor.match(/^[0-9a-zA-Z_]*(?:\((?:[^)]*\))?)?/);
-    return {
-      left: beforeMatch ? beforeMatch[0].length : 0,
-      right: afterMatch ? afterMatch[0].length : 0
-    };
-  };
-
   const addCleanTablePrimary = function (tables, tablePrimary) {
     if (tablePrimary.alias) {
       tables.push({ alias: tablePrimary.alias, identifierChain: tablePrimary.identifierChain });
@@ -1389,6 +1381,7 @@ const initSqlParser = function (parser) {
       linkTablePrimaries();
       parser.commitLocations();
       // Clean up and prioritize
+      adjustForPartialBackticks(parser);
       prioritizeSuggestions();
     } catch (err) {
       if (debug) {

+ 2 - 1
desktop/core/src/desktop/js/parse/sql/druid/test/druidAutocompleteParser.Select.test.js

@@ -232,8 +232,9 @@ describe('druidAutocompleteParser.js SELECT statements', () => {
       afterCursor: '',
       expectedResult: {
         lowerCase: false,
-        suggestTables: {},
+        suggestTables: { appendBacktick: true },
         suggestDatabases: {
+          appendBacktick: true,
           appendDot: true
         }
       }

+ 2 - 88
desktop/core/src/desktop/js/parse/sql/druid/test/druidAutocompleteParser.test.js

@@ -14,6 +14,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+import { assertPartials } from 'parse/sql/sharedParserTests';
 import druidAutocompleteParser from '../druidAutocompleteParser';
 
 describe('druidAutocompleteParser.js', () => {
@@ -277,94 +278,7 @@ describe('druidAutocompleteParser.js', () => {
 
   describe('partial removal', () => {
     it('should identify part lengths', () => {
-      const limitChars = [
-        ' ',
-        '\n',
-        '\t',
-        '&',
-        '~',
-        '%',
-        '!',
-        '.',
-        ',',
-        '+',
-        '-',
-        '*',
-        '/',
-        '=',
-        '<',
-        '>',
-        ')',
-        '[',
-        ']',
-        ';'
-      ];
-
-      expect(druidAutocompleteParser.identifyPartials('', '')).toEqual({ left: 0, right: 0 });
-      expect(druidAutocompleteParser.identifyPartials('foo', '')).toEqual({ left: 3, right: 0 });
-      expect(druidAutocompleteParser.identifyPartials(' foo', '')).toEqual({ left: 3, right: 0 });
-      expect(druidAutocompleteParser.identifyPartials('asdf 1234', '')).toEqual({
-        left: 4,
-        right: 0
-      });
-
-      expect(druidAutocompleteParser.identifyPartials('foo', 'bar')).toEqual({
-        left: 3,
-        right: 3
-      });
-
-      expect(druidAutocompleteParser.identifyPartials('fo', 'o()')).toEqual({
-        left: 2,
-        right: 3
-      });
-
-      expect(druidAutocompleteParser.identifyPartials('fo', 'o(')).toEqual({ left: 2, right: 2 });
-      expect(druidAutocompleteParser.identifyPartials('fo', 'o(bla bla)')).toEqual({
-        left: 2,
-        right: 10
-      });
-
-      expect(druidAutocompleteParser.identifyPartials('foo ', '')).toEqual({ left: 0, right: 0 });
-      expect(druidAutocompleteParser.identifyPartials("foo '", "'")).toEqual({
-        left: 0,
-        right: 0
-      });
-
-      expect(druidAutocompleteParser.identifyPartials('foo "', '"')).toEqual({
-        left: 0,
-        right: 0
-      });
-      limitChars.forEach(char => {
-        expect(druidAutocompleteParser.identifyPartials('bar foo' + char, '')).toEqual({
-          left: 0,
-          right: 0
-        });
-
-        expect(druidAutocompleteParser.identifyPartials('bar foo' + char + 'foofoo', '')).toEqual({
-          left: 6,
-          right: 0
-        });
-
-        expect(druidAutocompleteParser.identifyPartials('bar foo' + char + 'foofoo ', '')).toEqual({
-          left: 0,
-          right: 0
-        });
-
-        expect(druidAutocompleteParser.identifyPartials('', char + 'foo bar')).toEqual({
-          left: 0,
-          right: 0
-        });
-
-        expect(druidAutocompleteParser.identifyPartials('', 'foofoo' + char)).toEqual({
-          left: 0,
-          right: 6
-        });
-
-        expect(druidAutocompleteParser.identifyPartials('', ' foofoo' + char)).toEqual({
-          left: 0,
-          right: 0
-        });
-      });
+      assertPartials(druidAutocompleteParser);
     });
   });
 });

+ 3 - 10
desktop/core/src/desktop/js/parse/sql/elasticsearch/sqlParseSupport.js

@@ -20,7 +20,8 @@ import {
   initSyntaxParser,
   identifierEquals,
   equalIgnoreCase,
-  SIMPLE_TABLE_REF_SUGGESTIONS
+  SIMPLE_TABLE_REF_SUGGESTIONS,
+  adjustForPartialBackticks
 } from 'parse/sql/sqlParseUtils';
 
 const initSqlParser = function (parser) {
@@ -645,15 +646,6 @@ const initSqlParser = function (parser) {
     }
   };
 
-  parser.identifyPartials = function (beforeCursor, afterCursor) {
-    const beforeMatch = beforeCursor.match(/[0-9a-zA-Z_]*$/);
-    const afterMatch = afterCursor.match(/^[0-9a-zA-Z_]*(?:\((?:[^)]*\))?)?/);
-    return {
-      left: beforeMatch ? beforeMatch[0].length : 0,
-      right: afterMatch ? afterMatch[0].length : 0
-    };
-  };
-
   const addCleanTablePrimary = function (tables, tablePrimary) {
     if (tablePrimary.alias) {
       tables.push({ alias: tablePrimary.alias, identifierChain: tablePrimary.identifierChain });
@@ -1389,6 +1381,7 @@ const initSqlParser = function (parser) {
       linkTablePrimaries();
       parser.commitLocations();
       // Clean up and prioritize
+      adjustForPartialBackticks(parser);
       prioritizeSuggestions();
     } catch (err) {
       if (debug) {

+ 2 - 1
desktop/core/src/desktop/js/parse/sql/elasticsearch/test/elasticsearchAutocompleteParser.Select.test.js

@@ -232,8 +232,9 @@ describe('elasticsearchAutocompleteParser.js SELECT statements', () => {
       afterCursor: '',
       expectedResult: {
         lowerCase: false,
-        suggestTables: {},
+        suggestTables: { appendBacktick: true },
         suggestDatabases: {
+          appendBacktick: true,
           appendDot: true
         }
       }

+ 2 - 112
desktop/core/src/desktop/js/parse/sql/elasticsearch/test/elasticsearchAutocompleteParser.test.js

@@ -14,6 +14,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+import { assertPartials } from 'parse/sql/sharedParserTests';
 import elasticsearchAutocompleteParser from '../elasticsearchAutocompleteParser';
 
 describe('elasticsearchAutocompleteParser.js', () => {
@@ -277,118 +278,7 @@ describe('elasticsearchAutocompleteParser.js', () => {
 
   describe('partial removal', () => {
     it('should identify part lengths', () => {
-      const limitChars = [
-        ' ',
-        '\n',
-        '\t',
-        '&',
-        '~',
-        '%',
-        '!',
-        '.',
-        ',',
-        '+',
-        '-',
-        '*',
-        '/',
-        '=',
-        '<',
-        '>',
-        ')',
-        '[',
-        ']',
-        ';'
-      ];
-
-      expect(elasticsearchAutocompleteParser.identifyPartials('', '')).toEqual({
-        left: 0,
-        right: 0
-      });
-
-      expect(elasticsearchAutocompleteParser.identifyPartials('foo', '')).toEqual({
-        left: 3,
-        right: 0
-      });
-
-      expect(elasticsearchAutocompleteParser.identifyPartials(' foo', '')).toEqual({
-        left: 3,
-        right: 0
-      });
-
-      expect(elasticsearchAutocompleteParser.identifyPartials('asdf 1234', '')).toEqual({
-        left: 4,
-        right: 0
-      });
-
-      expect(elasticsearchAutocompleteParser.identifyPartials('foo', 'bar')).toEqual({
-        left: 3,
-        right: 3
-      });
-
-      expect(elasticsearchAutocompleteParser.identifyPartials('fo', 'o()')).toEqual({
-        left: 2,
-        right: 3
-      });
-
-      expect(elasticsearchAutocompleteParser.identifyPartials('fo', 'o(')).toEqual({
-        left: 2,
-        right: 2
-      });
-
-      expect(elasticsearchAutocompleteParser.identifyPartials('fo', 'o(bla bla)')).toEqual({
-        left: 2,
-        right: 10
-      });
-
-      expect(elasticsearchAutocompleteParser.identifyPartials('foo ', '')).toEqual({
-        left: 0,
-        right: 0
-      });
-
-      expect(elasticsearchAutocompleteParser.identifyPartials("foo '", "'")).toEqual({
-        left: 0,
-        right: 0
-      });
-
-      expect(elasticsearchAutocompleteParser.identifyPartials('foo "', '"')).toEqual({
-        left: 0,
-        right: 0
-      });
-      limitChars.forEach(char => {
-        expect(elasticsearchAutocompleteParser.identifyPartials('bar foo' + char, '')).toEqual({
-          left: 0,
-          right: 0
-        });
-
-        expect(
-          elasticsearchAutocompleteParser.identifyPartials('bar foo' + char + 'foofoo', '')
-        ).toEqual({
-          left: 6,
-          right: 0
-        });
-
-        expect(
-          elasticsearchAutocompleteParser.identifyPartials('bar foo' + char + 'foofoo ', '')
-        ).toEqual({
-          left: 0,
-          right: 0
-        });
-
-        expect(elasticsearchAutocompleteParser.identifyPartials('', char + 'foo bar')).toEqual({
-          left: 0,
-          right: 0
-        });
-
-        expect(elasticsearchAutocompleteParser.identifyPartials('', 'foofoo' + char)).toEqual({
-          left: 0,
-          right: 6
-        });
-
-        expect(elasticsearchAutocompleteParser.identifyPartials('', ' foofoo' + char)).toEqual({
-          left: 0,
-          right: 0
-        });
-      });
+      assertPartials(elasticsearchAutocompleteParser);
     });
   });
 });

+ 3 - 10
desktop/core/src/desktop/js/parse/sql/flink/sqlParseSupport.js

@@ -20,7 +20,8 @@ import {
   initSyntaxParser,
   identifierEquals,
   equalIgnoreCase,
-  SIMPLE_TABLE_REF_SUGGESTIONS
+  SIMPLE_TABLE_REF_SUGGESTIONS,
+  adjustForPartialBackticks
 } from 'parse/sql/sqlParseUtils';
 
 const initSqlParser = function (parser) {
@@ -645,15 +646,6 @@ const initSqlParser = function (parser) {
     }
   };
 
-  parser.identifyPartials = function (beforeCursor, afterCursor) {
-    const beforeMatch = beforeCursor.match(/[0-9a-zA-Z_]*$/);
-    const afterMatch = afterCursor.match(/^[0-9a-zA-Z_]*(?:\((?:[^)]*\))?)?/);
-    return {
-      left: beforeMatch ? beforeMatch[0].length : 0,
-      right: afterMatch ? afterMatch[0].length : 0
-    };
-  };
-
   const addCleanTablePrimary = function (tables, tablePrimary) {
     if (tablePrimary.alias) {
       tables.push({ alias: tablePrimary.alias, identifierChain: tablePrimary.identifierChain });
@@ -1389,6 +1381,7 @@ const initSqlParser = function (parser) {
       linkTablePrimaries();
       parser.commitLocations();
       // Clean up and prioritize
+      adjustForPartialBackticks(parser);
       prioritizeSuggestions();
     } catch (err) {
       if (debug) {

+ 2 - 1
desktop/core/src/desktop/js/parse/sql/flink/test/flinkAutocompleteParser.Select.test.js

@@ -232,8 +232,9 @@ describe('flinkAutocompleteParser.js SELECT statements', () => {
       afterCursor: '',
       expectedResult: {
         lowerCase: false,
-        suggestTables: {},
+        suggestTables: { appendBacktick: true },
         suggestDatabases: {
+          appendBacktick: true,
           appendDot: true
         }
       }

+ 2 - 88
desktop/core/src/desktop/js/parse/sql/flink/test/flinkAutocompleteParser.test.js

@@ -14,6 +14,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+import { assertPartials } from 'parse/sql/sharedParserTests';
 import flinkAutocompleteParser from '../flinkAutocompleteParser';
 
 describe('flinkAutocompleteParser.js', () => {
@@ -277,94 +278,7 @@ describe('flinkAutocompleteParser.js', () => {
 
   describe('partial removal', () => {
     it('should identify part lengths', () => {
-      const limitChars = [
-        ' ',
-        '\n',
-        '\t',
-        '&',
-        '~',
-        '%',
-        '!',
-        '.',
-        ',',
-        '+',
-        '-',
-        '*',
-        '/',
-        '=',
-        '<',
-        '>',
-        ')',
-        '[',
-        ']',
-        ';'
-      ];
-
-      expect(flinkAutocompleteParser.identifyPartials('', '')).toEqual({ left: 0, right: 0 });
-      expect(flinkAutocompleteParser.identifyPartials('foo', '')).toEqual({ left: 3, right: 0 });
-      expect(flinkAutocompleteParser.identifyPartials(' foo', '')).toEqual({ left: 3, right: 0 });
-      expect(flinkAutocompleteParser.identifyPartials('asdf 1234', '')).toEqual({
-        left: 4,
-        right: 0
-      });
-
-      expect(flinkAutocompleteParser.identifyPartials('foo', 'bar')).toEqual({
-        left: 3,
-        right: 3
-      });
-
-      expect(flinkAutocompleteParser.identifyPartials('fo', 'o()')).toEqual({
-        left: 2,
-        right: 3
-      });
-
-      expect(flinkAutocompleteParser.identifyPartials('fo', 'o(')).toEqual({ left: 2, right: 2 });
-      expect(flinkAutocompleteParser.identifyPartials('fo', 'o(bla bla)')).toEqual({
-        left: 2,
-        right: 10
-      });
-
-      expect(flinkAutocompleteParser.identifyPartials('foo ', '')).toEqual({ left: 0, right: 0 });
-      expect(flinkAutocompleteParser.identifyPartials("foo '", "'")).toEqual({
-        left: 0,
-        right: 0
-      });
-
-      expect(flinkAutocompleteParser.identifyPartials('foo "', '"')).toEqual({
-        left: 0,
-        right: 0
-      });
-      limitChars.forEach(char => {
-        expect(flinkAutocompleteParser.identifyPartials('bar foo' + char, '')).toEqual({
-          left: 0,
-          right: 0
-        });
-
-        expect(flinkAutocompleteParser.identifyPartials('bar foo' + char + 'foofoo', '')).toEqual({
-          left: 6,
-          right: 0
-        });
-
-        expect(flinkAutocompleteParser.identifyPartials('bar foo' + char + 'foofoo ', '')).toEqual({
-          left: 0,
-          right: 0
-        });
-
-        expect(flinkAutocompleteParser.identifyPartials('', char + 'foo bar')).toEqual({
-          left: 0,
-          right: 0
-        });
-
-        expect(flinkAutocompleteParser.identifyPartials('', 'foofoo' + char)).toEqual({
-          left: 0,
-          right: 6
-        });
-
-        expect(flinkAutocompleteParser.identifyPartials('', ' foofoo' + char)).toEqual({
-          left: 0,
-          right: 0
-        });
-      });
+      assertPartials(flinkAutocompleteParser);
     });
   });
 });

+ 3 - 10
desktop/core/src/desktop/js/parse/sql/generic/sqlParseSupport.js

@@ -20,7 +20,8 @@ import {
   initSyntaxParser,
   identifierEquals,
   equalIgnoreCase,
-  SIMPLE_TABLE_REF_SUGGESTIONS
+  SIMPLE_TABLE_REF_SUGGESTIONS,
+  adjustForPartialBackticks
 } from 'parse/sql/sqlParseUtils';
 
 const initSqlParser = function (parser) {
@@ -645,15 +646,6 @@ const initSqlParser = function (parser) {
     }
   };
 
-  parser.identifyPartials = function (beforeCursor, afterCursor) {
-    const beforeMatch = beforeCursor.match(/[0-9a-zA-Z_]*$/);
-    const afterMatch = afterCursor.match(/^[0-9a-zA-Z_]*(?:\((?:[^)]*\))?)?/);
-    return {
-      left: beforeMatch ? beforeMatch[0].length : 0,
-      right: afterMatch ? afterMatch[0].length : 0
-    };
-  };
-
   const addCleanTablePrimary = function (tables, tablePrimary) {
     if (tablePrimary.alias) {
       tables.push({ alias: tablePrimary.alias, identifierChain: tablePrimary.identifierChain });
@@ -1389,6 +1381,7 @@ const initSqlParser = function (parser) {
       linkTablePrimaries();
       parser.commitLocations();
       // Clean up and prioritize
+      adjustForPartialBackticks(parser);
       prioritizeSuggestions();
     } catch (err) {
       if (debug) {

+ 2 - 1
desktop/core/src/desktop/js/parse/sql/generic/test/genericAutocompleteParser.Select.test.js

@@ -232,8 +232,9 @@ describe('genericAutocompleteParser.js SELECT statements', () => {
       afterCursor: '',
       expectedResult: {
         lowerCase: false,
-        suggestTables: {},
+        suggestTables: { appendBacktick: true },
         suggestDatabases: {
+          appendBacktick: true,
           appendDot: true
         }
       }

+ 2 - 92
desktop/core/src/desktop/js/parse/sql/generic/test/genericAutocompleteParser.test.js

@@ -14,6 +14,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+import { assertPartials } from 'parse/sql/sharedParserTests';
 import genericAutocompleteParser from '../genericAutocompleteParser';
 
 describe('genericAutocompleteParser.js', () => {
@@ -277,98 +278,7 @@ describe('genericAutocompleteParser.js', () => {
 
   describe('partial removal', () => {
     it('should identify part lengths', () => {
-      const limitChars = [
-        ' ',
-        '\n',
-        '\t',
-        '&',
-        '~',
-        '%',
-        '!',
-        '.',
-        ',',
-        '+',
-        '-',
-        '*',
-        '/',
-        '=',
-        '<',
-        '>',
-        ')',
-        '[',
-        ']',
-        ';'
-      ];
-
-      expect(genericAutocompleteParser.identifyPartials('', '')).toEqual({ left: 0, right: 0 });
-      expect(genericAutocompleteParser.identifyPartials('foo', '')).toEqual({ left: 3, right: 0 });
-      expect(genericAutocompleteParser.identifyPartials(' foo', '')).toEqual({ left: 3, right: 0 });
-      expect(genericAutocompleteParser.identifyPartials('asdf 1234', '')).toEqual({
-        left: 4,
-        right: 0
-      });
-
-      expect(genericAutocompleteParser.identifyPartials('foo', 'bar')).toEqual({
-        left: 3,
-        right: 3
-      });
-
-      expect(genericAutocompleteParser.identifyPartials('fo', 'o()')).toEqual({
-        left: 2,
-        right: 3
-      });
-
-      expect(genericAutocompleteParser.identifyPartials('fo', 'o(')).toEqual({ left: 2, right: 2 });
-      expect(genericAutocompleteParser.identifyPartials('fo', 'o(bla bla)')).toEqual({
-        left: 2,
-        right: 10
-      });
-
-      expect(genericAutocompleteParser.identifyPartials('foo ', '')).toEqual({ left: 0, right: 0 });
-      expect(genericAutocompleteParser.identifyPartials("foo '", "'")).toEqual({
-        left: 0,
-        right: 0
-      });
-
-      expect(genericAutocompleteParser.identifyPartials('foo "', '"')).toEqual({
-        left: 0,
-        right: 0
-      });
-      limitChars.forEach(char => {
-        expect(genericAutocompleteParser.identifyPartials('bar foo' + char, '')).toEqual({
-          left: 0,
-          right: 0
-        });
-
-        expect(genericAutocompleteParser.identifyPartials('bar foo' + char + 'foofoo', '')).toEqual(
-          {
-            left: 6,
-            right: 0
-          }
-        );
-
-        expect(
-          genericAutocompleteParser.identifyPartials('bar foo' + char + 'foofoo ', '')
-        ).toEqual({
-          left: 0,
-          right: 0
-        });
-
-        expect(genericAutocompleteParser.identifyPartials('', char + 'foo bar')).toEqual({
-          left: 0,
-          right: 0
-        });
-
-        expect(genericAutocompleteParser.identifyPartials('', 'foofoo' + char)).toEqual({
-          left: 0,
-          right: 6
-        });
-
-        expect(genericAutocompleteParser.identifyPartials('', ' foofoo' + char)).toEqual({
-          left: 0,
-          right: 0
-        });
-      });
+      assertPartials(genericAutocompleteParser);
     });
   });
 });

+ 3 - 10
desktop/core/src/desktop/js/parse/sql/hive/sqlParseSupport.js

@@ -21,7 +21,8 @@ import {
   initSyntaxParser,
   identifierEquals,
   equalIgnoreCase,
-  SIMPLE_TABLE_REF_SUGGESTIONS
+  SIMPLE_TABLE_REF_SUGGESTIONS,
+  adjustForPartialBackticks
 } from 'parse/sql/sqlParseUtils';
 
 const initSqlParser = function (parser) {
@@ -708,15 +709,6 @@ const initSqlParser = function (parser) {
     }
   };
 
-  parser.identifyPartials = function (beforeCursor, afterCursor) {
-    const beforeMatch = beforeCursor.match(/[0-9a-zA-Z_]*$/);
-    const afterMatch = afterCursor.match(/^[0-9a-zA-Z_]*(?:\((?:[^)]*\))?)?/);
-    return {
-      left: beforeMatch ? beforeMatch[0].length : 0,
-      right: afterMatch ? afterMatch[0].length : 0
-    };
-  };
-
   parser.expandLateralViews = function (lateralViews, originalIdentifierChain, columnSuggestion) {
     let identifierChain = originalIdentifierChain.concat(); // Clone in case it's re-used
     let firstIdentifier = identifierChain[0];
@@ -1542,6 +1534,7 @@ const initSqlParser = function (parser) {
       linkTablePrimaries();
       parser.commitLocations();
       // Clean up and prioritize
+      adjustForPartialBackticks(parser);
       prioritizeSuggestions();
     } catch (err) {
       if (debug) {

+ 2 - 1
desktop/core/src/desktop/js/parse/sql/hive/test/hiveAutocompleteParser.Select.test.js

@@ -179,8 +179,9 @@ describe('hiveAutocompleteParser.js SELECT statements', () => {
       afterCursor: '',
       expectedResult: {
         lowerCase: false,
-        suggestTables: {},
+        suggestTables: { appendBacktick: true },
         suggestDatabases: {
+          appendBacktick: true,
           appendDot: true
         }
       }

+ 2 - 73
desktop/core/src/desktop/js/parse/sql/hive/test/hiveAutocompleteParser.test.js

@@ -14,6 +14,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+import { assertPartials } from 'parse/sql/sharedParserTests';
 import hiveAutocompleteParser from '../hiveAutocompleteParser';
 describe('hiveAutocompleteParser.js', () => {
   beforeAll(() => {
@@ -368,79 +369,7 @@ describe('hiveAutocompleteParser.js', () => {
 
   describe('partial removal', () => {
     it('should identify part lengths', () => {
-      const limitChars = [
-        ' ',
-        '\n',
-        '\t',
-        '&',
-        '~',
-        '%',
-        '!',
-        '.',
-        ',',
-        '+',
-        '-',
-        '*',
-        '/',
-        '=',
-        '<',
-        '>',
-        ')',
-        '[',
-        ']',
-        ';'
-      ];
-
-      expect(hiveAutocompleteParser.identifyPartials('', '')).toEqual({ left: 0, right: 0 });
-      expect(hiveAutocompleteParser.identifyPartials('foo', '')).toEqual({ left: 3, right: 0 });
-      expect(hiveAutocompleteParser.identifyPartials(' foo', '')).toEqual({ left: 3, right: 0 });
-      expect(hiveAutocompleteParser.identifyPartials('asdf 1234', '')).toEqual({
-        left: 4,
-        right: 0
-      });
-
-      expect(hiveAutocompleteParser.identifyPartials('foo', 'bar')).toEqual({ left: 3, right: 3 });
-      expect(hiveAutocompleteParser.identifyPartials('fo', 'o()')).toEqual({ left: 2, right: 3 });
-      expect(hiveAutocompleteParser.identifyPartials('fo', 'o(')).toEqual({ left: 2, right: 2 });
-      expect(hiveAutocompleteParser.identifyPartials('fo', 'o(bla bla)')).toEqual({
-        left: 2,
-        right: 10
-      });
-
-      expect(hiveAutocompleteParser.identifyPartials('foo ', '')).toEqual({ left: 0, right: 0 });
-      expect(hiveAutocompleteParser.identifyPartials("foo '", "'")).toEqual({ left: 0, right: 0 });
-      expect(hiveAutocompleteParser.identifyPartials('foo "', '"')).toEqual({ left: 0, right: 0 });
-      limitChars.forEach(char => {
-        expect(hiveAutocompleteParser.identifyPartials('bar foo' + char, '')).toEqual({
-          left: 0,
-          right: 0
-        });
-
-        expect(hiveAutocompleteParser.identifyPartials('bar foo' + char + 'foofoo', '')).toEqual({
-          left: 6,
-          right: 0
-        });
-
-        expect(hiveAutocompleteParser.identifyPartials('bar foo' + char + 'foofoo ', '')).toEqual({
-          left: 0,
-          right: 0
-        });
-
-        expect(hiveAutocompleteParser.identifyPartials('', char + 'foo bar')).toEqual({
-          left: 0,
-          right: 0
-        });
-
-        expect(hiveAutocompleteParser.identifyPartials('', 'foofoo' + char)).toEqual({
-          left: 0,
-          right: 6
-        });
-
-        expect(hiveAutocompleteParser.identifyPartials('', ' foofoo' + char)).toEqual({
-          left: 0,
-          right: 0
-        });
-      });
+      assertPartials(hiveAutocompleteParser);
     });
   });
 

+ 3 - 10
desktop/core/src/desktop/js/parse/sql/impala/sqlParseSupport.js

@@ -20,7 +20,8 @@ import {
   initSharedAutocomplete,
   identifierEquals,
   equalIgnoreCase,
-  SIMPLE_TABLE_REF_SUGGESTIONS
+  SIMPLE_TABLE_REF_SUGGESTIONS,
+  adjustForPartialBackticks
 } from 'parse/sql/sqlParseUtils';
 
 const initSqlParser = function (parser) {
@@ -917,15 +918,6 @@ const initSqlParser = function (parser) {
     return expand(expandedChain[0].name, expandedChain);
   };
 
-  parser.identifyPartials = function (beforeCursor, afterCursor) {
-    const beforeMatch = beforeCursor.match(/[0-9a-zA-Z_]*$/);
-    const afterMatch = afterCursor.match(/^[0-9a-zA-Z_]*(?:\((?:[^)]*\))?)?/);
-    return {
-      left: beforeMatch ? beforeMatch[0].length : 0,
-      right: afterMatch ? afterMatch[0].length : 0
-    };
-  };
-
   const addCleanTablePrimary = function (tables, tablePrimary) {
     if (tablePrimary.alias) {
       tables.push({ alias: tablePrimary.alias, identifierChain: tablePrimary.identifierChain });
@@ -1669,6 +1661,7 @@ const initSqlParser = function (parser) {
       linkTablePrimaries();
       parser.commitLocations();
       // Clean up and prioritize
+      adjustForPartialBackticks(parser);
       prioritizeSuggestions();
     } catch (err) {
       if (debug) {

+ 2 - 1
desktop/core/src/desktop/js/parse/sql/impala/test/impalaAutocompleteParser.Select.test.js

@@ -180,8 +180,9 @@ describe('impalaAutocompleteParser.js SELECT statements', () => {
       afterCursor: '',
       expectedResult: {
         lowerCase: false,
-        suggestTables: {},
+        suggestTables: { appendBacktick: true },
         suggestDatabases: {
+          appendBacktick: true,
           appendDot: true
         }
       }

+ 2 - 86
desktop/core/src/desktop/js/parse/sql/impala/test/impalaAutocompleteParser.test.js

@@ -14,6 +14,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+import { assertPartials } from 'parse/sql/sharedParserTests';
 import impalaAutocompleteParser from '../impalaAutocompleteParser';
 describe('impalaAutocompleteParser.js', () => {
   beforeAll(() => {
@@ -407,92 +408,7 @@ describe('impalaAutocompleteParser.js', () => {
 
   describe('partial removal', () => {
     it('should identify part lengths', () => {
-      const limitChars = [
-        ' ',
-        '\n',
-        '\t',
-        '&',
-        '~',
-        '%',
-        '!',
-        '.',
-        ',',
-        '+',
-        '-',
-        '*',
-        '/',
-        '=',
-        '<',
-        '>',
-        ')',
-        '[',
-        ']',
-        ';'
-      ];
-
-      expect(impalaAutocompleteParser.identifyPartials('', '')).toEqual({ left: 0, right: 0 });
-      expect(impalaAutocompleteParser.identifyPartials('foo', '')).toEqual({ left: 3, right: 0 });
-      expect(impalaAutocompleteParser.identifyPartials(' foo', '')).toEqual({ left: 3, right: 0 });
-      expect(impalaAutocompleteParser.identifyPartials('asdf 1234', '')).toEqual({
-        left: 4,
-        right: 0
-      });
-
-      expect(impalaAutocompleteParser.identifyPartials('foo', 'bar')).toEqual({
-        left: 3,
-        right: 3
-      });
-
-      expect(impalaAutocompleteParser.identifyPartials('fo', 'o()')).toEqual({ left: 2, right: 3 });
-      expect(impalaAutocompleteParser.identifyPartials('fo', 'o(')).toEqual({ left: 2, right: 2 });
-      expect(impalaAutocompleteParser.identifyPartials('fo', 'o(bla bla)')).toEqual({
-        left: 2,
-        right: 10
-      });
-
-      expect(impalaAutocompleteParser.identifyPartials('foo ', '')).toEqual({ left: 0, right: 0 });
-      expect(impalaAutocompleteParser.identifyPartials("foo '", "'")).toEqual({
-        left: 0,
-        right: 0
-      });
-
-      expect(impalaAutocompleteParser.identifyPartials('foo "', '"')).toEqual({
-        left: 0,
-        right: 0
-      });
-      limitChars.forEach(char => {
-        expect(impalaAutocompleteParser.identifyPartials('bar foo' + char, '')).toEqual({
-          left: 0,
-          right: 0
-        });
-
-        expect(impalaAutocompleteParser.identifyPartials('bar foo' + char + 'foofoo', '')).toEqual({
-          left: 6,
-          right: 0
-        });
-
-        expect(impalaAutocompleteParser.identifyPartials('bar foo' + char + 'foofoo ', '')).toEqual(
-          {
-            left: 0,
-            right: 0
-          }
-        );
-
-        expect(impalaAutocompleteParser.identifyPartials('', char + 'foo bar')).toEqual({
-          left: 0,
-          right: 0
-        });
-
-        expect(impalaAutocompleteParser.identifyPartials('', 'foofoo' + char)).toEqual({
-          left: 0,
-          right: 6
-        });
-
-        expect(impalaAutocompleteParser.identifyPartials('', ' foofoo' + char)).toEqual({
-          left: 0,
-          right: 0
-        });
-      });
+      assertPartials(impalaAutocompleteParser);
     });
   });
 });

+ 3 - 10
desktop/core/src/desktop/js/parse/sql/ksql/sqlParseSupport.js

@@ -20,7 +20,8 @@ import {
   initSyntaxParser,
   identifierEquals,
   equalIgnoreCase,
-  SIMPLE_TABLE_REF_SUGGESTIONS
+  SIMPLE_TABLE_REF_SUGGESTIONS,
+  adjustForPartialBackticks
 } from 'parse/sql/sqlParseUtils';
 
 const initSqlParser = function (parser) {
@@ -645,15 +646,6 @@ const initSqlParser = function (parser) {
     }
   };
 
-  parser.identifyPartials = function (beforeCursor, afterCursor) {
-    const beforeMatch = beforeCursor.match(/[0-9a-zA-Z_]*$/);
-    const afterMatch = afterCursor.match(/^[0-9a-zA-Z_]*(?:\((?:[^)]*\))?)?/);
-    return {
-      left: beforeMatch ? beforeMatch[0].length : 0,
-      right: afterMatch ? afterMatch[0].length : 0
-    };
-  };
-
   const addCleanTablePrimary = function (tables, tablePrimary) {
     if (tablePrimary.alias) {
       tables.push({ alias: tablePrimary.alias, identifierChain: tablePrimary.identifierChain });
@@ -1363,6 +1355,7 @@ const initSqlParser = function (parser) {
       linkTablePrimaries();
       parser.commitLocations();
       // Clean up and prioritize
+      adjustForPartialBackticks(parser);
       prioritizeSuggestions();
     } catch (err) {
       if (debug) {

+ 2 - 1
desktop/core/src/desktop/js/parse/sql/ksql/test/ksqlAutocompleteParser.Select.test.js

@@ -232,8 +232,9 @@ describe('ksqlAutocompleteParser.js SELECT statements', () => {
       afterCursor: '',
       expectedResult: {
         lowerCase: false,
-        suggestTables: {},
+        suggestTables: { appendBacktick: true },
         suggestDatabases: {
+          appendBacktick: true,
           appendDot: true
         }
       }

+ 2 - 88
desktop/core/src/desktop/js/parse/sql/ksql/test/ksqlAutocompleteParser.test.js

@@ -14,6 +14,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+import { assertPartials } from 'parse/sql/sharedParserTests';
 import ksqlAutocompleteParser from '../ksqlAutocompleteParser';
 
 describe('ksqlAutocompleteParser.js', () => {
@@ -277,94 +278,7 @@ describe('ksqlAutocompleteParser.js', () => {
 
   describe('partial removal', () => {
     it('should identify part lengths', () => {
-      const limitChars = [
-        ' ',
-        '\n',
-        '\t',
-        '&',
-        '~',
-        '%',
-        '!',
-        '.',
-        ',',
-        '+',
-        '-',
-        '*',
-        '/',
-        '=',
-        '<',
-        '>',
-        ')',
-        '[',
-        ']',
-        ';'
-      ];
-
-      expect(ksqlAutocompleteParser.identifyPartials('', '')).toEqual({ left: 0, right: 0 });
-      expect(ksqlAutocompleteParser.identifyPartials('foo', '')).toEqual({ left: 3, right: 0 });
-      expect(ksqlAutocompleteParser.identifyPartials(' foo', '')).toEqual({ left: 3, right: 0 });
-      expect(ksqlAutocompleteParser.identifyPartials('asdf 1234', '')).toEqual({
-        left: 4,
-        right: 0
-      });
-
-      expect(ksqlAutocompleteParser.identifyPartials('foo', 'bar')).toEqual({
-        left: 3,
-        right: 3
-      });
-
-      expect(ksqlAutocompleteParser.identifyPartials('fo', 'o()')).toEqual({
-        left: 2,
-        right: 3
-      });
-
-      expect(ksqlAutocompleteParser.identifyPartials('fo', 'o(')).toEqual({ left: 2, right: 2 });
-      expect(ksqlAutocompleteParser.identifyPartials('fo', 'o(bla bla)')).toEqual({
-        left: 2,
-        right: 10
-      });
-
-      expect(ksqlAutocompleteParser.identifyPartials('foo ', '')).toEqual({ left: 0, right: 0 });
-      expect(ksqlAutocompleteParser.identifyPartials("foo '", "'")).toEqual({
-        left: 0,
-        right: 0
-      });
-
-      expect(ksqlAutocompleteParser.identifyPartials('foo "', '"')).toEqual({
-        left: 0,
-        right: 0
-      });
-      limitChars.forEach(char => {
-        expect(ksqlAutocompleteParser.identifyPartials('bar foo' + char, '')).toEqual({
-          left: 0,
-          right: 0
-        });
-
-        expect(ksqlAutocompleteParser.identifyPartials('bar foo' + char + 'foofoo', '')).toEqual({
-          left: 6,
-          right: 0
-        });
-
-        expect(ksqlAutocompleteParser.identifyPartials('bar foo' + char + 'foofoo ', '')).toEqual({
-          left: 0,
-          right: 0
-        });
-
-        expect(ksqlAutocompleteParser.identifyPartials('', char + 'foo bar')).toEqual({
-          left: 0,
-          right: 0
-        });
-
-        expect(ksqlAutocompleteParser.identifyPartials('', 'foofoo' + char)).toEqual({
-          left: 0,
-          right: 6
-        });
-
-        expect(ksqlAutocompleteParser.identifyPartials('', ' foofoo' + char)).toEqual({
-          left: 0,
-          right: 0
-        });
-      });
+      assertPartials(ksqlAutocompleteParser);
     });
   });
 });

+ 3 - 10
desktop/core/src/desktop/js/parse/sql/phoenix/sqlParseSupport.js

@@ -20,7 +20,8 @@ import {
   initSyntaxParser,
   identifierEquals,
   equalIgnoreCase,
-  SIMPLE_TABLE_REF_SUGGESTIONS
+  SIMPLE_TABLE_REF_SUGGESTIONS,
+  adjustForPartialBackticks
 } from 'parse/sql/sqlParseUtils';
 
 const initSqlParser = function (parser) {
@@ -645,15 +646,6 @@ const initSqlParser = function (parser) {
     }
   };
 
-  parser.identifyPartials = function (beforeCursor, afterCursor) {
-    const beforeMatch = beforeCursor.match(/[0-9a-zA-Z_]*$/);
-    const afterMatch = afterCursor.match(/^[0-9a-zA-Z_]*(?:\((?:[^)]*\))?)?/);
-    return {
-      left: beforeMatch ? beforeMatch[0].length : 0,
-      right: afterMatch ? afterMatch[0].length : 0
-    };
-  };
-
   const addCleanTablePrimary = function (tables, tablePrimary) {
     if (tablePrimary.alias) {
       tables.push({ alias: tablePrimary.alias, identifierChain: tablePrimary.identifierChain });
@@ -1368,6 +1360,7 @@ const initSqlParser = function (parser) {
       linkTablePrimaries();
       parser.commitLocations();
       // Clean up and prioritize
+      adjustForPartialBackticks(parser);
       prioritizeSuggestions();
     } catch (err) {
       if (debug) {

+ 2 - 1
desktop/core/src/desktop/js/parse/sql/phoenix/test/phoenixAutocompleteParser.Select.test.js

@@ -232,8 +232,9 @@ describe('phoenixAutocompleteParser.js SELECT statements', () => {
       afterCursor: '',
       expectedResult: {
         lowerCase: false,
-        suggestTables: {},
+        suggestTables: { appendBacktick: true },
         suggestDatabases: {
+          appendBacktick: true,
           appendDot: true
         }
       }

+ 2 - 92
desktop/core/src/desktop/js/parse/sql/phoenix/test/phoenixAutocompleteParser.test.js

@@ -14,6 +14,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+import { assertPartials } from 'parse/sql/sharedParserTests';
 import phoenixAutocompleteParser from '../phoenixAutocompleteParser';
 
 describe('phoenixAutocompleteParser.js', () => {
@@ -277,98 +278,7 @@ describe('phoenixAutocompleteParser.js', () => {
 
   describe('partial removal', () => {
     it('should identify part lengths', () => {
-      const limitChars = [
-        ' ',
-        '\n',
-        '\t',
-        '&',
-        '~',
-        '%',
-        '!',
-        '.',
-        ',',
-        '+',
-        '-',
-        '*',
-        '/',
-        '=',
-        '<',
-        '>',
-        ')',
-        '[',
-        ']',
-        ';'
-      ];
-
-      expect(phoenixAutocompleteParser.identifyPartials('', '')).toEqual({ left: 0, right: 0 });
-      expect(phoenixAutocompleteParser.identifyPartials('foo', '')).toEqual({ left: 3, right: 0 });
-      expect(phoenixAutocompleteParser.identifyPartials(' foo', '')).toEqual({ left: 3, right: 0 });
-      expect(phoenixAutocompleteParser.identifyPartials('asdf 1234', '')).toEqual({
-        left: 4,
-        right: 0
-      });
-
-      expect(phoenixAutocompleteParser.identifyPartials('foo', 'bar')).toEqual({
-        left: 3,
-        right: 3
-      });
-
-      expect(phoenixAutocompleteParser.identifyPartials('fo', 'o()')).toEqual({
-        left: 2,
-        right: 3
-      });
-
-      expect(phoenixAutocompleteParser.identifyPartials('fo', 'o(')).toEqual({ left: 2, right: 2 });
-      expect(phoenixAutocompleteParser.identifyPartials('fo', 'o(bla bla)')).toEqual({
-        left: 2,
-        right: 10
-      });
-
-      expect(phoenixAutocompleteParser.identifyPartials('foo ', '')).toEqual({ left: 0, right: 0 });
-      expect(phoenixAutocompleteParser.identifyPartials("foo '", "'")).toEqual({
-        left: 0,
-        right: 0
-      });
-
-      expect(phoenixAutocompleteParser.identifyPartials('foo "', '"')).toEqual({
-        left: 0,
-        right: 0
-      });
-      limitChars.forEach(char => {
-        expect(phoenixAutocompleteParser.identifyPartials('bar foo' + char, '')).toEqual({
-          left: 0,
-          right: 0
-        });
-
-        expect(phoenixAutocompleteParser.identifyPartials('bar foo' + char + 'foofoo', '')).toEqual(
-          {
-            left: 6,
-            right: 0
-          }
-        );
-
-        expect(
-          phoenixAutocompleteParser.identifyPartials('bar foo' + char + 'foofoo ', '')
-        ).toEqual({
-          left: 0,
-          right: 0
-        });
-
-        expect(phoenixAutocompleteParser.identifyPartials('', char + 'foo bar')).toEqual({
-          left: 0,
-          right: 0
-        });
-
-        expect(phoenixAutocompleteParser.identifyPartials('', 'foofoo' + char)).toEqual({
-          left: 0,
-          right: 6
-        });
-
-        expect(phoenixAutocompleteParser.identifyPartials('', ' foofoo' + char)).toEqual({
-          left: 0,
-          right: 0
-        });
-      });
+      assertPartials(phoenixAutocompleteParser);
     });
   });
 });

+ 3 - 10
desktop/core/src/desktop/js/parse/sql/presto/sqlParseSupport.js

@@ -20,7 +20,8 @@ import {
   initSyntaxParser,
   identifierEquals,
   equalIgnoreCase,
-  SIMPLE_TABLE_REF_SUGGESTIONS
+  SIMPLE_TABLE_REF_SUGGESTIONS,
+  adjustForPartialBackticks
 } from 'parse/sql/sqlParseUtils';
 
 const initSqlParser = function (parser) {
@@ -679,15 +680,6 @@ const initSqlParser = function (parser) {
     }
   };
 
-  parser.identifyPartials = function (beforeCursor, afterCursor) {
-    const beforeMatch = beforeCursor.match(/[0-9a-zA-Z_]*$/);
-    const afterMatch = afterCursor.match(/^[0-9a-zA-Z_]*(?:\((?:[^)]*\))?)?/);
-    return {
-      left: beforeMatch ? beforeMatch[0].length : 0,
-      right: afterMatch ? afterMatch[0].length : 0
-    };
-  };
-
   parser.expandLateralViews = function (lateralViews, originalIdentifierChain, columnSuggestion) {
     let identifierChain = originalIdentifierChain.concat(); // Clone in case it's re-used
     let firstIdentifier = identifierChain[0];
@@ -1532,6 +1524,7 @@ const initSqlParser = function (parser) {
       linkTablePrimaries();
       parser.commitLocations();
       // Clean up and prioritize
+      adjustForPartialBackticks(parser);
       prioritizeSuggestions();
     } catch (err) {
       if (debug) {

+ 2 - 1
desktop/core/src/desktop/js/parse/sql/presto/test/prestoAutocompleteParser.Select.test.js

@@ -179,8 +179,9 @@ describe('prestoAutocompleteParser.js SELECT statements', () => {
       afterCursor: '',
       expectedResult: {
         lowerCase: false,
-        suggestTables: {},
+        suggestTables: { appendBacktick: true },
         suggestDatabases: {
+          appendBacktick: true,
           appendDot: true
         }
       }

+ 2 - 87
desktop/core/src/desktop/js/parse/sql/presto/test/prestoAutocompleteParser.test.js

@@ -14,6 +14,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+import { assertPartials } from 'parse/sql/sharedParserTests';
 import prestoAutocompleteParser from '../prestoAutocompleteParser';
 describe('prestoAutocompleteParser.js', () => {
   beforeAll(() => {
@@ -430,93 +431,7 @@ describe('prestoAutocompleteParser.js', () => {
 
   describe('partial removal', () => {
     it('should identify part lengths', () => {
-      const limitChars = [
-        ' ',
-        '\n',
-        '\t',
-        '&',
-        '~',
-        '%',
-        '!',
-        '.',
-        ',',
-        '+',
-        '-',
-        '*',
-        '/',
-        '=',
-        '<',
-        '>',
-        ')',
-        '[',
-        ']',
-        ';'
-      ];
-
-      expect(prestoAutocompleteParser.identifyPartials('', '')).toEqual({ left: 0, right: 0 });
-      expect(prestoAutocompleteParser.identifyPartials('foo', '')).toEqual({ left: 3, right: 0 });
-      expect(prestoAutocompleteParser.identifyPartials(' foo', '')).toEqual({ left: 3, right: 0 });
-      expect(prestoAutocompleteParser.identifyPartials('asdf 1234', '')).toEqual({
-        left: 4,
-        right: 0
-      });
-
-      expect(prestoAutocompleteParser.identifyPartials('foo', 'bar')).toEqual({
-        left: 3,
-        right: 3
-      });
-
-      expect(prestoAutocompleteParser.identifyPartials('fo', 'o()')).toEqual({ left: 2, right: 3 });
-      expect(prestoAutocompleteParser.identifyPartials('fo', 'o(')).toEqual({ left: 2, right: 2 });
-      expect(prestoAutocompleteParser.identifyPartials('fo', 'o(bla bla)')).toEqual({
-        left: 2,
-        right: 10
-      });
-
-      expect(prestoAutocompleteParser.identifyPartials('foo ', '')).toEqual({ left: 0, right: 0 });
-      expect(prestoAutocompleteParser.identifyPartials("foo '", "'")).toEqual({
-        left: 0,
-        right: 0
-      });
-
-      expect(prestoAutocompleteParser.identifyPartials('foo "', '"')).toEqual({
-        left: 0,
-        right: 0
-      });
-
-      limitChars.forEach(char => {
-        expect(prestoAutocompleteParser.identifyPartials('bar foo' + char, '')).toEqual({
-          left: 0,
-          right: 0
-        });
-
-        expect(prestoAutocompleteParser.identifyPartials('bar foo' + char + 'foofoo', '')).toEqual({
-          left: 6,
-          right: 0
-        });
-
-        expect(prestoAutocompleteParser.identifyPartials('bar foo' + char + 'foofoo ', '')).toEqual(
-          {
-            left: 0,
-            right: 0
-          }
-        );
-
-        expect(prestoAutocompleteParser.identifyPartials('', char + 'foo bar')).toEqual({
-          left: 0,
-          right: 0
-        });
-
-        expect(prestoAutocompleteParser.identifyPartials('', 'foofoo' + char)).toEqual({
-          left: 0,
-          right: 6
-        });
-
-        expect(prestoAutocompleteParser.identifyPartials('', ' foofoo' + char)).toEqual({
-          left: 0,
-          right: 0
-        });
-      });
+      assertPartials(prestoAutocompleteParser);
     });
   });
 

+ 146 - 0
desktop/core/src/desktop/js/parse/sql/sharedParserTests.ts

@@ -0,0 +1,146 @@
+interface CommonParser {
+  identifyPartials(
+    beforeCursor: string,
+    afterCursor: string
+  ): { backtickAfter: boolean; backtickBefore: boolean; left: number; right: number };
+}
+
+export const assertPartials = (parser: CommonParser): void => {
+  const limitChars = [
+    ' ',
+    '\n',
+    '\t',
+    '&',
+    '~',
+    '%',
+    '!',
+    '.',
+    ',',
+    '+',
+    '-',
+    '*',
+    '/',
+    '=',
+    '<',
+    '>',
+    ')',
+    '[',
+    ']',
+    ';'
+  ];
+
+  expect(parser.identifyPartials('', '')).toEqual({
+    backtickAfter: false,
+    backtickBefore: false,
+    left: 0,
+    right: 0
+  });
+  expect(parser.identifyPartials('foo', '')).toEqual({
+    backtickAfter: false,
+    backtickBefore: false,
+    left: 3,
+    right: 0
+  });
+  expect(parser.identifyPartials(' foo', '')).toEqual({
+    backtickAfter: false,
+    backtickBefore: false,
+    left: 3,
+    right: 0
+  });
+  expect(parser.identifyPartials('asdf 1234', '')).toEqual({
+    backtickAfter: false,
+    backtickBefore: false,
+    left: 4,
+    right: 0
+  });
+
+  expect(parser.identifyPartials('foo', 'bar')).toEqual({
+    backtickAfter: false,
+    backtickBefore: false,
+    left: 3,
+    right: 3
+  });
+
+  expect(parser.identifyPartials('fo', 'o()')).toEqual({
+    backtickAfter: false,
+    backtickBefore: false,
+    left: 2,
+    right: 3
+  });
+
+  expect(parser.identifyPartials('fo', 'o(')).toEqual({
+    backtickAfter: false,
+    backtickBefore: false,
+    left: 2,
+    right: 2
+  });
+  expect(parser.identifyPartials('fo', 'o(bla bla)')).toEqual({
+    backtickAfter: false,
+    backtickBefore: false,
+    left: 2,
+    right: 10
+  });
+
+  expect(parser.identifyPartials('foo ', '')).toEqual({
+    backtickAfter: false,
+    backtickBefore: false,
+    left: 0,
+    right: 0
+  });
+  expect(parser.identifyPartials("foo '", "'")).toEqual({
+    backtickAfter: false,
+    backtickBefore: false,
+    left: 0,
+    right: 0
+  });
+
+  expect(parser.identifyPartials('foo "', '"')).toEqual({
+    backtickAfter: false,
+    backtickBefore: false,
+    left: 0,
+    right: 0
+  });
+  limitChars.forEach(char => {
+    expect(parser.identifyPartials('bar foo' + char, '')).toEqual({
+      backtickAfter: false,
+      backtickBefore: false,
+      left: 0,
+      right: 0
+    });
+
+    expect(parser.identifyPartials('bar foo' + char + 'foofoo', '')).toEqual({
+      backtickAfter: false,
+      backtickBefore: false,
+      left: 6,
+      right: 0
+    });
+
+    expect(parser.identifyPartials('bar foo' + char + 'foofoo ', '')).toEqual({
+      backtickAfter: false,
+      backtickBefore: false,
+      left: 0,
+      right: 0
+    });
+
+    expect(parser.identifyPartials('', char + 'foo bar')).toEqual({
+      backtickAfter: false,
+      backtickBefore: false,
+      left: 0,
+      right: 0
+    });
+
+    expect(parser.identifyPartials('', 'foofoo' + char)).toEqual({
+      backtickAfter: false,
+      backtickBefore: false,
+      left: 0,
+      right: 6
+    });
+
+    expect(parser.identifyPartials('', ' foofoo' + char)).toEqual({
+      backtickAfter: false,
+      backtickBefore: false,
+      left: 0,
+      right: 0
+    });
+  });
+};

+ 32 - 0
desktop/core/src/desktop/js/parse/sql/sqlParseUtils.js

@@ -65,6 +65,24 @@ export const LOCATION_TYPES = {
   VARIABLE: 'variable'
 };
 
+const APPEND_BACKTICK_SUGGESTIONS = [
+  'suggestColumns',
+  'suggestCommonTableExpressions',
+  'suggestDatabases',
+  'suggestTables'
+];
+
+export const adjustForPartialBackticks = parser => {
+  const partials = parser.yy.partialLengths;
+  if (parser.yy.result && partials.backtickBefore && !partials.backtickAfter) {
+    APPEND_BACKTICK_SUGGESTIONS.forEach(suggestionType => {
+      if (parser.yy.result[suggestionType]) {
+        parser.yy.result[suggestionType].appendBacktick = true;
+      }
+    });
+  }
+};
+
 export const initSharedAutocomplete = parser => {
   parser.SELECT_FIRST_OPTIONAL_KEYWORDS = [
     { value: 'ALL', weight: 2 },
@@ -548,6 +566,20 @@ export const initSharedAutocomplete = parser => {
     };
   };
 
+  const PARTIAL_BEFORE_REGEX = /[0-9a-zA-Z_`]*$/;
+  const PARTIAL_AFTER_REGEX = /^[0-9a-zA-Z_`]*(?:\((?:[^)]*\))?)?/;
+
+  parser.identifyPartials = function (beforeCursor, afterCursor) {
+    const beforeMatch = beforeCursor.match(PARTIAL_BEFORE_REGEX);
+    const afterMatch = afterCursor.match(PARTIAL_AFTER_REGEX);
+    return {
+      left: beforeMatch ? beforeMatch[0].length : 0,
+      right: afterMatch ? afterMatch[0].length : 0,
+      backtickBefore: beforeMatch && beforeMatch[0].indexOf('`') !== -1,
+      backtickAfter: afterMatch && afterMatch[0].indexOf('`') !== -1
+    };
+  };
+
   parser.suggestKeywords = keywords => {
     if (typeof keywords === 'string') {
       keywords = (parser.KEYWORDS && parser.KEYWORDS[keywords]) || [];

+ 4 - 0
desktop/core/src/desktop/js/parse/types.ts

@@ -119,6 +119,7 @@ export interface AutocompleteParseResult {
   };
   suggestColumnAliases?: ColumnAliasDetails[];
   suggestColumns?: {
+    appendBacktick?: boolean;
     identifierChain?: IdentifierChainEntry[];
     source?: string;
     tables: ParsedTable[];
@@ -126,11 +127,13 @@ export interface AutocompleteParseResult {
     udfRef?: string;
   };
   suggestCommonTableExpressions?: {
+    appendBacktick?: boolean;
     name: string;
     prependFrom: boolean;
     prependQuestionMark: boolean;
   }[];
   suggestDatabases?: {
+    appendBacktick?: boolean;
     appendDot?: boolean;
     prependFrom?: boolean;
     prependQuestionMark?: boolean;
@@ -167,6 +170,7 @@ export interface AutocompleteParseResult {
   suggestOrderBys?: CommonPopularSuggestion;
   suggestSetOptions?: boolean;
   suggestTables?: {
+    appendBacktick?: boolean;
     identifierChain?: IdentifierChainEntry[];
     onlyTables?: boolean;
     onlyViews?: boolean;

+ 37 - 7
desktop/core/src/desktop/js/sql/autocompleteResults.js

@@ -852,7 +852,12 @@ class AutocompleteResults {
           databaseSuggestions.push({
             value:
               prefix +
-              (await sqlUtils.backTickIfNeeded(this.snippet.connector(), dbEntry.name)) +
+              (await sqlUtils.backTickIfNeeded(
+                this.snippet.connector(),
+                dbEntry.name,
+                undefined,
+                suggestDatabases.appendBacktick
+              )) +
               (suggestDatabases.appendDot ? '.' : ''),
             filterValue: dbEntry.name,
             meta: META_I18n.database,
@@ -920,7 +925,13 @@ class AutocompleteResults {
           }
           tableSuggestions.push({
             value:
-              prefix + (await sqlUtils.backTickIfNeeded(this.snippet.connector(), tableEntry.name)),
+              prefix +
+              (await sqlUtils.backTickIfNeeded(
+                this.snippet.connector(),
+                tableEntry.name,
+                undefined,
+                suggestTables.appendBacktick
+              )),
             filterValue: tableEntry.name,
             tableName: tableEntry.name,
             meta: META_I18n[tableEntry.getType().toLowerCase()],
@@ -1042,7 +1053,12 @@ class AutocompleteResults {
         typeof column.type !== 'undefined' && column.type !== 'COLREF' ? column.type : 'T';
       if (typeof column.alias !== 'undefined') {
         columnSuggestions.push({
-          value: await sqlUtils.backTickIfNeeded(this.snippet.connector(), column.alias),
+          value: await sqlUtils.backTickIfNeeded(
+            this.snippet.connector(),
+            column.alias,
+            undefined,
+            this.parseResult.suggestColumns?.appendBacktick
+          ),
           filterValue: column.alias,
           meta: type,
           category: CATEGORIES.COLUMN,
@@ -1058,7 +1074,9 @@ class AutocompleteResults {
         columnSuggestions.push({
           value: await sqlUtils.backTickIfNeeded(
             this.snippet.connector(),
-            column.identifierChain[column.identifierChain.length - 1].name
+            column.identifierChain[column.identifierChain.length - 1].name,
+            undefined,
+            this.parseResult.suggestColumns?.appendBacktick
           ),
           filterValue: column.identifierChain[column.identifierChain.length - 1].name,
           meta: type,
@@ -1086,7 +1104,12 @@ class AutocompleteResults {
             typeof column.type !== 'undefined' && column.type !== 'COLREF' ? column.type : 'T';
           if (column.alias) {
             columnSuggestions.push({
-              value: await sqlUtils.backTickIfNeeded(connector, column.alias),
+              value: await sqlUtils.backTickIfNeeded(
+                connector,
+                column.alias,
+                undefined,
+                this.parseResult.suggestColumns?.appendBacktick
+              ),
               filterValue: column.alias,
               meta: type,
               category: CATEGORIES.COLUMN,
@@ -1098,7 +1121,9 @@ class AutocompleteResults {
             columnSuggestions.push({
               value: await sqlUtils.backTickIfNeeded(
                 connector,
-                column.identifierChain[column.identifierChain.length - 1].name
+                column.identifierChain[column.identifierChain.length - 1].name,
+                undefined,
+                this.parseResult.suggestColumns?.appendBacktick
               ),
               filterValue: column.identifierChain[column.identifierChain.length - 1].name,
               meta: type,
@@ -1162,7 +1187,12 @@ class AutocompleteResults {
         });
 
         for (const childEntry of childEntries) {
-          let name = await sqlUtils.backTickIfNeeded(this.snippet.connector(), childEntry.name);
+          let name = await sqlUtils.backTickIfNeeded(
+            this.snippet.connector(),
+            childEntry.name,
+            undefined,
+            this.parseResult.suggestColumns?.appendBacktick
+          );
           if (this.dialect() === DIALECT.hive && (childEntry.isArray() || childEntry.isMap())) {
             name += '[]';
           }

+ 5 - 1
desktop/core/src/desktop/js/sql/sqlUtils.ts

@@ -264,8 +264,12 @@ export default {
   backTickIfNeeded: async (
     connector: Connector,
     identifier: string,
-    sqlReferenceProvider?: SqlReferenceProvider
+    sqlReferenceProvider?: SqlReferenceProvider,
+    forceAppendBacktick?: boolean
   ): Promise<string> => {
+    if (forceAppendBacktick) {
+      return identifier + '`';
+    }
     const quoteChar =
       (connector.dialect_properties && connector.dialect_properties.sql_identifier_quote) || '`';
     if (identifier.indexOf(quoteChar) === 0) {