Explorar el Código

HUE-4200 [editor] Autocompletion of SHOW statements

This covers all currently possible SHOW statements for Hive and Impala. I've also refactored the jasmine tests into separate files per statement type.
Johan Ahlen hace 9 años
padre
commit
3fea69c1c0

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 744 - 88
desktop/core/src/desktop/static/desktop/js/autocomplete/sql.jison


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
desktop/core/src/desktop/static/desktop/js/autocomplete/sql.js


+ 238 - 2411
desktop/core/src/desktop/static/desktop/spec/autocomplete/sqlSpec.js

@@ -16,7 +16,14 @@
 define([
   'knockout',
   'desktop/js/autocomplete/sql',
-  'desktop/spec/autocompleterTestUtils'
+  'desktop/spec/autocompleterTestUtils',
+  'desktop/spec/autocomplete/sqlSpecCreate',
+  'desktop/spec/autocomplete/sqlSpecDrop',
+  'desktop/spec/autocomplete/sqlSpecLoad',
+  'desktop/spec/autocomplete/sqlSpecSelect',
+  'desktop/spec/autocomplete/sqlSpecShow',
+  'desktop/spec/autocomplete/sqlSpecUpdate',
+  'desktop/spec/autocomplete/sqlSpecUse'
 ], function(ko, sql, testUtils) {
 
   describe('sql.js', function() {
@@ -28,2460 +35,280 @@ define([
       jasmine.addMatchers(testUtils.testDefinitionMatcher);
     });
 
-    var assertAutoComplete = function(testDefinition) {
-      expect(sql.parseSql(testDefinition.beforeCursor, testDefinition.afterCursor, testDefinition.dialect)).toEqualDefinition(testDefinition);
-    };
+    var assertAutoComplete = testUtils.assertAutocomplete;
 
-    describe('keyword completion', function () {
+    describe('Impala specific', function () {
       it('should suggest keywords for empty statement', function() {
         assertAutoComplete({
           beforeCursor: '',
           afterCursor: '',
-          expectedResult: {
-            lowerCase: false,
-            suggestKeywords: ['ALTER', 'CREATE', 'DELETE', 'DESCRIBE', 'DROP',
-              'EXPLAIN', 'INSERT', 'REVOKE', 'SELECT', 'SET', 'SHOW', 'TRUNCATE',
-              'UPDATE', 'USE']
-          }
-        });
-      });
-
-      it('should suggest keywords after complete statement', function() {
-        assertAutoComplete({
-          beforeCursor: 'SELECT * FROM bar;',
-          afterCursor: '',
-          expectedResult: {
-            lowerCase: false,
-            suggestKeywords: ['ALTER', 'CREATE', 'DELETE', 'DESCRIBE', 'DROP',
-              'EXPLAIN', 'INSERT', 'REVOKE', 'SELECT', 'SET', 'SHOW', 'TRUNCATE',
-              'UPDATE', 'USE']
-          }
-        });
-      });
-
-      it('should suggest keywords after complete statements', function() {
-        assertAutoComplete({
-          beforeCursor: 'SELECT * FROM bar;SELECT * FROM bar;',
-          afterCursor: '',
-          expectedResult: {
-            lowerCase: false,
-            suggestKeywords: ['ALTER', 'CREATE', 'DELETE', 'DESCRIBE', 'DROP',
-              'EXPLAIN', 'INSERT', 'REVOKE', 'SELECT', 'SET', 'SHOW', 'TRUNCATE',
-              'UPDATE', 'USE']
-          }
-        });
-      });
-
-      it('should suggest keywords for partial statement', function() {
-        assertAutoComplete({
-          beforeCursor: 'se',
-          afterCursor: '',
-          expectedResult: {
-            lowerCase: false,
-            suggestKeywords: ['ALTER', 'CREATE', 'DELETE', 'DESCRIBE', 'DROP',
-              'EXPLAIN', 'INSERT', 'REVOKE', 'SELECT', 'SET', 'SHOW', 'TRUNCATE',
-              'UPDATE', 'USE']
-          }
-        });
-      });
-
-      it('should suggest keywords after CREATE', function () {
-        assertAutoComplete({
-          beforeCursor: 'CREATE ',
-          afterCursor: '',
-          expectedResult: {
-            lowerCase: false,
-            suggestKeywords: ['DATABASE', 'SCHEMA', 'TABLE']
-          }
-        });
-      });
-
-      it('should suggest keywords after CREATE DATABASE ', function () {
-        assertAutoComplete({
-          beforeCursor: 'CREATE DATABASE ',
-          afterCursor: '',
-          expectedResult: {
-            lowerCase: false,
-            suggestKeywords: ['IF NOT EXISTS']
-          }
-        });
-      });
-
-      it('should suggest keywords after CREATE DATABASE IF ', function () {
-        assertAutoComplete({
-          beforeCursor: 'CREATE DATABASE IF ',
-          afterCursor: '',
-          expectedResult: {
-            lowerCase: false,
-            suggestKeywords: ['NOT EXISTS']
-          }
-        });
-      });
-
-      it('should suggest keywords after CREATE SCHEMA ', function () {
-        assertAutoComplete({
-          beforeCursor: 'CREATE SCHEMA ',
-          afterCursor: '',
-          expectedResult: {
-            lowerCase: false,
-            suggestKeywords: ['IF NOT EXISTS']
-          }
-        });
-      });
-
-      it('should suggest keywords after CREATE DATABASE and before Identifier', function () {
-        assertAutoComplete({
-          beforeCursor: 'CREATE DATABASE ',
-          afterCursor: ' bla;',
-          expectedResult: {
-            lowerCase: false,
-            suggestKeywords: ['IF NOT EXISTS']
-          }
-        });
-      });
-
-      it('should suggest keywords after CREATE TABLE identifier (identifier ', function () {
-        assertAutoComplete({
-          beforeCursor: 'CREATE TABLE foo (id ',
-          afterCursor: '',
-          expectedResult: {
-            lowerCase: false,
-            suggestKeywords: ['BIGINT', 'BOOLEAN', 'CHAR', 'DECIMAL', 'DOUBLE', 'FLOAT', 'INT', 'SMALLINT', 'TIMESTAMP', 'STRING', 'TINYINT', 'VARCHAR']
-          }
-        });
-      });
-
-      it('should suggest keywords after CREATE TABLE identifier (identifier INT, identifier FLOAT, identifier ', function () {
-        assertAutoComplete({
-          beforeCursor: 'CREATE TABLE foo (id INT, some FLOAT, bar ',
-          afterCursor: '',
-          expectedResult: {
-            lowerCase: false,
-            suggestKeywords: ['BIGINT', 'BOOLEAN', 'CHAR', 'DECIMAL', 'DOUBLE', 'FLOAT', 'INT', 'SMALLINT', 'TIMESTAMP', 'STRING', 'TINYINT', 'VARCHAR']
-          }
-        });
-      });
-
-      it('should suggest keywords after SELECT * ', function() {
-        assertAutoComplete({
-          beforeCursor: 'SELECT * ',
-          afterCursor: '',
-          expectedResult: {
-            lowerCase: false,
-            suggestTables:{
-              prependFrom:true
-            },
-            suggestDatabases:{
-              prependFrom:true,
-              appendDot:true
-            }
-          }
-        });
-      });
-
-      it('should suggest keywords after SELECT SelectList ', function() {
-        assertAutoComplete({
-          beforeCursor: 'SELECT foo, bar ',
-          afterCursor: '',
-          expectedResult: {
-            lowerCase: false,
-            suggestTables:{
-              prependFrom:true
-            },
-            suggestDatabases:{
-              prependFrom:true,
-              appendDot:true
-            }
-          }
-        });
-      });
-
-      it('should suggest keywords after SELECT SelectList FROM TablePrimary ', function() {
-        assertAutoComplete({
-          serverResponses: {},
-          beforeCursor: 'SELECT * FROM testTableA tta, testTableB ',
-          afterCursor: '',
-          expectedResult: {
-            lowerCase: false,
-            suggestKeywords: ['GROUP BY', 'JOIN', 'LIMIT', 'ORDER BY', 'WHERE']
-          }
-        });
-      });
-
-      it('should suggest keywords after SELECT SelectList FROM TablePrimary WHERE SearchCondition ', function () {
-        assertAutoComplete({
-          beforeCursor: 'SELECT bar FROM foo WHERE id = 1 ',
-          afterCursor: '',
-          expectedResult: {
-            lowerCase: false,
-            suggestKeywords: ['GROUP BY', 'LIMIT', 'ORDER BY']
-          }
-        });
-      });
-
-      it('should suggest keywords after UPDATE TableReference ', function () {
-        assertAutoComplete({
-          beforeCursor: 'UPDATE bar  ',
-          afterCursor: '',
-          expectedResult: {
-            lowerCase: false,
-            suggestKeywords: ['SET']
-          }
-        });
-      });
-
-      it('should suggest keywords after UPDATE TableReference SET SetClauseList ', function () {
-        assertAutoComplete({
-          beforeCursor: 'UPDATE bar SET id=1, foo=2 ',
-          afterCursor: '',
-          expectedResult: {
-            lowerCase: false,
-            suggestKeywords: ['WHERE']
-          }
-        });
-      });
-
-      it('should suggest keywords after UPDATE TableReference SET identifier ', function () {
-        assertAutoComplete({
-          beforeCursor: 'UPDATE bar SET id ',
-          afterCursor: '',
-          expectedResult: {
-            lowerCase: false,
-            suggestKeywords: ['=']
-          }
-        });
-      });
-
-      describe('Impala specific', function () {
-        it('should suggest keywords for empty statement', function() {
-          assertAutoComplete({
-            beforeCursor: '',
-            afterCursor: '',
-            dialect: 'impala',
-            expectedResult: {
-              lowerCase: false,
-              suggestKeywords: ['ALTER', 'COMPUTE', 'CREATE', 'DELETE', 'DESCRIBE',
-                'DROP', 'EXPLAIN', 'INSERT', 'INVALIDATE', 'LOAD', 'REFRESH',
-                'REVOKE', 'SELECT', 'SET', 'SHOW', 'TRUNCATE', 'UPDATE', 'USE']
-            }
-          });
-        });
-
-        it ('should suggest keywords after LOAD', function () {
-          assertAutoComplete({
-            beforeCursor: 'LOAD ',
-            afterCursor: '',
-            dialect: 'impala',
-            expectedResult: {
-              lowerCase: false,
-              suggestKeywords: ['DATA']
-            }
-          });
-        });
-
-        it ('should suggest keywords after LOAD DATA', function () {
-          assertAutoComplete({
-            beforeCursor: 'LOAD DATA ',
-            afterCursor: '',
-            dialect: 'impala',
-            expectedResult: {
-              lowerCase: false,
-              suggestKeywords: ['INPATH']
-            }
-          });
-        });
-
-        it ('should suggest keywords after LOAD DATA hdfsPath', function () {
-          assertAutoComplete({
-            beforeCursor: 'LOAD DATA INPATH \'/some/path\' ',
-            afterCursor: '',
-            dialect: 'impala',
-            expectedResult: {
-              lowerCase: false,
-              suggestKeywords: ['INTO']
-            }
-          });
-        });
-
-        it ('should suggest keywords after LOAD DATA hdfsPath INTO', function () {
-          assertAutoComplete({
-            beforeCursor: 'LOAD DATA INPATH \'some/path\' INTO ',
-            afterCursor: '',
-            dialect: 'impala',
-            expectedResult: {
-              lowerCase: false,
-              suggestKeywords: ['TABLE']
-            }
-          });
-        });
-
-        it('should suggest keywords after CREATE DATABASE foo ', function () {
-          assertAutoComplete({
-            beforeCursor: 'CREATE DATABASE foo ',
-            afterCursor: '',
-            dialect: 'impala',
-            expectedResult: {
-              lowerCase: false,
-              suggestKeywords: ['COMMENT', 'LOCATION']
-            }
-          });
-        });
-      });
-
-      describe('Hive specific', function () {
-        it('should suggest keywords for empty statement', function() {
-          assertAutoComplete({
-            beforeCursor: '',
-            afterCursor: '',
-            dialect: 'hive',
-            expectedResult: {
-              lowerCase: false,
-              suggestKeywords: ['ALTER', 'ANALYZE', 'CREATE', 'DELETE', 'DESCRIBE',
-                'DROP', 'EXPLAIN', 'EXPORT', 'IMPORT', 'INSERT', 'LOAD', 'MSCK',
-                'REVOKE', 'SELECT', 'SET', 'SHOW', 'TRUNCATE', 'UPDATE', 'USE']
-            }
-          });
-        });
-
-        it ('should suggest keywords after CREATE', function () {
-          assertAutoComplete({
-            beforeCursor: 'CREATE ',
-            afterCursor: '',
-            dialect: 'hive',
-            expectedResult: {
-              lowerCase: false,
-              suggestKeywords: ['DATABASE', 'EXTERNAL', 'SCHEMA', 'TABLE']
-            }
-          });
-        });
-
-        it ('should suggest keywords after CREATE EXTERNAL TABLE identifier tableElementList', function () {
-          assertAutoComplete({
-            beforeCursor: 'CREATE EXTERNAL TABLE foo (id int) ',
-            afterCursor: '',
-            dialect: 'hive',
-            expectedResult: {
-              lowerCase: false,
-              suggestKeywords: ['LOCATION']
-            }
-          });
-        });
-
-        it('should suggest keywords in after CREATE TABLE identifier (identifier ', function () {
-          assertAutoComplete({
-            beforeCursor: 'CREATE TABLE foo (id ',
-            afterCursor: '',
-            dialect: 'hive',
-            expectedResult: {
-              lowerCase: false,
-              suggestKeywords: ['BIGINT', 'BINARY', 'BOOLEAN', 'CHAR', 'DATE', 'DECIMAL', 'DOUBLE', 'FLOAT', 'INT', 'SMALLINT', 'TIMESTAMP', 'STRING', 'TINYINT', 'VARCHAR']
-            }
-          });
-        });
-
-        it('should suggest keywords after CREATE DATABASE foo ', function () {
-          assertAutoComplete({
-            beforeCursor: 'CREATE DATABASE foo ',
-            afterCursor: '',
-            dialect: 'hive',
-            expectedResult: {
-              lowerCase: false,
-              suggestKeywords: ['COMMENT', 'LOCATION', 'WITH DBPROPERTIES']
-            }
-          });
-        });
-
-        it('should suggest keywords after CREATE DATABASE foo COMMENT ', function () {
-          assertAutoComplete({
-            beforeCursor: 'CREATE DATABASE foo COMMENT \'bla\' ',
-            afterCursor: '',
-            dialect: 'hive',
-            expectedResult: {
-              lowerCase: false,
-              suggestKeywords: ['LOCATION', 'WITH DBPROPERTIES']
-            }
-          });
-        });
-
-        it('should suggest keywords after CREATE DATABASE foo COMMENT and LOCATION', function () {
-          assertAutoComplete({
-            beforeCursor: 'CREATE DATABASE foo COMMENT \'bla\' LOCATION \'/bla\' ',
-            afterCursor: '',
-            dialect: 'hive',
-            expectedResult: {
-              lowerCase: false,
-              suggestKeywords: ['WITH DBPROPERTIES']
-            }
-          });
-        });
-
-        it('should suggest keywords after SELECT SelectList FROM TablePrimary ', function () {
-          assertAutoComplete({
-            beforeCursor: 'SELECT bar FROM foo ',
-            afterCursor: '',
-            dialect: 'hive',
-            expectedResult: {
-              lowerCase: false,
-              suggestKeywords: ['GROUP BY', 'JOIN', 'LATERAL', 'LIMIT', 'ORDER BY', 'WHERE']
-            }
-          });
-        });
-
-        it('should suggest keywords after SELECT SelectList FROM TablePrimary JOIN TablePrimary ', function () {
-          assertAutoComplete({
-            beforeCursor: 'SELECT bar FROM foo JOIN baz ',
-            afterCursor: '',
-            dialect: 'hive',
-            expectedResult: {
-              lowerCase: false,
-              suggestKeywords: ['ON']
-            }
-          });
-        });
-
-        it('should suggest keywords after SELECT SelectList FROM TablePrimary with linebreaks', function () {
-          assertAutoComplete({
-            beforeCursor: 'SELECT bar\nFROM foo\n',
-            afterCursor: '',
-            dialect: 'hive',
-            expectedResult: {
-              lowerCase: false,
-              suggestKeywords: ['GROUP BY', 'JOIN', 'LATERAL', 'LIMIT', 'ORDER BY', 'WHERE']
-            }
-          });
-        });
-
-        it('should suggest keywords after SELECT SelectList FROM TablePrimary WHERE SearchCondition ', function () {
-          assertAutoComplete({
-            beforeCursor: 'SELECT bar FROM foo WHERE id = 1 ',
-            afterCursor: '',
-            dialect: 'hive',
-            expectedResult: {
-              lowerCase: false,
-              suggestKeywords: ['GROUP BY', 'LIMIT', 'ORDER BY']
-            }
-          });
-        });
-
-        it('should suggest keywords after SELECT SelectList FROM TablePrimary LATERAL ', function () {
-          assertAutoComplete({
-            beforeCursor: 'SELECT bar FROM foo LATERAL ',
-            afterCursor: '',
-            dialect: 'hive',
-            expectedResult: {
-              lowerCase: false,
-              suggestKeywords: ['VIEW']
-            }
-          });
-        });
-
-        it('should suggest keywords after SELECT SelectList FROM TablePrimary LATERAL VIEW ', function () {
-          assertAutoComplete({
-            beforeCursor: 'SELECT bar FROM foo LATERAL VIEW ',
-            afterCursor: '',
-            dialect: 'hive',
-            expectedResult: {
-              lowerCase: false,
-              suggestKeywords: ['explode', 'posexplode']
-            }
-          });
-        });
-
-        it('should suggest keywords after SELECT SelectList FROM TablePrimary LATERAL VIEW udtf ', function () {
-          assertAutoComplete({
-            beforeCursor: 'SELECT bar FROM foo LATERAL VIEW explode(bar) ',
-            afterCursor: '',
-            dialect: 'hive',
-            expectedResult: {
-              lowerCase: false,
-              suggestKeywords: ['AS']
-            }
-          });
-        });
-
-        it('should suggest keywords after SELECT SelectList FROM TablePrimary LATERAL VIEW udtf ', function () {
-          assertAutoComplete({
-            beforeCursor: 'SELECT bar FROM foo LATERAL VIEW explode(bar) b ',
-            afterCursor: '',
-            dialect: 'hive',
-            expectedResult: {
-              lowerCase: false,
-              suggestKeywords: ['AS']
-            }
-          });
-        });
-      });
-    });
-
-    it('should return empty suggestions for bogus statement', function() {
-      assertAutoComplete({
-        beforeCursor: 'foo',
-        afterCursor: 'bar',
-        expectedResult: {
-          lowerCase: false
-        }
-      });
-    });
-
-    describe('database awareness', function() {
-      it('should suggest databases after use', function () {
-        assertAutoComplete({
-          serverResponses: {},
-          beforeCursor: 'USE ',
-          afterCursor: '',
-          expectedResult: {
-            lowerCase: false,
-            suggestDatabases: { }
-          }
-        });
-      });
-
-      it('should suggest databases after use with started identifier', function () {
-        assertAutoComplete({
-          serverResponses: {},
-          beforeCursor: 'USE bla',
-          afterCursor: '',
-          expectedResult: {
-            lowerCase: false,
-            suggestDatabases: { }
-          }
-        });
-      });
-
-      it('should use a use statement before the cursor if present', function () {
-        assertAutoComplete({
-          beforeCursor: 'USE database_two; \n\select ',
-          afterCursor: '',
-          expectedResult: {
-            useDatabase: 'database_two',
-            lowerCase: true,
-            suggestStar: true,
-            suggestTables: {
-              prependQuestionMark: true,
-              prependFrom: true
-            },
-            suggestDatabases: {
-              prependQuestionMark: true,
-              prependFrom: true,
-              appendDot: true
-            }
-          }
-        });
-      });
-
-      it('should use the last use statement before the cursor if multiple are present', function () {
-        assertAutoComplete({
-          beforeCursor: 'USE other_db; USE closest_db; \n\tSELECT ',
-          afterCursor: '',
-          expectedResult: {
-            useDatabase: 'closest_db',
-            lowerCase: false,
-            suggestStar: true,
-            suggestTables: {
-              prependQuestionMark: true,
-              prependFrom: true
-            },
-            suggestDatabases: {
-              prependQuestionMark: true,
-              prependFrom: true,
-              appendDot: true
-            }
-          }
-        });
-      });
-
-      it('should use the use statement before the cursor if multiple are present after the cursor', function () {
-        assertAutoComplete({
-          beforeCursor: 'USE other_db; USE closest_db; \n\tSELECT ',
-          afterCursor: '; USE some_other_db;',
-          expectedResult: {
-            useDatabase: 'closest_db',
-            lowerCase: false,
-            suggestStar: true,
-            suggestTables: {
-              prependQuestionMark: true,
-              prependFrom: true
-            },
-            suggestDatabases: {
-              prependQuestionMark: true,
-              prependFrom: true,
-              appendDot: true
-            }
-          }
-        });
-      });
-    });
-
-    describe('text completer', function () {
-      it('should ignore line comments for local suggestions', function () {
-        assertAutoComplete({
-          beforeCursor: '-- line comment\nSELECT * from testTable1;\n',
-          afterCursor: '\n-- other line comment',
-          expectedResult: {
-            lowerCase: false,
-            suggestKeywords: ['ALTER', 'CREATE', 'DELETE', 'DESCRIBE', 'DROP',
-              'EXPLAIN', 'INSERT', 'REVOKE', 'SELECT', 'SET', 'SHOW', 'TRUNCATE',
-              'UPDATE', 'USE']
-          }
-        });
-      });
-
-      it('should ignore multi-line comments for local suggestions', function () {
-        assertAutoComplete({
-          beforeCursor: '/* line 1\nline 2\n*/\nSELECT * from testTable1;\n',
-          afterCursor: '',
-          expectedResult: {
-            lowerCase: false,
-            suggestKeywords: ['ALTER', 'CREATE', 'DELETE', 'DESCRIBE', 'DROP',
-              'EXPLAIN', 'INSERT', 'REVOKE', 'SELECT', 'SET', 'SHOW', 'TRUNCATE',
-              'UPDATE', 'USE']
-          }
-        });
-      });
-    });
-
-    describe('table completion', function() {
-      it('should suggest tables after SELECT', function () {
-        assertAutoComplete({
-          beforeCursor: 'SELECT ',
-          afterCursor: '',
-          expectedResult: {
-            lowerCase: false,
-            suggestStar: true,
-            suggestTables: {
-              prependQuestionMark: true,
-              prependFrom: true
-            },
-            suggestDatabases: {
-              prependQuestionMark: true,
-              prependFrom: true,
-              appendDot: true
-            }
-          }
-        });
-      });
-
-      it('should follow keyword case for table name completion', function() {
-        assertAutoComplete({
-          beforeCursor: 'select ',
-          afterCursor: '',
-          expectedResult: {
-            lowerCase: true,
-            suggestStar: true,
-            suggestTables: {
-              prependQuestionMark: true,
-              prependFrom: true
-            },
-            suggestDatabases: {
-              prependQuestionMark: true,
-              prependFrom: true,
-              appendDot: true
-            }
-          }
-        });
-      });
-
-      it('should suggest table names with *', function() {
-        assertAutoComplete({
-          beforeCursor: 'SELECT * ',
-          afterCursor: '',
-          expectedResult: {
-            lowerCase: false,
-            suggestTables: {
-              prependFrom: true
-            },
-            suggestDatabases: {
-              prependFrom: true,
-              appendDot: true
-            }
-          }
-        });
-      });
-
-      it('should suggest table names with started FROM', function() {
-        assertAutoComplete({
-          beforeCursor: 'SELECT * fr',
-          afterCursor: '',
-          expectedResult: {
-            lowerCase: false,
-            suggestTables: {
-              prependFrom: true
-            },
-            suggestDatabases: {
-              prependFrom: true,
-              appendDot: true
-            }
-          }
-        });
-      });
-
-      it('should suggest table names after FROM', function() {
-        assertAutoComplete({
-          beforeCursor: 'SELECT * FROM ',
-          afterCursor: '',
-          expectedResult: {
-            lowerCase: false,
-            suggestTables: {},
-            suggestDatabases: {
-              appendDot: true
-            }
-          }
-        });
-      });
-
-      it('should suggest database or table names after FROM with started name', function() {
-        assertAutoComplete({
-          beforeCursor: 'SELECT * FROM tes',
-          afterCursor: '',
-          expectedResult: {
-            lowerCase: false,
-            suggestTables: {},
-            suggestDatabases: {
-              appendDot: true
-            }
-          }
-        });
-      });
-
-      it('should suggest database or table names after FROM with started backticked name', function() {
-        assertAutoComplete({
-          beforeCursor: 'SELECT * FROM `tes',
-          afterCursor: '',
-          expectedResult: {
-            lowerCase: false,
-            suggestTables: {},
-            suggestDatabases: {
-              appendDot: true
-            }
-          }
-        });
-      });
-
-      it('should suggest table names after FROM with database reference', function() {
-        assertAutoComplete({
-          beforeCursor: 'SELECT * FROM database_two.',
-          afterCursor: '',
-          expectedResult: {
-            lowerCase: false,
-            suggestTables: {
-              database: 'database_two'
-            }
-          }
-        });
-      });
-
-      it('should suggest table names after FROM with backticked database reference', function() {
-        assertAutoComplete({
-          beforeCursor: 'SELECT * FROM `database_two`.',
-          afterCursor: '',
-          expectedResult: {
-            lowerCase: false,
-            suggestTables: {
-              database: 'database_two'
-            }
-          }
-        });
-      });
-
-      it('should suggest table names after FROM with partial backticked table reference', function() {
-        assertAutoComplete({
-          beforeCursor: 'SELECT * FROM `database_two`.`bla ',
-          afterCursor: '',
-          expectedResult: {
-            lowerCase: false,
-            suggestTables: {
-              database: 'database_two'
-            }
-          }
-        });
-      });
-
-      it('should suggest aliases', function() {
-        assertAutoComplete({
-          serverResponses: {},
-          beforeCursor: 'SELECT ',
-          afterCursor: ' FROM testTableA   tta, testTableB',
-          expectedResult: {
-            lowerCase: false,
-            suggestStar: true,
-            suggestIdentifiers: [{ name: 'tta.', type: 'alias' }, { name: 'testTableB.', type: 'table' }]
-          }
-        });
-      });
-
-      it('should suggest aliases in GROUP BY', function() {
-        assertAutoComplete({
-          beforeCursor: 'SELECT * FROM testTableA tta, testTableB GROUP BY ',
-          afterCursor: '',
-          expectedResult : {
-            lowerCase: false,
-            suggestIdentifiers: [{ name: 'tta.', type: 'alias' }, { name: 'testTableB.', type: 'table' }]
-          }
-        });
-      });
-
-      // TODO: fix me
-      xit('should suggest table aliases and select aliases', function() {
-        assertAutoComplete({
-          beforeCursor: 'SELECT ',
-          afterCursor: ' FROM testTableA tta, (SELECT SUM(A*B) total FROM tta.array) ttaSum, testTableB ttb',
-          ignoreErrors: true,
-          expectedResult: {
-            lowerCase: false,
-            suggestStar: true,
-            suggestIdentifiers: [{ name: 'tta.', type: 'alias' }, { name: 'ttaSum', type: 'alias' }, { name: 'ttb.', type: 'alias' }]
-          }
-        });
-      });
-    });
-
-    describe('functions', function () {
-      xit('should suggest fields in functions', function () {
-        assertAutoComplete({
-          beforeCursor: 'SELECT id, SUM(',
-          afterCursor: ' FROM testTable',
-          ignoreErrors: true,
-          expectedResult: {
-            lowerCase: false,
-            suggestColumns: {
-              table: 'testTable'
-            }
-          }
-        });
-      });
-
-      xit('should suggest fields in functions after operators', function () {
-        assertAutoComplete({
-          beforeCursor: 'SELECT id, SUM(a * ',
-          afterCursor: ' FROM testTable',
-          ignoreErrors: true,
-          expectedResult: {
-            lowerCase: false,
-            suggestColumns: {
-              table: 'testTable'
-            }
-          }
-        });
-      })
-    });
-
-    describe('drop statements', function () {
-      it('should suggest keywords after DROP', function() {
-        assertAutoComplete({
-          beforeCursor: 'DROP ',
-          afterCursor: '',
-          expectedResult: {
-            lowerCase: false,
-            suggestKeywords: ['ROLE', 'SCHEMA', 'TABLE', 'VIEW']
-          }
-        });
-      });
-
-      describe('hive specific', function () {
-        it('should suggest keywords after DROP', function() {
-          assertAutoComplete({
-            beforeCursor: 'DROP ',
-            afterCursor: '',
-            dialect: 'hive',
-            expectedResult: {
-              lowerCase: false,
-              suggestKeywords: ['DATABASE', 'FUNCTION', 'INDEX', 'MACRO', 'ROLE', 'SCHEMA', 'TABLE', 'TEMPORARY FUNCTION', 'TEMPORARY MACRO', 'VIEW']
-            }
-          });
-        });
-      });
-
-      describe('hive specific', function () {
-        it('should follow case after drop', function() {
-          assertAutoComplete({
-            beforeCursor: 'drop ',
-            afterCursor: '',
-            dialect: 'hive',
-            expectedResult: {
-              lowerCase: true,
-              suggestKeywords: ['DATABASE', 'FUNCTION', 'INDEX', 'MACRO', 'ROLE', 'SCHEMA', 'TABLE', 'TEMPORARY FUNCTION', 'TEMPORARY MACRO', 'VIEW']
-            }
-          });
-        });
-      });
-
-      describe('impala specific', function () {
-        it('should suggest keywords after DROP', function() {
-          assertAutoComplete({
-            beforeCursor: 'DROP ',
-            afterCursor: '',
-            dialect: 'impala',
-            expectedResult: {
-              lowerCase: false,
-              suggestKeywords: ['AGGREGATE FUNCTION', 'DATABASE', 'FUNCTION', 'INCREMENTAL STATS', 'ROLE', 'SCHEMA', 'STATS', 'TABLE', 'VIEW']
-            }
-          });
-        });
-      });
-
-      describe('drop database statements', function () {
-        it('should suggest databases after DROP DATABASE ', function() {
-          assertAutoComplete({
-            beforeCursor: 'DROP DATABASE ',
-            afterCursor: '',
-            dialect: 'hive',
-            expectedResult: {
-              lowerCase: false,
-              suggestDatabases: {},
-              suggestKeywords: ['IF EXISTS']
-            }
-          });
-        });
-
-        it('should suggest databases after DROP SCHEMA ', function() {
-          assertAutoComplete({
-            beforeCursor: 'DROP SCHEMA ',
-            afterCursor: '',
-            expectedResult: {
-              lowerCase: false,
-              suggestDatabases: {},
-              suggestKeywords: ['IF EXISTS']
-            }
-          });
-        });
-
-        it('should suggest keywords after DROP DATABASE IF ', function() {
-          assertAutoComplete({
-            beforeCursor: 'DROP DATABASE IF ',
-            afterCursor: '',
-            dialect: 'impala',
-            expectedResult: {
-              lowerCase: false,
-              suggestKeywords: ['EXISTS']
-            }
-          });
-        });
-
-        it('should suggest databases after DROP DATABASE IF EXISTS ', function() {
-          assertAutoComplete({
-            beforeCursor: 'DROP DATABASE IF EXISTS ',
-            afterCursor: '',
-            dialect: 'hive',
-            expectedResult: {
-              lowerCase: false,
-              suggestDatabases: {}
-            }
-          });
-        });
-
-        describe('Hive specific', function () {
-          it('should suggest keywords after DROP DATABASE foo ', function() {
-            assertAutoComplete({
-              beforeCursor: 'DROP DATABASE foo ',
-              afterCursor: '',
-              dialect: 'hive',
-              expectedResult: {
-                lowerCase: false,
-                suggestKeywords: ['CASCADE', 'RESTRICT']
-              }
-            });
-          });
-        });
-      });
-
-      describe('drop table statements', function () {
-        it('should suggest tables after DROP TABLE ', function() {
-          assertAutoComplete({
-            beforeCursor: 'DROP TABLE ',
-            afterCursor: '',
-            expectedResult: {
-              lowerCase: false,
-              suggestTables: {},
-              suggestKeywords: ['IF EXISTS'],
-              suggestDatabases: {
-                appendDot: true
-              }
-            }
-          });
-        });
-
-        it('should suggest tables after DROP TABLE db. ', function() {
-          assertAutoComplete({
-            beforeCursor: 'DROP TABLE db.',
-            afterCursor: '',
-            expectedResult: {
-              lowerCase: false,
-              suggestTables: { database: 'db' }
-            }
-          });
-        });
-
-        it('should suggest keywords after DROP TABLE IF ', function() {
-          assertAutoComplete({
-            beforeCursor: 'DROP TABLE IF ',
-            afterCursor: '',
-            expectedResult: {
-              lowerCase: false,
-              suggestKeywords: ['EXISTS']
-            }
-          });
-        });
-
-        it('should suggest tables after DROP TABLE IF EXISTS ', function() {
-          assertAutoComplete({
-            beforeCursor: 'DROP TABLE IF EXISTS ',
-            afterCursor: '',
-            expectedResult: {
-              lowerCase: false,
-              suggestTables: {},
-              suggestDatabases: {
-                appendDot: true
-              }
-            }
-          });
-        });
-
-        describe('Hive specific', function () {
-          it('should suggest keywords after DROP TABLE foo ', function() {
-            assertAutoComplete({
-              beforeCursor: 'DROP TABLE foo ',
-              afterCursor: '',
-              dialect: 'hive',
-              expectedResult: {
-                lowerCase: false,
-                suggestKeywords: ['PURGE']
-              }
-            });
-          });
-        });
-      });
-    });
-
-    describe('update statements', function () {
-      it('should suggest tables after UPDATE', function() {
-        assertAutoComplete({
-          beforeCursor: 'UPDATE ',
-          afterCursor: '',
-          expectedResult: {
-            lowerCase: false,
-            suggestTables: {},
-            suggestDatabases: {
-              appendDot: true
-            }
-          }
-        });
-      });
-
-      it('should suggest tables after UPDATE with partial table or schema ref', function() {
-        assertAutoComplete({
-          beforeCursor: 'UPDATE bla',
-          afterCursor: '',
-          expectedResult: {
-            lowerCase: false,
-            suggestTables: {},
-            suggestDatabases: {
-              appendDot: true
-            }
-          }
-        });
-      });
-
-      it('should suggest tables after UPDATE with database', function() {
-        assertAutoComplete({
-          beforeCursor: 'UPDATE bar.',
-          afterCursor: '',
-          expectedResult: {
-            lowerCase: false,
-            suggestTables: {
-              database: 'bar'
-            }
-          }
-        });
-      });
-
-      it('should suggest tables after UPDATE with database and partial table', function() {
-        assertAutoComplete({
-          beforeCursor: 'UPDATE bar.foo',
-          afterCursor: '',
-          expectedResult: {
-            lowerCase: false,
-            suggestTables: {
-              database: 'bar'
-            }
-          }
-        });
-      });
-
-      it('should suggest columns after SET', function() {
-        assertAutoComplete({
-          beforeCursor: 'UPDATE bar.foo SET ',
-          afterCursor: '',
-          expectedResult: {
-            lowerCase: false,
-            suggestColumns: {
-              database: 'bar',
-              table: 'foo'
-            }
-          }
-        });
-      });
-
-      it('should suggest columns after SET id = 1, bar = \'foo\', ', function() {
-        assertAutoComplete({
-          beforeCursor: 'UPDATE bar.foo SET id = 1, bar = \'foo\', ',
-          afterCursor: '',
-          expectedResult: {
-            lowerCase: false,
-            suggestColumns: {
-              database: 'bar',
-              table: 'foo'
-            }
-          }
-        });
-      });
-
-      it('should suggest columns after SET bar = \'foo\' WHERE ', function() {
-        assertAutoComplete({
-          beforeCursor: 'UPDATE bar.foo SET bar = \'foo\' WHERE ',
-          afterCursor: '',
-          expectedResult: {
-            lowerCase: false,
-            suggestColumns: {
-              database: 'bar',
-              table: 'foo'
-            }
-          }
-        });
-      });
-
-      it('should suggest values after SET bar = \'foo\' WHERE id = ', function() {
-        assertAutoComplete({
-          beforeCursor: 'UPDATE bar.foo SET bar = \'foo\' WHERE id = ',
-          afterCursor: '',
-          expectedResult: {
-            lowerCase: false,
-            suggestValues: {
-              database: 'bar',
-              table: 'foo',
-              identifierChain: [{ name: 'id' }]
-            }
-          }
-        });
-      });
-
-      it('should suggest columns after SET bar = \'foo\' WHERE id = 1 AND ', function() {
-        assertAutoComplete({
-          beforeCursor: 'UPDATE bar.foo SET bar = \'foo\' WHERE id = 1 AND ',
-          afterCursor: '',
-          expectedResult: {
-            lowerCase: false,
-            suggestColumns: {
-              database: 'bar',
-              table: 'foo'
-            }
-          }
-        });
-      });
-    });
-
-    describe('HDFS autocompletion', function () {
-      it('should autocomplete hdfs paths in database location references without initial /', function () {
-        assertAutoComplete({
-          beforeCursor: 'CREATE DATABASE foo LOCATION \'',
-          afterCursor: '\'',
-          dialect: 'hive',
-          expectedResult: {
-            lowerCase: false,
-            suggestHdfs : { path: '' }
-          }
-        });
-      });
-
-      it('should autocomplete hdfs paths in database location references after comment without initial /', function () {
-        assertAutoComplete({
-          beforeCursor: 'CREATE DATABASE foo COMMENT \'blabla\' LOCATION \'',
-          afterCursor: '\'',
-          dialect: 'hive',
-          expectedResult: {
-            lowerCase: false,
-            suggestHdfs : { path: '' }
-          }
-        });
-      });
-
-      it('should autocomplete hdfs paths in location references without initial /', function () {
-        assertAutoComplete({
-          beforeCursor: 'CREATE EXTERNAL TABLE foo (id int) LOCATION \'',
-          afterCursor: '\'',
-          dialect: 'hive',
-          expectedResult: {
-            lowerCase: false,
-            suggestHdfs : { path: '' }
-          }
-        });
-      });
-
-      it('should autocomplete hdfs paths in location references from root', function () {
-        assertAutoComplete({
-          beforeCursor: 'CREATE EXTERNAL TABLE foo (id int) LOCATION \'/',
-          afterCursor: '\'',
-          dialect: 'hive',
-          expectedResult: {
-            lowerCase: false,
-            suggestHdfs : { path: '/' }
-          }
-        });
-      });
-
-      it('should autocomplete hdfs paths and suggest trailing apostrophe if empty after cursor', function () {
-        assertAutoComplete({
-          beforeCursor: 'CREATE EXTERNAL TABLE foo (id int) LOCATION \'/',
-          afterCursor: '',
-          dialect: 'hive',
-          expectedResult: {
-            lowerCase: false,
-            suggestHdfs : { path: '/' }
-          }
-        });
-      });
-
-      it('should autocomplete hdfs paths in location references from inside a path', function () {
-        assertAutoComplete({
-          beforeCursor: 'CREATE EXTERNAL TABLE foo (id int) LOCATION \'/',
-          afterCursor: '/bar\'',
-          dialect: 'hive',
-          expectedResult: {
-            lowerCase: false,
-            suggestHdfs : { path: '/' }
-          }
-        });
-      });
-
-      it('should autocomplete hdfs paths in location references without initial /', function () {
-        assertAutoComplete({
-          beforeCursor: 'LOAD DATA INPATH \'',
-          afterCursor: '\'',
-          dialect: 'impala',
-          expectedResult: {
-            lowerCase: false,
-            suggestHdfs: { path: ''}
-          }
-        });
-      });
-
-      it('should autocomplete hdfs paths in location references from root', function () {
-        assertAutoComplete({
-          beforeCursor: 'LOAD DATA INPATH \'/',
-          afterCursor: '\'',
-          dialect: 'hive',
-          expectedResult: {
-            lowerCase: false,
-            suggestHdfs: { path: '/'}
-          }
-        });
-      });
-
-      it('should autocomplete hdfs paths and suggest trailing apostrophe if empty after cursor', function () {
-        assertAutoComplete({
-          beforeCursor: 'LOAD DATA INPATH \'/',
-          afterCursor: '',
-          dialect: 'impala',
-          expectedResult: {
-            lowerCase: false,
-            suggestHdfs: { path: '/'}
-          }
-        });
-      });
-
-      it('should autocomplete hdfs paths in location references from inside a path', function () {
-        assertAutoComplete({
-          serverResponses: {},
-          beforeCursor: 'LOAD DATA INPATH \'/',
-          afterCursor: '/bar\' INTO TABLE foo',
-          dialect: 'impala',
-          expectedResult: {
-            lowerCase: false,
-            suggestHdfs: { path: '/'}
-          }
-        });
-      });
-    });
-
-    describe('Hive specific', function() {
-      it('should suggest struct from map values', function() {
-        assertAutoComplete({
-          beforeCursor: 'SELECT testMap[\"anyKey\"].',
-          afterCursor: ' FROM testTable',
-          dialect: 'hive',
-          expectedResult: {
-            lowerCase: false,
-            suggestColumns : {
-              table: 'testTable',
-              identifierChain: [{ name: 'testMap', key: '\"anyKey\"' }]
-            }
-          }
-        });
-      });
-
-      it('should suggest struct from map values without a given key', function() {
-        assertAutoComplete({
-          beforeCursor: 'SELECT testMap[].',
-          afterCursor: ' FROM testTable',
-          dialect: 'hive',
-          expectedResult: {
-            lowerCase: false,
-            suggestColumns : {
-              table: 'testTable',
-              identifierChain: [{ name: 'testMap', key: null }]
-            }
-          }
-        });
-      });
-
-      it('should suggest struct from structs from map values', function() {
-        assertAutoComplete({
-          beforeCursor: 'SELECT testMap["anyKey"].fieldC.',
-          afterCursor: ' FROM testTable',
-          dialect: 'hive',
-          expectedResult: {
-            lowerCase: false,
-            suggestColumns : {
-              table: 'testTable',
-              identifierChain: [{ name: 'testMap', key: '\"anyKey\"' }, { name: 'fieldC' }]
-            }
-          }
-        });
-      });
-
-      it('should suggest struct from structs from arrays', function() {
-        assertAutoComplete({
-          beforeCursor: 'SELECT testArray[1].fieldC.',
-          afterCursor: ' FROM testTable',
-          dialect: 'hive',
-          expectedResult: {
-            lowerCase: false,
-            suggestColumns : {
-              table: 'testTable',
-              identifierChain: [{ name: 'testArray', key: 1 }, { name: 'fieldC' }]
-            }
-          }
-        });
-      });
-
-      it('should suggest structs from maps from arrays', function() {
-        assertAutoComplete({
-          beforeCursor: 'SELECT testArray[1].testMap[\"key\"].',
-          afterCursor: ' FROM testTable',
-          dialect: 'hive',
-          expectedResult: {
-            lowerCase: false,
-            suggestColumns : {
-              table: 'testTable',
-              identifierChain: [{ name: 'testArray', key: 1 }, { name: 'testMap', key: '\"key\"' }]
-            }
-          }
-        });
-      });
-
-      it('should suggest struct from map values without a given key after where', function() {
-        assertAutoComplete({
-          beforeCursor: 'SELECT * FROM testTable WHERE testMap[].',
-          afterCursor: '',
-          dialect: 'hive',
-          expectedResult: {
-            lowerCase: false,
-            suggestColumns : {
-              table: 'testTable',
-              identifierChain: [{ name: 'testMap', key: null }]
-            }
-          }
-        });
-      });
-
-      // Lateral view === only hive?
-      describe('lateral views', function() {
-
-        describe('identifierChain expansion', function () {
-          it('should expand 1', function () {
-            var tablePrimaries = [{
-              identifierChain: [{ name: 'testTable' }],
-              lateralViews: [{
-                columnAliases: [ 'testItem' ],
-                tableAlias: 'explodedTable',
-                udtf: {
-                  expression: [{ name: 'testArray' }],
-                  function: 'explode'
-                }
-              }]
-            }];
-
-            var identifierChain = [{ name: 'explodedTable' }, { name: 'testItem' }];
-
-            var result = sql.expandLateralViews(tablePrimaries, identifierChain);
-            expect(result).toEqual([{ name: 'testArray' }, { name: 'item' }]);
-          });
-
-          it('should expand 2', function () {
-            var tablePrimaries = [{
-              identifierChain: [{ name: 'testTable' }],
-              lateralViews: [{
-                columnAliases: [ 'testMapKey', 'testMapValue' ],
-                tableAlias: 'explodedMap',
-                udtf: {
-                  expression: [{ name: 'testMap' }],
-                  function: 'explode'
-                }
-              }]
-            }];
-
-            var identifierChain = [{ name: 'explodedMap' }, { name: 'testMapValue' }];
-
-            var result = sql.expandLateralViews(tablePrimaries, identifierChain);
-            expect(result).toEqual([{ name: 'testMap' }, { name: 'value' }]);
-          });
-
-          it('should expand 3', function () {
-            var tablePrimaries = [{ identifierChain: [{ name: 'testTable' }] }];
-            var identifierChain = [{ name: 'testMap', key: 'anyKey' }];
-            var result = sql.expandLateralViews(tablePrimaries, identifierChain);
-            expect(result).toEqual([{ name: 'testMap', key: 'anyKey' }]);
-          });
-
-          it('should expand 4', function () {
-            var tablePrimaries = [{
-              identifierChain: [{ name: 'testTable' }],
-              lateralViews: [{
-                columnAliases: [ 'testItem' ],
-                tableAlias: 'explodedTable',
-                udtf: {
-                  function: 'explode',
-                  expression: [{ name: 'testArray' }]
-                }
-              }]
-            }];
-            var identifierChain = [{ name: 'testItem' }];
-            var result = sql.expandLateralViews(tablePrimaries, identifierChain);
-            expect(result).toEqual([{ name: 'testArray' }, { name: 'item' }]);
-          });
-
-          it('should expand 5', function () {
-            var tablePrimaries = [{
-              identifierChain: [{ name: 'testTable' }],
-              lateralViews: [{
-                columnAliases: [ 'testItemB' ],
-                tableAlias: 'explodedTableB',
-                udtf: {
-                  function: 'explode',
-                  expression: [{ name: 'testArrayB' }]
-                }
-              }, {
-                columnAliases: [ 'testItemA' ],
-                tableAlias: 'explodedTableA',
-                udtf: {
-                  function: 'explode',
-                  expression: [{ name: 'testArrayA' }]
-                }
-              }]
-            }];
-            var identifierChain = [{ name: 'testItemA' }];
-            var result = sql.expandLateralViews(tablePrimaries, identifierChain);
-            expect(result).toEqual([{ name: 'testArrayA' }, { name: 'item' }]);
-          });
-
-          it('should expand 6', function () {
-            var tablePrimaries = [{
-              alias: 'tt2',
-              identifierChain: [{ name: 'testTable2' }],
-              lateralViews: [{
-                columnAliases: [ 'testItemB' ],
-                tableAlias: 'explodedTableB',
-                udtf: {
-                  function: 'explode',
-                  expression: [{ name: 'tt2' }, { name: 'testArrayB' }]
-                }
-              }, {
-                columnAliases: [ 'testItemA' ],
-                tableAlias: 'explodedTableA',
-                udtf: {
-                  function: 'explode',
-                  expression: [{ name: 'tt2' }, { name: 'testArrayA' }]
-                }
-              }]
-            }];
-            var identifierChain = [{ name: 'testItemB' }];
-            var result = sql.expandLateralViews(tablePrimaries, identifierChain);
-            expect(result).toEqual([{ name: 'tt2' }, { name: 'testArrayB' }, { name: 'item' }]);
-          });
-
-          it('should expand 7', function () {
-            var tablePrimaries = [{
-              alias: 'tt',
-              identifierChain: [{ name: 'testTable' }],
-              lateralViews: [{
-                columnAliases: [ 'ta1_exp' ],
-                tableAlias: 'ta1',
-                udtf: {
-                  expression: [{ name: 'tt' }, { name: 'testArray1' }],
-                  function: 'explode'
-                }
-              }, {
-                columnAliases: [ 'ta2_exp' ],
-                tableAlias: 'ta2',
-                udtf: {
-                  expression: [{ name: 'ta1_exp' },{ name: 'testArray2' }],
-                  function: 'explode'
-                }
-              }]
-            }];
-
-            var identifierChain = [{ name: 'ta2_exp' }];
-
-            var result = sql.expandLateralViews(tablePrimaries, identifierChain);
-            expect(result).toEqual([{ name: 'tt' }, { name: 'testArray1' }, { name: 'item' }, { name: 'testArray2' }, { name: 'item' }]);
-          });
-
-          it('should expand 8', function () {
-            var tablePrimaries = [{
-              identifierChain: [{ name: 'testTable' }],
-              lateralViews: [{
-                columnAliases: [ 'testIndex', 'testValue' ],
-                tableAlias: 'explodedTable',
-                udtf: {
-                  expression: [{ name: 'testArray' }],
-                  function: 'posexplode'
-                }
-              }]
-            }];
-
-            var identifierChain = [{ name: 'testValue' }];
-
-            var result = sql.expandLateralViews(tablePrimaries, identifierChain);
-            expect(result).toEqual([{ name: 'testArray' }, { name: 'item' }]);
-          });
-
-          it('should expand 9', function () {
-            var tablePrimaries = [{
-              identifierChain: [{ name: 'testTable' }],
-              lateralViews: [{
-                columnAliases: [ 'testMapKey', 'testMapValue' ],
-                tableAlias: 'explodedTable',
-                udtf: {
-                  expression: [{ name: 'testMap' }],
-                  function: 'explode'
-                }
-              }]
-            }];
-
-            var identifierChain = [{ name: 'testMapValue' }];
-
-            var result = sql.expandLateralViews(tablePrimaries, identifierChain);
-            expect(result).toEqual([{ name: 'testMap' }, { name: 'value' }]);
-          });
-        });
-
-        it('should suggest lateral view aliases', function () {
-          assertAutoComplete({
-            beforeCursor: 'SELECT ',
-            afterCursor: ' FROM testTable LATERAL VIEW explode(testArray) explodedTable AS testItem',
-            dialect: 'hive',
-            expectedResult: {
-              lowerCase: false,
-              suggestStar: true, // TODO: Verify that this is true
-              suggestColumns: {
-                table: 'testTable'
-              },
-              suggestIdentifiers: [{ name: 'explodedTable.', type: 'alias' }, { name: 'testItem', type: 'alias' }]
-            }
-          });
-        });
-
-        xit('should suggest columns in explode', function () {
-          assertAutoComplete({
-            beforeCursor: 'SELECT * FROM testTable LATERAL VIEW explode(',
-            afterCursor: '',
-            dialect: 'hive',
-            expectedResult: {
-              suggestColumns: {
-                table: 'testTable'
-              }
-            }
-          });
-        });
-
-        xit('should suggest columns in explode for structs', function () {
-          assertAutoComplete({
-            beforeCursor: 'SELECT * FROM testTable LATERAL VIEW explode(a.b.',
-            afterCursor: '',
-            dialect: 'hive',
-            expectedResult: {
-              suggestColumns: {
-                table: 'testTable',
-                identifierChain: [ { name: 'a' }, { name: 'b' }]
-              }
-            }
-          });
-        });
-
-        xit('should suggest columns in posexplode', function () {
-          assertAutoComplete({
-            beforeCursor: 'SELECT * FROM testTable LATERAL VIEW posexplode(',
-            afterCursor: '',
-            dialect: 'hive',
-            expectedResult: {
-              suggestColumns: {
-                table: 'testTable'
-              }
-            }
-          });
-        });
-
-        it('should suggest lateral view aliases with multiple column aliases', function () {
-          assertAutoComplete({
-            beforeCursor: 'SELECT ',
-            afterCursor: ' FROM testTable LATERAL VIEW explode(testMap) explodedTable AS (testKey, testValue)',
-            dialect: 'hive',
-            expectedResult: {
-              lowerCase: false,
-              suggestStar: true, // TODO: Verify that this is true
-              suggestColumns: {
-                table: 'testTable'
-              },
-              suggestIdentifiers: [{ name: 'explodedTable.', type: 'alias' }, { name: 'testKey', type: 'alias' }, { name: 'testValue', type: 'alias' }]
-            }
-          });
-        });
-
-        it('should suggest structs from exploded item references to arrays', function () {
-          assertAutoComplete({
-            beforeCursor: 'SELECT testItem.',
-            afterCursor: ' FROM testTable LATERAL VIEW explode(testArray) explodedTable AS testItem',
-            dialect: 'hive',
-            expectedResult: {
-              lowerCase: false,
-              suggestStar: true, // TODO: Verify that this is true
-              suggestColumns: {
-                table: 'testTable',
-                identifierChain: [{ name: 'testArray' }, { name: 'item' }]
-              }
-            }
-          });
-        });
-
-        it('should suggest structs from multiple exploded item references to arrays', function () {
-          assertAutoComplete({
-            beforeCursor: 'SELECT testItemA.',
-            afterCursor: ' FROM testTable' +
-            ' LATERAL VIEW explode(testArrayA) explodedTableA AS testItemA' +
-            ' LATERAL VIEW explode(testArrayB) explodedTableB AS testItemB',
-            dialect: 'hive',
-            expectedResult: {
-              lowerCase: false,
-              suggestStar: true, // TODO: Verify that this is true
-              suggestColumns: {
-                table: 'testTable',
-                identifierChain: [{ name: 'testArrayA' }, { name: 'item' }]
-              }
-            }
-          });
-        });
-
-        it('should support table references as arguments of explode function', function() {
-          assertAutoComplete({
-            beforeCursor: 'SELECT\n testItemA,\n testItemB.',
-            afterCursor: '\n\tFROM\n\t testTable2 tt2\n' +
-            '\t LATERAL VIEW EXPLODE(tt2.testArrayA) explodedTableA AS testItemA\n' +
-            '\t LATERAL VIEW EXPLODE(tt2.testArrayB) explodedTableB AS testItemB',
-            dialect: 'hive',
-            expectedResult: {
-              lowerCase: false,
-              suggestStar: true, // TODO: Verify that this is true
-              suggestColumns: {
-                table: 'testTable2',
-                identifierChain: [{ name: 'testArrayB' }, { name: 'item' }]
-              }
-            }
-          });
-        });
-
-        it('should suggest structs from exploded item references to exploded item references to arrays ', function () {
-          assertAutoComplete({
-            beforeCursor: 'SELECT ta2_exp.',
-            afterCursor: ' FROM ' +
-            '   testTable tt' +
-            ' LATERAL VIEW explode(tt.testArray1) ta1 AS ta1_exp\n' +
-            '   LATERAL VIEW explode(ta1_exp.testArray2)    ta2   AS  ta2_exp',
-            dialect: 'hive',
-            expectedResult: {
-              lowerCase: false,
-              suggestStar: true, // TODO: Verify that this is true
-              suggestColumns: {
-                table: 'testTable',
-                identifierChain: [{ name: 'testArray1' }, { name: 'item' }, { name: 'testArray2' }, { name: 'item' }]
-              }
-            }
-          });
-        });
-
-        it('should suggest structs from references to exploded arrays', function () {
-          assertAutoComplete({
-            beforeCursor: 'SELECT explodedTable.testItem.',
-            afterCursor: ' FROM testTable LATERAL VIEW explode(testArray) explodedTable AS testItem',
-            dialect: 'hive',
-            expectedResult: {
-              lowerCase: false,
-              suggestColumns: {
-                table: 'testTable',
-                identifierChain: [{ name: 'testArray' }, { name: 'item' }]
-              }
-            }
-          });
-        });
-
-        it('should suggest posexploded references to arrays', function () {
-          assertAutoComplete({
-            serverResponses: {
-              '/notebook/api/autocomplete/database_one/testTable/testArray/item': {
-                fields: [
-                  {'type': 'string', 'name': 'fieldA'},
-                  {'type': 'string', 'name': 'fieldB'}
-                ],
-                type: 'struct'
-              }
-            },
-            beforeCursor: 'SELECT testValue.',
-            afterCursor: ' FROM testTable LATERAL VIEW posexplode(testArray) explodedTable AS (testIndex, testValue)',
-            dialect: 'hive',
-            expectedResult: {
-              lowerCase: false,
-              suggestStar: true, // TODO: Verify that this is true
-              suggestColumns: {
-                table: 'testTable',
-                identifierChain: [{ name: 'testArray' }, { name: 'item' }]
-              }
-            }
-          });
-        });
-
-        it('should suggest exploded references to map values', function () {
-          assertAutoComplete({
-            beforeCursor: 'SELECT testMapValue.',
-            afterCursor: ' FROM testTable LATERAL VIEW explode(testMap) AS (testMapKey, testMapValue)',
-            dialect: 'hive',
-            expectedResult: {
-              lowerCase: false,
-              suggestStar: true, // TODO: Verify that this is true
-              suggestColumns: {
-                table: 'testTable',
-                identifierChain: [{ name: 'testMap' }, { name: 'value' }]
-              }
-            }
-          });
-        });
-
-        it('should suggest exploded references to map values from view references', function () {
-          assertAutoComplete({
-            beforeCursor: 'SELECT explodedMap.testMapValue.',
-            afterCursor: ' FROM testTable LATERAL VIEW explode(testMap) explodedMap AS (testMapKey, testMapValue)',
-            dialect: 'hive',
-            expectedResult: {
-              lowerCase: false,
-              suggestColumns: {
-                table: 'testTable',
-                identifierChain: [{ name: 'testMap' }, { name: 'value' }]
-              }
-            }
-          });
-        });
-
-        it('should suggest references to exploded references from view reference', function () {
-          assertAutoComplete({
-            serverResponses: {},
-            beforeCursor: 'SELECT explodedMap.',
-            afterCursor: ' FROM testTable LATERAL VIEW explode(testMap) explodedMap AS (testMapKey, testMapValue)',
-            dialect: 'hive',
-            expectedResult: {
-              lowerCase: false,
-              suggestStar: true, // TODO: Check if really true
-              suggestIdentifiers: [{ name: 'testMapKey', type: 'alias' }, { name: 'testMapValue', type: 'alias' }]
-            }
-          });
-        });
-
-        it('should suggest references to exploded references', function () {
-          assertAutoComplete({
-            serverResponses: {
-              '/notebook/api/autocomplete/database_one/testTable' : {
-                columns: ['testTableColumn1', 'testTableColumn2']
-              }
-            },
-            beforeCursor: 'SELECT ',
-            afterCursor: ' FROM testTable LATERAL VIEW explode(testMap) explodedMap AS (testMapKey, testMapValue)',
-            dialect: 'hive',
-            expectedResult: {
-              lowerCase: false,
-              suggestStar: true, // TODO: Check if really true
-              suggestIdentifiers: [{ name: 'explodedMap.', type: 'alias' }, { name: 'testMapKey', type: 'alias' }, { name: 'testMapValue', type: 'alias' }],
-              suggestColumns: {
-                table: 'testTable'
-              }
-            }
-          });
-        });
-      });
-    });
-
-    describe('Impala specific', function() {
-      describe('identifier chain expansion', function () {
-        it('should expand a simple map reference', function () {
-          var tablePrimaries = [
-            { alias: 't', identifierChain: [{ name: 'someDb' }, { name: 'someTable' }] },
-            { alias: 'm', identifierChain: [{ name: 't' }, { name: 'someMap' }] }
-          ];
-
-          var identifierChain = [{ name: 'm', key: 'foo' }, { name: 'bar' }];
-
-          var actual = sql.expandImpalaIdentifierChain(tablePrimaries, identifierChain);
-
-          expect(actual).toEqual([{ name: 't' }, { name: 'someMap', key: 'foo' }, { name: 'bar' }]);
-        });
-      });
-
-      it('should not suggest struct from map values with hive style syntax', function() {
-        assertAutoComplete({
-          beforeCursor: 'SELECT testMap[\"anyKey\"].',
-          afterCursor: ' FROM testTable',
-          dialect: 'impala',
-          expectedResult: {
-            lowerCase: false,
-            suggestColumns: {
-              table: 'testTable',
-              identifierChain: [{ name: 'testMap',  key: '\"anyKey\"' }]
-            }
-          }
-        });
-      });
-
-      it('should suggest fields from nested structs', function() {
-        assertAutoComplete({
-          beforeCursor: 'SELECT columnA.fieldC.',
-          afterCursor: ' FROM testTable',
-          dialect: 'impala',
-          expectedResult: {
-            lowerCase: false,
-            suggestColumns: {
-              table: 'testTable',
-              identifierChain: [{ name: 'columnA' }, { name: 'fieldC' }]
-            }
-          }
-        });
-      });
-
-      it('should suggest fields from nested structs with table alias', function() {
-        assertAutoComplete({
-          beforeCursor: 'SELECT tt.columnA.fieldC.',
-          afterCursor: ' FROM testTable tt',
-          dialect: 'impala',
-          expectedResult: {
-            lowerCase: false,
-            suggestColumns: {
-              table: 'testTable',
-              identifierChain: [{ name: 'columnA' }, { name: 'fieldC' }]
-            }
-          }
-        });
-      });
-
-      it('should suggest fields from nested structs with table alias', function() {
-        assertAutoComplete({
-          beforeCursor: 'SELECT tt.columnA.fieldC.',
-          afterCursor: ' FROM testTable tt',
-          dialect: 'impala',
-          expectedResult: {
-            lowerCase: false,
-            suggestColumns: {
-              table: 'testTable',
-              identifierChain: [{ name: 'columnA' }, { name: 'fieldC' }]
-            }
-          }
-        });
-      });
-
-
-      // TODO: Result should have 'key', 'key' is only possible after call to see column type but as it's
-      //       after FROM perhaps only maps are allowed there?
-      //       If the map has a scalar value type (int etc.) it should also suggest 'value'
-      //       For arrays it should suggest 'items' for scalar values
-      it('should suggest fields from map values of type structs', function() {
-        assertAutoComplete({
-          beforeCursor: 'SELECT tm.',
-          afterCursor: ' FROM testTable t, t.testMap tm;',
-          dialect: 'impala',
-          expectedResult: {
-            lowerCase: false,
-            suggestStar: true,
-            suggestColumns : {
-              table: 'testTable',
-              identifierChain: [{ name: 'testMap' }]
-            }
-          }
-        });
-      });
-
-      it('should suggest fields from map values of type structs with partial identifier', function() {
-        assertAutoComplete({
-          beforeCursor: 'SELECT tm.a',
-          afterCursor: ' FROM testTable t, t.testMap tm;',
-          dialect: 'impala',
-          expectedResult: {
-            lowerCase: false,
-            suggestStar: true,
-            suggestColumns : {
-              table: 'testTable',
-              identifierChain: [{ name: 'testMap' }]
-            }
-          }
-        });
-      });
-
-      // Same as above, 'items' or 'value' for scalar
-      it('should suggest items from arrays if complex in from clause', function() {
-        assertAutoComplete({
-
-          beforeCursor: 'SELECT ta.* FROM testTable t, t.testArray ta WHERE ta.',
-          afterCursor: '',
-          dialect: 'impala',
-          expectedResult: {
-            lowerCase: false,
-            suggestColumns : {
-              table: 'testTable',
-              identifierChain: [{ name: 'testArray' }]
-            }
-          }
-        });
-      });
-
-      it('should suggest columns from table refs in from clause', function() {
-        assertAutoComplete({
-          beforeCursor: 'SELECT t.*  FROM testTable t, t.',
-          afterCursor: '',
-          dialect: 'impala',
-          expectedResult: {
-            lowerCase: false,
-            suggestColumns : {
-              table: 'testTable'
-            }
-          }
-        });
-      });
-
-      it('should suggest map references in select', function() {
-        assertAutoComplete({
-          beforeCursor: 'SELECT ',
-          afterCursor: ' FROM testTable t, t.testMap tm;',
-          dialect: 'impala',
-          expectedResult: {
-            lowerCase: false,
-            suggestStar: true, // TODO: Check if really so
-            suggestIdentifiers: [{ name: 't.', type: 'alias' }, { name: 'tm.', type: 'alias' }]
-          }
-        });
-      });
-
-      // TODO: Should add Key and Value once we know it's a map
-      it('should suggest fields with key and value in where clause from map values of type structs', function() {
-        assertAutoComplete({
-          beforeCursor: 'SELECT tm.* FROM testTable t, t.testMap tm WHERE tm.',
-          afterCursor: '',
-          dialect: 'impala',
-          expectedResult: {
-            lowerCase: false,
-            suggestColumns: {
-              table: 'testTable',
-              identifierChain: [{ name: 'testMap' }]
-            }
-          }
-        });
-      });
-
-      it('should suggest fields in where clause from map values of type structs', function() {
-        assertAutoComplete({
-          beforeCursor: 'SELECT tm.* FROM testTable t, t.testMap tm WHERE tm.value.',
-          afterCursor: '',
-          dialect: 'impala',
-          expectedResult: {
-            lowerCase: false,
-            suggestColumns: {
-              table: 'testTable',
-              identifierChain: [{ name: 'testMap' }, { name: 'value' }]
-            }
-          }
-        });
-      });
-
-      it('should suggest values for map keys', function() {
-        assertAutoComplete({
-          beforeCursor: 'SELECT * FROM testTable t, t.testMap tm WHERE tm.key =',
-          afterCursor: '',
-          dialect: 'impala',
-          expectedResult: {
-            lowerCase: false,
-            suggestValues: {
-              table: 'testTable',
-              identifierChain: [{ name: 'testMap' }, { name: 'key' }]
-            },
-            suggestIdentifiers : [{ name: 't.', type: 'alias' }, { name: 'tm.', type: 'alias' }]
-          }
-        });
-      });
-
-      it('should suggest values from fields in map values in conditions', function() {
-        assertAutoComplete({
-          beforeCursor: 'SELECT * FROM testTable t, t.testMap m WHERE m.field = ',
-          afterCursor: '',
-          dialect: 'impala',
-          expectedResult: {
-            lowerCase: false,
-            suggestValues: {
-              table: 'testTable',
-              identifierChain: [{ name: 'testMap' }, { name: 'field' }]
-            },
-            suggestIdentifiers : [{ name: 't.', type: 'alias' }, { name: 'm.', type: 'alias' }]
-          }
-        });
-      })
-    });
-
-    describe('Hive and Impla struct completion', function() {
-      it('should suggest fields from columns that are structs', function() {
-        assertAutoComplete({
-          beforeCursor: 'SELECT columnA.',
-          afterCursor: ' FROM testTable',
-          dialect: 'impala',
-          expectedResult: {
-            lowerCase: false,
-            suggestStar: true, // TODO: Verify that this is true
-            suggestColumns: {
-              table: 'testTable',
-              identifierChain: [{ name: 'columnA' }]
-            }
-          }
-        });
-      });
-
-      it('should suggest fields from nested structs', function() {
-        assertAutoComplete({
-          beforeCursor: 'SELECT columnA.fieldC.',
-          afterCursor: ' FROM testTable',
           dialect: 'impala',
           expectedResult: {
             lowerCase: false,
-            suggestColumns: {
-              table: 'testTable',
-              identifierChain: [{ name: 'columnA' }, { name: 'fieldC' }]
-            }
-          }
-        });
-      });
-
-      it('should suggest fields from nested structs with database reference', function() {
-        assertAutoComplete({
-          beforeCursor: 'SELECT columnA.fieldC.',
-          afterCursor: ' FROM database_two.testTable',
-          dialect: 'hive',
-          expectedResult: {
-            lowerCase: false,
-            suggestColumns: {
-              table: 'testTable',
-              database: 'database_two',
-              identifierChain: [{ name: 'columnA' }, { name: 'fieldC' }]
-            }
+            suggestKeywords: ['ALTER', 'COMPUTE', 'CREATE', 'DELETE', 'DESCRIBE',
+              'DROP', 'EXPLAIN', 'INSERT', 'INVALIDATE', 'LOAD', 'REFRESH',
+              'REVOKE', 'SELECT', 'SET', 'SHOW', 'TRUNCATE', 'UPDATE', 'USE']
           }
         });
       });
     });
 
-    describe('value completion', function() {
-      it('should suggest values for columns in conditions', function() {
-        assertAutoComplete({
-          beforeCursor: 'SELECT * FROM testTable WHERE id =',
-          afterCursor: '',
-          expectedResult: {
-            lowerCase: false,
-            suggestValues: {
-              table: 'testTable',
-              identifierChain: [{ name: 'id' }]
-            }
-          }
-        });
-      });
-
-      it('should suggest values for columns in conditions', function() {
+    describe('Hive specific', function () {
+      it('should suggest keywords for empty statement', function() {
         assertAutoComplete({
-          beforeCursor: 'SELECT a, b, c FROM testTable WHERE d >= ',
+          beforeCursor: '',
           afterCursor: '',
+          dialect: 'hive',
           expectedResult: {
             lowerCase: false,
-            suggestValues: {
-              table: 'testTable',
-              identifierChain: [{ name: 'd' }]
-            }
+            suggestKeywords: ['ALTER', 'ANALYZE', 'CREATE', 'DELETE', 'DESCRIBE',
+              'DROP', 'EXPLAIN', 'EXPORT', 'IMPORT', 'INSERT', 'LOAD', 'MSCK',
+              'REVOKE', 'SELECT', 'SET', 'SHOW', 'TRUNCATE', 'UPDATE', 'USE']
           }
         });
       });
     });
 
-    describe('field completion', function() {
-      it('should suggest columns for table', function() {
-        assertAutoComplete({
-          beforeCursor: 'SELECT ',
-          afterCursor: ' FROM testTable',
-          expectedResult: {
-            lowerCase: false,
-            suggestStar: true,
-            suggestColumns: { table: 'testTable' }
-          }
-        });
-      });
-
-      it('should suggest multiple columns for table', function() {
-        assertAutoComplete({
-          beforeCursor: 'SELECT a, ',
-          afterCursor: ' FROM testTable',
-          expectedResult: {
-            lowerCase: false,
-            suggestStar: true, // TODO: Correct?
-            suggestColumns: { table: 'testTable' }
-          }
-        });
-      });
-
-      it('should suggest multiple columns for table without space', function() {
-        assertAutoComplete({
-          beforeCursor: 'SELECT a,',
-          afterCursor: ' FROM testTable',
-          expectedResult: {
-            lowerCase: false,
-            suggestStar: true, // TODO: Correct?
-            suggestColumns: { table: 'testTable' }
-          }
-        });
-      });
-
-      it('should suggest columns for tables with where keyword in name', function () {
-        assertAutoComplete({
-          beforeCursor: 'SELECT ',
-          afterCursor: ' FROM testwhere',
-          expectedResult: {
-            lowerCase: false,
-            suggestStar: true,
-            suggestColumns: { table: 'testwhere' }
-          }
-        });
-      });
-
-      it('should suggest columns for tables with on keyword in name', function () {
-        assertAutoComplete({
-          beforeCursor: 'SELECT ',
-          afterCursor: ' FROM teston',
-          expectedResult: {
-            lowerCase: false,
-            suggestStar: true,
-            suggestColumns: { table: 'teston' }
-          }
-        });
-      });
-
-      it('should suggest columns for table with database prefix', function() {
-        assertAutoComplete({
-          beforeCursor: 'select ',
-          afterCursor: ' from database_two.testTable',
-          expectedResult: {
-            lowerCase: true,
-            suggestStar: true,
-            suggestColumns: { table: 'testTable', database: 'database_two' }
-          }
-        });
-      });
-
-      it('should suggest columns for table with grave accents', function () {
-        assertAutoComplete({
-          beforeCursor: 'select ',
-          afterCursor: ' from `database one`.`test table`',
-          expectedResult: {
-            lowerCase: true,
-            suggestStar: true,
-            suggestColumns: { table: 'test table', database: 'database one' }
-          }
-        });
-      });
-
-      it('should suggest columns for table after WHERE', function() {
-        assertAutoComplete({
-          beforeCursor: 'SELECT * FROM testTable WHERE ',
-          afterCursor: '',
-          expectedResult: {
-            lowerCase: false,
-            suggestColumns: { table: 'testTable' }
-          }
-        });
+    it('should return empty suggestions for bogus statement', function() {
+      assertAutoComplete({
+        beforeCursor: 'foo',
+        afterCursor: 'bar',
+        expectedResult: {
+          lowerCase: false
+        }
       });
+    });
 
-      it('should suggest columns for table after WHERE with partial column', function() {
-        assertAutoComplete({
-          beforeCursor: 'SELECT * FROM testTable WHERE a',
-          afterCursor: '',
-          expectedResult: {
-            lowerCase: false,
-            suggestColumns: { table: 'testTable' }
-          }
-        });
+    it('should ignore line comments for local suggestions', function () {
+      assertAutoComplete({
+        beforeCursor: '-- line comment\nSELECT * from testTable1;\n',
+        afterCursor: '\n-- other line comment',
+        dialect: 'generic',
+        expectedResult: {
+          lowerCase: false,
+          suggestKeywords: ['ALTER', 'CREATE', 'DELETE', 'DESCRIBE', 'DROP',
+            'EXPLAIN', 'INSERT', 'REVOKE', 'SELECT', 'SET', 'SHOW', 'TRUNCATE',
+            'UPDATE', 'USE']
+        }
       });
+    });
 
-      it('should suggest BY after ORDER', function () {
-        assertAutoComplete({
-          beforeCursor: 'SELECT * FROM testTable ORDER ',
-          afterCursor: '',
-          expectedResult: {
-            lowerCase: false,
-            suggestKeywords: ['BY']
-          }
-        });
+    it('should ignore multi-line comments for local suggestions', function () {
+      assertAutoComplete({
+        beforeCursor: '/* line 1\nline 2\n*/\nSELECT * from testTable1;\n',
+        afterCursor: '',
+        dialect: 'generic',
+        expectedResult: {
+          lowerCase: false,
+          suggestKeywords: ['ALTER', 'CREATE', 'DELETE', 'DESCRIBE', 'DROP',
+            'EXPLAIN', 'INSERT', 'REVOKE', 'SELECT', 'SET', 'SHOW', 'TRUNCATE',
+            'UPDATE', 'USE']
+        }
       });
+    });
 
-      it('should suggest BY after GROUP', function () {
-        assertAutoComplete({
-          beforeCursor: 'SELECT * FROM testTable GROUP ',
-          afterCursor: '',
-          expectedResult: {
-            lowerCase: false,
-            suggestKeywords: ['BY']
-          }
-        });
+    describe('identifierChain expansion', function () {
+      it('should expand 1', function () {
+        var tablePrimaries = [{
+          identifierChain: [{ name: 'testTable' }],
+          lateralViews: [{
+            columnAliases: [ 'testItem' ],
+            tableAlias: 'explodedTable',
+            udtf: {
+              expression: [{ name: 'testArray' }],
+              function: 'explode'
+            }
+          }]
+        }];
+
+        var identifierChain = [{ name: 'explodedTable' }, { name: 'testItem' }];
+
+        var result = sql.expandLateralViews(tablePrimaries, identifierChain);
+        expect(result).toEqual([{ name: 'testArray' }, { name: 'item' }]);
+      });
+
+      it('should expand 2', function () {
+        var tablePrimaries = [{
+          identifierChain: [{ name: 'testTable' }],
+          lateralViews: [{
+            columnAliases: [ 'testMapKey', 'testMapValue' ],
+            tableAlias: 'explodedMap',
+            udtf: {
+              expression: [{ name: 'testMap' }],
+              function: 'explode'
+            }
+          }]
+        }];
+
+        var identifierChain = [{ name: 'explodedMap' }, { name: 'testMapValue' }];
+
+        var result = sql.expandLateralViews(tablePrimaries, identifierChain);
+        expect(result).toEqual([{ name: 'testMap' }, { name: 'value' }]);
+      });
+
+      it('should expand 3', function () {
+        var tablePrimaries = [{ identifierChain: [{ name: 'testTable' }] }];
+        var identifierChain = [{ name: 'testMap', key: 'anyKey' }];
+        var result = sql.expandLateralViews(tablePrimaries, identifierChain);
+        expect(result).toEqual([{ name: 'testMap', key: 'anyKey' }]);
+      });
+
+      it('should expand 4', function () {
+        var tablePrimaries = [{
+          identifierChain: [{ name: 'testTable' }],
+          lateralViews: [{
+            columnAliases: [ 'testItem' ],
+            tableAlias: 'explodedTable',
+            udtf: {
+              function: 'explode',
+              expression: [{ name: 'testArray' }]
+            }
+          }]
+        }];
+        var identifierChain = [{ name: 'testItem' }];
+        var result = sql.expandLateralViews(tablePrimaries, identifierChain);
+        expect(result).toEqual([{ name: 'testArray' }, { name: 'item' }]);
+      });
+
+      it('should expand 5', function () {
+        var tablePrimaries = [{
+          identifierChain: [{ name: 'testTable' }],
+          lateralViews: [{
+            columnAliases: [ 'testItemB' ],
+            tableAlias: 'explodedTableB',
+            udtf: {
+              function: 'explode',
+              expression: [{ name: 'testArrayB' }]
+            }
+          }, {
+            columnAliases: [ 'testItemA' ],
+            tableAlias: 'explodedTableA',
+            udtf: {
+              function: 'explode',
+              expression: [{ name: 'testArrayA' }]
+            }
+          }]
+        }];
+        var identifierChain = [{ name: 'testItemA' }];
+        var result = sql.expandLateralViews(tablePrimaries, identifierChain);
+        expect(result).toEqual([{ name: 'testArrayA' }, { name: 'item' }]);
+      });
+
+      it('should expand 6', function () {
+        var tablePrimaries = [{
+          alias: 'tt2',
+          identifierChain: [{ name: 'testTable2' }],
+          lateralViews: [{
+            columnAliases: [ 'testItemB' ],
+            tableAlias: 'explodedTableB',
+            udtf: {
+              function: 'explode',
+              expression: [{ name: 'tt2' }, { name: 'testArrayB' }]
+            }
+          }, {
+            columnAliases: [ 'testItemA' ],
+            tableAlias: 'explodedTableA',
+            udtf: {
+              function: 'explode',
+              expression: [{ name: 'tt2' }, { name: 'testArrayA' }]
+            }
+          }]
+        }];
+        var identifierChain = [{ name: 'testItemB' }];
+        var result = sql.expandLateralViews(tablePrimaries, identifierChain);
+        expect(result).toEqual([{ name: 'tt2' }, { name: 'testArrayB' }, { name: 'item' }]);
       });
 
-      it('should suggest columns for table after ORDER BY ', function() {
-        assertAutoComplete({
-          serverResponses: {
-            '/notebook/api/autocomplete/database_one/testTable' : {
-              columns: ['testTableColumn1', 'testTableColumn2']
+      it('should expand 7', function () {
+        var tablePrimaries = [{
+          alias: 'tt',
+          identifierChain: [{ name: 'testTable' }],
+          lateralViews: [{
+            columnAliases: [ 'ta1_exp' ],
+            tableAlias: 'ta1',
+            udtf: {
+              expression: [{ name: 'tt' }, { name: 'testArray1' }],
+              function: 'explode'
+            }
+          }, {
+            columnAliases: [ 'ta2_exp' ],
+            tableAlias: 'ta2',
+            udtf: {
+              expression: [{ name: 'ta1_exp' },{ name: 'testArray2' }],
+              function: 'explode'
             }
-          },
-          beforeCursor: 'SELECT * FROM testTable ORDER BY ',
-          afterCursor: '',
-          expectedResult: {
-            lowerCase: false,
-            suggestColumns: { table: 'testTable' }
-          }
-        });
-      });
-
-      it('should suggest columns for table after ORDER BY with db reference', function() {
-        assertAutoComplete({
-          beforeCursor: 'SELECT * FROM database_two.testTable ORDER BY ',
-          afterCursor: '',
-          expectedResult: {
-            lowerCase: false,
-            suggestColumns: { database: 'database_two', table: 'testTable' }
-          }
-        });
-      });
-
-      it('should suggest columns for table after GROUP BY ', function() {
-        assertAutoComplete({
-          beforeCursor: 'SELECT * FROM testTable GROUP BY ',
-          afterCursor: '',
-          expectedResult: {
-            lowerCase: false,
-            suggestColumns: { table: 'testTable' }
-          }
-        });
-      });
-
-      it('should suggest columns for table after GROUP BY with db reference ', function() {
-        assertAutoComplete({
-          beforeCursor: 'SELECT * FROM database_two.testTable GROUP BY ',
-          afterCursor: '',
-          expectedResult: {
-            lowerCase: false,
-            suggestColumns: { database: 'database_two', table: 'testTable' }
-          }
-        });
-      });
-
-      it('should suggest columns for table after ON ', function() {
-        assertAutoComplete({
-          beforeCursor: 'SELECT t1.testTableColumn1, t2.testTableColumn3 FROM testTable1 t1 JOIN testTable2 t2 ON t1.',
-          afterCursor: '',
-          expectedResult: {
-            lowerCase: false,
-            suggestColumns: { table: 'testTable1' }
-          }
-        });
-      });
-
-      it('should suggest columns for table after ON with database reference', function() {
-        assertAutoComplete({
-          beforeCursor: 'SELECT t1.testTableColumn1, t2.testTableColumn3 FROM database_two.testTable1 t1 JOIN testTable2 t2 ON t1.',
-          afterCursor: '',
-          expectedResult: {
-            lowerCase: false,
-            suggestColumns: { table: 'testTable1', database: 'database_two' }
-          }
-        });
-      });
-
-      it('should suggest columns for table with table ref', function() {
-        assertAutoComplete({
-          beforeCursor: 'SELECT testTable.',
-          afterCursor: ' FROM testTable',
-          expectedResult: {
-            lowerCase: false,
-            suggestStar: true,
-            suggestColumns: { table: 'testTable' }
-          }
-        });
-      });
+          }]
+        }];
 
-      it('should suggest columns with table alias', function() {
-        assertAutoComplete({
-          beforeCursor: 'SELECT tt.',
-          afterCursor: ' FROM testTable tt',
-          expectedResult: {
-            lowerCase: false,
-            suggestStar: true,
-            suggestColumns: { table: 'testTable' }
-          }
-        });
-      });
+        var identifierChain = [{ name: 'ta2_exp' }];
+
+        var result = sql.expandLateralViews(tablePrimaries, identifierChain);
+        expect(result).toEqual([{ name: 'tt' }, { name: 'testArray1' }, { name: 'item' }, { name: 'testArray2' }, { name: 'item' }]);
+      });
+
+      it('should expand 8', function () {
+        var tablePrimaries = [{
+          identifierChain: [{ name: 'testTable' }],
+          lateralViews: [{
+            columnAliases: [ 'testIndex', 'testValue' ],
+            tableAlias: 'explodedTable',
+            udtf: {
+              expression: [{ name: 'testArray' }],
+              function: 'posexplode'
+            }
+          }]
+        }];
+
+        var identifierChain = [{ name: 'testValue' }];
+
+        var result = sql.expandLateralViews(tablePrimaries, identifierChain);
+        expect(result).toEqual([{ name: 'testArray' }, { name: 'item' }]);
+      });
+
+      it('should expand 9', function () {
+        var tablePrimaries = [{
+          identifierChain: [{ name: 'testTable' }],
+          lateralViews: [{
+            columnAliases: [ 'testMapKey', 'testMapValue' ],
+            tableAlias: 'explodedTable',
+            udtf: {
+              expression: [{ name: 'testMap' }],
+              function: 'explode'
+            }
+          }]
+        }];
 
-      it('should suggest columns with table alias from database reference', function() {
-        assertAutoComplete({
-          beforeCursor: 'SELECT tt.',
-          afterCursor: ' FROM database_two.testTable tt',
-          expectedResult: {
-            lowerCase: false,
-            suggestStar: true,
-            suggestColumns: { table: 'testTable', database: 'database_two' }
-          }
-        });
-      });
+        var identifierChain = [{ name: 'testMapValue' }];
 
-      it('should suggest columns with multiple table aliases', function() {
-        assertAutoComplete({
-          beforeCursor: 'SELECT tta.',
-          afterCursor: ' FROM testTableA tta, testTableB ttb',
-          expectedResult: {
-            lowerCase: false,
-            suggestStar: true,
-            suggestColumns: { table: 'testTableA' }
-          }
-        });
-        assertAutoComplete({
-          beforeCursor: 'SELECT ttb.',
-          afterCursor: ' FROM testTableA tta, testTableB ttb',
-          expectedResult: {
-            lowerCase: false,
-            suggestStar: true,
-            suggestColumns: { table: 'testTableB' }
-          }
-        });
+        var result = sql.expandLateralViews(tablePrimaries, identifierChain);
+        expect(result).toEqual([{ name: 'testMap' }, { name: 'value' }]);
       });
-    });
 
-    describe('joins', function() {
-
-      it('should suggest tables to join with', function() {
-        assertAutoComplete({
-          beforeCursor: 'SELECT * FROM testTable1 JOIN ',
-          afterCursor: '',
-          expectedResult: {
-            lowerCase: false,
-            suggestTables: {},
-            suggestDatabases: { appendDot: true }
-          }
-        });
-      });
+      it('should expand a simple map reference', function () {
+        var tablePrimaries = [
+          { alias: 't', identifierChain: [{ name: 'someDb' }, { name: 'someTable' }] },
+          { alias: 'm', identifierChain: [{ name: 't' }, { name: 'someMap' }] }
+        ];
 
-      it('should suggest table references in join condition if not already there', function() {
-        assertAutoComplete({
-          beforeCursor: 'SELECT testTable1.* FROM testTable1 JOIN testTable2 ON (',
-          afterCursor: '',
-          expectedResult: {
-            lowerCase: false,
-            suggestIdentifiers: [{ name: 'testTable1.', type: 'table' }, { name: 'testTable2.', type: 'table' }]
-          }
-        });
-      });
+        var identifierChain = [{ name: 'm', key: 'foo' }, { name: 'bar' }];
 
-      it('should suggest table references in join condition if not already there for multiple conditions after AND', function() {
-        assertAutoComplete({
-          beforeCursor: 'SELECT testTable1.* FROM testTable1 JOIN testTable2 ON (testTable1.testColumn1 = testTable2.testColumn3 AND ',
-          afterCursor: '',
-          ignoreErrors: true, // Here the right parenthesis is missing
-          expectedResult: {
-            lowerCase: false,
-            suggestIdentifiers: [{ name: 'testTable1.', type: 'table' }, { name: 'testTable2.', type: 'table' }]
-          }
-        });
-      });
+        var actual = sql.expandImpalaIdentifierChain(tablePrimaries, identifierChain);
 
-      it('should suggest table references in join condition if not already there for multiple conditions', function() {
-        assertAutoComplete({
-          beforeCursor: 'SELECT testTable1.* FROM testTable1 JOIN testTable2 ON (',
-          afterCursor: ' AND testTable1.testColumn1 = testTable2.testColumn3',
-          expectedResult: {
-            lowerCase: false,
-            suggestIdentifiers: [{ name: 'testTable1.', type: 'table' }, { name: 'testTable2.', type: 'table' }]
-          }
-        });
+        expect(actual).toEqual([{ name: 't' }, { name: 'someMap', key: 'foo' }, { name: 'bar' }]);
       });
 
-      it('should suggest field references in join condition if table reference is present', function() {
-        assertAutoComplete({
-          beforeCursor: 'SELECT testTable1.* FROM testTable1 JOIN testTable2 ON (testTable2.',
-          afterCursor: '',
-          ignoreErrors: true,
-          expectedResult: {
-            lowerCase: false,
-            suggestColumns: { table: 'testTable2'}
-          }
-        });
-      });
+      it('should expand without map reference', function () {
+        var tablePrimaries = [
+          { alias: 't1', identifierChain: [{ name: 'databaseTwo' }, { name: 'testTable1' }] },
+          { alias: 't2', identifierChain: [{ name: 'testTable2' }] }
+        ];
 
-      xit('should suggest identifiers or values in join condition if table reference is present from multiple tables', function() {
-        assertAutoComplete({
-          beforeCursor: 'select * from testTable1 JOIN testTable2 on (testTable1.testColumn1 = ',
-          afterCursor: '',
-          ignoreErrors: true,
-          expectedResult: {
-            lowerCase: true,
-            suggestIdentifiers: [{ name: 'testTable1.', type: 'table' }, { name: 'testTable2.', type: 'table' }],
-            suggestValues: {
-              table: 'testTable1',
-              identifierChain: [{ name: 'testColumn1' }]
-            }
-          }
-        });
-      });
+        var identifierChain = [{ name: 't1' }];
 
-      it('should suggest field references in join condition if table reference is present from multiple tables', function() {
-        assertAutoComplete({
-          beforeCursor: 'select * from testTable1 JOIN testTable2 on (testTable1.testColumn1 = testTable2.',
-          afterCursor: '',
-          ignoreErrors: true,
-          expectedResult: {
-            lowerCase: true,
-            suggestColumns: { table: 'testTable2'}
-          }
-        });
-      });
+        var actual = sql.expandImpalaIdentifierChain(tablePrimaries, identifierChain);
 
-      it('should suggest field references in join condition if table reference is present from multiple tables for multiple conditions', function() {
-        assertAutoComplete({
-          beforeCursor: 'SELECT testTable1.* FROM testTable1 JOIN testTable2 ON (testTable1.testColumn1 = testTable2.testColumn3 AND testTable1.',
-          afterCursor: '',
-          ignoreErrors: true,
-          expectedResult: {
-            lowerCase: false,
-            suggestColumns: { table: 'testTable1'}
-          }
-        });
+        expect(actual).toEqual([{ name: 'databaseTwo' }, { name: 'testTable1' }]);
       });
-    })
+    });
   });
 });

+ 212 - 0
desktop/core/src/desktop/static/desktop/spec/autocomplete/sqlSpecCreate.js

@@ -0,0 +1,212 @@
+// 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.
+define([
+  'knockout',
+  'desktop/js/autocomplete/sql',
+  'desktop/spec/autocompleterTestUtils'
+], function(ko, sql, testUtils) {
+
+  describe('sql.js CREATE statements', function() {
+
+    beforeAll(function () {
+      sql.yy.parseError = function (msg) {
+        throw Error(msg);
+      };
+      jasmine.addMatchers(testUtils.testDefinitionMatcher);
+    });
+
+    var assertAutoComplete = testUtils.assertAutocomplete;
+
+    it('should suggest keywords for empty statement', function() {
+      assertAutoComplete({
+        beforeCursor: '',
+        afterCursor: '',
+        containsKeywords: ['CREATE'],
+        expectedResult: {
+          lowerCase: false
+        }
+      });
+    });
+
+    it('should suggest keywords after CREATE', function () {
+      assertAutoComplete({
+        beforeCursor: 'CREATE ',
+        afterCursor: '',
+        dialect: 'generic',
+        expectedResult: {
+          lowerCase: false,
+          suggestKeywords: ['DATABASE', 'SCHEMA', 'TABLE']
+        }
+      });
+    });
+
+    it('should suggest keywords after CREATE DATABASE ', function () {
+      assertAutoComplete({
+        beforeCursor: 'CREATE DATABASE ',
+        afterCursor: '',
+        expectedResult: {
+          lowerCase: false,
+          suggestKeywords: ['IF NOT EXISTS']
+        }
+      });
+    });
+
+    it('should suggest keywords after CREATE DATABASE IF ', function () {
+      assertAutoComplete({
+        beforeCursor: 'CREATE DATABASE IF ',
+        afterCursor: '',
+        expectedResult: {
+          lowerCase: false,
+          suggestKeywords: ['NOT EXISTS']
+        }
+      });
+    });
+
+    it('should suggest keywords after CREATE SCHEMA ', function () {
+      assertAutoComplete({
+        beforeCursor: 'CREATE SCHEMA ',
+        afterCursor: '',
+        expectedResult: {
+          lowerCase: false,
+          suggestKeywords: ['IF NOT EXISTS']
+        }
+      });
+    });
+
+    it('should suggest keywords after CREATE DATABASE and before Identifier', function () {
+      assertAutoComplete({
+        beforeCursor: 'CREATE DATABASE ',
+        afterCursor: ' bla;',
+        expectedResult: {
+          lowerCase: false,
+          suggestKeywords: ['IF NOT EXISTS']
+        }
+      });
+    });
+
+    it('should suggest keywords after CREATE TABLE identifier (identifier ', function () {
+      assertAutoComplete({
+        beforeCursor: 'CREATE TABLE foo (id ',
+        afterCursor: '',
+        dialect: 'generic',
+        expectedResult: {
+          lowerCase: false,
+          suggestKeywords: ['BIGINT', 'BOOLEAN', 'CHAR', 'DECIMAL', 'DOUBLE', 'FLOAT', 'INT', 'SMALLINT', 'TIMESTAMP', 'STRING', 'TINYINT', 'VARCHAR']
+        }
+      });
+    });
+
+    it('should suggest keywords after CREATE TABLE identifier (identifier INT, identifier FLOAT, identifier ', function () {
+      assertAutoComplete({
+        beforeCursor: 'CREATE TABLE foo (id INT, some FLOAT, bar ',
+        afterCursor: '',
+        dialect: 'generic',
+        expectedResult: {
+          lowerCase: false,
+          suggestKeywords: ['BIGINT', 'BOOLEAN', 'CHAR', 'DECIMAL', 'DOUBLE', 'FLOAT', 'INT', 'SMALLINT', 'TIMESTAMP', 'STRING', 'TINYINT', 'VARCHAR']
+        }
+      });
+    });
+
+    describe('Impala specific', function () {
+      it('should suggest keywords after CREATE DATABASE foo ', function () {
+        assertAutoComplete({
+          beforeCursor: 'CREATE DATABASE foo ',
+          afterCursor: '',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['COMMENT', 'LOCATION']
+          }
+        });
+      });
+    });
+
+    describe('Hive specific', function () {
+      it ('should suggest keywords after CREATE', function () {
+        assertAutoComplete({
+          beforeCursor: 'CREATE ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['DATABASE', 'EXTERNAL', 'SCHEMA', 'TABLE']
+          }
+        });
+      });
+
+      it ('should suggest keywords after CREATE EXTERNAL TABLE identifier tableElementList', function () {
+        assertAutoComplete({
+          beforeCursor: 'CREATE EXTERNAL TABLE foo (id int) ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['LOCATION']
+          }
+        });
+      });
+
+      it('should suggest keywords in after CREATE TABLE identifier (identifier ', function () {
+        assertAutoComplete({
+          beforeCursor: 'CREATE TABLE foo (id ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['BIGINT', 'BINARY', 'BOOLEAN', 'CHAR', 'DATE', 'DECIMAL', 'DOUBLE', 'FLOAT', 'INT', 'SMALLINT', 'TIMESTAMP', 'STRING', 'TINYINT', 'VARCHAR']
+          }
+        });
+      });
+
+      it('should suggest keywords after CREATE DATABASE foo ', function () {
+        assertAutoComplete({
+          beforeCursor: 'CREATE DATABASE foo ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['COMMENT', 'LOCATION', 'WITH DBPROPERTIES']
+          }
+        });
+      });
+
+      it('should suggest keywords after CREATE DATABASE foo COMMENT ', function () {
+        assertAutoComplete({
+          beforeCursor: 'CREATE DATABASE foo COMMENT \'bla\' ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['LOCATION', 'WITH DBPROPERTIES']
+          }
+        });
+      });
+
+      it('should suggest keywords after CREATE DATABASE foo COMMENT and LOCATION', function () {
+        assertAutoComplete({
+          beforeCursor: 'CREATE DATABASE foo COMMENT \'bla\' LOCATION \'/bla\' ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['WITH DBPROPERTIES']
+          }
+        });
+      });
+    });
+  });
+});

+ 230 - 0
desktop/core/src/desktop/static/desktop/spec/autocomplete/sqlSpecDrop.js

@@ -0,0 +1,230 @@
+// 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.
+define([
+  'knockout',
+  'desktop/js/autocomplete/sql',
+  'desktop/spec/autocompleterTestUtils'
+], function(ko, sql, testUtils) {
+
+  describe('sql.js DROP statements', function() {
+
+    beforeAll(function () {
+      sql.yy.parseError = function (msg) {
+        throw Error(msg);
+      };
+      jasmine.addMatchers(testUtils.testDefinitionMatcher);
+    });
+
+    var assertAutoComplete = testUtils.assertAutocomplete;
+
+    it('should suggest keywords for empty statement', function() {
+      assertAutoComplete({
+        beforeCursor: '',
+        afterCursor: '',
+        containsKeywords: ['DROP'],
+        expectedResult: {
+          lowerCase: false
+        }
+      });
+    });
+
+    it('should suggest keywords after DROP', function() {
+      assertAutoComplete({
+        beforeCursor: 'DROP ',
+        afterCursor: '',
+        dialect: 'generic',
+        expectedResult: {
+          lowerCase: false,
+          suggestKeywords: ['ROLE', 'SCHEMA', 'TABLE', 'VIEW']
+        }
+      });
+    });
+
+    describe('hive specific', function () {
+      it('should suggest keywords after DROP', function() {
+        assertAutoComplete({
+          beforeCursor: 'DROP ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['DATABASE', 'FUNCTION', 'INDEX', 'MACRO', 'ROLE', 'SCHEMA', 'TABLE', 'TEMPORARY FUNCTION', 'TEMPORARY MACRO', 'VIEW']
+          }
+        });
+      });
+    });
+
+    describe('hive specific', function () {
+      it('should follow case after drop', function() {
+        assertAutoComplete({
+          beforeCursor: 'drop ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: true,
+            suggestKeywords: ['DATABASE', 'FUNCTION', 'INDEX', 'MACRO', 'ROLE', 'SCHEMA', 'TABLE', 'TEMPORARY FUNCTION', 'TEMPORARY MACRO', 'VIEW']
+          }
+        });
+      });
+    });
+
+    describe('impala specific', function () {
+      it('should suggest keywords after DROP', function() {
+        assertAutoComplete({
+          beforeCursor: 'DROP ',
+          afterCursor: '',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['AGGREGATE FUNCTION', 'DATABASE', 'FUNCTION', 'INCREMENTAL STATS', 'ROLE', 'SCHEMA', 'STATS', 'TABLE', 'VIEW']
+          }
+        });
+      });
+    });
+
+    describe('drop database statements', function () {
+      it('should suggest databases after DROP DATABASE ', function() {
+        assertAutoComplete({
+          beforeCursor: 'DROP DATABASE ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestDatabases: {},
+            suggestKeywords: ['IF EXISTS']
+          }
+        });
+      });
+
+      it('should suggest databases after DROP SCHEMA ', function() {
+        assertAutoComplete({
+          beforeCursor: 'DROP SCHEMA ',
+          afterCursor: '',
+          expectedResult: {
+            lowerCase: false,
+            suggestDatabases: {},
+            suggestKeywords: ['IF EXISTS']
+          }
+        });
+      });
+
+      it('should suggest keywords after DROP DATABASE IF ', function() {
+        assertAutoComplete({
+          beforeCursor: 'DROP DATABASE IF ',
+          afterCursor: '',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['EXISTS']
+          }
+        });
+      });
+
+      it('should suggest databases after DROP DATABASE IF EXISTS ', function() {
+        assertAutoComplete({
+          beforeCursor: 'DROP DATABASE IF EXISTS ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestDatabases: {}
+          }
+        });
+      });
+
+      describe('Hive specific', function () {
+        it('should suggest keywords after DROP DATABASE foo ', function() {
+          assertAutoComplete({
+            beforeCursor: 'DROP DATABASE foo ',
+            afterCursor: '',
+            dialect: 'hive',
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['CASCADE', 'RESTRICT']
+            }
+          });
+        });
+      });
+    });
+
+    describe('drop table statements', function () {
+      it('should suggest tables after DROP TABLE ', function() {
+        assertAutoComplete({
+          beforeCursor: 'DROP TABLE ',
+          afterCursor: '',
+          expectedResult: {
+            lowerCase: false,
+            suggestTables: {},
+            suggestKeywords: ['IF EXISTS'],
+            suggestDatabases: {
+              appendDot: true
+            }
+          }
+        });
+      });
+
+      it('should suggest tables after DROP TABLE db. ', function() {
+        assertAutoComplete({
+          beforeCursor: 'DROP TABLE db.',
+          afterCursor: '',
+          expectedResult: {
+            lowerCase: false,
+            suggestTables: { database: 'db' }
+          }
+        });
+      });
+
+      it('should suggest keywords after DROP TABLE IF ', function() {
+        assertAutoComplete({
+          beforeCursor: 'DROP TABLE IF ',
+          afterCursor: '',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['EXISTS']
+          }
+        });
+      });
+
+      it('should suggest tables after DROP TABLE IF EXISTS ', function() {
+        assertAutoComplete({
+          beforeCursor: 'DROP TABLE IF EXISTS ',
+          afterCursor: '',
+          expectedResult: {
+            lowerCase: false,
+            suggestTables: {},
+            suggestDatabases: {
+              appendDot: true
+            }
+          }
+        });
+      });
+
+      describe('Hive specific', function () {
+        it('should suggest keywords after DROP TABLE foo ', function() {
+          assertAutoComplete({
+            beforeCursor: 'DROP TABLE foo ',
+            afterCursor: '',
+            dialect: 'hive',
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['PURGE']
+            }
+          });
+        });
+      });
+    });
+  });
+});

+ 158 - 0
desktop/core/src/desktop/static/desktop/spec/autocomplete/sqlSpecLoad.js

@@ -0,0 +1,158 @@
+// 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.
+define([
+  'knockout',
+  'desktop/js/autocomplete/sql',
+  'desktop/spec/autocompleterTestUtils'
+], function(ko, sql, testUtils) {
+
+  describe('sql.js LOAD statements', function() {
+
+    beforeAll(function () {
+      sql.yy.parseError = function (msg) {
+        throw Error(msg);
+      };
+      jasmine.addMatchers(testUtils.testDefinitionMatcher);
+    });
+
+    var assertAutoComplete = testUtils.assertAutocomplete;
+
+    describe('Impala specific', function () {
+      it('should suggest keywords for empty statement', function() {
+        assertAutoComplete({
+          beforeCursor: '',
+          afterCursor: '',
+          dialect: 'impala',
+          containsKeywords: ['LOAD'],
+          expectedResult: {
+            lowerCase: false
+          }
+        });
+      });
+
+      it ('should suggest keywords after LOAD', function () {
+        assertAutoComplete({
+          beforeCursor: 'LOAD ',
+          afterCursor: '',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['DATA']
+          }
+        });
+      });
+
+      it ('should suggest keywords after LOAD DATA', function () {
+        assertAutoComplete({
+          beforeCursor: 'LOAD DATA ',
+          afterCursor: '',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['INPATH']
+          }
+        });
+      });
+
+      it ('should suggest keywords after LOAD DATA hdfsPath', function () {
+        assertAutoComplete({
+          beforeCursor: 'LOAD DATA INPATH \'/some/path\' ',
+          afterCursor: '',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['INTO']
+          }
+        });
+      });
+
+      it ('should suggest keywords after LOAD DATA hdfsPath INTO', function () {
+        assertAutoComplete({
+          beforeCursor: 'LOAD DATA INPATH \'some/path\' INTO ',
+          afterCursor: '',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['TABLE']
+          }
+        });
+      });
+    });
+
+    describe('Hive specific', function () {
+      it('should suggest keywords for empty statement', function () {
+        assertAutoComplete({
+          beforeCursor: '',
+          afterCursor: '',
+          dialect: 'hive',
+          containsKeywords: ['LOAD'],
+          expectedResult: {
+            lowerCase: false
+          }
+        });
+      });
+    });
+
+    it('should autocomplete hdfs paths in location references without initial /', function () {
+      assertAutoComplete({
+        beforeCursor: 'LOAD DATA INPATH \'',
+        afterCursor: '\'',
+        dialect: 'impala',
+        expectedResult: {
+          lowerCase: false,
+          suggestHdfs: { path: ''}
+        }
+      });
+    });
+
+    it('should autocomplete hdfs paths in location references from root', function () {
+      assertAutoComplete({
+        beforeCursor: 'LOAD DATA INPATH \'/',
+        afterCursor: '\'',
+        dialect: 'hive',
+        expectedResult: {
+          lowerCase: false,
+          suggestHdfs: { path: '/'}
+        }
+      });
+    });
+
+    it('should autocomplete hdfs paths and suggest trailing apostrophe if empty after cursor', function () {
+      assertAutoComplete({
+        beforeCursor: 'LOAD DATA INPATH \'/',
+        afterCursor: '',
+        dialect: 'impala',
+        expectedResult: {
+          lowerCase: false,
+          suggestHdfs: { path: '/'}
+        }
+      });
+    });
+
+    it('should autocomplete hdfs paths in location references from inside a path', function () {
+      assertAutoComplete({
+        serverResponses: {},
+        beforeCursor: 'LOAD DATA INPATH \'/',
+        afterCursor: '/bar\' INTO TABLE foo',
+        dialect: 'impala',
+        expectedResult: {
+          lowerCase: false,
+          suggestHdfs: { path: '/'}
+        }
+      });
+    });
+  });
+});

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

@@ -0,0 +1,1413 @@
+// 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.
+define([
+  'knockout',
+  'desktop/js/autocomplete/sql',
+  'desktop/spec/autocompleterTestUtils'
+], function(ko, sql, testUtils) {
+
+  describe('sql.js SELECT statements', function() {
+
+    beforeAll(function () {
+      sql.yy.parseError = function (msg) {
+        throw Error(msg);
+      };
+      jasmine.addMatchers(testUtils.testDefinitionMatcher);
+    });
+
+    var assertAutoComplete = testUtils.assertAutocomplete;
+
+    it('should suggest keywords for empty statement', function() {
+      assertAutoComplete({
+        beforeCursor: '',
+        afterCursor: '',
+        containsKeywords: ['SELECT'],
+        expectedResult: {
+          lowerCase: false
+        }
+      });
+    });
+
+    it('should suggest keywords after SELECT * ', function() {
+      assertAutoComplete({
+        beforeCursor: 'SELECT * ',
+        afterCursor: '',
+        expectedResult: {
+          lowerCase: false,
+          suggestTables:{
+            prependFrom:true
+          },
+          suggestDatabases:{
+            prependFrom:true,
+            appendDot:true
+          }
+        }
+      });
+    });
+
+    it('should suggest keywords after SELECT SelectList ', function() {
+      assertAutoComplete({
+        beforeCursor: 'SELECT foo, bar ',
+        afterCursor: '',
+        expectedResult: {
+          lowerCase: false,
+          suggestTables:{
+            prependFrom:true
+          },
+          suggestDatabases:{
+            prependFrom:true,
+            appendDot:true
+          }
+        }
+      });
+    });
+
+    it('should suggest keywords after SELECT SelectList FROM TablePrimary ', function() {
+      assertAutoComplete({
+        serverResponses: {},
+        beforeCursor: 'SELECT * FROM testTableA tta, testTableB ',
+        afterCursor: '',
+        dialect: 'generic',
+        expectedResult: {
+          lowerCase: false,
+          suggestKeywords: ['GROUP BY', 'JOIN', 'LIMIT', 'ORDER BY', 'WHERE']
+        }
+      });
+    });
+
+    it('should suggest keywords after SELECT SelectList FROM TablePrimary WHERE SearchCondition ', function () {
+      assertAutoComplete({
+        beforeCursor: 'SELECT bar FROM foo WHERE id = 1 ',
+        afterCursor: '',
+        expectedResult: {
+          lowerCase: false,
+          suggestKeywords: ['GROUP BY', 'LIMIT', 'ORDER BY']
+        }
+      });
+    });
+
+    describe('Hive specific', function () {
+      it('should suggest keywords after SELECT SelectList FROM TablePrimary ', function () {
+        assertAutoComplete({
+          beforeCursor: 'SELECT bar FROM foo ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['GROUP BY', 'JOIN', 'LATERAL', 'LIMIT', 'ORDER BY', 'WHERE']
+          }
+        });
+      });
+
+      it('should suggest keywords after SELECT SelectList FROM TablePrimary JOIN TablePrimary ', function () {
+        assertAutoComplete({
+          beforeCursor: 'SELECT bar FROM foo JOIN baz ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['ON']
+          }
+        });
+      });
+
+      it('should suggest keywords after SELECT SelectList FROM TablePrimary with linebreaks', function () {
+        assertAutoComplete({
+          beforeCursor: 'SELECT bar\nFROM foo\n',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['GROUP BY', 'JOIN', 'LATERAL', 'LIMIT', 'ORDER BY', 'WHERE']
+          }
+        });
+      });
+
+      it('should suggest keywords after SELECT SelectList FROM TablePrimary WHERE SearchCondition ', function () {
+        assertAutoComplete({
+          beforeCursor: 'SELECT bar FROM foo WHERE id = 1 ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['GROUP BY', 'LIMIT', 'ORDER BY']
+          }
+        });
+      });
+
+      it('should suggest keywords after SELECT SelectList FROM TablePrimary LATERAL ', function () {
+        assertAutoComplete({
+          beforeCursor: 'SELECT bar FROM foo LATERAL ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['VIEW']
+          }
+        });
+      });
+
+      it('should suggest keywords after SELECT SelectList FROM TablePrimary LATERAL VIEW ', function () {
+        assertAutoComplete({
+          beforeCursor: 'SELECT bar FROM foo LATERAL VIEW ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['explode', 'posexplode']
+          }
+        });
+      });
+
+      it('should suggest keywords after SELECT SelectList FROM TablePrimary LATERAL VIEW udtf ', function () {
+        assertAutoComplete({
+          beforeCursor: 'SELECT bar FROM foo LATERAL VIEW explode(bar) ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['AS']
+          }
+        });
+      });
+
+      it('should suggest keywords after SELECT SelectList FROM TablePrimary LATERAL VIEW udtf ', function () {
+        assertAutoComplete({
+          beforeCursor: 'SELECT bar FROM foo LATERAL VIEW explode(bar) b ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['AS']
+          }
+        });
+      });
+    });
+
+    describe('table completion', function() {
+      it('should suggest tables after SELECT', function () {
+        assertAutoComplete({
+          beforeCursor: 'SELECT ',
+          afterCursor: '',
+          expectedResult: {
+            lowerCase: false,
+            suggestStar: true,
+            suggestTables: {
+              prependQuestionMark: true,
+              prependFrom: true
+            },
+            suggestDatabases: {
+              prependQuestionMark: true,
+              prependFrom: true,
+              appendDot: true
+            }
+          }
+        });
+      });
+
+      it('should follow keyword case for table name completion', function() {
+        assertAutoComplete({
+          beforeCursor: 'select ',
+          afterCursor: '',
+          expectedResult: {
+            lowerCase: true,
+            suggestStar: true,
+            suggestTables: {
+              prependQuestionMark: true,
+              prependFrom: true
+            },
+            suggestDatabases: {
+              prependQuestionMark: true,
+              prependFrom: true,
+              appendDot: true
+            }
+          }
+        });
+      });
+
+      it('should suggest table names with *', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT * ',
+          afterCursor: '',
+          expectedResult: {
+            lowerCase: false,
+            suggestTables: {
+              prependFrom: true
+            },
+            suggestDatabases: {
+              prependFrom: true,
+              appendDot: true
+            }
+          }
+        });
+      });
+
+      it('should suggest table names with started FROM', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT * fr',
+          afterCursor: '',
+          expectedResult: {
+            lowerCase: false,
+            suggestTables: {
+              prependFrom: true
+            },
+            suggestDatabases: {
+              prependFrom: true,
+              appendDot: true
+            }
+          }
+        });
+      });
+
+      it('should suggest table names after FROM', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT * FROM ',
+          afterCursor: '',
+          expectedResult: {
+            lowerCase: false,
+            suggestTables: {},
+            suggestDatabases: {
+              appendDot: true
+            }
+          }
+        });
+      });
+
+      it('should suggest database or table names after FROM with started name', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT * FROM tes',
+          afterCursor: '',
+          expectedResult: {
+            lowerCase: false,
+            suggestTables: {},
+            suggestDatabases: {
+              appendDot: true
+            }
+          }
+        });
+      });
+
+      it('should suggest database or table names after FROM with started backticked name', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT * FROM `tes',
+          afterCursor: '',
+          expectedResult: {
+            lowerCase: false,
+            suggestTables: {},
+            suggestDatabases: {
+              appendDot: true
+            }
+          }
+        });
+      });
+
+      it('should suggest table names after FROM with database reference', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT * FROM database_two.',
+          afterCursor: '',
+          expectedResult: {
+            lowerCase: false,
+            suggestTables: {
+              database: 'database_two'
+            }
+          }
+        });
+      });
+
+      it('should suggest table names after FROM with backticked database reference', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT * FROM `database_two`.',
+          afterCursor: '',
+          expectedResult: {
+            lowerCase: false,
+            suggestTables: {
+              database: 'database_two'
+            }
+          }
+        });
+      });
+
+      it('should suggest table names after FROM with partial backticked table reference', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT * FROM `database_two`.`bla ',
+          afterCursor: '',
+          expectedResult: {
+            lowerCase: false,
+            suggestTables: {
+              database: 'database_two'
+            }
+          }
+        });
+      });
+
+      it('should suggest aliases', function() {
+        assertAutoComplete({
+          serverResponses: {},
+          beforeCursor: 'SELECT ',
+          afterCursor: ' FROM testTableA   tta, testTableB',
+          expectedResult: {
+            lowerCase: false,
+            suggestStar: true,
+            suggestIdentifiers: [{ name: 'tta.', type: 'alias' }, { name: 'testTableB.', type: 'table' }]
+          }
+        });
+      });
+
+      it('should suggest aliases in GROUP BY', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT * FROM testTableA tta, testTableB GROUP BY ',
+          afterCursor: '',
+          dialect: 'generic',
+          expectedResult : {
+            lowerCase: false,
+            suggestIdentifiers: [{ name: 'tta.', type: 'alias' }, { name: 'testTableB.', type: 'table' }]
+          }
+        });
+      });
+
+      // TODO: fix me
+      xit('should suggest table aliases and select aliases', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT ',
+          afterCursor: ' FROM testTableA tta, (SELECT SUM(A*B) total FROM tta.array) ttaSum, testTableB ttb',
+          ignoreErrors: true,
+          expectedResult: {
+            lowerCase: false,
+            suggestStar: true,
+            suggestIdentifiers: [{ name: 'tta.', type: 'alias' }, { name: 'ttaSum', type: 'alias' }, { name: 'ttb.', type: 'alias' }]
+          }
+        });
+      });
+    });
+
+    describe('functions', function () {
+      xit('should suggest fields in functions', function () {
+        assertAutoComplete({
+          beforeCursor: 'SELECT id, SUM(',
+          afterCursor: ' FROM testTable',
+          ignoreErrors: true,
+          expectedResult: {
+            lowerCase: false,
+            suggestColumns: {
+              table: 'testTable'
+            }
+          }
+        });
+      });
+
+      xit('should suggest fields in functions after operators', function () {
+        assertAutoComplete({
+          beforeCursor: 'SELECT id, SUM(a * ',
+          afterCursor: ' FROM testTable',
+          ignoreErrors: true,
+          expectedResult: {
+            lowerCase: false,
+            suggestColumns: {
+              table: 'testTable'
+            }
+          }
+        });
+      })
+    });
+
+    describe('Hive specific', function() {
+      it('should suggest struct from map values', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT testMap[\"anyKey\"].',
+          afterCursor: ' FROM testTable',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestColumns : {
+              table: 'testTable',
+              identifierChain: [{ name: 'testMap', key: '\"anyKey\"' }]
+            }
+          }
+        });
+      });
+
+      it('should suggest struct from map values without a given key', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT testMap[].',
+          afterCursor: ' FROM testTable',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestColumns : {
+              table: 'testTable',
+              identifierChain: [{ name: 'testMap', key: null }]
+            }
+          }
+        });
+      });
+
+      it('should suggest struct from structs from map values', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT testMap["anyKey"].fieldC.',
+          afterCursor: ' FROM testTable',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestColumns : {
+              table: 'testTable',
+              identifierChain: [{ name: 'testMap', key: '\"anyKey\"' }, { name: 'fieldC' }]
+            }
+          }
+        });
+      });
+
+      it('should suggest struct from structs from arrays', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT testArray[1].fieldC.',
+          afterCursor: ' FROM testTable',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestColumns : {
+              table: 'testTable',
+              identifierChain: [{ name: 'testArray', key: 1 }, { name: 'fieldC' }]
+            }
+          }
+        });
+      });
+
+      it('should suggest structs from maps from arrays', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT testArray[1].testMap[\"key\"].',
+          afterCursor: ' FROM testTable',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestColumns : {
+              table: 'testTable',
+              identifierChain: [{ name: 'testArray', key: 1 }, { name: 'testMap', key: '\"key\"' }]
+            }
+          }
+        });
+      });
+
+      it('should suggest struct from map values without a given key after where', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT * FROM testTable WHERE testMap[].',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestColumns : {
+              table: 'testTable',
+              identifierChain: [{ name: 'testMap', key: null }]
+            }
+          }
+        });
+      });
+
+      // Lateral view === only hive?
+      describe('lateral views', function() {
+        it('should suggest lateral view aliases', function () {
+          assertAutoComplete({
+            beforeCursor: 'SELECT ',
+            afterCursor: ' FROM testTable LATERAL VIEW explode(testArray) explodedTable AS testItem',
+            dialect: 'hive',
+            expectedResult: {
+              lowerCase: false,
+              suggestStar: true, // TODO: Verify that this is true
+              suggestColumns: {
+                table: 'testTable'
+              },
+              suggestIdentifiers: [{ name: 'explodedTable.', type: 'alias' }, { name: 'testItem', type: 'alias' }]
+            }
+          });
+        });
+
+        xit('should suggest columns in explode', function () {
+          assertAutoComplete({
+            beforeCursor: 'SELECT * FROM testTable LATERAL VIEW explode(',
+            afterCursor: '',
+            dialect: 'hive',
+            expectedResult: {
+              suggestColumns: {
+                table: 'testTable'
+              }
+            }
+          });
+        });
+
+        xit('should suggest columns in explode for structs', function () {
+          assertAutoComplete({
+            beforeCursor: 'SELECT * FROM testTable LATERAL VIEW explode(a.b.',
+            afterCursor: '',
+            dialect: 'hive',
+            expectedResult: {
+              suggestColumns: {
+                table: 'testTable',
+                identifierChain: [ { name: 'a' }, { name: 'b' }]
+              }
+            }
+          });
+        });
+
+        xit('should suggest columns in posexplode', function () {
+          assertAutoComplete({
+            beforeCursor: 'SELECT * FROM testTable LATERAL VIEW posexplode(',
+            afterCursor: '',
+            dialect: 'hive',
+            expectedResult: {
+              suggestColumns: {
+                table: 'testTable'
+              }
+            }
+          });
+        });
+
+        it('should suggest lateral view aliases with multiple column aliases', function () {
+          assertAutoComplete({
+            beforeCursor: 'SELECT ',
+            afterCursor: ' FROM testTable LATERAL VIEW explode(testMap) explodedTable AS (testKey, testValue)',
+            dialect: 'hive',
+            expectedResult: {
+              lowerCase: false,
+              suggestStar: true, // TODO: Verify that this is true
+              suggestColumns: {
+                table: 'testTable'
+              },
+              suggestIdentifiers: [{ name: 'explodedTable.', type: 'alias' }, { name: 'testKey', type: 'alias' }, { name: 'testValue', type: 'alias' }]
+            }
+          });
+        });
+
+        it('should suggest structs from exploded item references to arrays', function () {
+          assertAutoComplete({
+            beforeCursor: 'SELECT testItem.',
+            afterCursor: ' FROM testTable LATERAL VIEW explode(testArray) explodedTable AS testItem',
+            dialect: 'hive',
+            expectedResult: {
+              lowerCase: false,
+              suggestStar: true, // TODO: Verify that this is true
+              suggestColumns: {
+                table: 'testTable',
+                identifierChain: [{ name: 'testArray' }, { name: 'item' }]
+              }
+            }
+          });
+        });
+
+        it('should suggest structs from multiple exploded item references to arrays', function () {
+          assertAutoComplete({
+            beforeCursor: 'SELECT testItemA.',
+            afterCursor: ' FROM testTable' +
+            ' LATERAL VIEW explode(testArrayA) explodedTableA AS testItemA' +
+            ' LATERAL VIEW explode(testArrayB) explodedTableB AS testItemB',
+            dialect: 'hive',
+            expectedResult: {
+              lowerCase: false,
+              suggestStar: true, // TODO: Verify that this is true
+              suggestColumns: {
+                table: 'testTable',
+                identifierChain: [{ name: 'testArrayA' }, { name: 'item' }]
+              }
+            }
+          });
+        });
+
+        it('should support table references as arguments of explode function', function() {
+          assertAutoComplete({
+            beforeCursor: 'SELECT\n testItemA,\n testItemB.',
+            afterCursor: '\n\tFROM\n\t testTable2 tt2\n' +
+            '\t LATERAL VIEW EXPLODE(tt2.testArrayA) explodedTableA AS testItemA\n' +
+            '\t LATERAL VIEW EXPLODE(tt2.testArrayB) explodedTableB AS testItemB',
+            dialect: 'hive',
+            expectedResult: {
+              lowerCase: false,
+              suggestStar: true, // TODO: Verify that this is true
+              suggestColumns: {
+                table: 'testTable2',
+                identifierChain: [{ name: 'testArrayB' }, { name: 'item' }]
+              }
+            }
+          });
+        });
+
+        it('should suggest structs from exploded item references to exploded item references to arrays ', function () {
+          assertAutoComplete({
+            beforeCursor: 'SELECT ta2_exp.',
+            afterCursor: ' FROM ' +
+            '   testTable tt' +
+            ' LATERAL VIEW explode(tt.testArray1) ta1 AS ta1_exp\n' +
+            '   LATERAL VIEW explode(ta1_exp.testArray2)    ta2   AS  ta2_exp',
+            dialect: 'hive',
+            expectedResult: {
+              lowerCase: false,
+              suggestStar: true, // TODO: Verify that this is true
+              suggestColumns: {
+                table: 'testTable',
+                identifierChain: [{ name: 'testArray1' }, { name: 'item' }, { name: 'testArray2' }, { name: 'item' }]
+              }
+            }
+          });
+        });
+
+        it('should suggest structs from references to exploded arrays', function () {
+          assertAutoComplete({
+            beforeCursor: 'SELECT explodedTable.testItem.',
+            afterCursor: ' FROM testTable LATERAL VIEW explode(testArray) explodedTable AS testItem',
+            dialect: 'hive',
+            expectedResult: {
+              lowerCase: false,
+              suggestColumns: {
+                table: 'testTable',
+                identifierChain: [{ name: 'testArray' }, { name: 'item' }]
+              }
+            }
+          });
+        });
+
+        it('should suggest posexploded references to arrays', function () {
+          assertAutoComplete({
+            serverResponses: {
+              '/notebook/api/autocomplete/database_one/testTable/testArray/item': {
+                fields: [
+                  {'type': 'string', 'name': 'fieldA'},
+                  {'type': 'string', 'name': 'fieldB'}
+                ],
+                type: 'struct'
+              }
+            },
+            beforeCursor: 'SELECT testValue.',
+            afterCursor: ' FROM testTable LATERAL VIEW posexplode(testArray) explodedTable AS (testIndex, testValue)',
+            dialect: 'hive',
+            expectedResult: {
+              lowerCase: false,
+              suggestStar: true, // TODO: Verify that this is true
+              suggestColumns: {
+                table: 'testTable',
+                identifierChain: [{ name: 'testArray' }, { name: 'item' }]
+              }
+            }
+          });
+        });
+
+        it('should suggest exploded references to map values', function () {
+          assertAutoComplete({
+            beforeCursor: 'SELECT testMapValue.',
+            afterCursor: ' FROM testTable LATERAL VIEW explode(testMap) AS (testMapKey, testMapValue)',
+            dialect: 'hive',
+            expectedResult: {
+              lowerCase: false,
+              suggestStar: true, // TODO: Verify that this is true
+              suggestColumns: {
+                table: 'testTable',
+                identifierChain: [{ name: 'testMap' }, { name: 'value' }]
+              }
+            }
+          });
+        });
+
+        it('should suggest exploded references to map values from view references', function () {
+          assertAutoComplete({
+            beforeCursor: 'SELECT explodedMap.testMapValue.',
+            afterCursor: ' FROM testTable LATERAL VIEW explode(testMap) explodedMap AS (testMapKey, testMapValue)',
+            dialect: 'hive',
+            expectedResult: {
+              lowerCase: false,
+              suggestColumns: {
+                table: 'testTable',
+                identifierChain: [{ name: 'testMap' }, { name: 'value' }]
+              }
+            }
+          });
+        });
+
+        it('should suggest references to exploded references from view reference', function () {
+          assertAutoComplete({
+            serverResponses: {},
+            beforeCursor: 'SELECT explodedMap.',
+            afterCursor: ' FROM testTable LATERAL VIEW explode(testMap) explodedMap AS (testMapKey, testMapValue)',
+            dialect: 'hive',
+            expectedResult: {
+              lowerCase: false,
+              suggestStar: true, // TODO: Check if really true
+              suggestIdentifiers: [{ name: 'testMapKey', type: 'alias' }, { name: 'testMapValue', type: 'alias' }]
+            }
+          });
+        });
+
+        it('should suggest references to exploded references', function () {
+          assertAutoComplete({
+            serverResponses: {
+              '/notebook/api/autocomplete/database_one/testTable' : {
+                columns: ['testTableColumn1', 'testTableColumn2']
+              }
+            },
+            beforeCursor: 'SELECT ',
+            afterCursor: ' FROM testTable LATERAL VIEW explode(testMap) explodedMap AS (testMapKey, testMapValue)',
+            dialect: 'hive',
+            expectedResult: {
+              lowerCase: false,
+              suggestStar: true, // TODO: Check if really true
+              suggestIdentifiers: [{ name: 'explodedMap.', type: 'alias' }, { name: 'testMapKey', type: 'alias' }, { name: 'testMapValue', type: 'alias' }],
+              suggestColumns: {
+                table: 'testTable'
+              }
+            }
+          });
+        });
+      });
+    });
+
+    describe('Impala specific', function() {
+      it('should not suggest struct from map values with hive style syntax', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT testMap[\"anyKey\"].',
+          afterCursor: ' FROM testTable',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestColumns: {
+              table: 'testTable',
+              identifierChain: [{ name: 'testMap',  key: '\"anyKey\"' }]
+            }
+          }
+        });
+      });
+
+      it('should suggest fields from nested structs', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT columnA.fieldC.',
+          afterCursor: ' FROM testTable',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestColumns: {
+              table: 'testTable',
+              identifierChain: [{ name: 'columnA' }, { name: 'fieldC' }]
+            }
+          }
+        });
+      });
+
+      it('should suggest fields from nested structs with table alias', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT tt.columnA.fieldC.',
+          afterCursor: ' FROM testTable tt',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestColumns: {
+              table: 'testTable',
+              identifierChain: [{ name: 'columnA' }, { name: 'fieldC' }]
+            }
+          }
+        });
+      });
+
+      it('should suggest fields from nested structs with table alias', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT tt.columnA.fieldC.',
+          afterCursor: ' FROM testTable tt',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestColumns: {
+              table: 'testTable',
+              identifierChain: [{ name: 'columnA' }, { name: 'fieldC' }]
+            }
+          }
+        });
+      });
+
+
+      // TODO: Result should have 'key', 'key' is only possible after call to see column type but as it's
+      //       after FROM perhaps only maps are allowed there?
+      //       If the map has a scalar value type (int etc.) it should also suggest 'value'
+      //       For arrays it should suggest 'items' for scalar values
+      it('should suggest fields from map values of type structs', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT tm.',
+          afterCursor: ' FROM testTable t, t.testMap tm;',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestStar: true,
+            suggestColumns : {
+              table: 'testTable',
+              identifierChain: [{ name: 'testMap' }]
+            }
+          }
+        });
+      });
+
+      it('should suggest fields from map values of type structs with partial identifier', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT tm.a',
+          afterCursor: ' FROM testTable t, t.testMap tm;',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestStar: true,
+            suggestColumns : {
+              table: 'testTable',
+              identifierChain: [{ name: 'testMap' }]
+            }
+          }
+        });
+      });
+
+      // Same as above, 'items' or 'value' for scalar
+      it('should suggest items from arrays if complex in from clause', function() {
+        assertAutoComplete({
+
+          beforeCursor: 'SELECT ta.* FROM testTable t, t.testArray ta WHERE ta.',
+          afterCursor: '',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestColumns : {
+              table: 'testTable',
+              identifierChain: [{ name: 'testArray' }]
+            }
+          }
+        });
+      });
+
+      it('should suggest columns from table refs in from clause', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT t.*  FROM testTable t, t.',
+          afterCursor: '',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestColumns : {
+              table: 'testTable'
+            }
+          }
+        });
+      });
+
+      it('should suggest map references in select', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT ',
+          afterCursor: ' FROM testTable t, t.testMap tm;',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestStar: true, // TODO: Check if really so
+            suggestIdentifiers: [{ name: 't.', type: 'alias' }, { name: 'tm.', type: 'alias' }]
+          }
+        });
+      });
+
+      // TODO: Should add Key and Value once we know it's a map
+      it('should suggest fields with key and value in where clause from map values of type structs', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT tm.* FROM testTable t, t.testMap tm WHERE tm.',
+          afterCursor: '',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestColumns: {
+              table: 'testTable',
+              identifierChain: [{ name: 'testMap' }]
+            }
+          }
+        });
+      });
+
+      it('should suggest fields in where clause from map values of type structs', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT tm.* FROM testTable t, t.testMap tm WHERE tm.value.',
+          afterCursor: '',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestColumns: {
+              table: 'testTable',
+              identifierChain: [{ name: 'testMap' }, { name: 'value' }]
+            }
+          }
+        });
+      });
+
+      it('should suggest values for map keys', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT * FROM testTable t, t.testMap tm WHERE tm.key =',
+          afterCursor: '',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestValues: {
+              table: 'testTable',
+              identifierChain: [{ name: 'testMap' }, { name: 'key' }]
+            },
+            suggestIdentifiers : [{ name: 't.', type: 'alias' }, { name: 'tm.', type: 'alias' }]
+          }
+        });
+      });
+
+      it('should suggest values from fields in map values in conditions', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT * FROM testTable t, t.testMap m WHERE m.field = ',
+          afterCursor: '',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestValues: {
+              table: 'testTable',
+              identifierChain: [{ name: 'testMap' }, { name: 'field' }]
+            },
+            suggestIdentifiers : [{ name: 't.', type: 'alias' }, { name: 'm.', type: 'alias' }]
+          }
+        });
+      })
+    });
+
+    describe('Hive and Impla struct completion', function() {
+      it('should suggest fields from columns that are structs', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT columnA.',
+          afterCursor: ' FROM testTable',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestStar: true, // TODO: Verify that this is true
+            suggestColumns: {
+              table: 'testTable',
+              identifierChain: [{ name: 'columnA' }]
+            }
+          }
+        });
+      });
+
+      it('should suggest fields from nested structs', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT columnA.fieldC.',
+          afterCursor: ' FROM testTable',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestColumns: {
+              table: 'testTable',
+              identifierChain: [{ name: 'columnA' }, { name: 'fieldC' }]
+            }
+          }
+        });
+      });
+
+      it('should suggest fields from nested structs with database reference', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT columnA.fieldC.',
+          afterCursor: ' FROM database_two.testTable',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestColumns: {
+              table: 'testTable',
+              database: 'database_two',
+              identifierChain: [{ name: 'columnA' }, { name: 'fieldC' }]
+            }
+          }
+        });
+      });
+    });
+
+    describe('value completion', function() {
+      it('should suggest values for columns in conditions', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT * FROM testTable WHERE id =',
+          afterCursor: '',
+          expectedResult: {
+            lowerCase: false,
+            suggestValues: {
+              table: 'testTable',
+              identifierChain: [{ name: 'id' }]
+            }
+          }
+        });
+      });
+
+      it('should suggest values for columns in conditions', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT a, b, c FROM testTable WHERE d >= ',
+          afterCursor: '',
+          expectedResult: {
+            lowerCase: false,
+            suggestValues: {
+              table: 'testTable',
+              identifierChain: [{ name: 'd' }]
+            }
+          }
+        });
+      });
+    });
+
+    describe('field completion', function() {
+      it('should suggest columns for table', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT ',
+          afterCursor: ' FROM testTable',
+          expectedResult: {
+            lowerCase: false,
+            suggestStar: true,
+            suggestColumns: { table: 'testTable' }
+          }
+        });
+      });
+
+      it('should suggest multiple columns for table', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT a, ',
+          afterCursor: ' FROM testTable',
+          expectedResult: {
+            lowerCase: false,
+            suggestStar: true, // TODO: Correct?
+            suggestColumns: { table: 'testTable' }
+          }
+        });
+      });
+
+      it('should suggest multiple columns for table without space', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT a,',
+          afterCursor: ' FROM testTable',
+          expectedResult: {
+            lowerCase: false,
+            suggestStar: true, // TODO: Correct?
+            suggestColumns: { table: 'testTable' }
+          }
+        });
+      });
+
+      it('should suggest columns for tables with where keyword in name', function () {
+        assertAutoComplete({
+          beforeCursor: 'SELECT ',
+          afterCursor: ' FROM testwhere',
+          expectedResult: {
+            lowerCase: false,
+            suggestStar: true,
+            suggestColumns: { table: 'testwhere' }
+          }
+        });
+      });
+
+      it('should suggest columns for tables with on keyword in name', function () {
+        assertAutoComplete({
+          beforeCursor: 'SELECT ',
+          afterCursor: ' FROM teston',
+          expectedResult: {
+            lowerCase: false,
+            suggestStar: true,
+            suggestColumns: { table: 'teston' }
+          }
+        });
+      });
+
+      it('should suggest columns for table with database prefix', function() {
+        assertAutoComplete({
+          beforeCursor: 'select ',
+          afterCursor: ' from database_two.testTable',
+          expectedResult: {
+            lowerCase: true,
+            suggestStar: true,
+            suggestColumns: { table: 'testTable', database: 'database_two' }
+          }
+        });
+      });
+
+      it('should suggest columns for table with grave accents', function () {
+        assertAutoComplete({
+          beforeCursor: 'select ',
+          afterCursor: ' from `database one`.`test table`',
+          expectedResult: {
+            lowerCase: true,
+            suggestStar: true,
+            suggestColumns: { table: 'test table', database: 'database one' }
+          }
+        });
+      });
+
+      it('should suggest columns for table after WHERE', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT * FROM testTable WHERE ',
+          afterCursor: '',
+          expectedResult: {
+            lowerCase: false,
+            suggestColumns: { table: 'testTable' }
+          }
+        });
+      });
+
+      it('should suggest columns for table after WHERE with partial column', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT * FROM testTable WHERE a',
+          afterCursor: '',
+          expectedResult: {
+            lowerCase: false,
+            suggestColumns: { table: 'testTable' }
+          }
+        });
+      });
+
+      it('should suggest BY after ORDER', function () {
+        assertAutoComplete({
+          beforeCursor: 'SELECT * FROM testTable ORDER ',
+          afterCursor: '',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['BY']
+          }
+        });
+      });
+
+      it('should suggest BY after GROUP', function () {
+        assertAutoComplete({
+          beforeCursor: 'SELECT * FROM testTable GROUP ',
+          afterCursor: '',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['BY']
+          }
+        });
+      });
+
+      it('should suggest columns for table after ORDER BY ', function() {
+        assertAutoComplete({
+          serverResponses: {
+            '/notebook/api/autocomplete/database_one/testTable' : {
+              columns: ['testTableColumn1', 'testTableColumn2']
+            }
+          },
+          beforeCursor: 'SELECT * FROM testTable ORDER BY ',
+          afterCursor: '',
+          expectedResult: {
+            lowerCase: false,
+            suggestColumns: { table: 'testTable' }
+          }
+        });
+      });
+
+      it('should suggest columns for table after ORDER BY with db reference', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT * FROM database_two.testTable ORDER BY ',
+          afterCursor: '',
+          expectedResult: {
+            lowerCase: false,
+            suggestColumns: { database: 'database_two', table: 'testTable' }
+          }
+        });
+      });
+
+      it('should suggest columns for table after GROUP BY ', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT * FROM testTable GROUP BY ',
+          afterCursor: '',
+          expectedResult: {
+            lowerCase: false,
+            suggestColumns: { table: 'testTable' }
+          }
+        });
+      });
+
+      it('should suggest columns for table after GROUP BY with db reference ', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT * FROM database_two.testTable GROUP BY ',
+          afterCursor: '',
+          expectedResult: {
+            lowerCase: false,
+            suggestColumns: { database: 'database_two', table: 'testTable' }
+          }
+        });
+      });
+
+      it('should suggest columns for table after ON ', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT t1.testTableColumn1, t2.testTableColumn3 FROM testTable1 t1 JOIN testTable2 t2 ON t1.',
+          afterCursor: '',
+          expectedResult: {
+            lowerCase: false,
+            suggestColumns: { table: 'testTable1' }
+          }
+        });
+      });
+
+      it('should suggest columns for table after ON with database reference', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT t1.testTableColumn1, t2.testTableColumn3 FROM database_two.testTable1 t1 JOIN testTable2 t2 ON t1.',
+          afterCursor: '',
+          expectedResult: {
+            lowerCase: false,
+            suggestColumns: { table: 'testTable1', database: 'database_two' }
+          }
+        });
+      });
+
+      it('should suggest columns for table with table ref', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT testTable.',
+          afterCursor: ' FROM testTable',
+          expectedResult: {
+            lowerCase: false,
+            suggestStar: true,
+            suggestColumns: { table: 'testTable' }
+          }
+        });
+      });
+
+      it('should suggest columns with table alias', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT tt.',
+          afterCursor: ' FROM testTable tt',
+          expectedResult: {
+            lowerCase: false,
+            suggestStar: true,
+            suggestColumns: { table: 'testTable' }
+          }
+        });
+      });
+
+      it('should suggest columns with table alias from database reference', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT tt.',
+          afterCursor: ' FROM database_two.testTable tt',
+          expectedResult: {
+            lowerCase: false,
+            suggestStar: true,
+            suggestColumns: { table: 'testTable', database: 'database_two' }
+          }
+        });
+      });
+
+      it('should suggest columns with multiple table aliases', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT tta.',
+          afterCursor: ' FROM testTableA tta, testTableB ttb',
+          expectedResult: {
+            lowerCase: false,
+            suggestStar: true,
+            suggestColumns: { table: 'testTableA' }
+          }
+        });
+        assertAutoComplete({
+          beforeCursor: 'SELECT ttb.',
+          afterCursor: ' FROM testTableA tta, testTableB ttb',
+          expectedResult: {
+            lowerCase: false,
+            suggestStar: true,
+            suggestColumns: { table: 'testTableB' }
+          }
+        });
+      });
+    });
+
+    describe('joins', function() {
+      it('should suggest tables to join with', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT * FROM testTable1 JOIN ',
+          afterCursor: '',
+          expectedResult: {
+            lowerCase: false,
+            suggestTables: {},
+            suggestDatabases: { appendDot: true }
+          }
+        });
+      });
+
+      it('should suggest table references in join condition if not already there', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT testTable1.* FROM testTable1 JOIN testTable2 ON (',
+          afterCursor: '',
+          expectedResult: {
+            lowerCase: false,
+            suggestIdentifiers: [{ name: 'testTable1.', type: 'table' }, { name: 'testTable2.', type: 'table' }]
+          }
+        });
+      });
+
+      it('should suggest table references in join condition if not already there for multiple conditions after AND', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT testTable1.* FROM testTable1 JOIN testTable2 ON (testTable1.testColumn1 = testTable2.testColumn3 AND ',
+          afterCursor: '',
+          ignoreErrors: true, // Here the right parenthesis is missing
+          expectedResult: {
+            lowerCase: false,
+            suggestIdentifiers: [{ name: 'testTable1.', type: 'table' }, { name: 'testTable2.', type: 'table' }]
+          }
+        });
+      });
+
+      it('should suggest table references in join condition if not already there for multiple conditions', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT testTable1.* FROM testTable1 JOIN testTable2 ON (',
+          afterCursor: ' AND testTable1.testColumn1 = testTable2.testColumn3',
+          expectedResult: {
+            lowerCase: false,
+            suggestIdentifiers: [{ name: 'testTable1.', type: 'table' }, { name: 'testTable2.', type: 'table' }]
+          }
+        });
+      });
+
+      it('should suggest field references in join condition if table reference is present', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT testTable1.* FROM testTable1 JOIN testTable2 ON (testTable2.',
+          afterCursor: '',
+          ignoreErrors: true,
+          expectedResult: {
+            lowerCase: false,
+            suggestColumns: { table: 'testTable2'}
+          }
+        });
+      });
+
+      xit('should suggest identifiers or values in join condition if table reference is present from multiple tables', function() {
+        assertAutoComplete({
+          beforeCursor: 'select * from testTable1 JOIN testTable2 on (testTable1.testColumn1 = ',
+          afterCursor: '',
+          ignoreErrors: true,
+          expectedResult: {
+            lowerCase: true,
+            suggestIdentifiers: [{ name: 'testTable1.', type: 'table' }, { name: 'testTable2.', type: 'table' }],
+            suggestValues: {
+              table: 'testTable1',
+              identifierChain: [{ name: 'testColumn1' }]
+            }
+          }
+        });
+      });
+
+      it('should suggest field references in join condition if table reference is present from multiple tables', function() {
+        assertAutoComplete({
+          beforeCursor: 'select * from testTable1 JOIN testTable2 on (testTable1.testColumn1 = testTable2.',
+          afterCursor: '',
+          ignoreErrors: true,
+          expectedResult: {
+            lowerCase: true,
+            suggestColumns: { table: 'testTable2'}
+          }
+        });
+      });
+
+      it('should suggest field references in join condition if table reference is present from multiple tables for multiple conditions', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT testTable1.* FROM testTable1 JOIN testTable2 ON (testTable1.testColumn1 = testTable2.testColumn3 AND testTable1.',
+          afterCursor: '',
+          ignoreErrors: true,
+          expectedResult: {
+            lowerCase: false,
+            suggestColumns: { table: 'testTable1'}
+          }
+        });
+      });
+    })
+  });
+});

+ 1519 - 0
desktop/core/src/desktop/static/desktop/spec/autocomplete/sqlSpecShow.js

@@ -0,0 +1,1519 @@
+// 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.
+define([
+  'knockout',
+  'desktop/js/autocomplete/sql',
+  'desktop/spec/autocompleterTestUtils'
+], function(ko, sql, testUtils) {
+
+  describe('sql.js SHOW statements', function() {
+
+    beforeAll(function () {
+      sql.yy.parseError = function (msg) {
+        throw Error(msg);
+      };
+      jasmine.addMatchers(testUtils.testDefinitionMatcher);
+    });
+
+    var assertAutoComplete = testUtils.assertAutocomplete;
+
+    it('should suggest keywords for empty statement', function() {
+      assertAutoComplete({
+        beforeCursor: '',
+        afterCursor: '',
+        dialect: 'generic',
+        containsKeywords: ['SHOW'],
+        expectedResult: {
+          lowerCase: false
+        }
+      });
+    });
+
+    it('should suggest keywords after SHOW', function() {
+      assertAutoComplete({
+        beforeCursor: 'SHOW ',
+        afterCursor: '',
+        dialect: 'generic',
+        expectedResult: {
+          lowerCase: false,
+          suggestKeywords: ['COLUMNS', 'DATABASES', 'TABLES']
+        }
+      });
+    });
+
+    describe('hive specific', function () {
+      it('should suggest keywords after SHOW', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['COLUMNS', 'COMPACTIONS', 'CONF', 'CREATE TABLE', 'CURRENT ROLES', 'DATABASES', 'FORMATTED', 'FUNCTIONS', 'GRANT', 'INDEX', 'INDEXES', 'LOCKS', 'PARTITIONS', 'PRINCIPALS', 'ROLE GRANT', 'ROLES', 'SCHEMAS', 'TABLE EXTENDED', 'TABLES', 'TBLPROPERTIES', 'TRANSACTIONS']
+          }
+        });
+      });
+
+      it('should handle SHOW COMPACTIONS', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW COMPACTIONS;',
+          afterCursor: '',
+          dialect: 'hive',
+          containsKeywords: ['SELECT'],
+          expectedResult: {
+            lowerCase: false
+          }
+        });
+      });
+
+      it('should handle SHOW CONF confName', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW CONF a.b.c;',
+          afterCursor: '',
+          dialect: 'hive',
+          containsKeywords: ['SELECT'],
+          expectedResult: {
+            lowerCase: false
+          }
+        });
+      });
+
+      it('should suggest keywords after SHOW COLUMNS', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW COLUMNS ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['FROM', 'IN']
+          }
+        });
+      });
+
+      it('should suggest tables after SHOW COLUMNS FROM ', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW COLUMNS FROM ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestTables: {}
+          }
+        });
+      });
+
+      it('should suggest tables after SHOW COLUMNS FROM partial', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW COLUMNS FROM partial',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestTables: {}
+          }
+        });
+      });
+
+      it('should suggest keywords after SHOW COLUMNS FROM tableName ', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW COLUMNS FROM tableName ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['FROM', 'IN']
+          }
+        });
+      });
+
+      it('should suggest databases after SHOW COLUMNS FROM tableName FROM', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW COLUMNS FROM tableName FROM ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestDatabases: {}
+          }
+        });
+      });
+
+      it('should suggest databases after SHOW COLUMNS FROM tableName FROM partial', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW COLUMNS FROM tableName FROM partial',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestDatabases: {}
+          }
+        });
+      });
+
+      it('should suggest databases after SHOW COLUMNS FROM tableName IN', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW COLUMNS FROM tableName IN ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestDatabases: {}
+          }
+        });
+      });
+
+      it('should suggest databases after SHOW COLUMNS FROM tableName IN partial', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW COLUMNS FROM tableName IN partial',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestDatabases: {}
+          }
+        });
+      });
+
+      it('should suggest tables after SHOW COLUMNS IN ', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW COLUMNS IN ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestTables: {}
+          }
+        });
+      });
+
+      it('should suggest tables after SHOW COLUMNS IN partial', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW COLUMNS IN partial',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestTables: {}
+          }
+        });
+      });
+
+      it('should suggest keywords after SHOW COLUMNS IN tableName ', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW COLUMNS IN tableName ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['FROM', 'IN']
+          }
+        });
+      });
+
+      it('should suggest databases after SHOW COLUMNS IN tableName FROM', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW COLUMNS IN tableName FROM ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestDatabases: {}
+          }
+        });
+      });
+
+      it('should suggest databases after SHOW COLUMNS IN tableName FROM partial', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW COLUMNS IN tableName FROM partial',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestDatabases: {}
+          }
+        });
+      });
+
+      it('should suggest databases after SHOW COLUMNS IN tableName IN', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW COLUMNS IN tableName IN ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestDatabases: {}
+          }
+        });
+      });
+
+      it('should suggest databases after SHOW COLUMNS IN tableName IN partial', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW COLUMNS IN tableName IN partial',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestDatabases: {}
+          }
+        });
+      });
+
+      it('should suggest keywords after SHOW CREATE', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW CREATE ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['TABLE']
+          }
+        });
+      });
+
+      it('should suggest tables after SHOW CREATE TABLE', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW CREATE TABLE ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestTables: {},
+            suggestDatabases: {
+              appendDot: true
+            }
+          }
+        });
+      });
+
+      it('should suggest tables after SHOW CREATE TABLE partial', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW CREATE TABLE partial',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestTables: {},
+            suggestDatabases: {
+              appendDot: true
+            }
+          }
+        });
+      });
+
+      it('should suggest tables after SHOW CREATE TABLE databaseOne.', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW CREATE TABLE databaseOne.',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestTables: {
+              database: 'databaseOne'
+            }
+          }
+        });
+      });
+
+      it('should suggest tables after SHOW CREATE TABLE databaseOne.partial', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW CREATE TABLE databaseOne.partial',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestTables: {
+              database: 'databaseOne'
+            }
+          }
+        });
+      });
+
+      it('should suggest keywords after SHOW CURRENT', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW CURRENT ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['ROLES']
+          }
+        });
+      });
+
+      it('should suggest keywords after SHOW DATABASES', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW DATABASES ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['LIKE']
+          }
+        });
+      });
+
+      it('should suggest keywords after SHOW FORMATTED', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW FORMATTED ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['INDEX', 'INDEXES']
+          }
+        });
+      });
+
+      it('should suggest keywords after SHOW FORMATTED INDEX', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW FORMATTED INDEX ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['ON']
+          }
+        });
+      });
+
+      it('should suggest tables after SHOW FORMATTED INDEX ON ', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW FORMATTED INDEX ON ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestTables: {}
+          }
+        });
+      });
+
+      it('should suggest tables after SHOW FORMATTED INDEX ON partial', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW FORMATTED INDEX ON partial',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestTables: {}
+          }
+        });
+      });
+
+      it('should suggest keywords after SHOW FORMATTED INDEX ON table', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW FORMATTED INDEX ON tableName ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['FROM', 'IN']
+          }
+        });
+      });
+
+      it('should suggest databases after SHOW FORMATTED INDEX ON table FROM ', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW FORMATTED INDEX ON tableName FROM ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestDatabases: {}
+          }
+        });
+      });
+
+      it('should suggest tables after SHOW FORMATTED INDEX ON with db specified ', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW FORMATTED INDEX ON ',
+          afterCursor: ' FROM databaseOne',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestTables: {
+              database: 'databaseOne'
+            }
+          }
+        });
+      });
+
+      it('should suggest keywords after SHOW FORMATTED INDEXES', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW FORMATTED INDEXES ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['ON']
+          }
+        });
+      });
+
+      it('should suggest tables after SHOW FORMATTED INDEXES ON ', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW FORMATTED INDEXES ON ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestTables: {}
+          }
+        });
+      });
+
+      it('should suggest tables after SHOW FORMATTED INDEXES ON partial', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW FORMATTED INDEXES ON partial',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestTables: {}
+          }
+        });
+      });
+
+      it('should suggest keywords after SHOW FORMATTED INDEX ON tableName ', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW FORMATTED INDEX ON tableOne ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['FROM', 'IN']
+          }
+        });
+      });
+
+      it('should suggest keywords after SHOW FORMATTED INDEXES', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW FORMATTED INDEXES ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['ON']
+          }
+        });
+      });
+
+      it('should suggest keywords after SHOW FORMATTED INDEXES ON tableName ', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW FORMATTED INDEXES ON tableOne ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['FROM', 'IN']
+          }
+        });
+      });
+
+      it('should suggest tables and keywords after SHOW GRANT', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW GRANT ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['ON']
+          }
+        });
+      });
+
+      it('should suggest tables and keywords after SHOW GRANT ON', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW GRANT ON ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestTables: {},
+            suggestKeywords: ['ALL', 'TABLE']
+          }
+        });
+      });
+
+      it('should suggest tables and keywords after SHOW GRANT ON partial', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW GRANT ON partial',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestTables: {},
+            suggestKeywords: ['ALL', 'TABLE']
+          }
+        });
+      });
+
+      it('should suggest tables after SHOW GRANT ON TABLE', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW GRANT ON TABLE ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestTables: {}
+          }
+        });
+      });
+
+      it('should suggest tables after SHOW GRANT ON TABLE partial', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW GRANT ON TABLE partial',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestTables: {}
+          }
+        });
+      });
+
+      it('should suggest tables and keywords after SHOW GRANT principal', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW GRANT pcp ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['ON']
+          }
+        });
+      });
+
+      it('should suggest tables and keywords after SHOW GRANT principal ON', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW GRANT pcp ON ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestTables: {},
+            suggestKeywords: ['ALL', 'TABLE']
+          }
+        });
+      });
+
+      it('should suggest tables and keywords after SHOW GRANT principal ON partial', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW GRANT pcp ON partial',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestTables: {},
+            suggestKeywords: ['ALL', 'TABLE']
+          }
+        });
+      });
+
+      it('should suggest tables after SHOW GRANT principal ON TABLE', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW GRANT pcp ON TABLE ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestTables: {}
+          }
+        });
+      });
+
+      it('should suggest tables after SHOW GRANT principal ON TABLE partial', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW GRANT pcp ON TABLE partial',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestTables: {}
+          }
+        });
+      });
+
+      it('should suggest keywords after SHOW INDEX', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW INDEX ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['ON']
+          }
+        });
+      });
+
+      it('should suggest tables after SHOW INDEX ON ', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW INDEX ON ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestTables: {}
+          }
+        });
+      });
+
+      it('should suggest tables after SHOW INDEX ON partial', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW INDEX ON partial',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestTables: {}
+          }
+        });
+      });
+
+      it('should suggest keywords after SHOW INDEX ON tableName ', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW INDEX ON tableOne ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['FROM', 'IN']
+          }
+        });
+      });
+
+      it('should suggest keywords after SHOW INDEXES', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW INDEXES ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['ON']
+          }
+        });
+      });
+
+      it('should suggest tables after SHOW INDEXES ON ', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW INDEXES ON ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestTables: {}
+          }
+        });
+      });
+
+      it('should suggest tables after SHOW INDEXES ON partial', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW INDEXES ON partial',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestTables: {}
+          }
+        });
+      });
+
+      it('should suggest keywords after SHOW INDEXES ON tableName ', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW INDEXES ON tableOne ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['FROM', 'IN']
+          }
+        });
+      });
+
+      it('should suggest tables and keywords after SHOW LOCKS', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW LOCKS ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestTables: {},
+            suggestDatabases: { // TODO: Is this ok for hive?
+              appendDot: true
+            },
+            suggestKeywords: ['DATABASE', 'SCHEMA']
+          }
+        });
+      });
+
+      it('should suggest tables and keywords after SHOW LOCKS partial', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW LOCKS partial',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestTables: {},
+            suggestDatabases: { // TODO: Is this ok for hive?
+              appendDot: true
+            },
+            suggestKeywords: ['DATABASE', 'SCHEMA']
+          }
+        });
+      });
+
+      it('should suggest databases after SHOW LOCKS DATABASE', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW LOCKS DATABASE ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestDatabases: {}
+          }
+        });
+      });
+
+      it('should suggest databases after SHOW LOCKS DATABASE partial', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW LOCKS DATABASE partial',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestDatabases: {}
+          }
+        });
+      });
+
+      it('should suggest databases after SHOW LOCKS SCHEMA', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW LOCKS SCHEMA ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestDatabases: {}
+          }
+        });
+      });
+
+      it('should suggest databases after SHOW LOCKS SCHEMA partial', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW LOCKS SCHEMA partial',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestDatabases: {}
+          }
+        });
+      });
+
+      it('should suggest keywords after SHOW LOCKS tableName', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW LOCKS tableName ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['EXTENDED', 'PARTITION']
+          }
+        });
+      });
+
+      it('should suggest keywords after SHOW LOCKS tableName PARTITION partitionSpec', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW LOCKS tableName PARTITION (ds=\'2010-03-03\', hr=\'12\') ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['EXTENDED']
+          }
+        });
+      });
+
+      it('should suggest tables after SHOW PARTITIONS ', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW PARTITIONS ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestTables: {},
+            suggestDatabases : {
+              appendDot: true
+            }
+          }
+        });
+      });
+
+      it('should suggest tables after SHOW PARTITIONS partial', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW PARTITIONS partial',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestTables: {},
+            suggestDatabases : {
+              appendDot: true
+            }
+          }
+        });
+      });
+
+      it('should suggest keywords after SHOW PARTITIONS tableName', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW PARTITIONS foo ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['PARTITION']
+          }
+        });
+      });
+
+      it('should suggest keywords after SHOW ROLE', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW ROLE ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['GRANT']
+          }
+        });
+      });
+
+      it('should suggest keywords after SHOW ROLE GRANT', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW ROLE GRANT ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['ROLE', 'USER']
+          }
+        });
+      });
+
+      it('should suggest keywords after SHOW SCHEMAS', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW SCHEMAS ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['LIKE']
+          }
+        });
+      });
+
+      it('should suggest keywords after SHOW TABLE', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW TABLE ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['EXTENDED']
+          }
+        });
+      });
+
+      it('should suggest keywords after SHOW TABLE EXTENDED', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW TABLE EXTENDED ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['FROM', 'IN', 'LIKE']
+          }
+        });
+      });
+
+      it('should suggest databases after SHOW TABLE EXTENDED FROM ', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW TABLE EXTENDED FROM ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestDatabases: {}
+          }
+        });
+      });
+
+      it('should suggest functions after SHOW TABLE EXTENDED FROM database LIKE identifier', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW TABLE EXTENDED FROM databaseOne LIKE \'f|oo*\' ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['PARTITION']
+          }
+        });
+      });
+
+      it('should suggest databases after SHOW TABLE EXTENDED IN ', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW TABLE EXTENDED IN ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestDatabases: {}
+          }
+        });
+      });
+
+      it('should suggest functions after SHOW TABLE EXTENDED IN database LIKE identifier', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW TABLE EXTENDED IN databaseOne LIKE \'f|oo*\' ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['PARTITION']
+          }
+        });
+      });
+
+      it('should suggest functions after SHOW TABLE EXTENDED LIKE identifier', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW TABLE EXTENDED LIKE \'f|oo*\' ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['PARTITION']
+          }
+        });
+      });
+
+      it('should suggest keywords after SHOW TABLES', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW TABLES ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['IN', 'LIKE']
+          }
+        });
+      });
+
+      it('should suggest databases after SHOW TABLES IN', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW TABLES IN ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestDatabases: {}
+          }
+        });
+      });
+
+      it('should suggest keywords after SHOW TABLES IN db ', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW TABLES IN db ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['LIKE']
+          }
+        });
+      });
+
+      it('should suggest tables after SHOW TBLPROPERTIES', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW TBLPROPERTIES ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestTables: {}
+          }
+        });
+      });
+
+      it('should suggest tables after SHOW TBLPROPERTIES partial', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW TBLPROPERTIES partial',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestTables: {}
+          }
+        });
+      });
+
+      it('should handle SHOW TRANSACTIONS', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW TRANSACTIONS;',
+          afterCursor: '',
+          dialect: 'hive',
+          containsKeywords: ['SELECT'],
+          expectedResult: {
+            lowerCase: false
+          }
+        });
+      });
+    });
+
+    describe('impala specific', function () {
+      it('should suggest keywords after SHOW', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW ',
+          afterCursor: '',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['AGGREGATE FUNCTIONS', 'ANALYTIC FUNCTIONS', 'COLUMN STATS', 'CREATE TABLE', 'CURRENT ROLES', 'DATABASES', 'FUNCTIONS', 'GRANT ROLE', 'PARTITIONS', 'ROLE GRANT GROUP', 'ROLES', 'SCHEMAS', 'TABLE STATS', 'TABLES']
+          }
+        });
+      });
+
+      it('should suggest keywords after SHOW AGGREGATE', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW AGGREGATE ',
+          afterCursor: '',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['FUNCTIONS']
+          }
+        });
+      });
+
+      it('should suggest keywords after SHOW AGGREGATE FUNCTIONS', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW AGGREGATE FUNCTIONS ',
+          afterCursor: '',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['IN', 'LIKE']
+          }
+        });
+      });
+
+      it('should suggest databases after SHOW AGGREGATE FUNCTIONS IN', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW AGGREGATE FUNCTIONS IN ',
+          afterCursor: '',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestDatabases: {}
+          }
+        });
+      });
+
+      it('should suggest databases after SHOW AGGREGATE FUNCTIONS IN partial', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW AGGREGATE FUNCTIONS IN partial',
+          afterCursor: '',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestDatabases: {}
+          }
+        });
+      });
+
+      it('should suggest keywords after SHOW ANALYTIC', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW ANALYTIC ',
+          afterCursor: '',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['FUNCTIONS']
+          }
+        });
+      });
+
+      it('should suggest keywords after SHOW ANALYTIC FUNCTIONS', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW ANALYTIC FUNCTIONS ',
+          afterCursor: '',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['IN', 'LIKE']
+          }
+        });
+      });
+
+      it('should suggest databases after SHOW ANALYTIC FUNCTIONS IN', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW ANALYTIC FUNCTIONS IN ',
+          afterCursor: '',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestDatabases: {}
+          }
+        });
+      });
+
+      it('should suggest databases after SHOW ANALYTIC FUNCTIONS IN partial', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW ANALYTIC FUNCTIONS IN partial',
+          afterCursor: '',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestDatabases: {}
+          }
+        });
+      });
+
+      it('should suggest keywords after SHOW COLUMN', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW COLUMN ',
+          afterCursor: '',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['STATS']
+          }
+        });
+      });
+
+      it('should suggest tables after SHOW COLUMN STATS', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW COLUMN STATS ',
+          afterCursor: '',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestTables: {},
+            suggestDatabases: {
+              appendDot: true
+            }
+          }
+        });
+      });
+
+      it('should suggest tables after SHOW COLUMN STATS partial', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW COLUMN STATS partial',
+          afterCursor: '',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestTables: {},
+            suggestDatabases: {
+              appendDot: true
+            }
+          }
+        });
+      });
+
+      it('should suggest keywords after SHOW CREATE', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW CREATE ',
+          afterCursor: '',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['TABLE']
+          }
+        });
+      });
+
+      it('should suggest tables after SHOW CREATE TABLE', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW CREATE TABLE ',
+          afterCursor: '',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestTables: {},
+            suggestDatabases: {
+              appendDot: true
+            }
+          }
+        });
+      });
+
+      it('should suggest tables after SHOW CREATE TABLE partial', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW CREATE TABLE partial',
+          afterCursor: '',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestTables: {},
+            suggestDatabases: {
+              appendDot: true
+            }
+          }
+        });
+      });
+
+      it('should suggest keywords after SHOW CURRENT', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW CURRENT ',
+          afterCursor: '',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['ROLES']
+          }
+        });
+      });
+
+      it('should handle SHOW CURRENT ROLES', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW CURRENT ROLES;',
+          afterCursor: '',
+          dialect: 'impala',
+          containsKeywords: ['SELECT'],
+          expectedResult: {
+            lowerCase: false
+          }
+        });
+      });
+
+      it('should suggest keywords after SHOW DATABASES', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW DATABASES ',
+          afterCursor: '',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['LIKE']
+          }
+        });
+      });
+
+      it('should suggest keywords after SHOW FUNCTIONS', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW FUNCTIONS ',
+          afterCursor: '',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['IN', 'LIKE']
+          }
+        });
+      });
+
+      it('should suggest databases after SHOW FUNCTIONS IN', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW FUNCTIONS IN ',
+          afterCursor: '',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestDatabases: {}
+          }
+        });
+      });
+
+      it('should suggest databases after SHOW FUNCTIONS IN partial', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW FUNCTIONS IN partial',
+          afterCursor: '',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestDatabases: {}
+          }
+        });
+      });
+
+      it('should suggest keywords after SHOW GRANT', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW GRANT ',
+          afterCursor: '',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['ROLE']
+          }
+        });
+      });
+
+      it('should suggest tables after SHOW PARTITIONS', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW PARTITIONS ',
+          afterCursor: '',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestTables: {},
+            suggestDatabases: {
+              appendDot: true
+            }
+          }
+        });
+      });
+
+      it('should suggest tables after SHOW PARTITIONS partial', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW PARTITIONS partial',
+          afterCursor: '',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestTables: {},
+            suggestDatabases: {
+              appendDot: true
+            }
+          }
+        });
+      });
+
+      it('should suggest keywords after SHOW ROLE', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW ROLE ',
+          afterCursor: '',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['GRANT']
+          }
+        });
+      });
+
+      it('should suggest keywords after SHOW ROLE GRANT', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW ROLE GRANT ',
+          afterCursor: '',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['GROUP']
+          }
+        });
+      });
+
+      it('should handle SHOW ROLES', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW ROLES;',
+          afterCursor: '',
+          dialect: 'impala',
+          containsKeywords: ['SELECT'],
+          expectedResult: {
+            lowerCase: false
+          }
+        });
+      });
+
+      it('should suggest keywords after SHOW SCHEMAS', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW SCHEMAS ',
+          afterCursor: '',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['LIKE']
+          }
+        });
+      });
+
+      it('should suggest keywords after SHOW TABLE', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW TABLE ',
+          afterCursor: '',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['STATS']
+          }
+        });
+      });
+
+      it('should suggest tables after SHOW TABLE STATS', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW TABLE STATS ',
+          afterCursor: '',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestTables: {},
+            suggestDatabases: {
+              appendDot: true
+            }
+          }
+        });
+      });
+
+      it('should suggest tables after SHOW TABLE STATS partial', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW TABLE STATS partial',
+          afterCursor: '',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestTables: {},
+            suggestDatabases: {
+              appendDot: true
+            }
+          }
+        });
+      });
+
+      it('should suggest keywords after SHOW TABLES', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW TABLES ',
+          afterCursor: '',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['IN', 'LIKE']
+          }
+        });
+      });
+
+      it('should suggest databases after SHOW TABLES IN', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW TABLES IN ',
+          afterCursor: '',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestDatabases: {}
+          }
+        });
+      });
+
+      it('should suggest databases after SHOW TABLES IN partial', function() {
+        assertAutoComplete({
+          beforeCursor: 'SHOW TABLES IN partial',
+          afterCursor: '',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestDatabases: {}
+          }
+        });
+      });
+    });
+  });
+});

+ 202 - 0
desktop/core/src/desktop/static/desktop/spec/autocomplete/sqlSpecUpdate.js

@@ -0,0 +1,202 @@
+// 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.
+define([
+  'knockout',
+  'desktop/js/autocomplete/sql',
+  'desktop/spec/autocompleterTestUtils'
+], function(ko, sql, testUtils) {
+
+  describe('sql.js UPDATE statements', function() {
+
+    beforeAll(function () {
+      sql.yy.parseError = function (msg) {
+        throw Error(msg);
+      };
+      jasmine.addMatchers(testUtils.testDefinitionMatcher);
+    });
+
+    var assertAutoComplete = testUtils.assertAutocomplete;
+
+    it('should suggest keywords for empty statement', function() {
+      assertAutoComplete({
+        beforeCursor: '',
+        afterCursor: '',
+        containsKeywords: ['UPDATE'],
+        expectedResult: {
+          lowerCase: false
+        }
+      });
+    });
+
+    it('should suggest keywords after UPDATE TableReference ', function () {
+      assertAutoComplete({
+        beforeCursor: 'UPDATE bar  ',
+        afterCursor: '',
+        expectedResult: {
+          lowerCase: false,
+          suggestKeywords: ['SET']
+        }
+      });
+    });
+
+    it('should suggest keywords after UPDATE TableReference SET SetClauseList ', function () {
+      assertAutoComplete({
+        beforeCursor: 'UPDATE bar SET id=1, foo=2 ',
+        afterCursor: '',
+        expectedResult: {
+          lowerCase: false,
+          suggestKeywords: ['WHERE']
+        }
+      });
+    });
+
+    it('should suggest keywords after UPDATE TableReference SET identifier ', function () {
+      assertAutoComplete({
+        beforeCursor: 'UPDATE bar SET id ',
+        afterCursor: '',
+        expectedResult: {
+          lowerCase: false,
+          suggestKeywords: ['=']
+        }
+      });
+    });
+
+    it('should suggest tables after UPDATE', function() {
+      assertAutoComplete({
+        beforeCursor: 'UPDATE ',
+        afterCursor: '',
+        expectedResult: {
+          lowerCase: false,
+          suggestTables: {},
+          suggestDatabases: {
+            appendDot: true
+          }
+        }
+      });
+    });
+
+    it('should suggest tables after UPDATE with partial table or schema ref', function() {
+      assertAutoComplete({
+        beforeCursor: 'UPDATE bla',
+        afterCursor: '',
+        expectedResult: {
+          lowerCase: false,
+          suggestTables: {},
+          suggestDatabases: {
+            appendDot: true
+          }
+        }
+      });
+    });
+
+    it('should suggest tables after UPDATE with database', function() {
+      assertAutoComplete({
+        beforeCursor: 'UPDATE bar.',
+        afterCursor: '',
+        expectedResult: {
+          lowerCase: false,
+          suggestTables: {
+            database: 'bar'
+          }
+        }
+      });
+    });
+
+    it('should suggest tables after UPDATE with database and partial table', function() {
+      assertAutoComplete({
+        beforeCursor: 'UPDATE bar.foo',
+        afterCursor: '',
+        expectedResult: {
+          lowerCase: false,
+          suggestTables: {
+            database: 'bar'
+          }
+        }
+      });
+    });
+
+    it('should suggest columns after SET', function() {
+      assertAutoComplete({
+        beforeCursor: 'UPDATE bar.foo SET ',
+        afterCursor: '',
+        expectedResult: {
+          lowerCase: false,
+          suggestColumns: {
+            database: 'bar',
+            table: 'foo'
+          }
+        }
+      });
+    });
+
+    it('should suggest columns after SET id = 1, bar = \'foo\', ', function() {
+      assertAutoComplete({
+        beforeCursor: 'UPDATE bar.foo SET id = 1, bar = \'foo\', ',
+        afterCursor: '',
+        expectedResult: {
+          lowerCase: false,
+          suggestColumns: {
+            database: 'bar',
+            table: 'foo'
+          }
+        }
+      });
+    });
+
+    it('should suggest columns after SET bar = \'foo\' WHERE ', function() {
+      assertAutoComplete({
+        beforeCursor: 'UPDATE bar.foo SET bar = \'foo\' WHERE ',
+        afterCursor: '',
+        expectedResult: {
+          lowerCase: false,
+          suggestColumns: {
+            database: 'bar',
+            table: 'foo'
+          }
+        }
+      });
+    });
+
+    it('should suggest values after SET bar = \'foo\' WHERE id = ', function() {
+      assertAutoComplete({
+        beforeCursor: 'UPDATE bar.foo SET bar = \'foo\' WHERE id = ',
+        afterCursor: '',
+        expectedResult: {
+          lowerCase: false,
+          suggestValues: {
+            database: 'bar',
+            table: 'foo',
+            identifierChain: [{ name: 'id' }]
+          }
+        }
+      });
+    });
+
+    it('should suggest columns after SET bar = \'foo\' WHERE id = 1 AND ', function() {
+      assertAutoComplete({
+        beforeCursor: 'UPDATE bar.foo SET bar = \'foo\' WHERE id = 1 AND ',
+        afterCursor: '',
+        expectedResult: {
+          lowerCase: false,
+          suggestColumns: {
+            database: 'bar',
+            table: 'foo'
+          }
+        }
+      });
+    });
+  });
+});

+ 131 - 0
desktop/core/src/desktop/static/desktop/spec/autocomplete/sqlSpecUse.js

@@ -0,0 +1,131 @@
+// 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.
+define([
+  'knockout',
+  'desktop/js/autocomplete/sql',
+  'desktop/spec/autocompleterTestUtils'
+], function(ko, sql, testUtils) {
+
+  describe('sql.js USE statements', function() {
+
+    beforeAll(function () {
+      sql.yy.parseError = function (msg) {
+        throw Error(msg);
+      };
+      jasmine.addMatchers(testUtils.testDefinitionMatcher);
+    });
+
+    var assertAutoComplete = testUtils.assertAutocomplete;
+
+    it('should suggest keywords for empty statement', function() {
+      assertAutoComplete({
+        beforeCursor: '',
+        afterCursor: '',
+        containsKeywords: ['USE'],
+        expectedResult: {
+          lowerCase: false
+        }
+      });
+    });
+
+    it('should suggest databases after use', function () {
+      assertAutoComplete({
+        serverResponses: {},
+        beforeCursor: 'USE ',
+        afterCursor: '',
+        expectedResult: {
+          lowerCase: false,
+          suggestDatabases: { }
+        }
+      });
+    });
+
+    it('should suggest databases after use with started identifier', function () {
+      assertAutoComplete({
+        serverResponses: {},
+        beforeCursor: 'USE bla',
+        afterCursor: '',
+        expectedResult: {
+          lowerCase: false,
+          suggestDatabases: { }
+        }
+      });
+    });
+
+    it('should use a use statement before the cursor if present', function () {
+      assertAutoComplete({
+        beforeCursor: 'USE database_two; \n\select ',
+        afterCursor: '',
+        expectedResult: {
+          useDatabase: 'database_two',
+          lowerCase: true,
+          suggestStar: true,
+          suggestTables: {
+            prependQuestionMark: true,
+            prependFrom: true
+          },
+          suggestDatabases: {
+            prependQuestionMark: true,
+            prependFrom: true,
+            appendDot: true
+          }
+        }
+      });
+    });
+
+    it('should use the last use statement before the cursor if multiple are present', function () {
+      assertAutoComplete({
+        beforeCursor: 'USE other_db; USE closest_db; \n\tSELECT ',
+        afterCursor: '',
+        expectedResult: {
+          useDatabase: 'closest_db',
+          lowerCase: false,
+          suggestStar: true,
+          suggestTables: {
+            prependQuestionMark: true,
+            prependFrom: true
+          },
+          suggestDatabases: {
+            prependQuestionMark: true,
+            prependFrom: true,
+            appendDot: true
+          }
+        }
+      });
+    });
+
+    it('should use the use statement before the cursor if multiple are present after the cursor', function () {
+      assertAutoComplete({
+        beforeCursor: 'USE other_db; USE closest_db; \n\tSELECT ',
+        afterCursor: '; USE some_other_db;',
+        expectedResult: {
+          useDatabase: 'closest_db',
+          lowerCase: false,
+          suggestStar: true,
+          suggestTables: {
+            prependQuestionMark: true,
+            prependFrom: true
+          },
+          suggestDatabases: {
+            prependQuestionMark: true,
+            prependFrom: true,
+            appendDot: true
+          }
+        }
+      });
+    });
+  });
+});

+ 36 - 3
desktop/core/src/desktop/static/desktop/spec/autocompleterTestUtils.js

@@ -14,7 +14,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 define([
-], function() {
+  'desktop/js/autocomplete/sql'
+], function(sql) {
   return {
     autocompleteMatcher : {
       toEqualAutocompleteValues : function() {
@@ -42,15 +43,47 @@ define([
             if (testDefinition.ignoreErrors) {
               delete actualResponse.error;
             }
+            if (typeof testDefinition.containsKeywords !== 'undefined') {
+              var keywords = actualResponse.suggestKeywords;
+              var contains = true;
+              testDefinition.containsKeywords.forEach(function (keyword) {
+                if (typeof keywords === 'undefined' || keywords.indexOf(keyword) === -1) {
+                  contains = false;
+                  return false;
+                }
+              });
+              if (!contains) {
+                return {
+                  pass: false,
+                  message: '\n        Statement: ' + testDefinition.beforeCursor + '|' + testDefinition.afterCursor + '\n' +
+                             '          Dialect: ' + testDefinition.dialect + '\n' +
+                             'Expected keywords: ' + JSON.stringify(testDefinition.containsKeywords) + '\n' +
+                             '  Parser keywords: ' + JSON.stringify(keywords) +   '\n'
+                }
+              }
+              delete actualResponse.suggestKeywords;
+            }
             return {
               pass: jasmine.matchersUtil.equals(actualResponse, testDefinition.expectedResult),
               message: '\n        Statement: ' + testDefinition.beforeCursor + '|' + testDefinition.afterCursor + '\n' +
-                       'Expected response: ' + JSON.stringify(testDefinition.expectedResult) + '\n' +
-                       '  Parser response: ' + JSON.stringify(actualResponse) +   '\n'
+                         '          Dialect: ' + testDefinition.dialect + '\n' +
+                         'Expected response: ' + JSON.stringify(testDefinition.expectedResult) + '\n' +
+                         '  Parser response: ' + JSON.stringify(actualResponse) +   '\n'
             };
           }
         }
       }
+    },
+    assertAutocomplete: function(testDefinition) {
+      if (typeof testDefinition.dialect === 'undefined') {
+        expect(sql.parseSql(testDefinition.beforeCursor, testDefinition.afterCursor, testDefinition.dialect)).toEqualDefinition(testDefinition);
+        testDefinition.dialect = 'hive';
+        expect(sql.parseSql(testDefinition.beforeCursor, testDefinition.afterCursor, testDefinition.dialect)).toEqualDefinition(testDefinition);
+        testDefinition.dialect = 'impala';
+        expect(sql.parseSql(testDefinition.beforeCursor, testDefinition.afterCursor, 'impala')).toEqualDefinition(testDefinition);
+      } else {
+        expect(sql.parseSql(testDefinition.beforeCursor, testDefinition.afterCursor, testDefinition.dialect)).toEqualDefinition(testDefinition);
+      }
     }
   }
 });

Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio