瀏覽代碼

HUE-6958 [autocomplete] Add autocomplete for Hive MERGE statements

Johan Ahlen 8 年之前
父節點
當前提交
ca44a34

+ 2 - 0
desktop/core/src/desktop/static/desktop/js/autocomplete/jison/sql.jisonlex

@@ -132,6 +132,8 @@
 <hive>'LOCATION'                           { this.begin('hdfs'); return '<hive>LOCATION'; }
 <hive>'LOCK'                               { return '<hive>LOCK'; }
 <hive>'LOCKS'                              { return '<hive>LOCKS'; }
+<hive>'MATCHED'                            { return '<hive>MATCHED'; }
+<hive>'MERGE'                              { return '<hive>MERGE'; }
 <hive>'METADATA'                           { return '<hive>METADATA'; }
 <hive>'MINUTE'                             { return '<hive>MINUTE'; }
 <hive>'MONTH'                              { return '<hive>MONTH'; }

+ 222 - 0
desktop/core/src/desktop/static/desktop/js/autocomplete/jison/sql_insert.jison

@@ -24,6 +24,7 @@ InsertStatement
  | ImpalaInsertOrUpsertStatement
  | CommonTableExpression HiveInsertStatement
  | CommonTableExpression ImpalaInsertOrUpsertStatement
+ | HiveMergeStatement
  ;
 
 DataManipulation_EDIT
@@ -40,6 +41,7 @@ DataManipulation_EDIT
      parser.addCommonTableExpressions($1);
    }
  | CommonTableExpression_EDIT ImpalaInsertOrUpsertStatement
+ | HiveMergeStatement_EDIT
  ;
 
 HiveInsertStatement
@@ -537,4 +539,224 @@ ParenthesizedImpalaRowValuesList_EDIT
      parser.suggestFunctions();
    }
  | '(' ValueExpressionList_EDIT RightParenthesisOrError
+ ;
+
+HiveMergeStatement
+ : HiveMergeStatementLeftPart 'ON' ValueExpression WhenList
+ ;
+
+HiveMergeStatement_EDIT
+ : HiveMergeStatementLeftPart_EDIT
+ | HiveMergeStatementLeftPart 'CURSOR'
+   {
+     parser.suggestKeywords(['ON']);
+   }
+ | HiveMergeStatementLeftPart 'ON' 'CURSOR'
+   {
+     parser.valueExpressionSuggest();
+   }
+ | HiveMergeStatementLeftPart 'ON' ValueExpression_EDIT
+ | HiveMergeStatementLeftPart 'ON' ValueExpression 'CURSOR'
+   {
+     parser.suggestValueExpressionKeywords($3, [{ value: 'WHEN', weight: 2 }]);
+   }
+ | HiveMergeStatementLeftPart 'ON' ValueExpression WhenList_EDIT
+ ;
+
+HiveMergeStatementLeftPart
+ : '<hive>MERGE' 'INTO' SchemaQualifiedTableIdentifier '<hive>AS' RegularIdentifier '<hive>USING' MergeSource '<hive>AS' RegularIdentifier
+   {
+     $3.alias = $5;
+     parser.addTablePrimary($3);
+     if ($7.subQuery) {
+       parser.addTablePrimary({ subQueryAlias: $9 });
+     } else {
+       $7.alias = $9;
+     }
+   }
+ ;
+
+HiveMergeStatementLeftPart_EDIT
+ : '<hive>MERGE' 'CURSOR'
+   {
+     parser.suggestKeywords(['INTO']);
+   }
+ | '<hive>MERGE' 'INTO' 'CURSOR'
+   {
+     parser.suggestDatabases({ appendDot: true });
+     parser.suggestTables();
+   }
+ | '<hive>MERGE' 'INTO' SchemaQualifiedTableIdentifier_EDIT
+ | '<hive>MERGE' 'INTO' SchemaQualifiedTableIdentifier 'CURSOR'
+   {
+     parser.addTablePrimary($3);
+     parser.suggestKeywords(['AS T USING']);
+   }
+ | '<hive>MERGE' 'INTO' SchemaQualifiedTableIdentifier '<hive>AS' 'CURSOR'
+   {
+     parser.addTablePrimary($3);
+     parser.suggestKeywords(['T USING']);
+   }
+ | '<hive>MERGE' 'INTO' SchemaQualifiedTableIdentifier '<hive>AS' RegularIdentifier 'CURSOR'
+   {
+     $3.alias = $5;
+     parser.addTablePrimary($3);
+     parser.suggestKeywords(['USING']);
+   }
+ | '<hive>MERGE' 'INTO' SchemaQualifiedTableIdentifier '<hive>AS' RegularIdentifier '<hive>USING' 'CURSOR'
+   {
+     $3.alias = $5;
+     parser.addTablePrimary($3);
+     parser.suggestDatabases({ appendDot: true });
+     parser.suggestTables();
+   }
+ | '<hive>MERGE' 'INTO' SchemaQualifiedTableIdentifier '<hive>AS' RegularIdentifier '<hive>USING' MergeSource_EDIT
+   {
+     $3.alias = $5;
+     parser.addTablePrimary($3);
+   }
+ | '<hive>MERGE' 'INTO' SchemaQualifiedTableIdentifier '<hive>AS' RegularIdentifier '<hive>USING' MergeSource 'CURSOR'
+   {
+     $3.alias = $5;
+     parser.addTablePrimary($3);
+     parser.suggestKeywords(['AS S ON']);
+   }
+ | '<hive>MERGE' 'INTO' SchemaQualifiedTableIdentifier '<hive>AS' RegularIdentifier '<hive>USING' MergeSource '<hive>AS' 'CURSOR'
+   {
+     $3.alias = $5;
+     parser.addTablePrimary($3);
+     parser.suggestKeywords(['S ON']);
+   }
+ ;
+
+MergeSource
+ : '(' TableSubQueryInner ')'  --> $2
+ | SchemaQualifiedTableIdentifier
+   {
+     parser.addTablePrimary($1);
+   }
+ ;
+
+MergeSource_EDIT
+ : '(' 'CURSOR' RightParenthesisOrError
+   {
+     parser.suggestKeywords(['SELECT']);
+   }
+ | '(' TableSubQueryInner_EDIT RightParenthesisOrError
+ | SchemaQualifiedTableIdentifier_EDIT
+ ;
+
+WhenList
+ : WhenClause
+ | WhenClause WhenClause
+ | WhenClause WhenClause WhenClause
+ ;
+
+WhenList_EDIT
+ : WhenClause_EDIT
+   {
+     if ($1.suggestThenKeywords) {
+       parser.suggestKeywords(['DELETE', 'INSERT VALUES', 'UPDATE SET']);
+     }
+   }
+ | WhenClause 'CURSOR'
+   {
+     if (!$1.notPresent) {
+       parser.suggestKeywords(['WHEN']);
+     }
+   }
+ | WhenClause WhenClause_EDIT
+  {
+     if (!$1.notPresent && $2.suggestThenKeywords) {
+       var keywords = [];
+       if (!$1.isDelete) {
+         keywords.push('DELETE');
+       }
+       if (!$1.isInsert) {
+         keywords.push('INSERT VALUES');
+       }
+       if (!$1.isUpdate) {
+         keywords.push('UPDATE SET');
+       }
+       parser.suggestKeywords(keywords);
+     }
+   }
+ | WhenClause WhenClause 'CURSOR'
+   {
+     if (!$2.notPresent) {
+       parser.suggestKeywords(['WHEN']);
+     }
+   }
+ | WhenClause WhenClause WhenClause_EDIT
+   {
+     if (!$2.notPresent && $3.suggestThenKeywords) {
+       var keywords = [];
+       if (!$1.isDelete && !$2.isDelete) {
+         keywords.push('DELETE');
+       }
+       if (!$1.isInsert && !$2.isInsert) {
+         keywords.push('INSERT VALUES');
+       }
+       if (!$1.isUpdate && !$2.isUpdate) {
+         keywords.push('UPDATE SET');
+       }
+       parser.suggestKeywords(keywords);
+     }
+   }
+ ;
+
+WhenClause
+ : 'WHEN' OptionalNot '<hive>MATCHED' OptionalMatchCondition 'THEN' UpdateDeleteOrInsert  --> { notPresent: !!$2, isDelete: $6.isDelete, isInsert: $6.isInsert, isUpdate: $6.isUpdate }
+ ;
+
+WhenClause_EDIT
+ : 'WHEN' OptionalNot 'CURSOR'
+   {
+     if (!$2) {
+       parser.suggestKeywords(['NOT MATCHED', 'MATCHED']);
+     } else {
+       parser.suggestKeywords(['MATCHED']);
+     }
+   }
+ | 'WHEN' OptionalNot '<hive>MATCHED' OptionalMatchCondition 'CURSOR'
+   {
+     if (!$4) {
+       parser.suggestKeywords(['AND', 'THEN']);
+     } else {
+       parser.suggestValueExpressionKeywords($4, [{ value: 'THEN', weight: 2 }]);
+     }
+   }
+ | 'WHEN' OptionalNot '<hive>MATCHED' MatchCondition_EDIT
+ | 'WHEN' OptionalNot '<hive>MATCHED' OptionalMatchCondition 'THEN' 'CURSOR' --> { suggestThenKeywords: true }
+ | 'WHEN' OptionalNot '<hive>MATCHED' OptionalMatchCondition 'THEN' UpdateDeleteOrInsert_EDIT
+ ;
+
+OptionalMatchCondition
+ :
+ | 'AND' ValueExpression --> $2
+ ;
+
+MatchCondition_EDIT
+ : 'AND' 'CURSOR'
+   {
+     parser.valueExpressionSuggest();
+   }
+ ;
+
+UpdateDeleteOrInsert
+ : 'UPDATE' 'SET' SetClauseList              --> { isUpdate: true }
+ | '<hive>DELETE'                            --> { isDelete: true }
+ | '<hive>INSERT' 'VALUES' InsertValuesList  --> { isInsert: true }
+ ;
+
+UpdateDeleteOrInsert_EDIT
+ : 'UPDATE' 'CURSOR'
+   {
+     parser.suggestKeywords(['SET']);
+   }
+ | 'UPDATE' 'SET' SetClauseList_EDIT
+ | '<hive>INSERT' 'CURSOR'
+   {
+     parser.suggestKeywords(['VALUES']);
+   }
  ;

文件差異過大導致無法顯示
+ 2 - 0
desktop/core/src/desktop/static/desktop/js/autocomplete/jison/sql_main.jison


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

@@ -424,7 +424,7 @@
           expectedResult: {
             lowerCase: false,
             suggestKeywords: ['ABORT', 'ALTER', 'ANALYZE TABLE', 'CREATE', 'DELETE', 'DESCRIBE',
-              'DROP', 'EXPLAIN', 'EXPORT', 'FROM', 'GRANT', 'IMPORT', 'INSERT', 'LOAD', 'MSCK',
+              'DROP', 'EXPLAIN', 'EXPORT', 'FROM', 'GRANT', 'IMPORT', 'INSERT', 'LOAD', 'MERGE', 'MSCK',
               'RELOAD FUNCTION', 'RESET', 'REVOKE', 'SELECT', 'SET', 'SHOW', 'TRUNCATE', 'UPDATE', 'USE', 'WITH']
           }
         });

+ 1263 - 907
desktop/core/src/desktop/static/desktop/js/autocomplete/spec/sqlSpecInsert.js

@@ -26,177 +26,11 @@
 
     var assertAutoComplete = SqlTestUtils.assertAutocomplete;
 
-    it('should handle "INSERT INTO bla.boo VALUES (1, 2, \'a\', 3); |"', function() {
-      assertAutoComplete({
-        beforeCursor: 'INSERT INTO bla.boo VALUES (1, 2, \'a\', 3); ',
-        afterCursor: '',
-        noErrors: true,
-        containsKeywords: ['SELECT'],
-        expectedResult: {
-          lowerCase: false
-        }
-      });
-    });
-
-    it('should suggest keywords for "|"', function() {
-      assertAutoComplete({
-        beforeCursor: '',
-        afterCursor: '',
-        containsKeywords: ['INSERT'],
-        noErrors: true,
-        expectedResult: {
-          lowerCase: false
-        }
-      });
-    });
-
-    it('should suggest keywords for "INSERT |"', function() {
-      assertAutoComplete({
-        beforeCursor: 'INSERT ',
-        afterCursor: '',
-        containsKeywords: ['INTO'],
-        noErrors: true,
-        expectedResult: {
-          lowerCase: false
-        }
-      });
-    });
-
-    it('should suggest tables for "INSERT INTO |"', function() {
-      assertAutoComplete({
-        beforeCursor: 'INSERT INTO ',
-        afterCursor: '',
-        noErrors: true,
-        expectedResult: {
-          lowerCase: false,
-          suggestTables: {},
-          suggestDatabases: { appendDot: true },
-          suggestKeywords: ['TABLE']
-        }
-      });
-    });
-
-    it('should suggest tables for "INSERT INTO baa.|"', function() {
-      assertAutoComplete({
-        beforeCursor: 'INSERT INTO baa.',
-        afterCursor: '',
-        noErrors: true,
-        expectedResult: {
-          lowerCase: false,
-          suggestTables: { identifierChain: [{ name: 'baa' }] }
-        }
-      });
-    });
-
-    it('should suggest tables for "INSERT INTO TABLE baa.|"', function() {
-      assertAutoComplete({
-        beforeCursor: 'INSERT INTO TABLE baa.',
-        afterCursor: '',
-        noErrors: true,
-        expectedResult: {
-          lowerCase: false,
-          suggestTables: { identifierChain: [{ name: 'baa' }] }
-        }
-      });
-    });
-
-    it('should suggest keywords for "INSERT INTO baa |"', function() {
-      assertAutoComplete({
-        beforeCursor: 'INSERT INTO baa ',
-        afterCursor: '',
-        containsKeywords: ['VALUES'],
-        noErrors: true,
-        expectedResult: {
-          lowerCase: false
-        }
-      });
-    });
-
-    it('should suggest keywords for "INSERT INTO TABLE baa |"', function() {
-      assertAutoComplete({
-        beforeCursor: 'INSERT INTO TABLE baa ',
-        afterCursor: '',
-        containsKeywords: ['VALUES'],
-        noErrors: true,
-        expectedResult: {
-          lowerCase: false
-        }
-      });
-    });
-
-    describe('Hive specific', function () {
-      it('should handle "INSERT OVERWRITE TABLE bla.boo PARTITION (bla=1, bo) IF NOT EXISTS SELECT ba.boo, ba, ble FROM db.tbl; |"', function() {
-        assertAutoComplete({
-          beforeCursor: 'INSERT OVERWRITE TABLE bla.boo PARTITION (bla=1, bo) IF NOT EXISTS SELECT ba.boo, ba, ble FROM db.tbl;',
-          afterCursor: '',
-          dialect: 'hive',
-          noErrors: true,
-          containsKeywords: ['SELECT'],
-          expectedResult: {
-            lowerCase: false
-          }
-        });
-      });
-
-      it('should handle "INSERT INTO TABLE bla.boo PARTITION (bla=1, bo) (a, b, c) SELECT ba.boo, ba, ble FROM db.tbl; |"', function() {
-        assertAutoComplete({
-          beforeCursor: 'INSERT INTO TABLE bla.boo PARTITION (bla=1, bo) (a, b, c) SELECT ba.boo, ba, ble FROM db.tbl;',
-          afterCursor: '',
-          dialect: 'hive',
-          noErrors: true,
-          containsKeywords: ['SELECT'],
-          expectedResult: {
-            lowerCase: false
-          }
-        });
-      });
-
-      it('should handle "INSERT OVERWRITE DIRECTORY \'blabla\' SELECT * FROM boo;|"', function() {
-        assertAutoComplete({
-          beforeCursor: 'INSERT OVERWRITE DIRECTORY \'blabla\' SELECT * FROM boo;',
-          afterCursor: '',
-          dialect: 'hive',
-          noErrors: true,
-          containsKeywords: ['SELECT'],
-          expectedResult: {
-            lowerCase: false
-          }
-        });
-      });
-
-      it('should handle "INSERT INTO bla.boo SELECT ba.boo, ba, ble FROM db.tbl; |"', function() {
-        assertAutoComplete({
-          beforeCursor: 'INSERT INTO bla.boo SELECT ba.boo, ba, ble FROM db.tbl;',
-          afterCursor: '',
-          dialect: 'hive',
-          noErrors: true,
-          containsKeywords: ['SELECT'],
-          expectedResult: {
-            lowerCase: false
-          }
-        });
-      });
-
-      it('should handle "FROM boo.baa\\nINSERT INTO TABLE baa2 PARTITION (a, b) SELECT * ORDER BY ba\\nINSERT INTO TABLE baa3 SELECT * GROUP BY boo;|"', function() {
-        assertAutoComplete({
-          beforeCursor: 'FROM boo.baa\n' +
-          'INSERT INTO TABLE baa2 PARTITION (a, b) SELECT * ORDER BY ba\n' +
-          'INSERT INTO TABLE baa3 SELECT * GROUP BY boo;',
-          afterCursor: '',
-          dialect: 'hive',
-          noErrors: true,
-          containsKeywords: ['SELECT'],
-          expectedResult: {
-            lowerCase: false
-          }
-        });
-      });
-
-      it('should handle "FROM boo.baa SELECT * ORDER BY ba;|"', function() {
+    describe('INSERT', function () {
+      it('should handle "INSERT INTO bla.boo VALUES (1, 2, \'a\', 3); |"', function() {
         assertAutoComplete({
-          beforeCursor: 'FROM boo.baa SELECT * ORDER BY ba;',
+          beforeCursor: 'INSERT INTO bla.boo VALUES (1, 2, \'a\', 3); ',
           afterCursor: '',
-          dialect: 'hive',
           noErrors: true,
           containsKeywords: ['SELECT'],
           expectedResult: {
@@ -209,8 +43,7 @@
         assertAutoComplete({
           beforeCursor: '',
           afterCursor: '',
-          dialect: 'hive',
-          containsKeywords: ['FROM', 'INSERT'],
+          containsKeywords: ['INSERT'],
           noErrors: true,
           expectedResult: {
             lowerCase: false
@@ -218,64 +51,22 @@
         });
       });
 
-      it('should suggest keywords for "WITH t1 as (select 1), t2 as (select 2) |"', function() {
+      it('should suggest keywords for "INSERT |"', function() {
         assertAutoComplete({
-          beforeCursor: 'WITH t1 as (select 1), t2 as (select 2) ',
+          beforeCursor: 'INSERT ',
           afterCursor: '',
-          dialect: 'hive',
+          containsKeywords: ['INTO'],
           noErrors: true,
-          containsKeywords: ['INSERT'],
           expectedResult: {
             lowerCase: false
           }
         });
       });
 
-      it('should suggest tables for "FROM |"', function() {
-        assertAutoComplete({
-          beforeCursor: 'FROM ',
-          afterCursor: '',
-          dialect: 'hive',
-          noErrors: true,
-          expectedResult: {
-            lowerCase: false,
-            suggestTables: {},
-            suggestDatabases: { appendDot: true }
-          }
-        });
-      });
-
-      it('should suggest keywords for "from baa.boo |"', function() {
-        assertAutoComplete({
-          beforeCursor: 'from baa.boo ',
-          afterCursor: '',
-          dialect: 'hive',
-          noErrors: true,
-          expectedResult: {
-            lowerCase: true,
-            suggestKeywords: ['INSERT INTO', 'INSERT OVERWRITE', 'SELECT']
-          }
-        });
-      });
-
-      it('should suggest keywords for "FROM baa.boo INSERT |"', function() {
-        assertAutoComplete({
-          beforeCursor: 'FROM baa.boo INSERT ',
-          afterCursor: '',
-          dialect: 'hive',
-          noErrors: true,
-          expectedResult: {
-            lowerCase: false,
-            suggestKeywords: ['INTO', 'OVERWRITE']
-          }
-        });
-      });
-
-      it('should suggest tables for "FROM baa.boo INSERT INTO |"', function() {
+      it('should suggest tables for "INSERT INTO |"', function() {
         assertAutoComplete({
-          beforeCursor: 'FROM baa.boo INSERT INTO ',
+          beforeCursor: 'INSERT INTO ',
           afterCursor: '',
-          dialect: 'hive',
           noErrors: true,
           expectedResult: {
             lowerCase: false,
@@ -286,11 +77,10 @@
         });
       });
 
-      it('should suggest tables for "FROM baa.boo INSERT INTO baa.|"', function() {
+      it('should suggest tables for "INSERT INTO baa.|"', function() {
         assertAutoComplete({
-          beforeCursor: 'FROM baa.boo INSERT INTO baa.',
+          beforeCursor: 'INSERT INTO baa.',
           afterCursor: '',
-          dialect: 'hive',
           noErrors: true,
           expectedResult: {
             lowerCase: false,
@@ -299,970 +89,1536 @@
         });
       });
 
-      it('should suggest keywords for "FROM baa.boo INSERT INTO TABLE baa |"', function() {
+      it('should suggest tables for "INSERT INTO TABLE baa.|"', function() {
         assertAutoComplete({
-          beforeCursor: 'FROM baa.boo INSERT INTO TABLE baa ',
+          beforeCursor: 'INSERT INTO TABLE baa.',
           afterCursor: '',
-          dialect: 'hive',
           noErrors: true,
           expectedResult: {
             lowerCase: false,
-            suggestKeywords: ['PARTITION', 'SELECT']
-          }
-        });
-      });
-
-      it('should suggest columns for "FROM baa.boo INSERT INTO TABLE baa PARTITION (|"', function() {
-        assertAutoComplete({
-          beforeCursor: 'FROM baa.boo INSERT INTO TABLE baa PARTITION (',
-          afterCursor: '',
-          dialect: 'hive',
-          expectedResult: {
-            lowerCase: false,
-            suggestColumns: { tables: [{ identifierChain: [{ name: 'baa' }] }] }
-          }
-        });
-      });
-
-      it('should suggest columns for "FROM baa.boo INSERT INTO TABLE baa PARTITION (a,b) (|"', function() {
-        assertAutoComplete({
-          beforeCursor: 'FROM baa.boo INSERT INTO TABLE baa PARTITION (a,b) (',
-          afterCursor: '',
-          dialect: 'hive',
-          expectedResult: {
-            lowerCase: false,
-            suggestColumns: { tables: [{ identifierChain: [{ name: 'baa' }] }] }
+            suggestTables: { identifierChain: [{ name: 'baa' }] }
           }
         });
       });
 
-      it('should suggest keywords for "FROM baa.boo INSERT INTO TABLE baa PARTITION (a,b) (x, z) |"', function() {
+      it('should suggest keywords for "INSERT INTO baa |"', function() {
         assertAutoComplete({
-          beforeCursor: 'FROM baa.boo INSERT INTO TABLE baa PARTITION (a,b) (x, z) ',
+          beforeCursor: 'INSERT INTO baa ',
           afterCursor: '',
-          dialect: 'hive',
+          containsKeywords: ['VALUES'],
           noErrors: true,
           expectedResult: {
-            lowerCase: false,
-            suggestKeywords: ['SELECT']
+            lowerCase: false
           }
         });
       });
 
-      it('should suggest columns for "FROM baa.boo INSERT INTO TABLE baa PARTITION (a,b) (x, z) SELECT |"', function() {
+      it('should suggest keywords for "INSERT INTO TABLE baa |"', function() {
         assertAutoComplete({
-          beforeCursor: 'FROM baa.boo INSERT INTO TABLE baa PARTITION (a,b) (x, z) SELECT ',
+          beforeCursor: 'INSERT INTO TABLE baa ',
           afterCursor: '',
-          dialect: 'hive',
+          containsKeywords: ['VALUES'],
           noErrors: true,
-          containsKeywords: ['ALL', 'DISTINCT'],
           expectedResult: {
-            lowerCase: false,
-            suggestFunctions: {},
-            suggestAggregateFunctions: { tables: [{ identifierChain: [{ name: 'baa' }, { name: 'boo' }] }] },
-            suggestAnalyticFunctions: true,
-            suggestColumns: { tables: [{ identifierChain: [{ name: 'baa' }, { name: 'boo' }] }] }
+            lowerCase: false
           }
         });
       });
 
-      it('should suggest columns for "FROM baa.boo INSERT INTO TABLE baa PARTITION (a,b) (x, z) SELECT c INSERT INTO TABLE baa PARTITION (a,b) (x, z) SELECT a, |"', function() {
-        assertAutoComplete({
-          beforeCursor: 'FROM baa.boo INSERT INTO TABLE baa PARTITION (a,b) (x, z) SELECT c INSERT INTO TABLE baa PARTITION (a,b) (x, z) SELECT a, ',
-          afterCursor: '',
-          dialect: 'hive',
-          noErrors: true,
-          containsKeywords: ['*'],
-          expectedResult: {
-            lowerCase: false,
-            suggestFunctions: {},
-            suggestAggregateFunctions: { tables: [{ identifierChain: [{ name: 'baa' }, { name: 'boo' }] }] },
-            suggestAnalyticFunctions: true,
-            suggestColumns: { tables: [{ identifierChain: [{ name: 'baa' }, { name: 'boo' }] }] }
-          }
+      describe('Hive specific', function () {
+        it('should handle "INSERT OVERWRITE TABLE bla.boo PARTITION (bla=1, bo) IF NOT EXISTS SELECT ba.boo, ba, ble FROM db.tbl; |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'INSERT OVERWRITE TABLE bla.boo PARTITION (bla=1, bo) IF NOT EXISTS SELECT ba.boo, ba, ble FROM db.tbl;',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            containsKeywords: ['SELECT'],
+            expectedResult: {
+              lowerCase: false
+            }
+          });
+        });
+
+        it('should handle "INSERT INTO TABLE bla.boo PARTITION (bla=1, bo) (a, b, c) SELECT ba.boo, ba, ble FROM db.tbl; |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'INSERT INTO TABLE bla.boo PARTITION (bla=1, bo) (a, b, c) SELECT ba.boo, ba, ble FROM db.tbl;',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            containsKeywords: ['SELECT'],
+            expectedResult: {
+              lowerCase: false
+            }
+          });
+        });
+
+        it('should handle "INSERT OVERWRITE DIRECTORY \'blabla\' SELECT * FROM boo;|"', function() {
+          assertAutoComplete({
+            beforeCursor: 'INSERT OVERWRITE DIRECTORY \'blabla\' SELECT * FROM boo;',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            containsKeywords: ['SELECT'],
+            expectedResult: {
+              lowerCase: false
+            }
+          });
+        });
+
+        it('should handle "INSERT INTO bla.boo SELECT ba.boo, ba, ble FROM db.tbl; |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'INSERT INTO bla.boo SELECT ba.boo, ba, ble FROM db.tbl;',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            containsKeywords: ['SELECT'],
+            expectedResult: {
+              lowerCase: false
+            }
+          });
+        });
+
+        it('should handle "FROM boo.baa\\nINSERT INTO TABLE baa2 PARTITION (a, b) SELECT * ORDER BY ba\\nINSERT INTO TABLE baa3 SELECT * GROUP BY boo;|"', function() {
+          assertAutoComplete({
+            beforeCursor: 'FROM boo.baa\n' +
+            'INSERT INTO TABLE baa2 PARTITION (a, b) SELECT * ORDER BY ba\n' +
+            'INSERT INTO TABLE baa3 SELECT * GROUP BY boo;',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            containsKeywords: ['SELECT'],
+            expectedResult: {
+              lowerCase: false
+            }
+          });
+        });
+
+        it('should handle "FROM boo.baa SELECT * ORDER BY ba;|"', function() {
+          assertAutoComplete({
+            beforeCursor: 'FROM boo.baa SELECT * ORDER BY ba;',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            containsKeywords: ['SELECT'],
+            expectedResult: {
+              lowerCase: false
+            }
+          });
+        });
+
+        it('should suggest keywords for "|"', function() {
+          assertAutoComplete({
+            beforeCursor: '',
+            afterCursor: '',
+            dialect: 'hive',
+            containsKeywords: ['FROM', 'INSERT'],
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false
+            }
+          });
+        });
+
+        it('should suggest keywords for "WITH t1 as (select 1), t2 as (select 2) |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'WITH t1 as (select 1), t2 as (select 2) ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            containsKeywords: ['INSERT'],
+            expectedResult: {
+              lowerCase: false
+            }
+          });
+        });
+
+        it('should suggest tables for "FROM |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'FROM ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestTables: {},
+              suggestDatabases: { appendDot: true }
+            }
+          });
+        });
+
+        it('should suggest keywords for "from baa.boo |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'from baa.boo ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: true,
+              suggestKeywords: ['INSERT INTO', 'INSERT OVERWRITE', 'SELECT']
+            }
+          });
+        });
+
+        it('should suggest keywords for "FROM baa.boo INSERT |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'FROM baa.boo INSERT ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['INTO', 'OVERWRITE']
+            }
+          });
+        });
+
+        it('should suggest tables for "FROM baa.boo INSERT INTO |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'FROM baa.boo INSERT INTO ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestTables: {},
+              suggestDatabases: { appendDot: true },
+              suggestKeywords: ['TABLE']
+            }
+          });
+        });
+
+        it('should suggest tables for "FROM baa.boo INSERT INTO baa.|"', function() {
+          assertAutoComplete({
+            beforeCursor: 'FROM baa.boo INSERT INTO baa.',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestTables: { identifierChain: [{ name: 'baa' }] }
+            }
+          });
+        });
+
+        it('should suggest keywords for "FROM baa.boo INSERT INTO TABLE baa |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'FROM baa.boo INSERT INTO TABLE baa ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['PARTITION', 'SELECT']
+            }
+          });
+        });
+
+        it('should suggest columns for "FROM baa.boo INSERT INTO TABLE baa PARTITION (|"', function() {
+          assertAutoComplete({
+            beforeCursor: 'FROM baa.boo INSERT INTO TABLE baa PARTITION (',
+            afterCursor: '',
+            dialect: 'hive',
+            expectedResult: {
+              lowerCase: false,
+              suggestColumns: { tables: [{ identifierChain: [{ name: 'baa' }] }] }
+            }
+          });
+        });
+
+        it('should suggest columns for "FROM baa.boo INSERT INTO TABLE baa PARTITION (a,b) (|"', function() {
+          assertAutoComplete({
+            beforeCursor: 'FROM baa.boo INSERT INTO TABLE baa PARTITION (a,b) (',
+            afterCursor: '',
+            dialect: 'hive',
+            expectedResult: {
+              lowerCase: false,
+              suggestColumns: { tables: [{ identifierChain: [{ name: 'baa' }] }] }
+            }
+          });
+        });
+
+        it('should suggest keywords for "FROM baa.boo INSERT INTO TABLE baa PARTITION (a,b) (x, z) |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'FROM baa.boo INSERT INTO TABLE baa PARTITION (a,b) (x, z) ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['SELECT']
+            }
+          });
+        });
+
+        it('should suggest columns for "FROM baa.boo INSERT INTO TABLE baa PARTITION (a,b) (x, z) SELECT |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'FROM baa.boo INSERT INTO TABLE baa PARTITION (a,b) (x, z) SELECT ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            containsKeywords: ['ALL', 'DISTINCT'],
+            expectedResult: {
+              lowerCase: false,
+              suggestFunctions: {},
+              suggestAggregateFunctions: { tables: [{ identifierChain: [{ name: 'baa' }, { name: 'boo' }] }] },
+              suggestAnalyticFunctions: true,
+              suggestColumns: { tables: [{ identifierChain: [{ name: 'baa' }, { name: 'boo' }] }] }
+            }
+          });
+        });
+
+        it('should suggest columns for "FROM baa.boo INSERT INTO TABLE baa PARTITION (a,b) (x, z) SELECT c INSERT INTO TABLE baa PARTITION (a,b) (x, z) SELECT a, |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'FROM baa.boo INSERT INTO TABLE baa PARTITION (a,b) (x, z) SELECT c INSERT INTO TABLE baa PARTITION (a,b) (x, z) SELECT a, ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            containsKeywords: ['*'],
+            expectedResult: {
+              lowerCase: false,
+              suggestFunctions: {},
+              suggestAggregateFunctions: { tables: [{ identifierChain: [{ name: 'baa' }, { name: 'boo' }] }] },
+              suggestAnalyticFunctions: true,
+              suggestColumns: { tables: [{ identifierChain: [{ name: 'baa' }, { name: 'boo' }] }] }
+            }
+          });
+        });
+
+        it('should suggest keywords for "FROM baa.boo INSERT INTO TABLE baa PARTITION (a,b) (x, z) SELECT c, d |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'FROM baa.boo INSERT INTO TABLE baa PARTITION (a,b) (x, z) SELECT c, d ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            containsColRefKeywords: true,
+            containsKeywords: ['WHERE', 'ORDER BY'],
+            doesNotContainKeywords: ['FROM'],
+            expectedResult: {
+              lowerCase: false,
+              colRef: { identifierChain: [{ name: 'baa' }, { name: 'boo' }, { name: 'd' }] }
+            }
+          });
+        });
+
+        it('should suggest keywords for "FROM baa.boo INSERT OVERWRITE bla.ble |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'FROM baa.boo INSERT OVERWRITE bla.ble ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['PARTITION', 'SELECT']
+            }
+          });
+        });
+
+        it('should suggest keywords for "FROM baa.boo INSERT OVERWRITE bla.ble |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'FROM baa.boo INSERT OVERWRITE bla.ble ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['PARTITION', 'SELECT']
+            }
+          });
+        });
+
+        it('should suggest columns for "FROM baa.boo INSERT OVERWRITE bla.ble PARTITION (|"', function() {
+          assertAutoComplete({
+            beforeCursor: 'FROM baa.boo INSERT OVERWRITE bla.ble PARTITION (',
+            afterCursor: '',
+            dialect: 'hive',
+            expectedResult: {
+              lowerCase: false,
+              suggestColumns: { tables: [{ identifierChain: [{ name: 'bla' }, { name: 'ble' }] }] }
+            }
+          });
+        });
+
+        it('should suggest keywords for "FROM baa.boo INSERT OVERWRITE bla.ble PARTITION (a, b) |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'FROM baa.boo INSERT OVERWRITE bla.ble PARTITION (a, b) ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['IF NOT EXISTS', 'SELECT']
+            }
+          });
+        });
+
+        it('should suggest keywords for "FROM baa.boo INSERT OVERWRITE bla.ble PARTITION (a, b) IF |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'FROM baa.boo INSERT OVERWRITE bla.ble PARTITION (a, b) IF ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['NOT EXISTS']
+            }
+          });
+        });
+
+        it('should suggest keywords for "FROM baa.boo INSERT OVERWRITE bla.ble PARTITION (a, b) IF NOT |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'FROM baa.boo INSERT OVERWRITE bla.ble PARTITION (a, b) IF NOT ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['EXISTS']
+            }
+          });
+        });
+
+        it('should suggest keywords for "FROM baa.boo INSERT OVERWRITE bla.ble PARTITION (a, b) IF NOT EXISTS |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'FROM baa.boo INSERT OVERWRITE bla.ble PARTITION (a, b) IF NOT EXISTS ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['SELECT']
+            }
+          });
+        });
+
+        it('should suggest columns for "FROM baa.boo INSERT OVERWRITE bla.ble PARTITION (a, b) IF NOT EXISTS SELECT |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'FROM baa.boo INSERT OVERWRITE bla.ble PARTITION (a, b) IF NOT EXISTS SELECT ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            containsKeywords: ['*'],
+            expectedResult: {
+              lowerCase: false,
+              suggestFunctions: {},
+              suggestAggregateFunctions: { tables: [{ identifierChain: [{ name: 'baa' }, { name: 'boo' }] }] },
+              suggestAnalyticFunctions: true,
+              suggestColumns: { tables: [{ identifierChain: [{ name: 'baa' }, { name: 'boo' }] }] }
+            }
+          });
+        });
+
+        it('should suggest keywords for "FROM baa.boo INSERT OVERWRITE bla.ble SELECT c, d |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'FROM baa.boo INSERT OVERWRITE bla.ble SELECT c, d ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            containsColRefKeywords: true,
+            containsKeywords: ['WHERE', 'ORDER BY'],
+            doesNotContainKeywords: ['FROM'],
+            expectedResult: {
+              lowerCase: false,
+              colRef: { identifierChain: [{ name: 'baa' }, { name: 'boo' }, { name: 'd' }] }
+            }
+          });
+        });
+
+        it('should suggest keywords for "FROM baa.boo INSERT OVERWRITE bla.ble SELECT c, d INSERT OVERWRITE bla.ble SELECT a |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'FROM baa.boo INSERT OVERWRITE bla.ble SELECT c, d INSERT OVERWRITE bla.ble SELECT a ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            containsColRefKeywords: true,
+            containsKeywords: ['WHERE', 'ORDER BY'],
+            doesNotContainKeywords: ['FROM'],
+            expectedResult: {
+              lowerCase: false,
+              colRef: { identifierChain: [{ name: 'baa' }, { name: 'boo' }, { name: 'a' }] }
+            }
+          });
+        });
+
+        it('should suggest columns for "FROM baa.boo SELECT |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'FROM baa.boo SELECT ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            containsKeywords: ['*'],
+            expectedResult: {
+              lowerCase: false,
+              suggestFunctions: {},
+              suggestAggregateFunctions: { tables: [{ identifierChain: [{ name: 'baa' }, { name: 'boo' }] }] },
+              suggestAnalyticFunctions: true,
+              suggestColumns: { tables: [{ identifierChain: [{ name: 'baa' }, { name: 'boo' }] }] }
+            }
+          });
+        });
+
+        it('should suggest keywords for "FROM baa.boo SELECT c, d |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'FROM baa.boo SELECT c, d ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            containsColRefKeywords: true,
+            containsKeywords: ['WHERE', 'ORDER BY'],
+            doesNotContainKeywords: ['FROM'],
+            expectedResult: {
+              lowerCase: false,
+              colRef: { identifierChain: [{ name: 'baa' }, { name: 'boo' }, { name: 'd' }] }
+            }
+          });
+        });
+
+        it('should suggest keywords for "INSERT |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'INSERT ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['INTO', 'OVERWRITE']
+            }
+          });
+        });
+
+        it('should suggest tables for "INSERT INTO |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'INSERT INTO ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestTables: {},
+              suggestDatabases: { appendDot: true },
+              suggestKeywords: ['TABLE']
+            }
+          });
+        });
+
+        it('should suggest tables for "INSERT INTO baa.|"', function() {
+          assertAutoComplete({
+            beforeCursor: 'INSERT INTO baa.',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestTables: { identifierChain: [{ name: 'baa' }] }
+            }
+          });
+        });
+
+        it('should suggest keywords for "INSERT INTO TABLE baa |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'INSERT INTO TABLE baa ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['PARTITION', 'VALUES', 'SELECT']
+            }
+          });
+        });
+
+        it('should suggest columns for "INSERT INTO TABLE baa PARTITION (|"', function() {
+          assertAutoComplete({
+            beforeCursor: 'INSERT INTO TABLE baa PARTITION (',
+            afterCursor: '',
+            dialect: 'hive',
+            expectedResult: {
+              lowerCase: false,
+              suggestColumns: { tables: [{ identifierChain: [{ name: 'baa' }] }] }
+            }
+          });
+        });
+
+        it('should suggest columns for "INSERT INTO TABLE baa PARTITION (a,b) (x, |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'INSERT INTO TABLE baa PARTITION (a,b) (x, ',
+            afterCursor: '',
+            dialect: 'hive',
+            expectedResult: {
+              lowerCase: false,
+              suggestColumns: { tables: [{ identifierChain: [{ name: 'baa' }] }] }
+            }
+          });
+        });
+
+        it('should suggest keywords for "insert into table baa partition (a,b) (x, z) |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'insert into table baa partition (a,b) (x, z) ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: true,
+              suggestKeywords: ['SELECT']
+            }
+          });
+        });
+
+        it('should suggest columns for "INSERT INTO TABLE baa PARTITION (a,b) (x, z) SELECT |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'INSERT INTO TABLE baa PARTITION (a,b) (x, z) SELECT ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            containsKeywords: ['*'],
+            expectedResult: {
+              lowerCase: false,
+              suggestFunctions: {},
+              suggestAggregateFunctions: { tables: [] },
+              suggestAnalyticFunctions: true,
+              suggestTables: { prependFrom: true, prependQuestionMark: true },
+              suggestDatabases:  { prependFrom: true, prependQuestionMark: true, appendDot: true }
+            }
+          });
+        });
+
+        it('should suggest columns for "INSERT INTO TABLE baa PARTITION (a,b) (x, z) SELECT c, |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'INSERT INTO TABLE baa PARTITION (a,b) (x, z) SELECT c, ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestFunctions: {},
+              suggestAggregateFunctions: { tables: [] },
+              suggestAnalyticFunctions: true,
+              suggestTables: { prependFrom: true, prependQuestionMark: true },
+              suggestDatabases:  { prependFrom: true, prependQuestionMark: true, appendDot: true }
+            }
+          });
+        });
+
+        it('should suggest keywords for "INSERT INTO TABLE baa PARTITION (a,b) (x, z) SELECT c, d |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'INSERT INTO TABLE baa PARTITION (a,b) (x, z) SELECT c, d ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            containsKeywords: ['AS', 'IN'],
+            expectedResult: {
+              lowerCase: false,
+              suggestTables: { prependFrom: true },
+              suggestDatabases:  { prependFrom: true, appendDot: true }
+            }
+          });
+        });
+
+        it('should suggest tables for "INSERT OVERWRITE |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'INSERT OVERWRITE ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestTables: {},
+              suggestDatabases: { appendDot: true },
+              suggestKeywords: ['DIRECTORY', 'LOCAL DIRECTORY', 'TABLE' ]
+            }
+          });
+        });
+
+        it('should suggest tables for "INSERT OVERWRITE LOCAL |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'INSERT OVERWRITE LOCAL ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['DIRECTORY' ]
+            }
+          });
+        });
+
+        it('should suggest hdfs for "INSERT OVERWRITE DIRECTORY \'|"', function() {
+          assertAutoComplete({
+            beforeCursor: 'INSERT OVERWRITE DIRECTORY \'',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestHdfs: { path: '' }
+            }
+          });
+        });
+
+        it('should suggest keywords for "INSERT OVERWRITE DIRECTORY \'blabla\' |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'INSERT OVERWRITE DIRECTORY \'blabla\' ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['SELECT']
+            }
+          });
+        });
+
+        it('should suggest keywords for "INSERT OVERWRITE bla.ble |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'INSERT OVERWRITE bla.ble ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['PARTITION', 'SELECT']
+            }
+          });
+        });
+
+        it('should suggest keywords for "INSERT OVERWRITE bla.ble |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'INSERT OVERWRITE bla.ble ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['PARTITION', 'SELECT']
+            }
+          });
+        });
+
+        it('should suggest columns for "INSERT OVERWRITE bla.ble PARTITION (|"', function() {
+          assertAutoComplete({
+            beforeCursor: 'INSERT OVERWRITE bla.ble PARTITION (',
+            afterCursor: '',
+            dialect: 'hive',
+            expectedResult: {
+              lowerCase: false,
+              suggestColumns: { tables: [{ identifierChain: [{ name: 'bla' }, { name: 'ble' }] }] }
+            }
+          });
+        });
+
+        it('should suggest keywords for "INSERT OVERWRITE bla.ble PARTITION (a, b) |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'INSERT OVERWRITE bla.ble PARTITION (a, b) ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['IF NOT EXISTS', 'SELECT']
+            }
+          });
+        });
+
+        it('should suggest keywords for "INSERT OVERWRITE bla.ble PARTITION (a, b) IF |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'INSERT OVERWRITE bla.ble PARTITION (a, b) IF ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['NOT EXISTS']
+            }
+          });
+        });
+
+        it('should suggest keywords for "INSERT OVERWRITE bla.ble PARTITION (a, b) IF NOT |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'INSERT OVERWRITE bla.ble PARTITION (a, b) IF NOT ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['EXISTS']
+            }
+          });
+        });
+
+        it('should suggest keywords for "INSERT OVERWRITE bla.ble PARTITION (a, b) IF NOT EXISTS |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'INSERT OVERWRITE bla.ble PARTITION (a, b) IF NOT EXISTS ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['SELECT']
+            }
+          });
+        });
+
+        it('should suggest columns for "INSERT OVERWRITE bla.ble PARTITION (a, b) IF NOT EXISTS SELECT |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'INSERT OVERWRITE bla.ble PARTITION (a, b) IF NOT EXISTS SELECT ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            containsKeywords: ['*'],
+            expectedResult: {
+              lowerCase: false,
+              suggestFunctions: {},
+              suggestAggregateFunctions: { tables: [] },
+              suggestAnalyticFunctions: true,
+              suggestTables: { prependFrom: true, prependQuestionMark: true },
+              suggestDatabases:  { prependFrom: true, prependQuestionMark: true, appendDot: true }
+            }
+          });
+        });
+
+        it('should suggest keywords for "INSERT OVERWRITE bla.ble SELECT c, d |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'INSERT OVERWRITE bla.ble SELECT c, d ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            containsKeywords: ['AS', 'IN'],
+            expectedResult: {
+              lowerCase: false,
+              suggestTables: { prependFrom: true },
+              suggestDatabases:  { prependFrom: true, appendDot: true }
+            }
+          });
+        });
+
+        it('should suggest identifier for "WITH t1 AS (SELECT 1), t2 AS (SELECT 2) INSERT INTO tab SELECT * FROM |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'WITH t1 AS (SELECT 1), t2 AS (SELECT 2) INSERT INTO tab SELECT * FROM ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestTables: {},
+              suggestDatabases: { appendDot: true },
+              suggestCommonTableExpressions: [{ name: 't1' }, { name: 't2' }],
+              commonTableExpressions: [{ alias: 't1', columns: [{ type: 'NUMBER' }] }, { alias: 't2', columns: [{ type: 'NUMBER' }] }],
+            }
+          });
+        });
+      });
+
+      describe('Impala specific', function () {
+        it('should suggest keywords for "|"', function() {
+          assertAutoComplete({
+            beforeCursor: '',
+            afterCursor: '',
+            dialect: 'impala',
+            containsKeywords: ['UPSERT'],
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false
+            }
+          });
+        });
+
+        it('should handle "UPSERT INTO TABLE boo.baa (a, b) VALUES (1, 2);|"', function() {
+          assertAutoComplete({
+            beforeCursor: 'UPSERT INTO TABLE boo.baa (a, b) VALUES (1, 2);',
+            afterCursor: '',
+            dialect: 'impala',
+            noErrors: true,
+            containsKeywords: ['SELECT'],
+            expectedResult: {
+              lowerCase: false
+            }
+          });
+        });
+
+        it('should handle "UPSERT INTO production_table SELECT * FROM staging_table WHERE c1 IS NOT NULL AND c2 > 0;|"', function() {
+          assertAutoComplete({
+            beforeCursor: 'UPSERT INTO production_table SELECT * FROM staging_table WHERE c1 IS NOT NULL AND c2 > 0;',
+            afterCursor: '',
+            dialect: 'impala',
+            noErrors: true,
+            containsKeywords: ['SELECT'],
+            expectedResult: {
+              lowerCase: false
+            }
+          });
+        });
+
+        it('should handle "UPSERT INTO boo.baa [SHUFFLE] SELECT * FROM bla;|"', function() {
+          assertAutoComplete({
+            beforeCursor: 'UPSERT INTO boo.baa [SHUFFLE] SELECT * FROM bla;',
+            afterCursor: '',
+            dialect: 'impala',
+            noErrors: true,
+            containsKeywords: ['SELECT'],
+            expectedResult: {
+              lowerCase: false
+            }
+          });
+        });
+
+        it('should handle "INSERT INTO TABLE boo.baa (a, b) PARTITION (a=1) VALUES (1, 2);|"', function() {
+          assertAutoComplete({
+            beforeCursor: 'INSERT INTO TABLE boo.baa (a, b) PARTITION (a=1) VALUES (1, 2);',
+            afterCursor: '',
+            dialect: 'impala',
+            noErrors: true,
+            containsKeywords: ['SELECT'],
+            expectedResult: {
+              lowerCase: false
+            }
+          });
+        });
+
+        it('should handle "INSERT OVERWRITE boo.baa [SHUFFLE] SELECT * FROM bla;|"', function() {
+          assertAutoComplete({
+            beforeCursor: 'INSERT OVERWRITE boo.baa [SHUFFLE] SELECT * FROM bla;',
+            afterCursor: '',
+            dialect: 'impala',
+            noErrors: true,
+            containsKeywords: ['SELECT'],
+            expectedResult: {
+              lowerCase: false
+            }
+          });
+        });
+
+        it('should handle "WITH t1 AS (SELECT 1), t2 AS (SELECT 2) INSERT OVERWRITE tab SELECT * FROM t1, t2;|"', function() {
+          assertAutoComplete({
+            beforeCursor: 'WITH t1 AS (SELECT 1), t2 AS (SELECT 2) INSERT OVERWRITE tab SELECT * FROM t1, t2;',
+            afterCursor: '',
+            dialect: 'impala',
+            noErrors: true,
+            containsKeywords: ['SELECT'],
+            expectedResult: {
+              lowerCase: false
+            }
+          });
+        });
+
+        it('should suggest keywords for "WITH t1 as (select 1), t2 as (select 2) |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'WITH t1 as (select 1), t2 as (select 2) ',
+            afterCursor: '',
+            dialect: 'impala',
+            noErrors: true,
+            containsKeywords: ['INSERT'],
+            expectedResult: {
+              lowerCase: false
+            }
+          });
+        });
+
+        it('should suggest keywords for "UPSERT |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'UPSERT ',
+            afterCursor: '',
+            dialect: 'impala',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['INTO']
+            }
+          });
+        });
+
+        it('should suggest tables for "UPSERT INTO |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'UPSERT INTO ',
+            afterCursor: '',
+            dialect: 'impala',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestTables: {},
+              suggestDatabases: { appendDot: true },
+              suggestKeywords: ['TABLE' ]
+            }
+          });
+        });
+
+        it('should suggest tables for "UPSERT INTO boo.|"', function() {
+          assertAutoComplete({
+            beforeCursor: 'UPSERT INTO boo.',
+            afterCursor: '',
+            dialect: 'impala',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestTables: { identifierChain: [{ name: 'boo' }] }
+            }
+          });
+        });
+
+        it('should suggest keywords for "UPSERT INTO baa |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'UPSERT INTO baa ',
+            afterCursor: '',
+            dialect: 'impala',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['[NOSHUFFLE]', '[SHUFFLE]', 'SELECT', 'VALUES']
+            }
+          });
+        });
+
+        it('should suggest tables for "UPSERT INTO baa [SHUFFLE] SELECT * FROM |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'UPSERT INTO baa [SHUFFLE] SELECT * FROM ',
+            afterCursor: '',
+            dialect: 'impala',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestTables: {},
+              suggestDatabases: { appendDot: true }
+            }
+          });
+        });
+
+        it('should suggest columns for "UPSERT INTO TABLE boo.baa (|"', function() {
+          assertAutoComplete({
+            beforeCursor: 'UPSERT INTO boo.baa (',
+            afterCursor: '',
+            dialect: 'impala',
+            expectedResult: {
+              lowerCase: false,
+              suggestColumns: { tables: [{ identifierChain: [{ name: 'boo' }, { name: 'baa' }] }] }
+            }
+          });
+        });
+
+        it('should suggest keywords for "INSERT |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'INSERT ',
+            afterCursor: '',
+            dialect: 'impala',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['INTO', 'OVERWRITE' ]
+            }
+          });
+        });
+
+        it('should suggest tables for "INSERT INTO |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'INSERT INTO ',
+            afterCursor: '',
+            dialect: 'impala',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestTables: {},
+              suggestDatabases: { appendDot: true },
+              suggestKeywords: ['TABLE' ]
+            }
+          });
+        });
+
+        it('should suggest tables for "INSERT INTO boo.|"', function() {
+          assertAutoComplete({
+            beforeCursor: 'INSERT INTO boo.',
+            afterCursor: '',
+            dialect: 'impala',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestTables: { identifierChain: [{ name: 'boo' }] }
+            }
+          });
+        });
+
+        it('should suggest keywords for "INSERT INTO baa |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'INSERT INTO baa ',
+            afterCursor: '',
+            dialect: 'impala',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['PARTITION', '[NOSHUFFLE]', '[SHUFFLE]', 'SELECT', 'VALUES']
+            }
+          });
+        });
+
+        it('should suggest keywords for "INSERT INTO baa [SHUFFLE] |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'INSERT INTO baa [SHUFFLE] ',
+            afterCursor: '',
+            dialect: 'impala',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['SELECT']
+            }
+          });
+        });
+
+        it('should suggest tables for "INSERT INTO baa [SHUFFLE] SELECT * FROM |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'INSERT INTO baa [SHUFFLE] SELECT * FROM ',
+            afterCursor: '',
+            dialect: 'impala',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestTables: {},
+              suggestDatabases: { appendDot: true }
+            }
+          });
+        });
+
+        it('should suggest columns for "INSERT INTO TABLE boo.baa (|"', function() {
+          assertAutoComplete({
+            beforeCursor: 'INSERT INTO boo.baa (',
+            afterCursor: '',
+            dialect: 'impala',
+            expectedResult: {
+              lowerCase: false,
+              suggestColumns: { tables: [{ identifierChain: [{ name: 'boo' }, { name: 'baa' }] }] }
+            }
+          });
+        });
+
+        it('should suggest columns for "INSERT INTO TABLE boo.baa (a, |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'INSERT INTO boo.baa (a, ',
+            afterCursor: '',
+            dialect: 'impala',
+            expectedResult: {
+              lowerCase: false,
+              suggestColumns: { tables: [{ identifierChain: [{ name: 'boo' }, { name: 'baa' }] }] }
+            }
+          });
+        });
+
+        it('should suggest keywords for "WITH t1 as (select 1), t2 as (select 2) INSERT INTO baa (a, b) |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'WITH t1 as (select 1), t2 as (select 2) INSERT INTO baa ',
+            afterCursor: '',
+            dialect: 'impala',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['PARTITION', '[NOSHUFFLE]', '[SHUFFLE]', 'SELECT', 'VALUES'],
+              commonTableExpressions: [{ alias: 't1', columns: [{ type: 'NUMBER' }] }, { alias: 't2', columns: [{ type: 'NUMBER' }] }]
+            }
+          });
+        });
+
+        it('should suggest columns for "INSERT INTO TABLE boo.baa (a, b) PARTITION(a = 1, |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'INSERT INTO TABLE boo.baa (a, b) PARTITION(a = 1, ',
+            afterCursor: '',
+            dialect: 'impala',
+            expectedResult: {
+              lowerCase: false,
+              suggestColumns: { tables: [{ identifierChain: [{ name: 'boo' }, { name: 'baa' }] }] }
+            }
+          });
+        });
+
+        it('should not suggest keywords for "INSERT INTO TABLE boo.baa (a, b) VALUES (1, 2) |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'INSERT INTO TABLE boo.baa (a, b) VALUES (1, 2) ',
+            afterCursor: '',
+            dialect: 'impala',
+            expectedResult: {
+              lowerCase: false
+            }
+          });
+        });
+
+        it('should suggest tables for "INSERT OVERWRITE |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'INSERT OVERWRITE ',
+            afterCursor: '',
+            dialect: 'impala',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestTables: {},
+              suggestDatabases: { appendDot: true },
+              suggestKeywords: ['TABLE' ]
+            }
+          });
+        });
+
+        it('should suggest identifier for "with t1 as (select 1), t2 as (select 2) insert into tab select * from |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'with t1 as (select 1), t2 as (select 2) insert into tab select * from ',
+            afterCursor: '',
+            dialect: 'impala',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: true,
+              suggestTables: {},
+              suggestDatabases: { appendDot: true },
+              suggestCommonTableExpressions: [{ name: 't1' },{ name: 't2' }],
+              commonTableExpressions: [{ alias: 't1', columns: [{ type: 'NUMBER' }] }, { alias: 't2', columns: [{ type: 'NUMBER' }] }]
+            }
+          });
         });
       });
+    });
 
-      it('should suggest keywords for "FROM baa.boo INSERT INTO TABLE baa PARTITION (a,b) (x, z) SELECT c, d |"', function() {
-        assertAutoComplete({
-          beforeCursor: 'FROM baa.boo INSERT INTO TABLE baa PARTITION (a,b) (x, z) SELECT c, d ',
-          afterCursor: '',
-          dialect: 'hive',
-          noErrors: true,
-          containsColRefKeywords: true,
-          containsKeywords: ['WHERE', 'ORDER BY'],
-          doesNotContainKeywords: ['FROM'],
-          expectedResult: {
-            lowerCase: false,
-            colRef: { identifierChain: [{ name: 'baa' }, { name: 'boo' }, { name: 'd' }] }
-          }
-        });
-      });
+    describe('MERGE', function () {
 
-      it('should suggest keywords for "FROM baa.boo INSERT OVERWRITE bla.ble |"', function() {
+      it('should handle "MERGE INTO target AS T USING source AS S ON T.col = S.col ' +
+        ' WHEN MATCHED AND (S.col2 IS NOT NULL) THEN UPDATE SET col2 = S.col' +
+        ' WHEN MATCHED AND S.col2 IS NULL THEN DELETE' +
+        ' WHEN NOT MATCHED THEN INSERT VALUES (S.col, S.col2);"', function() {
         assertAutoComplete({
-          beforeCursor: 'FROM baa.boo INSERT OVERWRITE bla.ble ',
+          beforeCursor: 'MERGE INTO target AS T USING source AS S ON T.col = S.col\n' +
+          ' WHEN MATCHED AND (S.col2 IS NOT NULL) THEN UPDATE SET col2 = S.col\n' +
+          ' WHEN MATCHED AND S.col2 IS NULL THEN DELETE\n' +
+          ' WHEN NOT MATCHED THEN INSERT VALUES (S.col, S.col2);',
           afterCursor: '',
           dialect: 'hive',
+          containsKeywords: ['SELECT'],
           noErrors: true,
           expectedResult: {
-            lowerCase: false,
-            suggestKeywords: ['PARTITION', 'SELECT']
+            lowerCase: false
           }
         });
       });
 
-      it('should suggest keywords for "FROM baa.boo INSERT OVERWRITE bla.ble |"', function() {
+      it('should suggest keywords for "|"', function() {
         assertAutoComplete({
-          beforeCursor: 'FROM baa.boo INSERT OVERWRITE bla.ble ',
+          beforeCursor: '',
           afterCursor: '',
           dialect: 'hive',
+          containsKeywords: ['MERGE'],
           noErrors: true,
           expectedResult: {
-            lowerCase: false,
-            suggestKeywords: ['PARTITION', 'SELECT']
-          }
-        });
-      });
-
-      it('should suggest columns for "FROM baa.boo INSERT OVERWRITE bla.ble PARTITION (|"', function() {
-        assertAutoComplete({
-          beforeCursor: 'FROM baa.boo INSERT OVERWRITE bla.ble PARTITION (',
-          afterCursor: '',
-          dialect: 'hive',
-          expectedResult: {
-            lowerCase: false,
-            suggestColumns: { tables: [{ identifierChain: [{ name: 'bla' }, { name: 'ble' }] }] }
+            lowerCase: false
           }
         });
       });
 
-      it('should suggest keywords for "FROM baa.boo INSERT OVERWRITE bla.ble PARTITION (a, b) |"', function() {
+      it('should suggest keywords for "MERGE |"', function() {
         assertAutoComplete({
-          beforeCursor: 'FROM baa.boo INSERT OVERWRITE bla.ble PARTITION (a, b) ',
+          beforeCursor: 'MERGE ',
           afterCursor: '',
           dialect: 'hive',
           noErrors: true,
           expectedResult: {
             lowerCase: false,
-            suggestKeywords: ['IF NOT EXISTS', 'SELECT']
+            suggestKeywords: ['INTO']
           }
         });
       });
 
-      it('should suggest keywords for "FROM baa.boo INSERT OVERWRITE bla.ble PARTITION (a, b) IF |"', function() {
+      it('should suggest tables for "MERGE INTO |"', function() {
         assertAutoComplete({
-          beforeCursor: 'FROM baa.boo INSERT OVERWRITE bla.ble PARTITION (a, b) IF ',
+          beforeCursor: 'MERGE INTO ',
           afterCursor: '',
           dialect: 'hive',
           noErrors: true,
           expectedResult: {
             lowerCase: false,
-            suggestKeywords: ['NOT EXISTS']
-          }
+            suggestDatabases: { appendDot: true },
+            suggestTables: {}
+            }
         });
       });
 
-      it('should suggest keywords for "FROM baa.boo INSERT OVERWRITE bla.ble PARTITION (a, b) IF NOT |"', function() {
+      it('should suggest keywords for "MERGE INTO tbl |"', function() {
         assertAutoComplete({
-          beforeCursor: 'FROM baa.boo INSERT OVERWRITE bla.ble PARTITION (a, b) IF NOT ',
+          beforeCursor: 'MERGE INTO tbl ',
           afterCursor: '',
           dialect: 'hive',
           noErrors: true,
           expectedResult: {
             lowerCase: false,
-            suggestKeywords: ['EXISTS']
+            suggestKeywords: ['AS T USING']
           }
         });
       });
 
-      it('should suggest keywords for "FROM baa.boo INSERT OVERWRITE bla.ble PARTITION (a, b) IF NOT EXISTS |"', function() {
+      it('should suggest keywords for "MERGE INTO tbl AS |"', function() {
         assertAutoComplete({
-          beforeCursor: 'FROM baa.boo INSERT OVERWRITE bla.ble PARTITION (a, b) IF NOT EXISTS ',
+          beforeCursor: 'MERGE INTO tbl AS ',
           afterCursor: '',
           dialect: 'hive',
           noErrors: true,
           expectedResult: {
             lowerCase: false,
-            suggestKeywords: ['SELECT']
+            suggestKeywords: ['T USING']
           }
         });
       });
 
-      it('should suggest columns for "FROM baa.boo INSERT OVERWRITE bla.ble PARTITION (a, b) IF NOT EXISTS SELECT |"', function() {
+      it('should suggest keywords for "MERGE INTO tbl AS T |"', function() {
         assertAutoComplete({
-          beforeCursor: 'FROM baa.boo INSERT OVERWRITE bla.ble PARTITION (a, b) IF NOT EXISTS SELECT ',
+          beforeCursor: 'MERGE INTO tbl AS T ',
           afterCursor: '',
           dialect: 'hive',
           noErrors: true,
-          containsKeywords: ['*'],
           expectedResult: {
             lowerCase: false,
-            suggestFunctions: {},
-            suggestAggregateFunctions: { tables: [{ identifierChain: [{ name: 'baa' }, { name: 'boo' }] }] },
-            suggestAnalyticFunctions: true,
-            suggestColumns: { tables: [{ identifierChain: [{ name: 'baa' }, { name: 'boo' }] }] }
+            suggestKeywords: ['USING']
           }
         });
       });
 
-      it('should suggest keywords for "FROM baa.boo INSERT OVERWRITE bla.ble SELECT c, d |"', function() {
+      it('should suggest tables for "MERGE INTO tbl AS T USING |"', function() {
         assertAutoComplete({
-          beforeCursor: 'FROM baa.boo INSERT OVERWRITE bla.ble SELECT c, d ',
+          beforeCursor: 'MERGE INTO tbl AS T USING ',
           afterCursor: '',
           dialect: 'hive',
           noErrors: true,
-          containsColRefKeywords: true,
-          containsKeywords: ['WHERE', 'ORDER BY'],
-          doesNotContainKeywords: ['FROM'],
           expectedResult: {
             lowerCase: false,
-            colRef: { identifierChain: [{ name: 'baa' }, { name: 'boo' }, { name: 'd' }] }
+            suggestDatabases: { appendDot: true },
+            suggestTables: {}
           }
         });
       });
 
-      it('should suggest keywords for "FROM baa.boo INSERT OVERWRITE bla.ble SELECT c, d INSERT OVERWRITE bla.ble SELECT a |"', function() {
+      it('should suggest keywords for "MERGE INTO tbl AS T USING (|"', function() {
         assertAutoComplete({
-          beforeCursor: 'FROM baa.boo INSERT OVERWRITE bla.ble SELECT c, d INSERT OVERWRITE bla.ble SELECT a ',
+          beforeCursor: 'MERGE INTO tbl AS T USING (',
           afterCursor: '',
           dialect: 'hive',
-          noErrors: true,
-          containsColRefKeywords: true,
-          containsKeywords: ['WHERE', 'ORDER BY'],
-          doesNotContainKeywords: ['FROM'],
           expectedResult: {
             lowerCase: false,
-            colRef: { identifierChain: [{ name: 'baa' }, { name: 'boo' }, { name: 'a' }] }
+            suggestKeywords: ['SELECT']
           }
         });
       });
 
-      it('should suggest columns for "FROM baa.boo SELECT |"', function() {
+      it('should suggest keywords for "MERGE INTO tbl AS T USING db.tbl2 |"', function() {
         assertAutoComplete({
-          beforeCursor: 'FROM baa.boo SELECT ',
+          beforeCursor: 'MERGE INTO tbl AS T USING db.tbl2 ',
           afterCursor: '',
           dialect: 'hive',
           noErrors: true,
-          containsKeywords: ['*'],
           expectedResult: {
             lowerCase: false,
-            suggestFunctions: {},
-            suggestAggregateFunctions: { tables: [{ identifierChain: [{ name: 'baa' }, { name: 'boo' }] }] },
-            suggestAnalyticFunctions: true,
-            suggestColumns: { tables: [{ identifierChain: [{ name: 'baa' }, { name: 'boo' }] }] }
+            suggestKeywords: ['AS S ON']
           }
         });
       });
 
-      it('should suggest keywords for "FROM baa.boo SELECT c, d |"', function() {
+      it('should suggest keywords for "MERGE INTO tbl AS T USING db.tbl2 AS |"', function() {
         assertAutoComplete({
-          beforeCursor: 'FROM baa.boo SELECT c, d ',
+          beforeCursor: 'MERGE INTO tbl AS T USING db.tbl2 AS ',
           afterCursor: '',
           dialect: 'hive',
           noErrors: true,
-          containsColRefKeywords: true,
-          containsKeywords: ['WHERE', 'ORDER BY'],
-          doesNotContainKeywords: ['FROM'],
           expectedResult: {
             lowerCase: false,
-            colRef: { identifierChain: [{ name: 'baa' }, { name: 'boo' }, { name: 'd' }] }
+            suggestKeywords: ['S ON']
           }
         });
       });
 
-      it('should suggest keywords for "INSERT |"', function() {
+      it('should suggest keywords for "MERGE INTO tbl AS T USING db.tbl2 AS S |"', function() {
         assertAutoComplete({
-          beforeCursor: 'INSERT ',
+          beforeCursor: 'MERGE INTO tbl AS T USING db.tbl2 AS S ',
           afterCursor: '',
           dialect: 'hive',
           noErrors: true,
           expectedResult: {
             lowerCase: false,
-            suggestKeywords: ['INTO', 'OVERWRITE']
+            suggestKeywords: ['ON']
           }
         });
       });
 
-      it('should suggest tables for "INSERT INTO |"', function() {
+      it('should suggest columns for "MERGE INTO tbl AS T USING db.tbl2 AS S ON |"', function() {
         assertAutoComplete({
-          beforeCursor: 'INSERT INTO ',
+          beforeCursor: 'MERGE INTO tbl AS T USING db.tbl2 AS S ON ',
           afterCursor: '',
           dialect: 'hive',
           noErrors: true,
           expectedResult: {
             lowerCase: false,
-            suggestTables: {},
-            suggestDatabases: { appendDot: true },
-            suggestKeywords: ['TABLE']
+            suggestColumns: { tables: [{ identifierChain: [{ name: 'db' }, { name: 'tbl2' }], alias: 'S' }, { identifierChain: [{ name: 'tbl' }], alias: 'T' }] },
+            suggestFunctions: {},
+            suggestKeywords: ['CASE', 'EXISTS', 'NOT', 'NULL'],
+            suggestIdentifiers: [{ name: 'S.', type: 'alias' }, { name: 'T.', type: 'alias' }]
           }
         });
       });
 
-      it('should suggest tables for "INSERT INTO baa.|"', function() {
+      it('should suggest keywords for "MERGE INTO tbl AS T USING db.tbl2 AS S ON T.foo = S.bar |"', function() {
         assertAutoComplete({
-          beforeCursor: 'INSERT INTO baa.',
+          beforeCursor: 'MERGE INTO tbl AS T USING db.tbl2 AS S ON T.foo = S.bar  ',
           afterCursor: '',
           dialect: 'hive',
           noErrors: true,
+          containsKeywords: ['WHEN', 'OR'],
           expectedResult: {
-            lowerCase: false,
-            suggestTables: { identifierChain: [{ name: 'baa' }] }
+            lowerCase: false
           }
         });
       });
 
-      it('should suggest keywords for "INSERT INTO TABLE baa |"', function() {
+      it('should suggest keywords for "MERGE INTO tbl AS T USING db.tbl2 AS S ON T.foo = S.bar WHEN |"', function() {
         assertAutoComplete({
-          beforeCursor: 'INSERT INTO TABLE baa ',
+          beforeCursor: 'MERGE INTO tbl AS T USING db.tbl2 AS S ON T.foo = S.bar WHEN ',
           afterCursor: '',
           dialect: 'hive',
           noErrors: true,
           expectedResult: {
             lowerCase: false,
-            suggestKeywords: ['PARTITION', 'VALUES', 'SELECT']
-          }
-        });
-      });
-
-      it('should suggest columns for "INSERT INTO TABLE baa PARTITION (|"', function() {
-        assertAutoComplete({
-          beforeCursor: 'INSERT INTO TABLE baa PARTITION (',
-          afterCursor: '',
-          dialect: 'hive',
-          expectedResult: {
-            lowerCase: false,
-            suggestColumns: { tables: [{ identifierChain: [{ name: 'baa' }] }] }
-          }
-        });
-      });
-
-      it('should suggest columns for "INSERT INTO TABLE baa PARTITION (a,b) (x, |"', function() {
-        assertAutoComplete({
-          beforeCursor: 'INSERT INTO TABLE baa PARTITION (a,b) (x, ',
-          afterCursor: '',
-          dialect: 'hive',
-          expectedResult: {
-            lowerCase: false,
-            suggestColumns: { tables: [{ identifierChain: [{ name: 'baa' }] }] }
-          }
-        });
-      });
-
-      it('should suggest keywords for "insert into table baa partition (a,b) (x, z) |"', function() {
-        assertAutoComplete({
-          beforeCursor: 'insert into table baa partition (a,b) (x, z) ',
-          afterCursor: '',
-          dialect: 'hive',
-          noErrors: true,
-          expectedResult: {
-            lowerCase: true,
-            suggestKeywords: ['SELECT']
+            suggestKeywords: ['MATCHED', 'NOT MATCHED']
           }
         });
       });
 
-      it('should suggest columns for "INSERT INTO TABLE baa PARTITION (a,b) (x, z) SELECT |"', function() {
+      it('should suggest keywords for "MERGE INTO tbl AS T USING db.tbl2 AS S ON T.foo = S.bar WHEN NOT |"', function() {
         assertAutoComplete({
-          beforeCursor: 'INSERT INTO TABLE baa PARTITION (a,b) (x, z) SELECT ',
+          beforeCursor: 'MERGE INTO tbl AS T USING db.tbl2 AS S ON T.foo = S.bar WHEN NOT ',
           afterCursor: '',
           dialect: 'hive',
           noErrors: true,
-          containsKeywords: ['*'],
           expectedResult: {
             lowerCase: false,
-            suggestFunctions: {},
-            suggestAggregateFunctions: { tables: [] },
-            suggestAnalyticFunctions: true,
-            suggestTables: { prependFrom: true, prependQuestionMark: true },
-            suggestDatabases:  { prependFrom: true, prependQuestionMark: true, appendDot: true }
+            suggestKeywords: ['MATCHED']
           }
         });
       });
 
-      it('should suggest columns for "INSERT INTO TABLE baa PARTITION (a,b) (x, z) SELECT c, |"', function() {
+      it('should suggest keywords for "MERGE INTO tbl AS T USING db.tbl2 AS S ON T.foo = S.bar WHEN MATCHED |"', function() {
         assertAutoComplete({
-          beforeCursor: 'INSERT INTO TABLE baa PARTITION (a,b) (x, z) SELECT c, ',
+          beforeCursor: 'MERGE INTO tbl AS T USING db.tbl2 AS S ON T.foo = S.bar WHEN MATCHED ',
           afterCursor: '',
           dialect: 'hive',
           noErrors: true,
           expectedResult: {
             lowerCase: false,
-            suggestFunctions: {},
-            suggestAggregateFunctions: { tables: [] },
-            suggestAnalyticFunctions: true,
-            suggestTables: { prependFrom: true, prependQuestionMark: true },
-            suggestDatabases:  { prependFrom: true, prependQuestionMark: true, appendDot: true }
+            suggestKeywords: ['AND', 'THEN']
           }
         });
       });
 
-      it('should suggest keywords for "INSERT INTO TABLE baa PARTITION (a,b) (x, z) SELECT c, d |"', function() {
+      it('should suggest keywords for "MERGE INTO tbl AS T USING db.tbl2 AS S ON T.foo = S.bar WHEN MATCHED AND (S.col2 IS NOT NULL) |"', function() {
         assertAutoComplete({
-          beforeCursor: 'INSERT INTO TABLE baa PARTITION (a,b) (x, z) SELECT c, d ',
+          beforeCursor: 'MERGE INTO tbl AS T USING db.tbl2 AS S ON T.foo = S.bar WHEN MATCHED AND (S.col2 IS NOT NULL) ',
           afterCursor: '',
           dialect: 'hive',
           noErrors: true,
-          containsKeywords: ['AS', 'IN'],
+          containsKeywords: ['AND', 'THEN'],
           expectedResult: {
-            lowerCase: false,
-            suggestTables: { prependFrom: true },
-            suggestDatabases:  { prependFrom: true, appendDot: true }
+            lowerCase: false
           }
         });
       });
 
-      it('should suggest tables for "INSERT OVERWRITE |"', function() {
+      it('should suggest keywords for "MERGE INTO tbl AS T USING db.tbl2 AS S ON T.foo = S.bar WHEN MATCHED THEN |"', function() {
         assertAutoComplete({
-          beforeCursor: 'INSERT OVERWRITE ',
+          beforeCursor: 'MERGE INTO tbl AS T USING db.tbl2 AS S ON T.foo = S.bar WHEN MATCHED THEN ',
           afterCursor: '',
           dialect: 'hive',
           noErrors: true,
           expectedResult: {
             lowerCase: false,
-            suggestTables: {},
-            suggestDatabases: { appendDot: true },
-            suggestKeywords: ['DIRECTORY', 'LOCAL DIRECTORY', 'TABLE' ]
+            suggestKeywords: ['DELETE', 'INSERT VALUES', 'UPDATE SET']
           }
         });
       });
 
-      it('should suggest tables for "INSERT OVERWRITE LOCAL |"', function() {
+      it('should suggest columns for "MERGE INTO tbl AS T USING db.tbl2 AS S ON T.foo = S.bar WHEN MATCHED THEN UPDATE SET |"', function() {
         assertAutoComplete({
-          beforeCursor: 'INSERT OVERWRITE LOCAL ',
+          beforeCursor: 'MERGE INTO tbl AS T USING db.tbl2 AS S ON T.foo = S.bar WHEN MATCHED THEN UPDATE SET ',
           afterCursor: '',
           dialect: 'hive',
           noErrors: true,
           expectedResult: {
             lowerCase: false,
-            suggestKeywords: ['DIRECTORY' ]
+            suggestColumns: { tables: [{ identifierChain: [{ name: 'db' }, { name: 'tbl2' }], alias: 'S' }, { identifierChain: [{ name: 'tbl' }], alias: 'T' }] },
+            suggestIdentifiers: [{ name: 'S.', type: 'alias' }, { name: 'T.', type: 'alias' }]
           }
         });
       });
 
-      it('should suggest hdfs for "INSERT OVERWRITE DIRECTORY \'|"', function() {
+      it('should suggest keywords for "MERGE INTO tbl AS T USING db.tbl2 AS S ON T.foo = S.bar WHEN MATCHED THEN UPDATE SET a = b |"', function() {
         assertAutoComplete({
-          beforeCursor: 'INSERT OVERWRITE DIRECTORY \'',
+          beforeCursor: 'MERGE INTO tbl AS T USING db.tbl2 AS S ON T.foo = S.bar WHEN MATCHED THEN UPDATE SET a = b ',
           afterCursor: '',
           dialect: 'hive',
           noErrors: true,
           expectedResult: {
             lowerCase: false,
-            suggestHdfs: { path: '' }
+            suggestKeywords: ['WHEN']
           }
         });
       });
 
-      it('should suggest keywords for "INSERT OVERWRITE DIRECTORY \'blabla\' |"', function() {
+      it('should not suggest keywords for "MERGE INTO tbl AS T USING db.tbl2 AS S ON T.foo = S.bar WHEN NOT MATCHED THEN UPDATE SET a = b |"', function() {
         assertAutoComplete({
-          beforeCursor: 'INSERT OVERWRITE DIRECTORY \'blabla\' ',
+          beforeCursor: 'MERGE INTO tbl AS T USING db.tbl2 AS S ON T.foo = S.bar WHEN NOT MATCHED THEN UPDATE SET a = b ',
           afterCursor: '',
           dialect: 'hive',
           noErrors: true,
           expectedResult: {
-            lowerCase: false,
-            suggestKeywords: ['SELECT']
+            lowerCase: false
           }
         });
       });
 
-      it('should suggest keywords for "INSERT OVERWRITE bla.ble |"', function() {
+      it('should suggest keywords for "MERGE INTO tbl AS T USING db.tbl2 AS S ON T.foo = S.bar WHEN MATCHED THEN UPDATE SET a = b WHEN MATCHED AND a = b THEN |"', function() {
         assertAutoComplete({
-          beforeCursor: 'INSERT OVERWRITE bla.ble ',
+          beforeCursor: 'MERGE INTO tbl AS T USING db.tbl2 AS S ON T.foo = S.bar WHEN MATCHED THEN UPDATE SET a = b WHEN MATCHED AND a = b THEN ',
           afterCursor: '',
           dialect: 'hive',
           noErrors: true,
           expectedResult: {
             lowerCase: false,
-            suggestKeywords: ['PARTITION', 'SELECT']
+            suggestKeywords: ['DELETE', 'INSERT VALUES']
           }
         });
       });
 
-      it('should suggest keywords for "INSERT OVERWRITE bla.ble |"', function() {
+      it('should suggest keywords for "MERGE INTO tbl AS T USING db.tbl2 AS S ON T.foo = S.bar WHEN MATCHED THEN UPDATE SET a = b WHEN MATCHED AND a = b THEN DELETE ' +
+        'WHEN MATCHED THEN |"', function() {
         assertAutoComplete({
-          beforeCursor: 'INSERT OVERWRITE bla.ble ',
+          beforeCursor: 'MERGE INTO tbl AS T USING db.tbl2 AS S ON T.foo = S.bar WHEN MATCHED THEN UPDATE SET a = b WHEN MATCHED AND a = b THEN DELETE ' +
+          'WHEN MATCHED THEN ',
           afterCursor: '',
           dialect: 'hive',
           noErrors: true,
           expectedResult: {
             lowerCase: false,
-            suggestKeywords: ['PARTITION', 'SELECT']
+            suggestKeywords: ['INSERT VALUES']
           }
         });
       });
 
-      it('should suggest columns for "INSERT OVERWRITE bla.ble PARTITION (|"', function() {
+      it('should suggest keywords for "MERGE INTO tbl AS T USING db.tbl2 AS S ON T.foo = S.bar WHEN MATCHED THEN UPDATE SET a = b WHEN MATCHED AND a = b THEN DELETE ' +
+        'WHEN MATCHED THEN |"', function() {
         assertAutoComplete({
-          beforeCursor: 'INSERT OVERWRITE bla.ble PARTITION (',
+          beforeCursor: 'MERGE INTO tbl AS T USING db.tbl2 AS S ON T.foo = S.bar WHEN MATCHED THEN UPDATE SET a = b WHEN MATCHED AND a = b THEN DELETE ' +
+          'WHEN MATCHED THEN INSERT ',
           afterCursor: '',
           dialect: 'hive',
+          noErrors: true,
           expectedResult: {
             lowerCase: false,
-            suggestColumns: { tables: [{ identifierChain: [{ name: 'bla' }, { name: 'ble' }] }] }
+            suggestKeywords: ['VALUES']
           }
         });
       });
 
-      it('should suggest keywords for "INSERT OVERWRITE bla.ble PARTITION (a, b) |"', function() {
+      it('should not suggest keywords for "MERGE INTO tbl AS T USING db.tbl2 AS S ON T.foo = S.bar WHEN MATCHED THEN UPDATE SET a = b WHEN NOT MATCHED AND a = b THEN DELETE |"', function() {
         assertAutoComplete({
-          beforeCursor: 'INSERT OVERWRITE bla.ble PARTITION (a, b) ',
+          beforeCursor: 'MERGE INTO tbl AS T USING db.tbl2 AS S ON T.foo = S.bar WHEN MATCHED THEN UPDATE SET a = b WHEN NOT MATCHED AND a = b THEN DELETE ',
           afterCursor: '',
           dialect: 'hive',
           noErrors: true,
           expectedResult: {
-            lowerCase: false,
-            suggestKeywords: ['IF NOT EXISTS', 'SELECT']
+            lowerCase: false
           }
         });
       });
-
-      it('should suggest keywords for "INSERT OVERWRITE bla.ble PARTITION (a, b) IF |"', function() {
-        assertAutoComplete({
-          beforeCursor: 'INSERT OVERWRITE bla.ble PARTITION (a, b) IF ',
-          afterCursor: '',
-          dialect: 'hive',
-          noErrors: true,
-          expectedResult: {
-            lowerCase: false,
-            suggestKeywords: ['NOT EXISTS']
-          }
-        });
-      });
-
-      it('should suggest keywords for "INSERT OVERWRITE bla.ble PARTITION (a, b) IF NOT |"', function() {
-        assertAutoComplete({
-          beforeCursor: 'INSERT OVERWRITE bla.ble PARTITION (a, b) IF NOT ',
-          afterCursor: '',
-          dialect: 'hive',
-          noErrors: true,
-          expectedResult: {
-            lowerCase: false,
-            suggestKeywords: ['EXISTS']
-          }
-        });
-      });
-
-      it('should suggest keywords for "INSERT OVERWRITE bla.ble PARTITION (a, b) IF NOT EXISTS |"', function() {
-        assertAutoComplete({
-          beforeCursor: 'INSERT OVERWRITE bla.ble PARTITION (a, b) IF NOT EXISTS ',
-          afterCursor: '',
-          dialect: 'hive',
-          noErrors: true,
-          expectedResult: {
-            lowerCase: false,
-            suggestKeywords: ['SELECT']
-          }
-        });
-      });
-
-      it('should suggest columns for "INSERT OVERWRITE bla.ble PARTITION (a, b) IF NOT EXISTS SELECT |"', function() {
-        assertAutoComplete({
-          beforeCursor: 'INSERT OVERWRITE bla.ble PARTITION (a, b) IF NOT EXISTS SELECT ',
-          afterCursor: '',
-          dialect: 'hive',
-          noErrors: true,
-          containsKeywords: ['*'],
-          expectedResult: {
-            lowerCase: false,
-            suggestFunctions: {},
-            suggestAggregateFunctions: { tables: [] },
-            suggestAnalyticFunctions: true,
-            suggestTables: { prependFrom: true, prependQuestionMark: true },
-            suggestDatabases:  { prependFrom: true, prependQuestionMark: true, appendDot: true }
-          }
-        });
-      });
-
-      it('should suggest keywords for "INSERT OVERWRITE bla.ble SELECT c, d |"', function() {
-        assertAutoComplete({
-          beforeCursor: 'INSERT OVERWRITE bla.ble SELECT c, d ',
-          afterCursor: '',
-          dialect: 'hive',
-          noErrors: true,
-          containsKeywords: ['AS', 'IN'],
-          expectedResult: {
-            lowerCase: false,
-            suggestTables: { prependFrom: true },
-            suggestDatabases:  { prependFrom: true, appendDot: true }
-          }
-        });
-      });
-
-      it('should suggest identifier for "WITH t1 AS (SELECT 1), t2 AS (SELECT 2) INSERT INTO tab SELECT * FROM |"', function() {
-        assertAutoComplete({
-          beforeCursor: 'WITH t1 AS (SELECT 1), t2 AS (SELECT 2) INSERT INTO tab SELECT * FROM ',
-          afterCursor: '',
-          dialect: 'hive',
-          noErrors: true,
-          expectedResult: {
-            lowerCase: false,
-            suggestTables: {},
-            suggestDatabases: { appendDot: true },
-            suggestCommonTableExpressions: [{ name: 't1' }, { name: 't2' }],
-            commonTableExpressions: [{ alias: 't1', columns: [{ type: 'NUMBER' }] }, { alias: 't2', columns: [{ type: 'NUMBER' }] }],
-          }
-        });
-      });
-    });
-
-    describe('Impala specific', function () {
-      it('should suggest keywords for "|"', function() {
-        assertAutoComplete({
-          beforeCursor: '',
-          afterCursor: '',
-          dialect: 'impala',
-          containsKeywords: ['UPSERT'],
-          noErrors: true,
-          expectedResult: {
-            lowerCase: false
-          }
-        });
-      });
-
-      it('should handle "UPSERT INTO TABLE boo.baa (a, b) VALUES (1, 2);|"', function() {
-        assertAutoComplete({
-          beforeCursor: 'UPSERT INTO TABLE boo.baa (a, b) VALUES (1, 2);',
-          afterCursor: '',
-          dialect: 'impala',
-          noErrors: true,
-          containsKeywords: ['SELECT'],
-          expectedResult: {
-            lowerCase: false
-          }
-        });
-      });
-
-      it('should handle "UPSERT INTO production_table SELECT * FROM staging_table WHERE c1 IS NOT NULL AND c2 > 0;|"', function() {
-        assertAutoComplete({
-          beforeCursor: 'UPSERT INTO production_table SELECT * FROM staging_table WHERE c1 IS NOT NULL AND c2 > 0;',
-          afterCursor: '',
-          dialect: 'impala',
-          noErrors: true,
-          containsKeywords: ['SELECT'],
-          expectedResult: {
-            lowerCase: false
-          }
-        });
-      });
-
-      it('should handle "UPSERT INTO boo.baa [SHUFFLE] SELECT * FROM bla;|"', function() {
-        assertAutoComplete({
-          beforeCursor: 'UPSERT INTO boo.baa [SHUFFLE] SELECT * FROM bla;',
-          afterCursor: '',
-          dialect: 'impala',
-          noErrors: true,
-          containsKeywords: ['SELECT'],
-          expectedResult: {
-            lowerCase: false
-          }
-        });
-      });
-
-      it('should handle "INSERT INTO TABLE boo.baa (a, b) PARTITION (a=1) VALUES (1, 2);|"', function() {
-        assertAutoComplete({
-          beforeCursor: 'INSERT INTO TABLE boo.baa (a, b) PARTITION (a=1) VALUES (1, 2);',
-          afterCursor: '',
-          dialect: 'impala',
-          noErrors: true,
-          containsKeywords: ['SELECT'],
-          expectedResult: {
-            lowerCase: false
-          }
-        });
-      });
-
-      it('should handle "INSERT OVERWRITE boo.baa [SHUFFLE] SELECT * FROM bla;|"', function() {
-        assertAutoComplete({
-          beforeCursor: 'INSERT OVERWRITE boo.baa [SHUFFLE] SELECT * FROM bla;',
-          afterCursor: '',
-          dialect: 'impala',
-          noErrors: true,
-          containsKeywords: ['SELECT'],
-          expectedResult: {
-            lowerCase: false
-          }
-        });
-      });
-
-      it('should handle "WITH t1 AS (SELECT 1), t2 AS (SELECT 2) INSERT OVERWRITE tab SELECT * FROM t1, t2;|"', function() {
-        assertAutoComplete({
-          beforeCursor: 'WITH t1 AS (SELECT 1), t2 AS (SELECT 2) INSERT OVERWRITE tab SELECT * FROM t1, t2;',
-          afterCursor: '',
-          dialect: 'impala',
-          noErrors: true,
-          containsKeywords: ['SELECT'],
-          expectedResult: {
-            lowerCase: false
-          }
-        });
-      });
-
-      it('should suggest keywords for "WITH t1 as (select 1), t2 as (select 2) |"', function() {
-        assertAutoComplete({
-          beforeCursor: 'WITH t1 as (select 1), t2 as (select 2) ',
-          afterCursor: '',
-          dialect: 'impala',
-          noErrors: true,
-          containsKeywords: ['INSERT'],
-          expectedResult: {
-            lowerCase: false
-          }
-        });
-      });
-
-      it('should suggest keywords for "UPSERT |"', function() {
-        assertAutoComplete({
-          beforeCursor: 'UPSERT ',
-          afterCursor: '',
-          dialect: 'impala',
-          noErrors: true,
-          expectedResult: {
-            lowerCase: false,
-            suggestKeywords: ['INTO']
-          }
-        });
-      });
-
-      it('should suggest tables for "UPSERT INTO |"', function() {
-        assertAutoComplete({
-          beforeCursor: 'UPSERT INTO ',
-          afterCursor: '',
-          dialect: 'impala',
-          noErrors: true,
-          expectedResult: {
-            lowerCase: false,
-            suggestTables: {},
-            suggestDatabases: { appendDot: true },
-            suggestKeywords: ['TABLE' ]
-          }
-        });
-      });
-
-      it('should suggest tables for "UPSERT INTO boo.|"', function() {
-        assertAutoComplete({
-          beforeCursor: 'UPSERT INTO boo.',
-          afterCursor: '',
-          dialect: 'impala',
-          noErrors: true,
-          expectedResult: {
-            lowerCase: false,
-            suggestTables: { identifierChain: [{ name: 'boo' }] }
-          }
-        });
-      });
-
-      it('should suggest keywords for "UPSERT INTO baa |"', function() {
-        assertAutoComplete({
-          beforeCursor: 'UPSERT INTO baa ',
-          afterCursor: '',
-          dialect: 'impala',
-          noErrors: true,
-          expectedResult: {
-            lowerCase: false,
-            suggestKeywords: ['[NOSHUFFLE]', '[SHUFFLE]', 'SELECT', 'VALUES']
-          }
-        });
-      });
-
-      it('should suggest tables for "UPSERT INTO baa [SHUFFLE] SELECT * FROM |"', function() {
-        assertAutoComplete({
-          beforeCursor: 'UPSERT INTO baa [SHUFFLE] SELECT * FROM ',
-          afterCursor: '',
-          dialect: 'impala',
-          noErrors: true,
-          expectedResult: {
-            lowerCase: false,
-            suggestTables: {},
-            suggestDatabases: { appendDot: true }
-          }
-        });
-      });
-
-      it('should suggest columns for "UPSERT INTO TABLE boo.baa (|"', function() {
-        assertAutoComplete({
-          beforeCursor: 'UPSERT INTO boo.baa (',
-          afterCursor: '',
-          dialect: 'impala',
-          expectedResult: {
-            lowerCase: false,
-            suggestColumns: { tables: [{ identifierChain: [{ name: 'boo' }, { name: 'baa' }] }] }
-          }
-        });
-      });
-
-      it('should suggest keywords for "INSERT |"', function() {
-        assertAutoComplete({
-          beforeCursor: 'INSERT ',
-          afterCursor: '',
-          dialect: 'impala',
-          noErrors: true,
-          expectedResult: {
-            lowerCase: false,
-            suggestKeywords: ['INTO', 'OVERWRITE' ]
-          }
-        });
-      });
-
-      it('should suggest tables for "INSERT INTO |"', function() {
-        assertAutoComplete({
-          beforeCursor: 'INSERT INTO ',
-          afterCursor: '',
-          dialect: 'impala',
-          noErrors: true,
-          expectedResult: {
-            lowerCase: false,
-            suggestTables: {},
-            suggestDatabases: { appendDot: true },
-            suggestKeywords: ['TABLE' ]
-          }
-        });
-      });
-
-      it('should suggest tables for "INSERT INTO boo.|"', function() {
-        assertAutoComplete({
-          beforeCursor: 'INSERT INTO boo.',
-          afterCursor: '',
-          dialect: 'impala',
-          noErrors: true,
-          expectedResult: {
-            lowerCase: false,
-            suggestTables: { identifierChain: [{ name: 'boo' }] }
-          }
-        });
-      });
-
-      it('should suggest keywords for "INSERT INTO baa |"', function() {
-        assertAutoComplete({
-          beforeCursor: 'INSERT INTO baa ',
-          afterCursor: '',
-          dialect: 'impala',
-          noErrors: true,
-          expectedResult: {
-            lowerCase: false,
-            suggestKeywords: ['PARTITION', '[NOSHUFFLE]', '[SHUFFLE]', 'SELECT', 'VALUES']
-          }
-        });
-      });
-
-      it('should suggest keywords for "INSERT INTO baa [SHUFFLE] |"', function() {
-        assertAutoComplete({
-          beforeCursor: 'INSERT INTO baa [SHUFFLE] ',
-          afterCursor: '',
-          dialect: 'impala',
-          noErrors: true,
-          expectedResult: {
-            lowerCase: false,
-            suggestKeywords: ['SELECT']
-          }
-        });
-      });
-
-      it('should suggest tables for "INSERT INTO baa [SHUFFLE] SELECT * FROM |"', function() {
-        assertAutoComplete({
-          beforeCursor: 'INSERT INTO baa [SHUFFLE] SELECT * FROM ',
-          afterCursor: '',
-          dialect: 'impala',
-          noErrors: true,
-          expectedResult: {
-            lowerCase: false,
-            suggestTables: {},
-            suggestDatabases: { appendDot: true }
-          }
-        });
-      });
-
-      it('should suggest columns for "INSERT INTO TABLE boo.baa (|"', function() {
-        assertAutoComplete({
-          beforeCursor: 'INSERT INTO boo.baa (',
-          afterCursor: '',
-          dialect: 'impala',
-          expectedResult: {
-            lowerCase: false,
-            suggestColumns: { tables: [{ identifierChain: [{ name: 'boo' }, { name: 'baa' }] }] }
-          }
-        });
-      });
-
-      it('should suggest columns for "INSERT INTO TABLE boo.baa (a, |"', function() {
-        assertAutoComplete({
-          beforeCursor: 'INSERT INTO boo.baa (a, ',
-          afterCursor: '',
-          dialect: 'impala',
-          expectedResult: {
-            lowerCase: false,
-            suggestColumns: { tables: [{ identifierChain: [{ name: 'boo' }, { name: 'baa' }] }] }
-          }
-        });
-      });
-
-      it('should suggest keywords for "WITH t1 as (select 1), t2 as (select 2) INSERT INTO baa (a, b) |"', function() {
-        assertAutoComplete({
-          beforeCursor: 'WITH t1 as (select 1), t2 as (select 2) INSERT INTO baa ',
-          afterCursor: '',
-          dialect: 'impala',
-          noErrors: true,
-          expectedResult: {
-            lowerCase: false,
-            suggestKeywords: ['PARTITION', '[NOSHUFFLE]', '[SHUFFLE]', 'SELECT', 'VALUES'],
-            commonTableExpressions: [{ alias: 't1', columns: [{ type: 'NUMBER' }] }, { alias: 't2', columns: [{ type: 'NUMBER' }] }]
-          }
-        });
-      });
-
-      it('should suggest columns for "INSERT INTO TABLE boo.baa (a, b) PARTITION(a = 1, |"', function() {
-        assertAutoComplete({
-          beforeCursor: 'INSERT INTO TABLE boo.baa (a, b) PARTITION(a = 1, ',
-          afterCursor: '',
-          dialect: 'impala',
-          expectedResult: {
-            lowerCase: false,
-            suggestColumns: { tables: [{ identifierChain: [{ name: 'boo' }, { name: 'baa' }] }] }
-          }
-        });
-      });
-
-      it('should not suggest keywords for "INSERT INTO TABLE boo.baa (a, b) VALUES (1, 2) |"', function() {
-        assertAutoComplete({
-          beforeCursor: 'INSERT INTO TABLE boo.baa (a, b) VALUES (1, 2) ',
-          afterCursor: '',
-          dialect: 'impala',
-          expectedResult: {
-            lowerCase: false
-          }
-        });
-      });
-
-      it('should suggest tables for "INSERT OVERWRITE |"', function() {
-        assertAutoComplete({
-          beforeCursor: 'INSERT OVERWRITE ',
-          afterCursor: '',
-          dialect: 'impala',
-          noErrors: true,
-          expectedResult: {
-            lowerCase: false,
-            suggestTables: {},
-            suggestDatabases: { appendDot: true },
-            suggestKeywords: ['TABLE' ]
-          }
-        });
-      });
-
-      it('should suggest identifier for "with t1 as (select 1), t2 as (select 2) insert into tab select * from |"', function() {
-        assertAutoComplete({
-          beforeCursor: 'with t1 as (select 1), t2 as (select 2) insert into tab select * from ',
-          afterCursor: '',
-          dialect: 'impala',
-          noErrors: true,
-          expectedResult: {
-            lowerCase: true,
-            suggestTables: {},
-            suggestDatabases: { appendDot: true },
-            suggestCommonTableExpressions: [{ name: 't1' },{ name: 't2' }],
-            commonTableExpressions: [{ alias: 't1', columns: [{ type: 'NUMBER' }] }, { alias: 't2', columns: [{ type: 'NUMBER' }] }]
-          }
-        });
-      });
-    });
+    })
   });
 })();

+ 1 - 1
desktop/core/src/desktop/static/desktop/js/autocomplete/spec/sqlSyntaxParserSpec.js

@@ -162,7 +162,7 @@
       it('should suggest expected words for "SLELECT "', function() {
         var result = sqlSyntaxParser.parseSyntax('SLELECT ', '', 'hive');
         expect(result).toBeTruthy();
-        expect(expectedToStrings(result.expected)).toEqual(['SELECT', 'DELETE', 'SET', 'ALTER', 'INSERT', 'RELOAD', 'ABORT', 'ANALYZE', 'CREATE', 'EXPLAIN', 'EXPORT', 'GRANT', 'IMPORT', 'LOAD', 'MSCK', 'REVOKE', 'SHOW', 'USE', 'DROP', 'FROM', 'TRUNCATE', 'UPDATE', 'WITH', 'DESCRIBE']);
+        expect(expectedToStrings(result.expected)).toEqual(['SELECT', 'DELETE', 'SET', 'ALTER', 'INSERT', 'RELOAD', 'ABORT', 'ANALYZE', 'CREATE', 'EXPLAIN', 'EXPORT', 'GRANT', 'IMPORT', 'LOAD', 'MERGE', 'MSCK', 'REVOKE', 'SHOW', 'USE', 'DROP', 'FROM', 'TRUNCATE', 'UPDATE', 'WITH', 'DESCRIBE']);
       });
     });
 

文件差異過大導致無法顯示
+ 0 - 0
desktop/core/src/desktop/static/desktop/js/autocomplete/sqlAutocompleteParser.js


+ 1 - 1
desktop/core/src/desktop/static/desktop/js/autocomplete/sqlParseSupport.js

@@ -1184,7 +1184,7 @@ var SqlParseSupport = (function () {
       }
 
       if (parser.isHive()) {
-        keywords = keywords.concat(['ABORT', 'ANALYZE TABLE', 'DELETE', 'EXPORT', 'IMPORT', 'LOAD', 'MSCK', 'RELOAD FUNCTION', 'RESET']);
+        keywords = keywords.concat(['ABORT', 'ANALYZE TABLE', 'DELETE', 'EXPORT', 'IMPORT', 'LOAD', 'MERGE', 'MSCK', 'RELOAD FUNCTION', 'RESET']);
       }
 
       if (parser.isImpala()) {

文件差異過大導致無法顯示
+ 0 - 0
desktop/core/src/desktop/static/desktop/js/autocomplete/sqlSyntaxParser.js


部分文件因文件數量過多而無法顯示