Browse Source

HUE-9454 [editor] Make it possible to define reserved keyword per dialect

Johan Ahlen 5 years ago
parent
commit
2b7b7b97ce
24 changed files with 2076 additions and 1043 deletions
  1. 0 128
      desktop/core/src/desktop/js/api/cancellablePromise.js
  2. 126 0
      desktop/core/src/desktop/js/api/cancellablePromise.ts
  3. 3 1
      desktop/core/src/desktop/js/catalog/dataCatalog.js
  4. 1 1
      desktop/core/src/desktop/js/catalog/optimizer/baseStrategy.js
  5. 19 0
      desktop/core/src/desktop/js/catalog/types.ts
  6. 2 2
      desktop/core/src/desktop/js/ko/bindings/ace/aceLocationHandler.js
  7. 41 29
      desktop/core/src/desktop/js/ko/components/assist/assistDbEntry.js
  8. 15 9
      desktop/core/src/desktop/js/ko/components/contextPopover/asteriskContextTabs.js
  9. 9 7
      desktop/core/src/desktop/js/ko/components/ko.editorDroppableMenu.js
  10. 31 0
      desktop/core/src/desktop/js/parse/types.ts
  11. 8 7
      desktop/core/src/desktop/js/sql/autocompleteResults.js
  12. 380 0
      desktop/core/src/desktop/js/sql/reference/calcite/reservedKeywords.ts
  13. 103 0
      desktop/core/src/desktop/js/sql/reference/generic/reservedKeywords.ts
  14. 168 0
      desktop/core/src/desktop/js/sql/reference/hive/reservedKeywords.ts
  15. 554 0
      desktop/core/src/desktop/js/sql/reference/impala/reservedKeywords.ts
  16. 118 0
      desktop/core/src/desktop/js/sql/reference/postgresql/reservedKeywords.ts
  17. 87 0
      desktop/core/src/desktop/js/sql/reference/presto/reservedKeywords.ts
  18. 21 0
      desktop/core/src/desktop/js/sql/reference/sqlReferenceRepository.ts
  19. 0 824
      desktop/core/src/desktop/js/sql/sqlUtils.js
  20. 279 0
      desktop/core/src/desktop/js/sql/sqlUtils.ts
  21. 32 0
      desktop/core/src/desktop/js/sql/types.ts
  22. 19 1
      desktop/core/src/desktop/js/types/config.ts
  23. 16 0
      desktop/core/src/desktop/js/types/types.ts
  24. 44 34
      desktop/libs/indexer/src/indexer/templates/importer.mako

+ 0 - 128
desktop/core/src/desktop/js/api/cancellablePromise.js

@@ -1,128 +0,0 @@
-// Licensed to Cloudera, Inc. under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  Cloudera, Inc. licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License.  You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-import $ from 'jquery';
-import { cancelActiveRequest } from './apiUtils';
-
-class CancellablePromise {
-  constructor(deferred, request, otherCancellables) {
-    const self = this;
-    self.cancelCallbacks = [];
-    self.deferred = deferred;
-    self.request = request;
-    self.otherCancellables = otherCancellables;
-    self.cancelled = false;
-    self.cancelPrevented = false;
-  }
-
-  /**
-   * A promise might be shared across multiple components in the UI, in some cases cancel is not an option and calling
-   * this will prevent that to happen.
-   *
-   * One example is autocompletion of databases while the assist is loading the database tree, closing the autocomplete
-   * results would make the assist loading fail if cancel hasn't been prevented.
-   *
-   * @returns {CancellablePromise}
-   */
-  preventCancel() {
-    const self = this;
-    self.cancelPrevented = true;
-    return self;
-  }
-
-  cancel() {
-    const self = this;
-    if (self.cancelPrevented || self.cancelled || self.state() !== 'pending') {
-      return $.Deferred().resolve().promise();
-    }
-
-    self.cancelled = true;
-    if (self.request) {
-      cancelActiveRequest(self.request);
-    }
-
-    if (self.state && self.state() === 'pending' && self.deferred.reject) {
-      self.deferred.reject();
-    }
-
-    const cancelPromises = [];
-    if (self.otherCancellables) {
-      self.otherCancellables.forEach(cancellable => {
-        if (cancellable.cancel) {
-          cancelPromises.push(cancellable.cancel());
-        }
-      });
-    }
-
-    while (self.cancelCallbacks.length) {
-      self.cancelCallbacks.pop()();
-    }
-    return $.when(cancelPromises);
-  }
-
-  onCancel(callback) {
-    const self = this;
-    if (self.cancelled) {
-      callback();
-    } else {
-      self.cancelCallbacks.push(callback);
-    }
-    return self;
-  }
-
-  then() {
-    const self = this;
-    self.deferred.then.apply(self.deferred, arguments);
-    return self;
-  }
-
-  done(callback) {
-    const self = this;
-    self.deferred.done.apply(self.deferred, arguments);
-    return self;
-  }
-
-  fail(callback) {
-    const self = this;
-    self.deferred.fail.apply(self.deferred, arguments);
-    return self;
-  }
-
-  always(callback) {
-    const self = this;
-    self.deferred.always.apply(self.deferred, arguments);
-    return self;
-  }
-
-  pipe(callback) {
-    const self = this;
-    self.deferred.pipe.apply(self.deferred, arguments);
-    return self;
-  }
-
-  progress(callback) {
-    const self = this;
-    self.deferred.progress.apply(self.deferred, arguments);
-    return self;
-  }
-
-  state() {
-    const self = this;
-    return self.deferred.state && self.deferred.state();
-  }
-}
-
-export default CancellablePromise;

+ 126 - 0
desktop/core/src/desktop/js/api/cancellablePromise.ts

@@ -0,0 +1,126 @@
+// Licensed to Cloudera, Inc. under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  Cloudera, Inc. licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import $ from 'jquery';
+import { cancelActiveRequest } from './apiUtils';
+
+export default class CancellablePromise<T> {
+  cancelCallbacks: (() => void)[] = [];
+  deferred: JQuery.Deferred<T>;
+  request?: JQuery.jqXHR;
+  otherCancellables?: CancellablePromise<unknown>[];
+  cancelled = false;
+  cancelPrevented = false;
+
+  constructor(
+    deferred: JQuery.Deferred<T>,
+    request?: JQuery.jqXHR,
+    otherCancellables?: CancellablePromise<unknown>[]
+  ) {
+    this.deferred = deferred;
+    this.request = request;
+    this.otherCancellables = otherCancellables;
+  }
+
+  /**
+   * A promise might be shared across multiple components in the UI, in some cases cancel is not an option and calling
+   * this will prevent that to happen.
+   *
+   * One example is autocompletion of databases while the assist is loading the database tree, closing the autocomplete
+   * results would make the assist loading fail if cancel hasn't been prevented.
+   *
+   * @returns {CancellablePromise}
+   */
+  preventCancel(): CancellablePromise<T> {
+    this.cancelPrevented = true;
+    return this;
+  }
+
+  cancel(): JQuery.Promise<unknown> {
+    if (this.cancelPrevented || this.cancelled || this.state() !== 'pending') {
+      return $.Deferred().resolve().promise();
+    }
+
+    this.cancelled = true;
+    if (this.request) {
+      cancelActiveRequest(this.request);
+    }
+
+    if (this.state && this.state() === 'pending' && this.deferred.reject) {
+      this.deferred.reject();
+    }
+
+    const cancelPromises: JQuery.Promise<unknown>[] = [];
+    if (this.otherCancellables) {
+      this.otherCancellables.forEach(cancellable => {
+        if (cancellable.cancel) {
+          cancelPromises.push(cancellable.cancel());
+        }
+      });
+    }
+
+    while (this.cancelCallbacks.length) {
+      const fn = this.cancelCallbacks.pop();
+      if (fn) {
+        fn();
+      }
+    }
+    return $.when(cancelPromises);
+  }
+
+  onCancel(callback: () => void): CancellablePromise<T> {
+    if (this.cancelled) {
+      callback();
+    } else {
+      this.cancelCallbacks.push(callback);
+    }
+    return this;
+  }
+
+  then(then: (result: T) => void): CancellablePromise<T> {
+    this.deferred.then(then);
+    return this;
+  }
+
+  done(done: (result: T) => void): CancellablePromise<T> {
+    this.deferred.done(done);
+    return this;
+  }
+
+  fail(fail: (error: unknown) => void): CancellablePromise<T> {
+    this.deferred.fail(fail);
+    return this;
+  }
+
+  always(always: (result: T) => void): CancellablePromise<T> {
+    this.deferred.always(always);
+    return this;
+  }
+
+  pipe(pipe: (result: T) => void): CancellablePromise<T> {
+    this.deferred.pipe(pipe);
+    return this;
+  }
+
+  progress(progress: (progress: unknown) => void): CancellablePromise<T> {
+    this.deferred.progress(progress);
+    return this;
+  }
+
+  state(): string {
+    return this.deferred.state && this.deferred.state();
+  }
+}

+ 3 - 1
desktop/core/src/desktop/js/catalog/dataCatalog.js

@@ -849,9 +849,10 @@ export default {
    * @param {Connector} options.connector
    * @param {string|string[]} options.path
    * @param {Object} [options.definition] - Optional initial definition
+   * @param {boolean} [options.cachedOnly] - Default: false
    * @param {boolean} [options.temporaryOnly] - Default: false
    *
-   * @return {Promise}
+   * @return {JQuery.Promise<DataCatalogEntry>}
    */
   getEntry: function (options) {
     return getCatalog(options.connector).getEntry(options);
@@ -882,6 +883,7 @@ export default {
    * @param {Object} [options.definition] - Optional initial definition of the parent entry
    * @param {boolean} [options.silenceErrors]
    * @param {boolean} [options.cachedOnly]
+   * @param {boolean} [options.temporaryOnly]
    * @param {boolean} [options.refreshCache]
    * @param {boolean} [options.cancellable] - Default false
    *

+ 1 - 1
desktop/core/src/desktop/js/catalog/optimizer/baseStrategy.js

@@ -16,7 +16,7 @@
 
 import $ from 'jquery';
 
-import CancellablePromise from '/api/cancellablePromise';
+import CancellablePromise from 'api/cancellablePromise';
 
 export default class BaseStrategy {
   constructor(connector) {

+ 19 - 0
desktop/core/src/desktop/js/catalog/types.ts

@@ -0,0 +1,19 @@
+// Licensed to Cloudera, Inc. under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  Cloudera, Inc. licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+export interface CatalogEntry {
+  getType: () => string;
+}

+ 2 - 2
desktop/core/src/desktop/js/ko/bindings/ace/aceLocationHandler.js

@@ -1076,7 +1076,7 @@ class AceLocationHandler {
 
           self
             .fetchPossibleValues(token)
-            .done(possibleValues => {
+            .done(async possibleValues => {
               // Tokens might change while making api calls
               if (!token.parseLocation) {
                 self.verifyThrottle = window.setTimeout(verify, VERIFY_DELAY);
@@ -1095,7 +1095,7 @@ class AceLocationHandler {
               const uniqueIndex = {};
               const uniqueValues = [];
               for (let i = 0; i < possibleValues.length; i++) {
-                possibleValues[i].name = sqlUtils.backTickIfNeeded(
+                possibleValues[i].name = await sqlUtils.backTickIfNeeded(
                   self.snippet.connector(),
                   possibleValues[i].name
                 );

+ 41 - 29
desktop/core/src/desktop/js/ko/components/assist/assistDbEntry.js

@@ -20,12 +20,15 @@ import * as ko from 'knockout';
 import huePubSub from 'utils/huePubSub';
 import sqlUtils from 'sql/sqlUtils';
 
-const findNameInHierarchy = (entry, searchCondition) => {
+const findNameInHierarchy = async (entry, searchCondition) => {
   while (entry && !searchCondition(entry)) {
     entry = entry.parent;
   }
   if (entry) {
-    return sqlUtils.backTickIfNeeded(entry.catalogEntry.getConnector(), entry.catalogEntry.name);
+    return await sqlUtils.backTickIfNeeded(
+      entry.catalogEntry.getConnector(),
+      entry.catalogEntry.name
+    );
   }
 };
 
@@ -155,15 +158,19 @@ class AssistDbEntry {
       self.columnName = self.catalogEntry.name;
     }
 
-    self.editorText = ko.pureComputed(() => {
+    self.editorText = ko.observable();
+
+    const setEditorText = async () => {
       if (self.catalogEntry.isTableOrView()) {
-        return self.getTableName();
-      }
-      if (self.catalogEntry.isColumn()) {
-        return self.getColumnName() + ', ';
+        self.editorText(await self.getTableName());
+      } else if (self.catalogEntry.isColumn()) {
+        self.editorText((await self.getColumnName()) + ', ');
+      } else {
+        self.editorText((await self.getComplexName()) + ', ');
       }
-      return self.getComplexName() + ', ';
-    });
+    };
+
+    setEditorText();
   }
 
   knownFacetValues() {
@@ -196,19 +203,19 @@ class AssistDbEntry {
     return {};
   }
 
-  getDatabaseName() {
-    return findNameInHierarchy(this, entry => entry.catalogEntry.isDatabase());
+  async getDatabaseName() {
+    return await findNameInHierarchy(this, entry => entry.catalogEntry.isDatabase());
   }
 
-  getTableName() {
-    return findNameInHierarchy(this, entry => entry.catalogEntry.isTableOrView());
+  async getTableName() {
+    return await findNameInHierarchy(this, entry => entry.catalogEntry.isTableOrView());
   }
 
-  getColumnName() {
-    return findNameInHierarchy(this, entry => entry.catalogEntry.isColumn());
+  async getColumnName() {
+    return await findNameInHierarchy(this, entry => entry.catalogEntry.isColumn());
   }
 
-  getComplexName() {
+  async getComplexName() {
     let entry = this;
     const sourceType = entry.sourceType;
     const parts = [];
@@ -221,7 +228,12 @@ class AssistDbEntry {
           parts.push('[]');
         }
       } else {
-        parts.push(sqlUtils.backTickIfNeeded(entry.getConnector(), entry.catalogEntry.name));
+        parts.push(
+          await sqlUtils.backTickIfNeeded(
+            entry.catalogEntry.getConnector(),
+            entry.catalogEntry.name
+          )
+        );
         parts.push('.');
       }
       entry = entry.parent;
@@ -432,29 +444,29 @@ class AssistDbEntry {
     return self.catalogEntry.path.concat();
   }
 
-  dblClick() {
+  async dblClick() {
     const self = this;
     if (self.catalogEntry.isTableOrView()) {
       huePubSub.publish('editor.insert.table.at.cursor', {
-        name: self.getTableName(),
-        database: self.getDatabaseName()
+        name: await self.getTableName(),
+        database: await self.getDatabaseName()
       });
     } else if (self.catalogEntry.isColumn()) {
       huePubSub.publish('editor.insert.column.at.cursor', {
-        name: self.getColumnName(),
-        table: self.getTableName(),
-        database: self.getDatabaseName()
+        name: await self.getColumnName(),
+        table: await self.getTableName(),
+        database: await self.getDatabaseName()
       });
     } else {
       huePubSub.publish('editor.insert.column.at.cursor', {
-        name: self.getComplexName(),
-        table: self.getTableName(),
-        database: self.getDatabaseName()
+        name: await self.getComplexName(),
+        table: await self.getTableName(),
+        database: await self.getDatabaseName()
       });
     }
   }
 
-  explore(isSolr) {
+  async explore(isSolr) {
     const self = this;
     if (isSolr) {
       huePubSub.publish('open.link', '/hue/dashboard/browse/' + self.catalogEntry.name);
@@ -462,9 +474,9 @@ class AssistDbEntry {
       huePubSub.publish(
         'open.link',
         '/hue/dashboard/browse/' +
-          self.getDatabaseName() +
+          (await self.getDatabaseName()) +
           '.' +
-          self.getTableName() +
+          (await self.getTableName()) +
           '?engine=' +
           self.assistDbNamespace.sourceType
       );

+ 15 - 9
desktop/core/src/desktop/js/ko/components/contextPopover/asteriskContextTabs.js

@@ -59,26 +59,32 @@ class AsteriskData {
           delete colIndex[name];
         }
       });
-      huePubSub.publish('ace.replace', {
-        location: data.location,
-        text: $.map(colsToExpand, column => {
+
+      Promise.all(
+        colsToExpand.map(async column => {
           if (column.tableAlias) {
             return (
-              sqlUtils.backTickIfNeeded(connector, column.tableAlias) +
+              (await sqlUtils.backTickIfNeeded(connector, column.tableAlias)) +
               '.' +
-              sqlUtils.backTickIfNeeded(connector, column.name)
+              (await sqlUtils.backTickIfNeeded(connector, column.name))
             );
           }
           if (colIndex[column.name]) {
             return (
-              sqlUtils.backTickIfNeeded(connector, column.table) +
+              (await sqlUtils.backTickIfNeeded(connector, column.table)) +
               '.' +
-              sqlUtils.backTickIfNeeded(connector, column.name)
+              (await sqlUtils.backTickIfNeeded(connector, column.name))
             );
           }
-          return sqlUtils.backTickIfNeeded(connector, column.name);
-        }).join(', ')
+          return await sqlUtils.backTickIfNeeded(connector, column.name);
+        })
+      ).then(backtickedCols => {
+        huePubSub.publish('ace.replace', {
+          location: data.location,
+          text: backtickedCols.join(', ')
+        });
       });
+
       huePubSub.publish('context.popover.hide');
     };
 

+ 9 - 7
desktop/core/src/desktop/js/ko/components/ko.editorDroppableMenu.js

@@ -63,16 +63,18 @@ class EditorDroppableMenu extends DisposableComponent {
 
     this.meta = ko.observable();
 
-    this.identifier = ko.pureComputed(() => {
-      const meta = this.meta();
+    this.identifier = ko.observable('');
+
+    this.meta.subscribe(async meta => {
       if (meta && meta.database && meta.table) {
-        return (
-          sqlUtils.backTickIfNeeded(meta.connector, meta.database) +
-          '.' +
-          sqlUtils.backTickIfNeeded(meta.connector, meta.table)
+        this.identifier(
+          (await sqlUtils.backTickIfNeeded(meta.connector, meta.database)) +
+            '.' +
+            (await sqlUtils.backTickIfNeeded(meta.connector, meta.table))
         );
+      } else {
+        this.identifier('');
       }
-      return '';
     });
 
     super.subscribe(DRAGGABLE_TEXT_META_EVENT, this.meta);

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

@@ -0,0 +1,31 @@
+// Licensed to Cloudera, Inc. under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  Cloudera, Inc. licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+export interface IdentifierChainEntry {
+  name: string;
+}
+
+export interface ParsedTable {
+  identifierChain: IdentifierChainEntry[];
+  subQuery?: unknown; // TODO: Define
+}
+
+export interface ParsedLocation {
+  first_line: number;
+  first_column: number;
+  last_line: number;
+  last_column: number;
+}

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

@@ -839,7 +839,7 @@ class AutocompleteResults {
           databaseSuggestions.push({
             value:
               prefix +
-              sqlUtils.backTickIfNeeded(this.snippet.connector(), dbEntry.name) +
+              (await sqlUtils.backTickIfNeeded(this.snippet.connector(), dbEntry.name)) +
               (suggestDatabases.appendDot ? '.' : ''),
             filterValue: dbEntry.name,
             meta: META_I18n.database,
@@ -906,7 +906,8 @@ class AutocompleteResults {
             continue;
           }
           tableSuggestions.push({
-            value: prefix + sqlUtils.backTickIfNeeded(this.snippet.connector(), tableEntry.name),
+            value:
+              prefix + (await sqlUtils.backTickIfNeeded(this.snippet.connector(), tableEntry.name)),
             filterValue: tableEntry.name,
             tableName: tableEntry.name,
             meta: META_I18n[tableEntry.getType().toLowerCase()],
@@ -1024,7 +1025,7 @@ class AutocompleteResults {
         typeof column.type !== 'undefined' && column.type !== 'COLREF' ? column.type : 'T';
       if (typeof column.alias !== 'undefined') {
         columnSuggestions.push({
-          value: sqlUtils.backTickIfNeeded(this.snippet.connector(), column.alias),
+          value: await sqlUtils.backTickIfNeeded(this.snippet.connector(), column.alias),
           filterValue: column.alias,
           meta: type,
           category: CATEGORIES.COLUMN,
@@ -1038,7 +1039,7 @@ class AutocompleteResults {
         typeof column.identifierChain[column.identifierChain.length - 1].name !== 'undefined'
       ) {
         columnSuggestions.push({
-          value: sqlUtils.backTickIfNeeded(
+          value: await sqlUtils.backTickIfNeeded(
             this.snippet.connector(),
             column.identifierChain[column.identifierChain.length - 1].name
           ),
@@ -1068,7 +1069,7 @@ class AutocompleteResults {
             typeof column.type !== 'undefined' && column.type !== 'COLREF' ? column.type : 'T';
           if (column.alias) {
             columnSuggestions.push({
-              value: sqlUtils.backTickIfNeeded(connector, column.alias),
+              value: await sqlUtils.backTickIfNeeded(connector, column.alias),
               filterValue: column.alias,
               meta: type,
               category: CATEGORIES.COLUMN,
@@ -1078,7 +1079,7 @@ class AutocompleteResults {
             });
           } else if (column.identifierChain && column.identifierChain.length > 0) {
             columnSuggestions.push({
-              value: sqlUtils.backTickIfNeeded(
+              value: await sqlUtils.backTickIfNeeded(
                 connector,
                 column.identifierChain[column.identifierChain.length - 1].name
               ),
@@ -1144,7 +1145,7 @@ class AutocompleteResults {
         });
 
         for (const childEntry of childEntries) {
-          let name = sqlUtils.backTickIfNeeded(this.snippet.connector(), childEntry.name);
+          let name = await sqlUtils.backTickIfNeeded(this.snippet.connector(), childEntry.name);
           if (this.dialect() === DIALECT.hive && (childEntry.isArray() || childEntry.isMap())) {
             name += '[]';
           }

+ 380 - 0
desktop/core/src/desktop/js/sql/reference/calcite/reservedKeywords.ts

@@ -0,0 +1,380 @@
+// Licensed to Cloudera, Inc. under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  Cloudera, Inc. licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+export const RESERVED_WORDS: Set<string> = new Set([
+  'ABS',
+  'ALL',
+  'ALLOCATE',
+  'ALLOW',
+  'ALTER',
+  'AND',
+  'ANY',
+  'ARE',
+  'ARRAY',
+  'ARRAY_MAX_CARDINALITY',
+  'AS',
+  'ASENSITIVE',
+  'ASYMMETRIC',
+  'AT',
+  'ATOMIC',
+  'AUTHORIZATION',
+  'AVG',
+  'BEGIN',
+  'BEGIN_FRAME',
+  'BEGIN_PARTITION',
+  'BETWEEN',
+  'BIGINT',
+  'BINARY',
+  'BIT',
+  'BLOB',
+  'BOOLEAN',
+  'BOTH',
+  'BY',
+  'CALL',
+  'CALLED',
+  'CARDINALITY',
+  'CASCADED',
+  'CASE',
+  'CAST',
+  'CEIL',
+  'CEILING',
+  'CHAR',
+  'CHAR_LENGTH',
+  'CHARACTER',
+  'CHARACTER_LENGTH',
+  'CHECK',
+  'CLASSIFIER',
+  'CLOB',
+  'CLOSE',
+  'COALESCE',
+  'COLLATE',
+  'COLLECT',
+  'COLUMN',
+  'COMMIT',
+  'CONDITION',
+  'CONNECT',
+  'CONSTRAINT',
+  'CONTAINS',
+  'CONVERT',
+  'CORR',
+  'CORRESPONDING',
+  'COUNT',
+  'COVAR_POP',
+  'COVAR_SAMP',
+  'CREATE',
+  'CROSS',
+  'CUBE',
+  'CUME_DIST',
+  'CURRENT',
+  'CURRENT_CATALOG',
+  'CURRENT_DATE',
+  'CURRENT_DEFAULT_TRANSFORM_GROUP',
+  'CURRENT_PATH',
+  'CURRENT_ROLE',
+  'CURRENT_ROW',
+  'CURRENT_SCHEMA',
+  'CURRENT_TIME',
+  'CURRENT_TIMESTAMP',
+  'CURRENT_TRANSFORM_GROUP_FOR_TYPE',
+  'CURRENT_USER',
+  'CURSOR',
+  'CYCLE',
+  'DATE',
+  'DAY',
+  'DEALLOCATE',
+  'DEC',
+  'DECIMAL',
+  'DECLARE',
+  'DEFAULT',
+  'DEFINE',
+  'DELETE',
+  'DENSE_RANK',
+  'DEREF',
+  'DESCRIBE',
+  'DETERMINISTIC',
+  'DISALLOW',
+  'DISCONNECT',
+  'DISTINCT',
+  'DOUBLE',
+  'DROP',
+  'DYNAMIC',
+  'EACH',
+  'ELEMENT',
+  'ELSE',
+  'EMPTY',
+  'END',
+  'END-EXEC',
+  'END_FRAME',
+  'END_PARTITION',
+  'EQUALS',
+  'ESCAPE',
+  'EVERY',
+  'EXCEPT',
+  'EXEC',
+  'EXECUTE',
+  'EXISTS',
+  'EXP',
+  'EXPLAIN',
+  'EXTEND',
+  'EXTERNAL',
+  'EXTRACT',
+  'FALSE',
+  'FETCH',
+  'FILTER',
+  'FIRST_VALUE',
+  'FLOAT',
+  'FLOOR',
+  'FOR',
+  'FOREIGN',
+  'FRAME_ROW',
+  'FREE',
+  'FROM',
+  'FULL',
+  'FUNCTION',
+  'FUSION',
+  'GET',
+  'GLOBAL',
+  'GRANT',
+  'GROUP',
+  'GROUPING',
+  'GROUPS',
+  'HAVING',
+  'HOLD',
+  'HOUR',
+  'IDENTITY',
+  'IMPORT',
+  'IN',
+  'INDICATOR',
+  'INITIAL',
+  'INNER',
+  'INOUT',
+  'INSENSITIVE',
+  'INSERT',
+  'INT',
+  'INTEGER',
+  'INTERSECT',
+  'INTERSECTION',
+  'INTERVAL',
+  'INTO',
+  'IS',
+  'JOIN',
+  'JSON_ARRAY',
+  'JSON_ARRAYAGG',
+  'JSON_EXISTS',
+  'JSON_OBJECT',
+  'JSON_OBJECTAGG',
+  'JSON_QUERY',
+  'JSON_VALUE',
+  'LAG',
+  'LANGUAGE',
+  'LARGE',
+  'LAST_VALUE',
+  'LATERAL',
+  'LEAD',
+  'LEADING',
+  'LEFT',
+  'LIKE',
+  'LIKE_REGEX',
+  'LIMIT',
+  'LN',
+  'LOCAL',
+  'LOCALTIME',
+  'LOCALTIMESTAMP',
+  'LOWER',
+  'MATCH',
+  'MATCH_NUMBER',
+  'MATCH_RECOGNIZE',
+  'MATCHES',
+  'MAX',
+  'MEASURES',
+  'MEMBER',
+  'MERGE',
+  'METHOD',
+  'MIN',
+  'MINUS',
+  'MINUTE',
+  'MOD',
+  'MODIFIES',
+  'MODULE',
+  'MONTH',
+  'MULTISET',
+  'NATIONAL',
+  'NATURAL',
+  'NCHAR',
+  'NCLOB',
+  'NEW',
+  'NEXT',
+  'NO',
+  'NONE',
+  'NORMALIZE',
+  'NOT',
+  'NTH_VALUE',
+  'NTILE',
+  'NULL',
+  'NULLIF',
+  'NUMERIC',
+  'OCCURRENCES_REGEX',
+  'OCTET_LENGTH',
+  'OF',
+  'OFFSET',
+  'OLD',
+  'OMIT',
+  'ON',
+  'ONE',
+  'ONLY',
+  'OPEN',
+  'OR',
+  'ORDER',
+  'OUT',
+  'OUTER',
+  'OVER',
+  'OVERLAPS',
+  'OVERLAY',
+  'PARAMETER',
+  'PARTITION',
+  'PATTERN',
+  'PER',
+  'PERCENT',
+  'PERCENT_RANK',
+  'PERCENTILE_CONT',
+  'PERCENTILE_DISC',
+  'PERIOD',
+  'PERMUTE',
+  'PORTION',
+  'POSITION',
+  'POSITION_REGEX',
+  'POWER',
+  'PRECEDES',
+  'PRECISION',
+  'PREPARE',
+  'PREV',
+  'PRIMARY',
+  'PROCEDURE',
+  'RANGE',
+  'RANK',
+  'READS',
+  'REAL',
+  'RECURSIVE',
+  'REF',
+  'REFERENCES',
+  'REFERENCING',
+  'REGR_AVGX',
+  'REGR_AVGY',
+  'REGR_COUNT',
+  'REGR_INTERCEPT',
+  'REGR_R2',
+  'REGR_SLOPE',
+  'REGR_SXX',
+  'REGR_SXY',
+  'REGR_SYY',
+  'RELEASE',
+  'RESET',
+  'RESULT',
+  'RETURN',
+  'RETURNS',
+  'REVOKE',
+  'RIGHT',
+  'ROLLBACK',
+  'ROLLUP',
+  'ROW',
+  'ROW_NUMBER',
+  'ROWS',
+  'RUNNING',
+  'SAVEPOINT',
+  'SCOPE',
+  'SCROLL',
+  'SEARCH',
+  'SECOND',
+  'SEEK',
+  'SELECT',
+  'SENSITIVE',
+  'SESSION_USER',
+  'SET',
+  'SHOW',
+  'SIMILAR',
+  'SKIP',
+  'SMALLINT',
+  'SOME',
+  'SPECIFIC',
+  'SPECIFICTYPE',
+  'SQL',
+  'SQLEXCEPTION',
+  'SQLSTATE',
+  'SQLWARNING',
+  'SQRT',
+  'START',
+  'STATIC',
+  'STDDEV_POP',
+  'STDDEV_SAMP',
+  'STREAM',
+  'SUBMULTISET',
+  'SUBSET',
+  'SUBSTRING',
+  'SUBSTRING_REGEX',
+  'SUCCEEDS',
+  'SUM',
+  'SYMMETRIC',
+  'SYSTEM',
+  'SYSTEM_TIME',
+  'SYSTEM_USER',
+  'TABLE',
+  'TABLESAMPLE',
+  'THEN',
+  'TIME',
+  'TIMESTAMP',
+  'TIMEZONE_HOUR',
+  'TIMEZONE_MINUTE',
+  'TINYINT',
+  'TO',
+  'TRAILING',
+  'TRANSLATE',
+  'TRANSLATE_REGEX',
+  'TRANSLATION',
+  'TREAT',
+  'TRIGGER',
+  'TRIM',
+  'TRIM_ARRAY',
+  'TRUE',
+  'TRUNCATE',
+  'UESCAPE',
+  'UNION',
+  'UNIQUE',
+  'UNKNOWN',
+  'UNNEST',
+  'UPDATE',
+  'UPPER',
+  'UPSERT',
+  'USER',
+  'USING',
+  'VALUE',
+  'VALUE_OF',
+  'VALUES',
+  'VAR_POP',
+  'VAR_SAMP',
+  'VARBINARY',
+  'VARCHAR',
+  'VARYING',
+  'VERSIONING',
+  'WHEN',
+  'WHENEVER',
+  'WHERE',
+  'WIDTH_BUCKET',
+  'WINDOW',
+  'WITH',
+  'WITHIN',
+  'WITHOUT',
+  'YEAR'
+]);

+ 103 - 0
desktop/core/src/desktop/js/sql/reference/generic/reservedKeywords.ts

@@ -0,0 +1,103 @@
+// Licensed to Cloudera, Inc. under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  Cloudera, Inc. licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+export const RESERVED_WORDS: Set<string> = new Set([
+  'ALL',
+  'ALTER',
+  'AND',
+  'AS',
+  'ASC',
+  'BETWEEN',
+  'BIGINT',
+  'BOOLEAN',
+  'BY',
+  'CASCADE',
+  'CASE',
+  'CHAR',
+  'COMMENT',
+  'CREATE',
+  'CROSS',
+  'CURRENT',
+  'DATABASE',
+  'DECIMAL',
+  'DESC',
+  'DISTINCT',
+  'DIV',
+  'DOUBLE',
+  'DROP',
+  'ELSE',
+  'END',
+  'EXISTS',
+  'FALSE',
+  'FLOAT',
+  'FOLLOWING',
+  'FROM',
+  'FULL',
+  'GROUP',
+  'HAVING',
+  'IF',
+  'IN',
+  'INNER',
+  'INSERT',
+  'INT',
+  'INTO',
+  'IS',
+  'JOIN',
+  'LEFT',
+  'LIKE',
+  'LIMIT',
+  'NOT',
+  'NULL',
+  'ON',
+  'OPTION',
+  'OR',
+  'ORDER',
+  'OUTER',
+  'PARTITION',
+  'PRECEDING',
+  'PURGE',
+  'RANGE',
+  'REGEXP',
+  'RIGHT',
+  'RLIKE',
+  'ROLE',
+  'ROW',
+  'ROWS',
+  'SCHEMA',
+  'SELECT',
+  'SEMI',
+  'SET',
+  'SHOW',
+  'SMALLINT',
+  'STRING',
+  'TABLE',
+  'THEN',
+  'TIMESTAMP',
+  'TINYINT',
+  'TO',
+  'TRUE',
+  'TRUNCATE',
+  'UNBOUNDED',
+  'UNION',
+  'UPDATE',
+  'USE',
+  'VALUES',
+  'VARCHAR',
+  'VIEW',
+  'WHEN',
+  'WHERE',
+  'WITH'
+]);

+ 168 - 0
desktop/core/src/desktop/js/sql/reference/hive/reservedKeywords.ts

@@ -0,0 +1,168 @@
+// Licensed to Cloudera, Inc. under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  Cloudera, Inc. licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+export const RESERVED_WORDS: Set<string> = new Set([
+  'ALL',
+  'ALTER',
+  'AND',
+  'ARRAY',
+  'AS',
+  'ASC',
+  'AUTHORIZATION',
+  'BETWEEN',
+  'BIGINT',
+  'BINARY',
+  'BOOLEAN',
+  'BOTH',
+  'BY',
+  'CACHE',
+  'CASE',
+  'CAST',
+  'CHAR',
+  'CLUSTER',
+  'COLUMN',
+  'COMMIT',
+  'CONF',
+  'CONSTRAINT',
+  'CREATE',
+  'CROSS',
+  'CUBE',
+  'CURRENT',
+  'CURRENT_DATE',
+  'CURRENT_TIMESTAMP',
+  'CURSOR',
+  'DATABASE',
+  'DATE',
+  'DAYOFWEEK',
+  'DECIMAL',
+  'DELETE',
+  'DESC',
+  'DESCRIBE',
+  'DISTINCT',
+  'DISTRIBUTE',
+  'DOUBLE',
+  'DROP',
+  'ELSE',
+  'END',
+  'EXCHANGE',
+  'EXISTS',
+  'EXTENDED',
+  'EXTERNAL',
+  'EXTRACT',
+  'FALSE',
+  'FETCH',
+  'FLOAT',
+  'FLOOR',
+  'FOLLOWING',
+  'FOR',
+  'FOREIGN',
+  'FORMATTED',
+  'FROM',
+  'FULL',
+  'FUNCTION',
+  'FUNCTION',
+  'GRANT',
+  'GROUP',
+  'GROUPING',
+  'HAVING',
+  'IF',
+  'IMPORT',
+  'IN',
+  'INDEX',
+  'INDEXES',
+  'INNER',
+  'INSERT',
+  'INT',
+  'INTEGER',
+  'INTERSECT',
+  'INTERVAL',
+  'INTO',
+  'IS',
+  'JOIN',
+  'LATERAL',
+  'LEFT',
+  'LESS',
+  'LIKE',
+  'LIMIT',
+  'LOCAL',
+  'LOCK',
+  'MACRO',
+  'MAP',
+  'MORE',
+  'NONE',
+  'NOT',
+  'NULL',
+  'NUMERIC',
+  'OF',
+  'ON',
+  'ONLY',
+  'OR',
+  'ORDER',
+  'OUT',
+  'OUTER',
+  'OVER',
+  'PARTIALSCAN',
+  'PARTITION',
+  'PERCENT',
+  'PRECEDING',
+  'PRECISION',
+  'PRESERVE',
+  'PRIMARY',
+  'PROCEDURE',
+  'RANGE',
+  'READS',
+  'REDUCE',
+  'REFERENCES',
+  'REGEXP',
+  'REVOKE',
+  'RIGHT',
+  'RLIKE',
+  'ROLLBACK',
+  'ROLLUP',
+  'ROW',
+  'ROWS',
+  'SCHEMA',
+  'SELECT',
+  'SET',
+  'SMALLINT',
+  'SORT',
+  'START',
+  'SYNC',
+  'TABLE',
+  'TABLESAMPLE',
+  'THEN',
+  'TIME',
+  'TIMESTAMP',
+  'TO',
+  'TRANSFORM',
+  'TRIGGER',
+  'TRUE',
+  'TRUNCATE',
+  'UNBOUNDED',
+  'UNION',
+  'UNIQUEJOIN',
+  'UPDATE',
+  'USER',
+  'USING',
+  'UTC_TMESTAMP',
+  'VALUES',
+  'VARCHAR',
+  'VIEWS',
+  'WHEN',
+  'WHERE',
+  'WINDOW',
+  'WITH'
+]);

+ 554 - 0
desktop/core/src/desktop/js/sql/reference/impala/reservedKeywords.ts

@@ -0,0 +1,554 @@
+// Licensed to Cloudera, Inc. under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  Cloudera, Inc. licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+export const RESERVED_WORDS: Set<string> = new Set([
+  'ABS',
+  'ACOS',
+  'ADD',
+  'AGGREGATE',
+  'ALL',
+  'ALLOCATE',
+  'ALTER',
+  'ANALYTIC',
+  'AND',
+  'ANTI',
+  'ANY',
+  'API_VERSION',
+  'ARE',
+  'ARRAY',
+  'ARRAY_AGG',
+  'ARRAY_MAX_CARDINALITY',
+  'AS',
+  'ASC',
+  'ASENSITIVE',
+  'ASIN',
+  'ASYMMETRIC',
+  'AT',
+  'ATAN',
+  'ATOMIC',
+  'AUTHORIZATION',
+  'AVG',
+  'AVRO',
+  'BACKUP',
+  'BEGIN',
+  'BEGIN_FRAME',
+  'BEGIN_PARTITION',
+  'BETWEEN',
+  'BIGINT',
+  'BINARY',
+  'BLOB',
+  'BLOCK_SIZE',
+  'BOOLEAN',
+  'BOTH',
+  'BREAK',
+  'BROWSE',
+  'BULK',
+  'BY',
+  'CACHE',
+  'CACHED',
+  'CALL',
+  'CALLED',
+  'CARDINALITY',
+  'CASCADE',
+  'CASCADED',
+  'CASE',
+  'CAST',
+  'CEIL',
+  'CEILING',
+  'CHANGE',
+  'CHAR',
+  'CHAR_LENGTH',
+  'CHARACTER',
+  'CHARACTER_LENGTH',
+  'CHECK',
+  'CHECKPOINT',
+  'CLASS',
+  'CLASSIFIER',
+  'CLOB',
+  'CLOSE',
+  'CLOSE_FN',
+  'CLUSTERED',
+  'COALESCE',
+  'COLLATE',
+  'COLLECT',
+  'COLUMN',
+  'COLUMNS',
+  'COMMENT',
+  'COMMIT',
+  'COMPRESSION',
+  'COMPUTE',
+  'CONDITION',
+  'CONF',
+  'CONNECT',
+  'CONSTRAINT',
+  'CONTAINS',
+  'CONTINUE',
+  'CONVERT',
+  'COPY',
+  'CORR',
+  'CORRESPONDING',
+  'COS',
+  'COSH',
+  'COUNT',
+  'COVAR_POP',
+  'COVAR_SAMP',
+  'CREATE',
+  'CROSS',
+  'CUBE',
+  'CUME_DIST',
+  'CURRENT',
+  'CURRENT_CATALOG',
+  'CURRENT_DATE',
+  'CURRENT_DEFAULT_TRANSFORM_GROUP',
+  'CURRENT_PATH',
+  'CURRENT_ROLE',
+  'CURRENT_ROW',
+  'CURRENT_SCHEMA',
+  'CURRENT_TIME',
+  'CURRENT_TIMESTAMP',
+  'CURRENT_TRANSFORM_GROUP_FOR_TYPE',
+  'CURRENT_USER',
+  'CURSOR',
+  'CYCLE',
+  'DATA',
+  'DATABASE',
+  'DATABASES',
+  'DATE',
+  'DATETIME',
+  'DAY',
+  'DAYOFWEEK',
+  'DBCC',
+  'DEALLOCATE',
+  'DEC',
+  'DECFLOAT',
+  'DECIMAL',
+  'DECLARE',
+  'DEFAULT',
+  'DEFINE',
+  'DELETE',
+  'DELIMITED',
+  'DENSE_RANK',
+  'DENY',
+  'DEREF',
+  'DESC',
+  'DESCRIBE',
+  'DETERMINISTIC',
+  'DISCONNECT',
+  'DISK',
+  'DISTINCT',
+  'DISTRIBUTED',
+  'DIV',
+  'DOUBLE',
+  'DROP',
+  'DUMP',
+  'DYNAMIC',
+  'EACH',
+  'ELEMENT',
+  'ELSE',
+  'EMPTY',
+  'ENCODING',
+  'END',
+  'END-EXEC',
+  'END_FRAME',
+  'END_PARTITION',
+  'EQUALS',
+  'ERRLVL',
+  'ESCAPE',
+  'ESCAPED',
+  'EVERY',
+  'EXCEPT',
+  'EXCHANGE',
+  'EXEC',
+  'EXECUTE',
+  'EXISTS',
+  'EXIT',
+  'EXP',
+  'EXPLAIN',
+  'EXTENDED',
+  'EXTERNAL',
+  'EXTRACT',
+  'FALSE',
+  'FETCH',
+  'FIELDS',
+  'FILE',
+  'FILEFACTOR',
+  'FILEFORMAT',
+  'FILES',
+  'FILTER',
+  'FINALIZE_FN',
+  'FIRST',
+  'FIRST_VALUE',
+  'FLOAT',
+  'FLOOR',
+  'FOLLOWING',
+  'FOR',
+  'FOREIGN',
+  'FORMAT',
+  'FORMATTED',
+  'FRAME_ROW',
+  'FREE',
+  'FREETEXT',
+  'FROM',
+  'FULL',
+  'FUNCTION',
+  'FUNCTIONS',
+  'FUSION',
+  'GET',
+  'GLOBAL',
+  'GOTO',
+  'GRANT',
+  'GROUP',
+  'GROUPING',
+  'GROUPS',
+  'HASH',
+  'HAVING',
+  'HOLD',
+  'HOLDLOCK',
+  'HOUR',
+  'IDENTITY',
+  'IF',
+  'IGNORE',
+  'ILIKE',
+  'IMPORT',
+  'IN',
+  'INCREMENTAL',
+  'INDEX',
+  'INDICATOR',
+  'INIT_FN',
+  'INITIAL',
+  'INNER',
+  'INOUT',
+  'INPATH',
+  'INSENSITIVE',
+  'INSERT',
+  'INT',
+  'INTEGER',
+  'INTERMEDIATE',
+  'INTERSECT',
+  'INTERSECTION',
+  'INTERVAL',
+  'INTO',
+  'INVALIDATE',
+  'IREGEXP',
+  'IS',
+  'JOIN',
+  'JSON_ARRAY',
+  'JSON_ARRAYAGG',
+  'JSON_EXISTS',
+  'JSON_OBJECT',
+  'JSON_OBJECTAGG',
+  'JSON_QUERY',
+  'JSON_TABLE',
+  'JSON_TABLE_PRIMITIVE',
+  'JSON_VALUE',
+  'KEY',
+  'KILL',
+  'KUDU',
+  'LAG',
+  'LANGUAGE',
+  'LARGE',
+  'LAST',
+  'LAST_VALUE',
+  'LATERAL',
+  'LEAD',
+  'LEADING',
+  'LEFT',
+  'LESS',
+  'LIKE',
+  'LIKE_REGEX',
+  'LIMIT',
+  'LINENO',
+  'LINES',
+  'LISTAGG',
+  'LN',
+  'LOAD',
+  'LOCAL',
+  'LOCALTIME',
+  'LOCALTIMESTAMP',
+  'LOCATION',
+  'LOG',
+  'LOG10',
+  'LOWER',
+  'MACRO',
+  'MAP',
+  'MATCH',
+  'MATCH_NUMBER',
+  'MATCH_RECOGNIZE',
+  'MATCHES',
+  'MAX',
+  'MEMBER',
+  'MERGE',
+  'MERGE_FN',
+  'METADATA',
+  'METHOD',
+  'MIN',
+  'MINUTE',
+  'MOD',
+  'MODIFIES',
+  'MODULE',
+  'MONTH',
+  'MORE',
+  'MULTISET',
+  'NATIONAL',
+  'NATURAL',
+  'NCHAR',
+  'NCLOB',
+  'NEW',
+  'NO',
+  'NOCHECK',
+  'NONCLUSTERED',
+  'NONE',
+  'NORMALIZE',
+  'NOT',
+  'NTH_VALUE',
+  'NTILE',
+  'NULL',
+  'NULLIF',
+  'NULLS',
+  'NUMERIC',
+  'OCCURRENCES_REGEX',
+  'OCTET_LENGTH',
+  'OF',
+  'OFF',
+  'OFFSET',
+  'OFFSETS',
+  'OLD',
+  'OMIT',
+  'ON',
+  'ONE',
+  'ONLY',
+  'OPEN',
+  'OPTION',
+  'OR',
+  'ORDER',
+  'OUT',
+  'OUTER',
+  'OVER',
+  'OVERLAPS',
+  'OVERLAY',
+  'OVERWRITE',
+  'PARAMETER',
+  'PARQUET',
+  'PARQUETFILE',
+  'PARTIALSCAN',
+  'PARTITION',
+  'PARTITIONED',
+  'PARTITIONS',
+  'PATTERN',
+  'PER',
+  'PERCENT',
+  'PERCENT_RANK',
+  'PERCENTILE_CONT',
+  'PERCENTILE_DISC',
+  'PERIOD',
+  'PIVOT',
+  'PLAN',
+  'PORTION',
+  'POSITION',
+  'POSITION_REGEX',
+  'POWER',
+  'PRECEDES',
+  'PRECEDING',
+  'PRECISION',
+  'PREPARE',
+  'PREPARE_FN',
+  'PRESERVE',
+  'PRIMARY',
+  'PRINT',
+  'PROC',
+  'PROCEDURE',
+  'PRODUCED',
+  'PTF',
+  'PUBLIC',
+  'PURGE',
+  'RAISEERROR',
+  'RANGE',
+  'RANK',
+  'RCFILE',
+  'READ',
+  'READS',
+  'READTEXT',
+  'REAL',
+  'RECONFIGURE',
+  'RECOVER',
+  'RECURSIVE',
+  'REDUCE',
+  'REF',
+  'REFERENCES',
+  'REFERENCING',
+  'REFRESH',
+  'REGEXP',
+  'REGR_AVGX',
+  'REGR_AVGY',
+  'REGR_COUNT',
+  'REGR_INTERCEPT',
+  'REGR_R2',
+  'REGR_SLOPE',
+  'REGR_SXX',
+  'REGR_SXY',
+  'REGR_SYY',
+  'RELEASE',
+  'RENAME',
+  'REPEATABLE',
+  'REPLACE',
+  'REPLICATION',
+  'RESTORE',
+  'RESTRICT',
+  'RESULT',
+  'RETURN',
+  'RETURNS',
+  'REVERT',
+  'REVOKE',
+  'RIGHT',
+  'RLIKE',
+  'ROLE',
+  'ROLES',
+  'ROLLBACK',
+  'ROLLUP',
+  'ROW',
+  'ROW_NUMBER',
+  'ROWCOUNT',
+  'ROWS',
+  'RULE',
+  'RUNNING',
+  'SAVE',
+  'SAVEPOINT',
+  'SCHEMA',
+  'SCHEMAS',
+  'SCOPE',
+  'SCROLL',
+  'SEARCH',
+  'SECOND',
+  'SECURITYAUDIT',
+  'SEEK',
+  'SELECT',
+  'SEMI',
+  'SENSITIVE',
+  'SEQUENCEFILE',
+  'SERDEPROPERTIES',
+  'SERIALIZE_FN',
+  'SESSION_USER',
+  'SET',
+  'SETUSER',
+  'SHOW',
+  'SHUTDOWN',
+  'SIMILAR',
+  'SIN',
+  'SINH',
+  'SKIP',
+  'SMALLINT',
+  'SOME',
+  'SORT',
+  'SPECIFIC',
+  'SPECIFICTYPE',
+  'SQL',
+  'SQLEXCEPTION',
+  'SQLSTATE',
+  'SQLWARNING',
+  'SQRT',
+  'START',
+  'STATIC',
+  'STATISTICS',
+  'STATS',
+  'STDDEV_POP',
+  'STDDEV_SAMP',
+  'STORED',
+  'STRAIGHT_JOIN',
+  'STRING',
+  'STRUCT',
+  'SUBMULTISET',
+  'SUBSET',
+  'SUBSTRING',
+  'SUBSTRING_REGEX',
+  'SUCCEEDS',
+  'SUM',
+  'SYMBOL',
+  'SYMMETRIC',
+  'SYSTEM',
+  'SYSTEM_TIME',
+  'SYSTEM_USER',
+  'TABLE',
+  'TABLES',
+  'TABLESAMPLE',
+  'TAN',
+  'TANH',
+  'TBLPROPERTIES',
+  'TERMINATED',
+  'TEXTFILE',
+  'TEXTSIZE',
+  'THEN',
+  'TIME',
+  'TIMESTAMP',
+  'TIMEZONE_HOUR',
+  'TIMEZONE_MINUTE',
+  'TINYINT',
+  'TO',
+  'TOP',
+  'TRAILING',
+  'TRAN',
+  'TRANSFORM',
+  'TRANSLATE',
+  'TRANSLATE_REGEX',
+  'TRANSLATION',
+  'TREAT',
+  'TRIGGER',
+  'TRIM',
+  'TRIM_ARRAY',
+  'TRUE',
+  'TRUNCATE',
+  'TRY_CONVERT',
+  'UESCAPE',
+  'UNBOUNDED',
+  'UNCACHED',
+  'UNION',
+  'UNIQUE',
+  'UNIQUEJOIN',
+  'UNKNOWN',
+  'UNNEST',
+  'UNPIVOT',
+  'UPDATE',
+  'UPDATE_FN',
+  'UPDATETEXT',
+  'UPPER',
+  'UPSERT',
+  'USE',
+  'USER',
+  'USING',
+  'UTC_TMESTAMP',
+  'VALUE',
+  'VALUE_OF',
+  'VALUES',
+  'VAR_POP',
+  'VAR_SAMP',
+  'VARBINARY',
+  'VARCHAR',
+  'VARYING',
+  'VERSIONING',
+  'VIEW',
+  'VIEWS',
+  'WAITFOR',
+  'WHEN',
+  'WHENEVER',
+  'WHERE',
+  'WHILE',
+  'WIDTH_BUCKET',
+  'WINDOW',
+  'WITH',
+  'WITHIN',
+  'WITHOUT',
+  'WRITETEXT',
+  'YEAR'
+]);

+ 118 - 0
desktop/core/src/desktop/js/sql/reference/postgresql/reservedKeywords.ts

@@ -0,0 +1,118 @@
+// Licensed to Cloudera, Inc. under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  Cloudera, Inc. licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+export const RESERVED_WORDS: Set<string> = new Set([
+  'ALL',
+  'ANALYSE',
+  'ANALYZE',
+  'AND',
+  'ANY',
+  'ARRAY',
+  'AS',
+  'ASC',
+  'ASYMMETRIC',
+  'AUTHORIZATION',
+  'BINARY',
+  'BOTH',
+  'CASE',
+  'CAST',
+  'CHECK',
+  'COLLATE',
+  'COLLATION',
+  'COLUMN',
+  'CONCURRENTLY',
+  'CONSTRAINT',
+  'CREATE',
+  'CROSS',
+  'CURRENT_CATALOG',
+  'CURRENT_DATE',
+  'CURRENT_ROLE',
+  'CURRENT_SCHEMA',
+  'CURRENT_TIME',
+  'CURRENT_TIMESTAMP',
+  'CURRENT_USER',
+  'DEFAULT',
+  'DEFERRABLE',
+  'DESC',
+  'DISTINCT',
+  'DO',
+  'ELSE',
+  'END',
+  'EXCEPT',
+  'FALSE',
+  'FETCH',
+  'FOR',
+  'FOREIGN',
+  'FREEZE',
+  'FROM',
+  'FULL',
+  'GRANT',
+  'GROUP',
+  'HAVING',
+  'ILIKE',
+  'IN',
+  'INITIALLY',
+  'INNER',
+  'INTERSECT',
+  'INTO',
+  'IS',
+  'ISNULL',
+  'JOIN',
+  'LATERAL',
+  'LEADING',
+  'LEFT',
+  'LIKE',
+  'LIMIT',
+  'LOCALTIME',
+  'LOCALTIMESTAMP',
+  'NATURAL',
+  'NOT',
+  'NOTNULL',
+  'NULL',
+  'OFFSET',
+  'ON',
+  'ONLY',
+  'OR',
+  'ORDER',
+  'OUTER',
+  'OVERLAPS',
+  'PLACING',
+  'PRIMARY',
+  'REFERENCES',
+  'RETURNING',
+  'RIGHT',
+  'SELECT',
+  'SESSION_USER',
+  'SIMILAR',
+  'SOME',
+  'SYMMETRIC',
+  'TABLE',
+  'TABLESAMPLE',
+  'THEN',
+  'TO',
+  'TRAILING',
+  'TRUE',
+  'UNION',
+  'UNIQUE',
+  'USER',
+  'USING',
+  'VARIADIC',
+  'VERBOSE',
+  'WHEN',
+  'WHERE',
+  'WINDOW',
+  'WITH'
+]);

+ 87 - 0
desktop/core/src/desktop/js/sql/reference/presto/reservedKeywords.ts

@@ -0,0 +1,87 @@
+// Licensed to Cloudera, Inc. under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  Cloudera, Inc. licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+export const RESERVED_WORDS: Set<string> = new Set([
+  'ALTER',
+  'AND',
+  'AS',
+  'BETWEEN',
+  'BY',
+  'CASE',
+  'CAST',
+  'CONSTRAINT',
+  'CREATE',
+  'CROSS',
+  'CUBE',
+  'CURRENT_DATE',
+  'CURRENT_TIME',
+  'CURRENT_TIMESTAMP',
+  'CURRENT_USER',
+  'DEALLOCATE',
+  'DELETE',
+  'DESCRIBE',
+  'DISTINCT',
+  'DROP',
+  'ELSE',
+  'END',
+  'ESCAPE',
+  'EXCEPT',
+  'EXECUTE',
+  'EXISTS',
+  'EXTRACT',
+  'FALSE',
+  'FOR',
+  'FROM',
+  'FULL',
+  'GROUP',
+  'GROUPING',
+  'HAVING',
+  'IN',
+  'INNER',
+  'INSERT',
+  'INTERSECT',
+  'INTO',
+  'IS',
+  'JOIN',
+  'LEFT',
+  'LIKE',
+  'LOCALTIME',
+  'LOCALTIMESTAMP',
+  'NATURAL',
+  'NORMALIZE',
+  'NOT',
+  'NULL',
+  'ON',
+  'OR',
+  'ORDER',
+  'OUTER',
+  'PREPARE',
+  'RECURSIVE',
+  'RIGHT',
+  'ROLLUP',
+  'SELECT',
+  'TABLE',
+  'THEN',
+  'TRUE',
+  'UESCAPE',
+  'UNION',
+  'UNNEST',
+  'USING',
+  'VALUES',
+  'WHEN',
+  'WHERE',
+  'WITH'
+]);

+ 21 - 0
desktop/core/src/desktop/js/sql/reference/sqlReferenceRepository.ts

@@ -32,6 +32,18 @@ export const CLEAR_UDF_CACHE_EVENT = 'hue.clear.udf.cache';
 export const DESCRIBE_UDF_EVENT = 'hue.describe.udf';
 export const UDF_DESCRIBED_EVENT = 'hue.udf.described';
 
+const GENERIC = 'generic';
+
+const KEYWORD_REFS: { [attr: string]: () => Promise<{ RESERVED_WORDS?: Set<string> }> } = {
+  calcite: async () => import(/* webpackChunkName: "calcite-ref" */ './calcite/reservedKeywords'),
+  generic: async () => import(/* webpackChunkName: "generic-ref" */ './generic/reservedKeywords'),
+  hive: async () => import(/* webpackChunkName: "impala-ref" */ './hive/reservedKeywords'),
+  impala: async () => import(/* webpackChunkName: "hive-ref" */ './impala/reservedKeywords'),
+  postgresql: async () =>
+    import(/* webpackChunkName: "generic-ref" */ './postgresql/reservedKeywords'),
+  presto: async () => import(/* webpackChunkName: "generic-ref" */ './presto/reservedKeywords')
+};
+
 const SET_REFS: { [attr: string]: () => Promise<{ SET_OPTIONS?: SetOptions }> } = {
   impala: async () => import(/* webpackChunkName: "impala-ref" */ './impala/setReference')
 };
@@ -235,6 +247,15 @@ export const getSetOptions = async (connector: Connector): Promise<SetOptions> =
   return {};
 };
 
+export const isReserved = async (connector: Connector, word: string): Promise<boolean> => {
+  const module = await KEYWORD_REFS[connector.dialect || GENERIC]();
+  if (module.RESERVED_WORDS) {
+    return module.RESERVED_WORDS.has(word.toUpperCase());
+  }
+
+  return false;
+};
+
 const findUdfInCategories = (
   categories: UdfCategory[],
   udfName: string

+ 0 - 824
desktop/core/src/desktop/js/sql/sqlUtils.js

@@ -1,824 +0,0 @@
-// Licensed to Cloudera, Inc. under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  Cloudera, Inc. licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License.  You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-import $ from 'jquery';
-
-import CancellablePromise from 'api/cancellablePromise';
-import dataCatalog from 'catalog/dataCatalog';
-
-const hiveReservedKeywords = {
-  ALL: true,
-  ALTER: true,
-  AND: true,
-  ARRAY: true,
-  AS: true,
-  AUTHORIZATION: true,
-  BETWEEN: true,
-  BIGINT: true,
-  BINARY: true,
-  BOOLEAN: true,
-  BOTH: true,
-  BY: true,
-  CACHE: true,
-  CASE: true,
-  CAST: true,
-  CHAR: true,
-  COLUMN: true,
-  COMMIT: true,
-  CONF: true,
-  CONSTRAINT: true,
-  CREATE: true,
-  CROSS: true,
-  CUBE: true,
-  CURRENT: true,
-  CURRENT_DATE: true,
-  CURRENT_TIMESTAMP: true,
-  CURSOR: true,
-  DATABASE: true,
-  DATE: true,
-  DAYOFWEEK: true,
-  DECIMAL: true,
-  DELETE: true,
-  DESCRIBE: true,
-  DISTINCT: true,
-  DIV: true,
-  DOUBLE: true,
-  DROP: true,
-  ELSE: true,
-  END: true,
-  EXCHANGE: true,
-  EXISTS: true,
-  EXTENDED: true,
-  EXTERNAL: true,
-  EXTRACT: true,
-  FALSE: true,
-  FETCH: true,
-  FLOAT: true,
-  FLOOR: true,
-  FOLLOWING: true,
-  FOR: true,
-  FOREIGN: true,
-  FROM: true,
-  FULL: true,
-  FUNCTION: true,
-  GRANT: true,
-  GROUP: true,
-  GROUPING: true,
-  HAVING: true,
-  IF: true,
-  IMPORT: true,
-  IN: true,
-  INNER: true,
-  INSERT: true,
-  INT: true,
-  INTEGER: true,
-  INTERSECT: true,
-  INTERVAL: true,
-  INTO: true,
-  IS: true,
-  JOIN: true,
-  LATERAL: true,
-  LEFT: true,
-  LESS: true,
-  LIKE: true,
-  LOCAL: true,
-  MACRO: true,
-  MAP: true,
-  MORE: true,
-  NONE: true,
-  NOT: true,
-  NULL: true,
-  NUMERIC: true,
-  OF: true,
-  ON: true,
-  ONLY: true,
-  OR: true,
-  ORDER: true,
-  OUT: true,
-  OUTER: true,
-  OVER: true,
-  PARTIALSCAN: true,
-  PARTITION: true,
-  PERCENT: true,
-  PRECEDING: true,
-  PRECISION: true,
-  PRESERVE: true,
-  PRIMARY: true,
-  PROCEDURE: true,
-  RANGE: true,
-  READS: true,
-  REDUCE: true,
-  REFERENCES: true,
-  REGEXP: true,
-  REVOKE: true,
-  RIGHT: true,
-  RLIKE: true,
-  ROLLBACK: true,
-  ROLLUP: true,
-  ROW: true,
-  ROWS: true,
-  SELECT: true,
-  SET: true,
-  SMALLINT: true,
-  START: true,
-  SYNC: true,
-  TABLE: true,
-  TABLESAMPLE: true,
-  THEN: true,
-  TIME: true,
-  TIMESTAMP: true,
-  TO: true,
-  TRANSFORM: true,
-  TRIGGER: true,
-  TRUE: true,
-  TRUNCATE: true,
-  UNBOUNDED: true,
-  UNION: true,
-  UNIQUEJOIN: true,
-  UPDATE: true,
-  USER: true,
-  USING: true,
-  UTC_TIMESTAMP: true,
-  VALUES: true,
-  VARCHAR: true,
-  VIEWS: true,
-  WHEN: true,
-  WHERE: true,
-  WINDOW: true,
-  WITH: true
-};
-
-const extraHiveReservedKeywords = {
-  ASC: true,
-  CLUSTER: true,
-  DESC: true,
-  DISTRIBUTE: true,
-  FORMATTED: true,
-  FUNCTION: true,
-  INDEX: true,
-  INDEXES: true,
-  LIMIT: true,
-  LOCK: true,
-  SCHEMA: true,
-  SORT: true
-};
-
-const impalaReservedKeywords = {
-  ADD: true,
-  AGGREGATE: true,
-  ALL: true,
-  ALLOCATE: true,
-  ALTER: true,
-  ANALYTIC: true,
-  AND: true,
-  ANTI: true,
-  ANY: true,
-  API_VERSION: true,
-  ARE: true,
-  ARRAY: true,
-  ARRAY_AGG: true,
-  ARRAY_MAX_CARDINALITY: true,
-  AS: true,
-  ASC: true,
-  ASENSITIVE: true,
-  ASYMMETRIC: true,
-  AT: true,
-  ATOMIC: true,
-  AUTHORIZATION: true,
-  AVRO: true,
-  BEGIN_FRAME: true,
-  BEGIN_PARTITION: true,
-  BETWEEN: true,
-  BIGINT: true,
-  BINARY: true,
-  BLOB: true,
-  BLOCK_SIZE: true,
-  BOOLEAN: true,
-  BOTH: true,
-  BY: true,
-  CACHED: true,
-  CALLED: true,
-  CARDINALITY: true,
-  CASCADE: true,
-  CASCADED: true,
-  CASE: true,
-  CAST: true,
-  CHANGE: true,
-  CHAR: true,
-  CHARACTER: true,
-  CLASS: true,
-  CLOB: true,
-  CLOSE_FN: true,
-  COLLATE: true,
-  COLLECT: true,
-  COLUMN: true,
-  COLUMNS: true,
-  COMMENT: true,
-  COMMIT: true,
-  COMPRESSION: true,
-  COMPUTE: true,
-  CONDITION: true,
-  CONNECT: true,
-  CONSTRAINT: true,
-  CONTAINS: true,
-  CONVERT: true,
-  COPY: true,
-  CORR: true,
-  CORRESPONDING: true,
-  COVAR_POP: true,
-  COVAR_SAMP: true,
-  CREATE: true,
-  CROSS: true,
-  CUBE: true,
-  CURRENT: true,
-  CURRENT_DATE: true,
-  CURRENT_DEFAULT_TRANSFORM_GROUP: true,
-  CURRENT_PATH: true,
-  CURRENT_ROLE: true,
-  CURRENT_ROW: true,
-  CURRENT_SCHEMA: true,
-  CURRENT_TIME: true,
-  CURRENT_TRANSFORM_GROUP_FOR_TYPE: true,
-  CURSOR: true,
-  CYCLE: true,
-  DATA: true,
-  DATABASE: true,
-  DATABASES: true,
-  DATE: true,
-  DATETIME: true,
-  DEALLOCATE: true,
-  DEC: true,
-  DECFLOAT: true,
-  DECIMAL: true,
-  DECLARE: true,
-  DEFINE: true,
-  DELETE: true,
-  DELIMITED: true,
-  DEREF: true,
-  DESC: true,
-  DESCRIBE: true,
-  DETERMINISTIC: true,
-  DISCONNECT: true,
-  DISTINCT: true,
-  DIV: true,
-  DOUBLE: true,
-  DROP: true,
-  DYNAMIC: true,
-  EACH: true,
-  ELEMENT: true,
-  ELSE: true,
-  EMPTY: true,
-  ENCODING: true,
-  END: true,
-  END_FRAME: true,
-  END_PARTITION: true,
-  EQUALS: true,
-  ESCAPE: true,
-  ESCAPED: true,
-  EVERY: true,
-  EXCEPT: true,
-  EXEC: true,
-  EXECUTE: true,
-  EXISTS: true,
-  EXPLAIN: true,
-  EXTENDED: true,
-  EXTERNAL: true,
-  FALSE: true,
-  FETCH: true,
-  FIELDS: true,
-  FILEFORMAT: true,
-  FILES: true,
-  FILTER: true,
-  FINALIZE_FN: true,
-  FIRST: true,
-  FLOAT: true,
-  FOLLOWING: true,
-  FOR: true,
-  FOREIGN: true,
-  FORMAT: true,
-  FORMATTED: true,
-  FRAME_ROW: true,
-  FREE: true,
-  FROM: true,
-  FULL: true,
-  FUNCTION: true,
-  FUNCTIONS: true,
-  FUSION: true,
-  GET: true,
-  GLOBAL: true,
-  GRANT: true,
-  GROUP: true,
-  GROUPING: true,
-  GROUPS: true,
-  HASH: true,
-  HAVING: true,
-  HOLD: true,
-  IF: true,
-  IGNORE: true,
-  ILIKE: true,
-  IN: true,
-  INCREMENTAL: true,
-  INDICATOR: true,
-  INIT_FN: true,
-  INITIAL: true,
-  INNER: true,
-  INOUT: true,
-  INPATH: true,
-  INSENSITIVE: true,
-  INSERT: true,
-  INT: true,
-  INTEGER: true,
-  INTERMEDIATE: true,
-  INTERSECT: true,
-  INTERSECTION: true,
-  INTERVAL: true,
-  INTO: true,
-  INVALIDATE: true,
-  IREGEXP: true,
-  IS: true,
-  JOIN: true,
-  JSON_ARRAY: true,
-  JSON_ARRAYAGG: true,
-  JSON_EXISTS: true,
-  JSON_OBJECT: true,
-  JSON_OBJECTAGG: true,
-  JSON_QUERY: true,
-  JSON_TABLE: true,
-  JSON_TABLE_PRIMITIVE: true,
-  JSON_VALUE: true,
-  KEY: true,
-  KUDU: true,
-  LARGE: true,
-  LAST: true,
-  LATERAL: true,
-  LEADING: true,
-  LEFT: true,
-  LIKE: true,
-  LIKE_REGEX: true,
-  LIMIT: true,
-  LINES: true,
-  LISTAGG: true,
-  LOAD: true,
-  LOCAL: true,
-  LOCALTIMESTAMP: true,
-  LOCATION: true,
-  MAP: true,
-  MATCH: true,
-  MATCH_NUMBER: true,
-  MATCH_RECOGNIZE: true,
-  MATCHES: true,
-  MERGE: true,
-  MERGE_FN: true,
-  METADATA: true,
-  METHOD: true,
-  MODIFIES: true,
-  MULTISET: true,
-  NATIONAL: true,
-  NATURAL: true,
-  NCHAR: true,
-  NCLOB: true,
-  NO: true,
-  NONE: true,
-  NORMALIZE: true,
-  NOT: true,
-  NTH_VALUE: true,
-  NULL: true,
-  NULLS: true,
-  NUMERIC: true,
-  OCCURRENCES_REGEX: true,
-  OCTET_LENGTH: true,
-  OF: true,
-  OFFSET: true,
-  OMIT: true,
-  ON: true,
-  ONE: true,
-  ONLY: true,
-  OR: true,
-  ORDER: true,
-  OUT: true,
-  OUTER: true,
-  OVER: true,
-  OVERLAPS: true,
-  OVERLAY: true,
-  OVERWRITE: true,
-  PARQUET: true,
-  PARQUETFILE: true,
-  PARTITION: true,
-  PARTITIONED: true,
-  PARTITIONS: true,
-  PATTERN: true,
-  PER: true,
-  PERCENT: true,
-  PERCENTILE_CONT: true,
-  PERCENTILE_DISC: true,
-  PORTION: true,
-  POSITION: true,
-  POSITION_REGEX: true,
-  PRECEDES: true,
-  PRECEDING: true,
-  PREPARE: true,
-  PREPARE_FN: true,
-  PRIMARY: true,
-  PROCEDURE: true,
-  PRODUCED: true,
-  PTF: true,
-  PURGE: true,
-  RANGE: true,
-  RCFILE: true,
-  READS: true,
-  REAL: true,
-  RECOVER: true,
-  RECURSIVE: true,
-  REF: true,
-  REFERENCES: true,
-  REFERENCING: true,
-  REFRESH: true,
-  REGEXP: true,
-  REGR_AVGX: true,
-  REGR_AVGY: true,
-  REGR_COUNT: true,
-  REGR_INTERCEPT: true,
-  REGR_R2: true,
-  REGR_SLOPE: true,
-  REGR_SXX: true,
-  REGR_SXY: true,
-  REGR_SYY: true,
-  RELEASE: true,
-  RENAME: true,
-  REPEATABLE: true,
-  REPLACE: true,
-  REPLICATION: true,
-  RESTRICT: true,
-  RETURNS: true,
-  REVOKE: true,
-  RIGHT: true,
-  RLIKE: true,
-  ROLE: true,
-  ROLES: true,
-  ROLLBACK: true,
-  ROLLUP: true,
-  ROW: true,
-  ROWS: true,
-  RUNNING: true,
-  SAVEPOINT: true,
-  SCHEMA: true,
-  SCHEMAS: true,
-  SCOPE: true,
-  SCROLL: true,
-  SEARCH: true,
-  SEEK: true,
-  SELECT: true,
-  SEMI: true,
-  SENSITIVE: true,
-  SEQUENCEFILE: true,
-  SERDEPROPERTIES: true,
-  SERIALIZE_FN: true,
-  SET: true,
-  SHOW: true,
-  SIMILAR: true,
-  SKIP: true,
-  SMALLINT: true,
-  SOME: true,
-  SORT: true,
-  SPECIFIC: true,
-  SPECIFICTYPE: true,
-  SQLEXCEPTION: true,
-  SQLSTATE: true,
-  SQLWARNING: true,
-  STATIC: true,
-  STATS: true,
-  STORED: true,
-  STRAIGHT_JOIN: true,
-  STRING: true,
-  STRUCT: true,
-  SUBMULTISET: true,
-  SUBSET: true,
-  SUBSTRING_REGEX: true,
-  SUCCEEDS: true,
-  SYMBOL: true,
-  SYMMETRIC: true,
-  SYSTEM_TIME: true,
-  SYSTEM_USER: true,
-  TABLE: true,
-  TABLES: true,
-  TABLESAMPLE: true,
-  TBLPROPERTIES: true,
-  TERMINATED: true,
-  TEXTFILE: true,
-  THEN: true,
-  TIMESTAMP: true,
-  TIMEZONE_HOUR: true,
-  TIMEZONE_MINUTE: true,
-  TINYINT: true,
-  TO: true,
-  TRAILING: true,
-  TRANSLATE_REGEX: true,
-  TRANSLATION: true,
-  TREAT: true,
-  TRIGGER: true,
-  TRIM_ARRAY: true,
-  TRUE: true,
-  TRUNCATE: true,
-  UESCAPE: true,
-  UNBOUNDED: true,
-  UNCACHED: true,
-  UNION: true,
-  UNIQUE: true,
-  UNKNOWN: true,
-  UNNEST: true,
-  UPDATE: true,
-  UPDATE_FN: true,
-  UPSERT: true,
-  USE: true,
-  USER: true,
-  USING: true,
-  VALUE_OF: true,
-  VALUES: true,
-  VARBINARY: true,
-  VARCHAR: true,
-  VARYING: true,
-  VERSIONING: true,
-  VIEW: true,
-  WHEN: true,
-  WHENEVER: true,
-  WHERE: true,
-  WIDTH_BUCKET: true,
-  WINDOW: true,
-  WITH: true,
-  WITHIN: true,
-  WITHOUT: true
-};
-
-const identifierEquals = (a, b) =>
-  a &&
-  b &&
-  a.replace(/^\s*`/, '').replace(/`\s*$/, '').toLowerCase() ===
-    b.replace(/^\s*`/, '').replace(/`\s*$/, '').toLowerCase();
-
-const autocompleteFilter = (filter, entries) => {
-  const lowerCaseFilter = filter.toLowerCase();
-  return entries.filter(suggestion => {
-    // TODO: Extend with fuzzy matches
-    let foundIndex = suggestion.value.toLowerCase().indexOf(lowerCaseFilter);
-    if (foundIndex !== -1) {
-      if (
-        foundIndex === 0 ||
-        (suggestion.filterValue &&
-          suggestion.filterValue.toLowerCase().indexOf(lowerCaseFilter) === 0)
-      ) {
-        suggestion.filterWeight = 3;
-      } else {
-        suggestion.filterWeight = 2;
-      }
-    } else if (
-      suggestion.details &&
-      suggestion.details.comment &&
-      lowerCaseFilter.indexOf(' ') === -1
-    ) {
-      foundIndex = suggestion.details.comment.toLowerCase().indexOf(lowerCaseFilter);
-      if (foundIndex !== -1) {
-        suggestion.filterWeight = 1;
-        suggestion.matchComment = true;
-      }
-    }
-    if (foundIndex !== -1) {
-      suggestion.matchIndex = foundIndex;
-      suggestion.matchLength = filter.length;
-      return true;
-    }
-    return false;
-  });
-};
-
-const sortSuggestions = (suggestions, filter, sortOverride) => {
-  suggestions.sort((a, b) => {
-    if (filter) {
-      if (
-        typeof a.filterWeight !== 'undefined' &&
-        typeof b.filterWeight !== 'undefined' &&
-        b.filterWeight !== a.filterWeight
-      ) {
-        return b.filterWeight - a.filterWeight;
-      }
-      if (typeof a.filterWeight !== 'undefined' && typeof b.filterWeight === 'undefined') {
-        return -1;
-      }
-      if (typeof a.filterWeight === 'undefined' && typeof b.filterWeight !== 'undefined') {
-        return 1;
-      }
-    }
-    if (sortOverride && sortOverride.partitionColumnsFirst) {
-      if (a.partitionKey && !b.partitionKey) {
-        return -1;
-      }
-      if (b.partitionKey && !a.partitionKey) {
-        return 1;
-      }
-    }
-    const aWeight = a.category.weight + (a.weightAdjust || 0);
-    const bWeight = b.category.weight + (b.weightAdjust || 0);
-    if (typeof aWeight !== 'undefined' && typeof bWeight !== 'undefined' && bWeight !== aWeight) {
-      return bWeight - aWeight;
-    }
-    if (typeof aWeight !== 'undefined' && typeof bWeight === 'undefined') {
-      return -1;
-    }
-    if (typeof aWeight === 'undefined' && typeof bWeight !== 'undefined') {
-      return 1;
-    }
-    return a.value.localeCompare(b.value);
-  });
-};
-
-const identifierChainToPath = identifierChain => identifierChain.map(identifier => identifier.name);
-
-/**
- *
- * @param {Object} options
- * @param {String} options.connector
- * @param {ContextNamespace} options.namespace
- * @param {ContextCompute} options.compute
- * @param {boolean} [options.temporaryOnly] - Default: false
- * @param {Object[]} [options.identifierChain]
- * @param {Object[]} [options.tables]
- * @param {Object} [options.cancellable]
- * @param {Object} [options.cachedOnly]
- *
- * @return {CancellablePromise}
- */
-export const resolveCatalogEntry = options => {
-  const cancellablePromises = [];
-  const deferred = $.Deferred();
-  const promise = new CancellablePromise(deferred, undefined, cancellablePromises);
-  dataCatalog.applyCancellable(promise, options);
-
-  if (!options.identifierChain) {
-    deferred.reject();
-    return promise;
-  }
-
-  const findInTree = (currentEntry, fieldsToGo) => {
-    if (fieldsToGo.length === 0) {
-      deferred.reject();
-      return;
-    }
-
-    let nextField;
-    if (currentEntry.getType() === 'map') {
-      nextField = 'value';
-    } else if (currentEntry.getType() === 'array') {
-      nextField = 'item';
-    } else {
-      nextField = fieldsToGo.shift();
-    }
-
-    cancellablePromises.push(
-      currentEntry
-        .getChildren({
-          cancellable: options.cancellable,
-          cachedOnly: options.cachedOnly,
-          silenceErrors: true
-        })
-        .done(childEntries => {
-          let foundEntry = undefined;
-          childEntries.some(childEntry => {
-            if (identifierEquals(childEntry.name, nextField)) {
-              foundEntry = childEntry;
-              return true;
-            }
-          });
-          if (foundEntry && fieldsToGo.length) {
-            findInTree(foundEntry, fieldsToGo);
-          } else if (foundEntry) {
-            deferred.resolve(foundEntry);
-          } else {
-            deferred.reject();
-          }
-        })
-        .fail(deferred.reject)
-    );
-  };
-
-  const findTable = tablesToGo => {
-    if (tablesToGo.length === 0) {
-      deferred.reject();
-      return;
-    }
-
-    const nextTable = tablesToGo.pop();
-    if (typeof nextTable.subQuery !== 'undefined') {
-      findTable(tablesToGo);
-      return;
-    }
-
-    cancellablePromises.push(
-      dataCatalog
-        .getChildren({
-          connector: options.connector,
-          namespace: options.namespace,
-          compute: options.compute,
-          path: identifierChainToPath(nextTable.identifierChain),
-          cachedOnly: options && options.cachedOnly,
-          cancellable: options && options.cancellable,
-          temporaryOnly: options && options.temporaryOnly,
-          silenceErrors: true
-        })
-        .done(childEntries => {
-          let foundEntry = undefined;
-          childEntries.some(childEntry => {
-            if (identifierEquals(childEntry.name, options.identifierChain[0].name)) {
-              foundEntry = childEntry;
-              return true;
-            }
-          });
-
-          if (foundEntry && options.identifierChain.length > 1) {
-            findInTree(foundEntry, identifierChainToPath(options.identifierChain.slice(1)));
-          } else if (foundEntry) {
-            deferred.resolve(foundEntry);
-          } else {
-            findTable(tablesToGo);
-          }
-        })
-        .fail(deferred.reject)
-    );
-  };
-
-  if (options.tables) {
-    findTable(options.tables.concat());
-  } else {
-    dataCatalog
-      .getEntry({
-        namespace: options.namespace,
-        compute: options.compute,
-        connector: options.connector,
-        path: [],
-        cachedOnly: options && options.cachedOnly,
-        cancellable: options && options.cancellable,
-        temporaryOnly: options && options.temporaryOnly,
-        silenceErrors: true
-      })
-      .done(entry => {
-        findInTree(entry, identifierChainToPath(options.identifierChain));
-      });
-  }
-
-  return promise;
-};
-
-export default {
-  autocompleteFilter: autocompleteFilter,
-  backTickIfNeeded: (connector, identifier) => {
-    const quoteChar =
-      (connector.dialect_properties && connector.dialect_properties.sql_identifier_quote) || '`';
-    if (identifier.indexOf(quoteChar) === 0) {
-      return identifier;
-    }
-    const upperIdentifier = identifier.toUpperCase();
-    if (
-      connector.dialect === 'hive' &&
-      (hiveReservedKeywords[upperIdentifier] || extraHiveReservedKeywords[upperIdentifier])
-    ) {
-      return quoteChar + identifier + quoteChar;
-    }
-    if (connector.dialect === 'impala' && impalaReservedKeywords[upperIdentifier]) {
-      return quoteChar + identifier + quoteChar;
-    }
-    if (
-      connector.dialect !== 'impala' &&
-      connector.dialect !== 'hive' &&
-      (impalaReservedKeywords[upperIdentifier] ||
-        hiveReservedKeywords[upperIdentifier] ||
-        extraHiveReservedKeywords[upperIdentifier])
-    ) {
-      return quoteChar + identifier + quoteChar;
-    }
-    if (!/^[A-Za-z][A-Za-z0-9_]*$/.test(identifier)) {
-      return quoteChar + identifier + quoteChar;
-    }
-    return identifier;
-  },
-  locationEquals: (a, b) =>
-    a &&
-    b &&
-    a.first_line === b.first_line &&
-    a.first_column === b.first_column &&
-    a.last_line === b.last_line &&
-    a.last_column === b.last_column,
-  identifierEquals: identifierEquals,
-  sortSuggestions: sortSuggestions,
-  identifierChainToPath: identifierChainToPath
-};

+ 279 - 0
desktop/core/src/desktop/js/sql/sqlUtils.ts

@@ -0,0 +1,279 @@
+// Licensed to Cloudera, Inc. under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  Cloudera, Inc. licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import DataCatalogEntry from 'catalog/dataCatalogEntry';
+import $ from 'jquery';
+
+import CancellablePromise from 'api/cancellablePromise';
+import dataCatalog from 'catalog/dataCatalog';
+import { IdentifierChainEntry, ParsedLocation, ParsedTable } from 'parse/types';
+import { isReserved } from 'sql/reference/sqlReferenceRepository';
+import { Suggestion } from 'sql/types';
+import { Compute, Connector, Namespace } from 'types/config';
+
+const identifierEquals = (a?: string, b?: string): boolean =>
+  !!a &&
+  !!b &&
+  a.replace(/^\s*`/, '').replace(/`\s*$/, '').toLowerCase() ===
+    b.replace(/^\s*`/, '').replace(/`\s*$/, '').toLowerCase();
+
+const autocompleteFilter = (filter: string, entries: Suggestion[]): Suggestion[] => {
+  const lowerCaseFilter = filter.toLowerCase();
+  return entries.filter(suggestion => {
+    // TODO: Extend with fuzzy matches
+    let foundIndex = suggestion.value.toLowerCase().indexOf(lowerCaseFilter);
+    if (foundIndex !== -1) {
+      if (
+        foundIndex === 0 ||
+        (suggestion.filterValue &&
+          suggestion.filterValue.toLowerCase().indexOf(lowerCaseFilter) === 0)
+      ) {
+        suggestion.filterWeight = 3;
+      } else {
+        suggestion.filterWeight = 2;
+      }
+    } else if (
+      suggestion.details &&
+      suggestion.details.comment &&
+      lowerCaseFilter.indexOf(' ') === -1
+    ) {
+      foundIndex = suggestion.details.comment.toLowerCase().indexOf(lowerCaseFilter);
+      if (foundIndex !== -1) {
+        suggestion.filterWeight = 1;
+        suggestion.matchComment = true;
+      }
+    }
+    if (foundIndex !== -1) {
+      suggestion.matchIndex = foundIndex;
+      suggestion.matchLength = filter.length;
+      return true;
+    }
+    return false;
+  });
+};
+
+interface SortOverride {
+  partitionColumnsFirst?: boolean;
+}
+
+const sortSuggestions = (
+  suggestions: Suggestion[],
+  filter: string,
+  sortOverride?: SortOverride
+): void => {
+  suggestions.sort((a, b) => {
+    if (filter) {
+      if (
+        typeof a.filterWeight !== 'undefined' &&
+        typeof b.filterWeight !== 'undefined' &&
+        b.filterWeight !== a.filterWeight
+      ) {
+        return b.filterWeight - a.filterWeight;
+      }
+      if (typeof a.filterWeight !== 'undefined' && typeof b.filterWeight === 'undefined') {
+        return -1;
+      }
+      if (typeof a.filterWeight === 'undefined' && typeof b.filterWeight !== 'undefined') {
+        return 1;
+      }
+    }
+    if (sortOverride && sortOverride.partitionColumnsFirst) {
+      if (a.partitionKey && !b.partitionKey) {
+        return -1;
+      }
+      if (b.partitionKey && !a.partitionKey) {
+        return 1;
+      }
+    }
+    const aWeight = a.category.weight + (a.weightAdjust || 0);
+    const bWeight = b.category.weight + (b.weightAdjust || 0);
+    if (typeof aWeight !== 'undefined' && typeof bWeight !== 'undefined' && bWeight !== aWeight) {
+      return bWeight - aWeight;
+    }
+    if (typeof aWeight !== 'undefined' && typeof bWeight === 'undefined') {
+      return -1;
+    }
+    if (typeof aWeight === 'undefined' && typeof bWeight !== 'undefined') {
+      return 1;
+    }
+    return a.value.localeCompare(b.value);
+  });
+};
+
+const identifierChainToPath = (identifierChain: IdentifierChainEntry[]): string[] =>
+  identifierChain.map(identifier => identifier.name);
+
+export const resolveCatalogEntry = (options: {
+  connector: Connector;
+  namespace: Namespace;
+  compute: Compute;
+  temporaryOnly?: boolean;
+  cachedOnly?: boolean;
+  cancellable?: boolean;
+  identifierChain?: IdentifierChainEntry[];
+  tables?: ParsedTable[];
+}): CancellablePromise<DataCatalogEntry> => {
+  const cancellablePromises: CancellablePromise<unknown>[] = [];
+  const deferred = $.Deferred();
+  const promise = new CancellablePromise(deferred, undefined, cancellablePromises);
+  dataCatalog.applyCancellable(promise, { cancellable: !!options.cancellable });
+
+  if (!options.identifierChain) {
+    deferred.reject();
+    return promise;
+  }
+
+  const findInTree = (currentEntry: DataCatalogEntry, fieldsToGo: string[]): void => {
+    if (fieldsToGo.length === 0) {
+      deferred.reject();
+      return;
+    }
+
+    let nextField: string;
+    if (currentEntry.getType() === 'map') {
+      nextField = 'value';
+    } else if (currentEntry.getType() === 'array') {
+      nextField = 'item';
+    } else {
+      nextField = fieldsToGo.shift() || '';
+    }
+
+    cancellablePromises.push(
+      currentEntry
+        .getChildren({
+          cancellable: !!options.cancellable,
+          cachedOnly: !!options.cachedOnly,
+          silenceErrors: true
+        })
+        .done(childEntries => {
+          let foundEntry = undefined;
+          childEntries.some((childEntry: { name: string }) => {
+            if (identifierEquals(childEntry.name, nextField)) {
+              foundEntry = childEntry;
+              return true;
+            }
+          });
+          if (foundEntry && fieldsToGo.length) {
+            findInTree(foundEntry, fieldsToGo);
+          } else if (foundEntry) {
+            deferred.resolve(foundEntry);
+          } else {
+            deferred.reject();
+          }
+        })
+        .fail(deferred.reject)
+    );
+  };
+
+  const findTable = (tablesToGo: ParsedTable[]): void => {
+    if (tablesToGo.length === 0) {
+      deferred.reject();
+      return;
+    }
+
+    const nextTable = tablesToGo.pop();
+    if (nextTable && typeof nextTable.subQuery !== 'undefined') {
+      findTable(tablesToGo);
+      return;
+    }
+
+    cancellablePromises.push(
+      dataCatalog
+        .getChildren({
+          connector: options.connector,
+          namespace: options.namespace,
+          compute: options.compute,
+          path: identifierChainToPath((nextTable && nextTable.identifierChain) || []),
+          cachedOnly: !!options.cachedOnly,
+          cancellable: !!options.cancellable,
+          temporaryOnly: !!options.temporaryOnly,
+          silenceErrors: true
+        })
+        .done(childEntries => {
+          let foundEntry = undefined;
+          childEntries.some((childEntry: { name: string }) => {
+            if (
+              options.identifierChain &&
+              options.identifierChain.length &&
+              identifierEquals(childEntry.name, options.identifierChain[0].name)
+            ) {
+              foundEntry = childEntry;
+              return true;
+            }
+          });
+
+          if (foundEntry && options.identifierChain && options.identifierChain.length > 1) {
+            findInTree(foundEntry, identifierChainToPath(options.identifierChain.slice(1)));
+          } else if (foundEntry) {
+            deferred.resolve(foundEntry);
+          } else {
+            findTable(tablesToGo);
+          }
+        })
+        .fail(deferred.reject)
+    );
+  };
+
+  if (options.tables) {
+    findTable(options.tables.concat());
+  } else {
+    dataCatalog
+      .getEntry({
+        namespace: options.namespace,
+        compute: options.compute,
+        connector: options.connector,
+        path: [],
+        cachedOnly: !!options.cachedOnly,
+        temporaryOnly: !!options.temporaryOnly
+      })
+      .done(entry => {
+        if (options.identifierChain) {
+          findInTree(entry, identifierChainToPath(options.identifierChain));
+        }
+      });
+  }
+
+  return promise;
+};
+
+export default {
+  autocompleteFilter: autocompleteFilter,
+  backTickIfNeeded: async (connector: Connector, identifier: string): Promise<string> => {
+    const quoteChar =
+      (connector.dialect_properties && connector.dialect_properties.sql_identifier_quote) || '`';
+    if (identifier.indexOf(quoteChar) === 0) {
+      return identifier;
+    }
+    if (await isReserved(connector, identifier)) {
+      return quoteChar + identifier + quoteChar;
+    }
+
+    if (!/^[A-Za-z][A-Za-z0-9_]*$/.test(identifier)) {
+      return quoteChar + identifier + quoteChar;
+    }
+    return identifier;
+  },
+  locationEquals: (a?: ParsedLocation, b?: ParsedLocation): boolean =>
+    !!a &&
+    !!b &&
+    a.first_line === b.first_line &&
+    a.first_column === b.first_column &&
+    a.last_line === b.last_line &&
+    a.last_column === b.last_column,
+  identifierEquals: identifierEquals,
+  sortSuggestions: sortSuggestions,
+  identifierChainToPath: identifierChainToPath
+};

+ 32 - 0
desktop/core/src/desktop/js/sql/types.ts

@@ -0,0 +1,32 @@
+// Licensed to Cloudera, Inc. under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  Cloudera, Inc. licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+export interface Suggestion {
+  value: string;
+  filterValue?: string;
+  filterWeight?: number;
+  details?: {
+    comment?: string;
+  };
+  matchComment?: boolean;
+  matchIndex?: number;
+  matchLength?: number;
+  category: {
+    weight: number;
+  };
+  weightAdjust?: number;
+  partitionKey?: boolean;
+}

+ 19 - 1
desktop/core/src/desktop/js/types/config.ts

@@ -16,6 +16,20 @@
 
 import { GenericApiResponse } from 'types/types';
 
+export interface Compute {
+  id: string;
+  name: string;
+  type: string;
+  namespace?: string;
+}
+
+export interface Namespace {
+  id: string;
+  name: string;
+  status: string;
+  computes: Compute[];
+}
+
 export interface Cluster {
   credentials: Record<string, unknown>;
   id: string;
@@ -82,7 +96,11 @@ export interface IdentifiableInterpreter extends Interpreter {
 }
 
 /* eslint-disable @typescript-eslint/no-empty-interface */
-export interface Connector extends IdentifiableInterpreter {}
+export interface Connector extends IdentifiableInterpreter {
+  dialect_properties?: {
+    sql_identifier_quote?: string;
+  };
+}
 
 export interface EditorInterpreter extends IdentifiableInterpreter {
   dialect_properties: Record<string, unknown> | null;

+ 16 - 0
desktop/core/src/desktop/js/types/types.ts

@@ -1,3 +1,19 @@
+// Licensed to Cloudera, Inc. under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  Cloudera, Inc. licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
 export interface GenericApiResponse {
   status: number;
   message?: string;

+ 44 - 34
desktop/libs/indexer/src/indexer/templates/importer.mako

@@ -1637,44 +1637,54 @@ ${ commonheader(_("Importer"), "indexer", user, request, "60px") | n,unicode }
 
           var statementCols = [];
           var temporaryColumns = [];
+
+          var deferreds = []; // TODO: Move to async/await when in webpack
+
           sampleCols.forEach(function (sampleCol) {
-            statementCols.push(sqlUtils.backTickIfNeeded({ id: self.sourceType, dialect: self.sourceType }, sampleCol.name()));
-            var col = {
-              name: sampleCol.name(),
-              type: sampleCol.type()
-            };
-            temporaryColumns.push(col);
-            var colNameSub = sampleCol.name.subscribe(function () {
-              refreshTemporaryTable(self.sampleCols())
-            });
-            var colTypeSub = sampleCol.type.subscribe(function () {
-              refreshTemporaryTable(self.sampleCols())
+            var deferred = $.Deferred();
+            deferreds.push(deferred);
+            sqlUtils.backTickIfNeeded({ id: self.sourceType, dialect: self.sourceType }, sampleCol.name()).then(function (value) {
+              statementCols.push(value);
+              var col = {
+                name: sampleCol.name(),
+                type: sampleCol.type()
+              };
+              temporaryColumns.push(col);
+              var colNameSub = sampleCol.name.subscribe(function () {
+                refreshTemporaryTable(self.sampleCols())
+              });
+              var colTypeSub = sampleCol.type.subscribe(function () {
+                refreshTemporaryTable(self.sampleCols())
+              });
+              sampleColSubDisposals.push(function () {
+                colNameSub.dispose();
+                colTypeSub.dispose();
+              })
+              deferred.resolve();
+            }).catch(deferred.reject);
+          });
+
+          $.when.apply($, deferreds).done(function () {
+            var statement = 'SELECT ';
+            statement += statementCols.join(',\n    ');
+            statement += '\n FROM ' + sqlUtils.backTickIfNeeded({ id: self.sourceType, dialect: self.sourceType }, tableName) + ';';
+            if (!wizard.destination.fieldEditorValue() || wizard.destination.fieldEditorValue() === lastStatement) {
+              wizard.destination.fieldEditorValue(statement);
+            }
+            lastStatement = statement;
+            wizard.destination.fieldEditorPlaceHolder('${ _('Example: SELECT') }' + ' * FROM ' + sqlUtils.backTickIfNeeded({ id: self.sourceType, dialect: self.sourceType }, tableName));
+
+            var handle = dataCatalog.addTemporaryTable({
+              namespace: self.namespace(),
+              compute: self.compute(),
+              connector: { id: self.sourceType }, // TODO: Migrate importer to connectors
+              name: tableName,
+              columns: temporaryColumns,
+              sample: self.sample()
             });
             sampleColSubDisposals.push(function () {
-              colNameSub.dispose();
-              colTypeSub.dispose();
+              handle.delete();
             })
-          });
-
-          var statement = 'SELECT ';
-          statement += statementCols.join(',\n    ');
-          statement += '\n FROM ' + sqlUtils.backTickIfNeeded({ id: self.sourceType, dialect: self.sourceType }, tableName) + ';';
-          if (!wizard.destination.fieldEditorValue() || wizard.destination.fieldEditorValue() === lastStatement) {
-            wizard.destination.fieldEditorValue(statement);
-          }
-          lastStatement = statement;
-          wizard.destination.fieldEditorPlaceHolder('${ _('Example: SELECT') }' + ' * FROM ' + sqlUtils.backTickIfNeeded({ id: self.sourceType, dialect: self.sourceType }, tableName));
-
-          var handle = dataCatalog.addTemporaryTable({
-            namespace: self.namespace(),
-            compute: self.compute(),
-            connector: { id: self.sourceType }, // TODO: Migrate importer to connectors
-            name: tableName,
-            columns: temporaryColumns,
-            sample: self.sample()
-          });
-          sampleColSubDisposals.push(function () {
-            handle.delete();
           })
         }, 500)
       };