Parcourir la source

HUE-8856 [autocomplete] Extract jison for Impala lexer, ALTER, ANALYZE and CREATE

Johan Ahlen il y a 6 ans
Parent
commit
8c9108108a

+ 554 - 0
desktop/core/src/desktop/js/parse/jison/impala/sql.jisonlex

@@ -0,0 +1,554 @@
+// Licensed to Cloudera, Inc. under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  Cloudera, Inc. licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+%options case-insensitive flex
+%s between
+%x hdfs doubleQuotedValue singleQuotedValue backtickedValue
+%%
+
+\s                                         { /* skip whitespace */ }
+'--'.*                                     { /* skip comments */ }
+[/][*][^*]*[*]+([^/*][^*]*[*]+)*[/]        { /* skip comments */ }
+
+'\u2020'                                   { parser.yy.partialCursor = false; parser.yy.cursorFound = yylloc; return 'CURSOR'; }
+'\u2021'                                   { parser.yy.partialCursor = true; parser.yy.cursorFound = yylloc; return 'PARTIAL_CURSOR'; }
+
+// Reserved Keywords
+'ADD'                              { return 'ADD'; }
+'AGGREGATE'                        { return 'AGGREGATE'; }
+'ALL'                              { return 'ALL'; }
+'ALLOCATE'                         { return 'ALLOCATE'; }
+'ALTER'                            { parser.determineCase(yytext); parser.addStatementTypeLocation('ALTER', yylloc, yy.lexer.upcomingInput()); return 'ALTER'; }
+'ANALYTIC'                         { return 'ANALYTIC'; }
+'AND'                              { return 'AND'; }
+'ANTI'                             { return 'ANTI'; }
+'ANY'                              { return 'ANY'; }
+'ARE'                              { return 'ARE'; }
+'ARRAY_AGG'                        { return 'ARRAY_AGG'; }
+'ARRAY_MAX_CARDINALITY'            { return 'ARRAY_MAX_CARDINALITY'; }
+'AS'                               { return 'AS'; }
+'ASC'                              { return 'ASC'; }
+'ASENSITIVE'                       { return 'ASENSITIVE'; }
+'ASYMMETRIC'                       { return 'ASYMMETRIC'; }
+'AT'                               { return 'AT'; }
+'ATOMIC'                           { return 'ATOMIC'; }
+'AUTHORIZATION'                    { return 'AUTHORIZATION'; }
+'AVRO'                             { return 'AVRO'; }
+'BEGIN_FRAME'                      { return 'BEGIN_FRAME'; }
+'BEGIN_PARTITION'                  { return 'BEGIN_PARTITION'; }
+'BETWEEN'                          { this.begin('between'); return 'BETWEEN'; }
+'BIGINT'                           { return 'BIGINT'; }
+'BLOB'                             { return 'BLOB'; }
+'BLOCK_SIZE'                       { return 'BLOCK_SIZE'; }
+'BOOLEAN'                          { return 'BOOLEAN'; }
+'BOTH'                             { return 'BOTH'; }
+'BY'                               { return 'BY'; }
+'CACHED'                           { return 'CACHED'; }
+'CALLED'                           { return 'CALLED'; }
+'CARDINALITY'                      { return 'CARDINALITY'; }
+'CASCADE'                          { return 'CASCADE'; }
+'CASCADED'                         { return 'CASCADED'; }
+'CASE'                             { return 'CASE'; }
+'CHANGE'                           { return 'CHANGE'; }
+'CHAR'                             { return 'CHAR'; }
+'CHARACTER'                        { return 'CHARACTER'; }
+'CLOB'                             { return 'CLOB'; }
+'CLOSE_FN'                         { return 'CLOSE_FN'; }
+'COLLATE'                          { return 'COLLATE'; }
+'COLLECT'                          { return 'COLLECT'; }
+'COLUMN'                           { return 'COLUMN'; }
+'COLUMNS'                          { return 'COLUMNS'; }
+'COMMENT'                          { parser.determineCase(yytext); return 'COMMENT'; }
+'COMMIT'                           { return 'COMMIT'; }
+'COMPRESSION'                      { return 'COMPRESSION'; }
+'COMPUTE'                          { parser.determineCase(yytext); return 'COMPUTE'; }
+'CONDITION'                        { return 'CONDITION'; }
+'CONNECT'                          { return 'CONNECT'; }
+'CONSTRAINT'                       { return 'CONSTRAINT'; }
+'CONTAINS'                         { return 'CONTAINS'; }
+'CONVERT'                          { return 'CONVERT'; }
+'COPY'                             { return 'COPY'; }
+'CORR'                             { return 'CORR'; }
+'CORRESPONDING'                    { return 'CORRESPONDING'; }
+'COVAR_POP'                        { return 'COVAR_POP'; }
+'COVAR_SAMP'                       { return 'COVAR_SAMP'; }
+'CREATE'                           { parser.determineCase(yytext); parser.addStatementTypeLocation('CREATE', yylloc, yy.lexer.upcomingInput()); return 'CREATE'; }
+'CREATE'                           { parser.determineCase(yytext); return 'CREATE'; }
+'CROSS'                            { return 'CROSS'; }
+'CUBE'                             { return 'CUBE'; }
+'CURRENT'                          { return 'CURRENT'; }
+'CURRENT'                          { return 'CURRENT'; }
+'CURRENT_DATE'                     { return 'CURRENT_DATE'; }
+'CURRENT_DEFAULT_TRANSFORM_GROUP'  { return 'CURRENT_DEFAULT_TRANSFORM_GROUP'; }
+'CURRENT_PATH'                     { return 'CURRENT_PATH'; }
+'CURRENT_ROLE'                     { return 'CURRENT_ROLE'; }
+'CURRENT_ROW'                      { return 'CURRENT_ROW'; }
+'CURRENT_SCHEMA'                   { return 'CURRENT_SCHEMA'; }
+'CURRENT_TIME'                     { return 'CURRENT_TIME'; }
+'CURRENT_TRANSFORM_GROUP_FOR_TYPE' { return 'CURRENT_TRANSFORM_GROUP_FOR_TYPE'; }
+'CURSOR'                           { return 'CURSOR'; }
+'CYCLE'                            { return 'CYCLE'; }
+'DATA'                             { return 'DATA'; }
+'DATABASE'                         { return 'DATABASE'; }
+'DATABASES'                        { return 'DATABASES'; }
+'DEALLOCATE'                       { return 'DEALLOCATE'; }
+'DEC'                              { return 'DEC'; }
+'DECFLOAT'                         { return 'DECFLOAT'; }
+'DECIMAL'                          { return 'DECIMAL'; }
+'DECLARE'                          { return 'DECLARE'; }
+'DEFINE'                           { return 'DEFINE'; }
+'DELETE'                           { return 'DELETE'; }
+'DELIMITED'                        { return 'DELIMITED'; }
+'DEREF'                            { return 'DEREF'; }
+'DESC'                             { return 'DESC'; }
+'DESCRIBE'                         { parser.determineCase(yytext); parser.addStatementTypeLocation('DESCRIBE', yylloc); return 'DESCRIBE'; }
+'DETERMINISTIC'                    { return 'DETERMINISTIC'; }
+'DISCONNECT'                       { return 'DISCONNECT'; }
+'DISTINCT'                         { return 'DISTINCT'; }
+'DIV'                              { return 'ARITHMETIC_OPERATOR'; }
+'DOUBLE'                           { return 'DOUBLE'; }
+'DROP'                             { parser.determineCase(yytext); parser.addStatementTypeLocation('DROP', yylloc, yy.lexer.upcomingInput()); return 'DROP'; }
+'DYNAMIC'                          { return 'DYNAMIC'; }
+'EACH'                             { return 'EACH'; }
+'ELEMENT'                          { return 'ELEMENT'; }
+'ELSE'                             { return 'ELSE'; }
+'EMPTY'                            { return 'EMPTY'; }
+'ENCODING'                         { return 'ENCODING'; }
+'END'                              { return 'END'; }
+'END_FRAME'                        { return 'END_FRAME'; }
+'END_PARTITION'                    { return 'END_PARTITION'; }
+'EQUALS'                           { return 'EQUALS'; }
+'ESCAPE'                           { return 'ESCAPE'; }
+'ESCAPED'                          { return 'ESCAPED'; }
+'EVERY'                            { return 'EVERY'; }
+'EXCEPT'                           { return 'EXCEPT'; }
+'EXEC'                             { return 'EXEC'; }
+'EXECUTE'                          { return 'EXECUTE'; }
+'EXISTS'                           { parser.yy.correlatedSubQuery = true; return 'EXISTS'; }
+'EXPLAIN'                          { parser.determineCase(yytext); parser.addStatementTypeLocation('EXPLAIN', yylloc); return 'EXPLAIN'; }
+'EXTENDED'                         { return 'EXTENDED'; }
+'EXTERNAL'                         { return 'EXTERNAL'; }
+'FALSE'                            { return 'FALSE'; }
+'FETCH'                            { return 'FETCH'; }
+'FIELDS'                           { return 'FIELDS'; }
+'FILEFORMAT'                       { return 'FILEFORMAT'; }
+'FILES'                            { return 'FILES'; }
+'FILTER'                           { return 'FILTER'; }
+'FINALIZE_FN'                      { return 'FINALIZE_FN'; }
+'FIRST'                            { return 'FIRST'; }
+'FLOAT'                            { return 'FLOAT'; }
+'FOLLOWING'                        { return 'FOLLOWING'; }
+'FOR'                              { return 'FOR'; }
+'FOREIGN'                          { return 'FOREIGN'; }
+'FORMAT'                           { return 'FORMAT'; }
+'FORMATTED'                        { return 'FORMATTED'; }
+'FRAME_ROW'                        { return 'FRAME_ROW'; }
+'FREE'                             { return 'FREE'; }
+'FROM'                             { parser.determineCase(yytext); return 'FROM'; }
+'FULL'                             { return 'FULL'; }
+'FUNCTION'                         { return 'FUNCTION'; }
+'FUNCTIONS'                        { return 'FUNCTIONS'; }
+'FUSION'                           { return 'FUSION'; }
+'GET'                              { return 'GET'; }
+'GLOBAL'                           { return 'GLOBAL'; }
+'GRANT'                            { parser.determineCase(yytext); parser.addStatementTypeLocation('GRANT', yylloc); return 'GRANT'; }
+'GROUP'                            { return 'GROUP'; }
+'GROUP'                            { return 'GROUP'; }
+'GROUPING'                         { return 'GROUPING'; }
+'GROUPS'                           { return 'GROUPS'; }
+'HASH'                             { return 'HASH'; }
+'HAVING'                           { return 'HAVING'; }
+'HOLD'                             { return 'HOLD'; }
+'IF'                               { return 'IF'; }
+'IGNORE'                           { return 'IGNORE'; }
+'ILIKE'                            { return 'ILIKE'; }
+'IN'                               { return 'IN'; }
+'INCREMENTAL'                      { return 'INCREMENTAL'; }
+'INDICATOR'                        { return 'INDICATOR'; }
+'INIT_FN'                          { return 'INIT_FN'; }
+'INITIAL'                          { return 'INITIAL'; }
+'INNER'                            { return 'INNER'; }
+'INOUT'                            { return 'INOUT'; }
+'INPATH'                           { this.begin('hdfs'); return 'INPATH'; }
+'INSENSITIVE'                      { return 'INSENSITIVE'; }
+'INSERT'                           { parser.determineCase(yytext); parser.addStatementTypeLocation('INSERT', yylloc); return 'INSERT'; }
+'INSERT'                           { return 'INSERT'; }
+'INT'                              { return 'INT'; }
+'INTERMEDIATE'                     { return 'INTERMEDIATE'; }
+'INTERSECT'                        { return 'INTERSECT'; }
+'INTERSECTION'                     { return 'INTERSECTION'; }
+'INTERVAL'                         { return 'INTERVAL'; }
+'INTO'                             { return 'INTO'; }
+'INVALIDATE'                       { parser.determineCase(yytext); parser.addStatementTypeLocation('INVALIDATE', yylloc, yy.lexer.upcomingInput()); return 'INVALIDATE'; }
+'IREGEXP'                          { return 'IREGEXP'; }
+'IS'                               { return 'IS'; }
+'JOIN'                             { return 'JOIN'; }
+'JSON_ARRAY'                       { return 'JSON_ARRAY'; }
+'JSON_ARRAYAGG'                    { return 'JSON_ARRAYAGG'; }
+'JSON_EXISTS'                      { return 'JSON_EXISTS'; }
+'JSON_OBJECT'                      { return 'JSON_OBJECT'; }
+'JSON_OBJECTAGG'                   { return 'JSON_OBJECTAGG'; }
+'JSON_QUERY'                       { return 'JSON_QUERY'; }
+'JSON_TABLE'                       { return 'JSON_TABLE'; }
+'JSON_TABLE_PRIMITIVE'             { return 'JSON_TABLE_PRIMITIVE'; }
+'JSON_VALUE'                       { return 'JSON_VALUE'; }
+'KEY'                              { return 'KEY'; }
+'KUDU'                             { return 'KUDU'; }
+'LARGE'                            { return 'LARGE'; }
+'LAST'                             { return 'LAST'; }
+'LATERAL'                          { return 'LATERAL'; }
+'LEADING'                          { return 'LEADING'; }
+'LEFT'                             { return 'LEFT'; }
+'LIKE'                             { return 'LIKE'; }
+'LIKE_REGEX'                       { return 'LIKE_REGEX'; }
+'LIMIT'                            { return 'LIMIT'; }
+'LIMIT'                            { return 'LIMIT'; }
+'LINES'                            { return 'LINES'; }
+'LISTAGG'                          { return 'LISTAGG'; }
+'LOAD'                             { parser.determineCase(yytext); parser.addStatementTypeLocation('LOAD', yylloc, yy.lexer.upcomingInput()); return 'LOAD'; }
+'LOCAL'                            { return 'LOCAL'; }
+'LOCALTIMESTAMP'                   { return 'LOCALTIMESTAMP'; }
+'LOCATION'                         { this.begin('hdfs'); return 'LOCATION'; }
+'MATCH'                            { return 'MATCH'; }
+'MATCH_NUMBER'                     { return 'MATCH_NUMBER'; }
+'MATCH_RECOGNIZE'                  { return 'MATCH_RECOGNIZE'; }
+'MATCHES'                          { return 'MATCHES'; }
+'MERGE'                            { return 'MERGE'; }
+'MERGE_FN'                         { return 'MERGE_FN'; }
+'METADATA'                         { return 'METADATA'; }
+'METHOD'                           { return 'METHOD'; }
+'MODIFIES'                         { return 'MODIFIES'; }
+'MULTISET'                         { return 'MULTISET'; }
+'NATIONAL'                         { return 'NATIONAL'; }
+'NATURAL'                          { return 'NATURAL'; }
+'NCHAR'                            { return 'NCHAR'; }
+'NCLOB'                            { return 'NCLOB'; }
+'NO'                               { return 'NO'; }
+'NONE'                             { return 'NONE'; }
+'NORMALIZE'                        { return 'NORMALIZE'; }
+'NOT'                              { return 'NOT'; }
+'NTH_VALUE'                        { return 'NTH_VALUE'; }
+'NULL'                             { return 'NULL'; }
+'NULLS'                            { return 'NULLS'; }
+'NUMERIC'                          { return 'NUMERIC'; }
+'OCCURRENCES_REGEX'                { return 'OCCURRENCES_REGEX'; }
+'OCTET_LENGTH'                     { return 'OCTET_LENGTH'; }
+'OF'                               { return 'OF'; }
+'OFFSET'                           { return 'OFFSET'; }
+'OMIT'                             { return 'OMIT'; }
+'ON'                               { return 'ON'; }
+'ONE'                              { return 'ONE'; }
+'ONLY'                             { return 'ONLY'; }
+'OPTION'                           { return 'OPTION'; }
+'OR'                               { return 'OR'; }
+'ORC'                              { return 'ORC'; }
+'ORDER'                            { return 'ORDER'; }
+'OUT'                              { return 'OUT'; }
+'OUTER'                            { return 'OUTER'; }
+'OVER'                             { return 'OVER'; }
+'OVERLAPS'                         { return 'OVERLAPS'; }
+'OVERLAY'                          { return 'OVERLAY'; }
+'OVERWRITE'                        { return 'OVERWRITE'; }
+'PARQUET'                          { return 'PARQUET'; }
+'PARTITION'                        { return 'PARTITION'; }
+'PARTITIONED'                      { return 'PARTITIONED'; }
+'PARTITIONS'                       { return 'PARTITIONS'; }
+'PATTERN'                          { return 'PATTERN'; }
+'PER'                              { return 'PER'; }
+'PERCENT'                          { return 'PERCENT'; }
+'PERCENTILE_CONT'                  { return 'PERCENTILE_CONT'; }
+'PERCENTILE_DISC'                  { return 'PERCENTILE_DISC'; }
+'PORTION'                          { return 'PORTION'; }
+'POSITION'                         { return 'POSITION'; }
+'POSITION_REGEX'                   { return 'POSITION_REGEX'; }
+'PRECEDES'                         { return 'PRECEDES'; }
+'PRECEDING'                        { return 'PRECEDING'; }
+'PREPARE'                          { return 'PREPARE'; }
+'PREPARE_FN'                       { return 'PREPARE_FN'; }
+'PRIMARY'                          { return 'PRIMARY'; }
+'PROCEDURE'                        { return 'PROCEDURE'; }
+'PTF'                              { return 'PTF'; }
+'PURGE'                            { return 'PURGE'; }
+'RANGE'                            { return 'RANGE'; }
+'RANGE'                            { return 'RANGE'; }
+'RCFILE'                           { return 'RCFILE'; }
+'READS'                            { return 'READS'; }
+'REAL'                             { return 'REAL'; }
+'RECOVER'                          { return 'RECOVER'; }
+'RECURSIVE'                        { return 'RECURSIVE'; }
+'REF'                              { return 'REF'; }
+'REFERENCES'                       { return 'REFERENCES'; }
+'REFERENCING'                      { return 'REFERENCING'; }
+'REFRESH'                          { parser.determineCase(yytext); parser.addStatementTypeLocation('REFRESH', yylloc); return 'REFRESH'; }
+'REGEXP'                           { return 'REGEXP'; }
+'REGR_AVGX'                        { return 'REGR_AVGX'; }
+'REGR_AVGY'                        { return 'REGR_AVGY'; }
+'REGR_COUNT'                       { return 'REGR_COUNT'; }
+'REGR_INTERCEPT'                   { return 'REGR_INTERCEPT'; }
+'REGR_R2REGR_SLOPE'                { return 'REGR_R2REGR_SLOPE'; }
+'REGR_SXX'                         { return 'REGR_SXX'; }
+'REGR_SXY'                         { return 'REGR_SXY'; }
+'REGR_SYY'                         { return 'REGR_SYY'; }
+'RELEASE'                          { return 'RELEASE'; }
+'RENAME'                           { return 'RENAME'; }
+'REPEATABLE'                       { return 'REPEATABLE'; }
+'REPLACE'                          { return 'REPLACE'; }
+'REPLICATION'                      { return 'REPLICATION'; }
+'RESTRICT'                         { return 'RESTRICT'; }
+'RETURNS'                          { return 'RETURNS'; }
+'REVOKE'                           { parser.determineCase(yytext); parser.addStatementTypeLocation('REVOKE', yylloc); return 'REVOKE'; }
+'RIGHT'                            { return 'RIGHT'; }
+'RLIKE'                            { return 'RLIKE'; }
+'ROLE'                             { return 'ROLE'; }
+'ROLES'                            { return 'ROLES'; }
+'ROLLBACK'                         { return 'ROLLBACK'; }
+'ROLLUP'                           { return 'ROLLUP'; }
+'ROW'                              { return 'ROW'; }
+'ROWS'                             { return 'ROWS'; }
+'RUNNING'                          { return 'RUNNING'; }
+'SAVEPOINT'                        { return 'SAVEPOINT'; }
+'SCHEMA'                           { return 'SCHEMA'; }
+'SCHEMAS'                          { return 'SCHEMAS'; }
+'SCOPE'                            { return 'SCOPE'; }
+'SCROLL'                           { return 'SCROLL'; }
+'SEARCH'                           { return 'SEARCH'; }
+'SEEK'                             { return 'SEEK'; }
+'SELECT'                           { parser.determineCase(yytext); parser.addStatementTypeLocation('SELECT', yylloc); return 'SELECT'; }
+'SEMI'                             { return 'SEMI'; }
+'SENSITIVE'                        { return 'SENSITIVE'; }
+'SEQUENCEFILE'                     { return 'SEQUENCEFILE'; }
+'SERDEPROPERTIES'                  { return 'SERDEPROPERTIES'; }
+'SERIALIZE_FN'                     { return 'SERIALIZE_FN'; }
+'SERVER'                           { return 'SERVER'; }
+'SET'                              { parser.determineCase(yytext); parser.addStatementTypeLocation('SET', yylloc); return 'SET'; }
+'SHOW'                             { parser.determineCase(yytext); parser.addStatementTypeLocation('SHOW', yylloc); return 'SHOW'; }
+'SIMILAR'                          { return 'SIMILAR'; }
+'SKIP'                             { return 'SKIP'; }
+'SMALLINT'                         { return 'SMALLINT'; }
+'SOME'                             { return 'SOME'; }
+'SORT'                             { return 'SORT'; }
+'SPECIFIC'                         { return 'SPECIFIC'; }
+'SPECIFICTYPE'                     { return 'SPECIFICTYPE'; }
+'SQLEXCEPTION'                     { return 'SQLEXCEPTION'; }
+'SQLSTATE'                         { return 'SQLSTATE'; }
+'SQLWARNING'                       { return 'SQLWARNING'; }
+'STATIC'                           { return 'STATIC'; }
+'STATS'                            { return 'STATS'; }
+'STORED'                           { return 'STORED'; }
+'STRAIGHT_JOIN'                    { return 'STRAIGHT_JOIN'; }
+'STRING'                           { return 'STRING'; }
+'SUBMULTISET'                      { return 'SUBMULTISET'; }
+'SUBSET'                           { return 'SUBSET'; }
+'SUBSTRING_REGEX'                  { return 'SUBSTRING_REGEX'; }
+'SUCCEEDS'                         { return 'SUCCEEDS'; }
+'SYMBOL'                           { return 'SYMBOL'; }
+'SYMMETRIC'                        { return 'SYMMETRIC'; }
+'SYSTEM_TIME'                      { return 'SYSTEM_TIME'; }
+'SYSTEM_USER'                      { return 'SYSTEM_USER'; }
+'TABLE'                            { return 'TABLE'; }
+'TABLE'                            { return 'TABLE'; }
+'TABLES'                           { return 'TABLES'; }
+'TABLESAMPLE'                      { return 'TABLESAMPLE'; }
+'TBLPROPERTIES'                    { return 'TBLPROPERTIES'; }
+'TERMINATED'                       { return 'TERMINATED'; }
+'TEXTFILE'                         { return 'TEXTFILE'; }
+'THEN'                             { return 'THEN'; }
+'TIMESTAMP'                        { return 'TIMESTAMP'; }
+'TIMEZONE_HOUR'                    { return 'TIMEZONE_HOUR'; }
+'TIMEZONE_MINUTE'                  { return 'TIMEZONE_MINUTE'; }
+'TINYINT'                          { return 'TINYINT'; }
+'TO'                               { return 'TO'; }
+'TRAILING'                         { return 'TRAILING'; }
+'TRANSLATE_REGEX'                  { return 'TRANSLATE_REGEX'; }
+'TRANSLATION'                      { return 'TRANSLATION'; }
+'TREAT'                            { return 'TREAT'; }
+'TRIGGER'                          { return 'TRIGGER'; }
+'TRIM_ARRAY'                       { return 'TRIM_ARRAY'; }
+'TRUE'                             { return 'TRUE'; }
+'TRUNCATE'                         { parser.determineCase(yytext); parser.addStatementTypeLocation('TRUNCATE', yylloc, yy.lexer.upcomingInput()); return 'TRUNCATE'; }
+'UESCAPE'                          { return 'UESCAPE'; }
+'UNBOUNDED'                        { return 'UNBOUNDED'; }
+'UNCACHED'                         { return 'UNCACHED'; }
+'UNION'                            { return 'UNION'; }
+'UNIQUE'                           { return 'UNIQUE'; }
+'UNKNOWN'                          { return 'UNKNOWN'; }
+'UNNEST'                           { return 'UNNEST'; }
+'UPDATE'                           { parser.determineCase(yytext); return 'UPDATE'; }
+'UPDATE_FN'                        { return 'UPDATE_FN'; }
+'UPSERT'                           { parser.determineCase(yytext); parser.addStatementTypeLocation('UPSERT', yylloc); return 'UPSERT'; }
+'URI'                              { return 'URI'; }
+'USE'                              { parser.determineCase(yytext); parser.addStatementTypeLocation('USE', yylloc); return 'USE'; }
+'USER'                             { return 'USER'; }
+'USING'                            { return 'USING'; }
+'VALUE_OF'                         { return 'VALUE_OF'; }
+'VALUES'                           { return 'VALUES'; }
+'VARBINARY'                        { return 'VARBINARY'; }
+'VARCHAR'                          { return 'VARCHAR'; }
+'VARCHAR'                          { return 'VARCHAR'; } // Not in Impala
+'VARYING'                          { return 'VARYING'; }
+'VERSIONING'                       { return 'VERSIONING'; }
+'VIEW'                             { return 'VIEW'; }
+'WHEN'                             { return 'WHEN'; }
+'WHENEVER'                         { return 'WHENEVER'; }
+'WHERE'                            { return 'WHERE'; }
+'WIDTH_BUCKET'                     { return 'WIDTH_BUCKET'; }
+'WINDOW'                           { return 'WINDOW'; }
+'WITH'                             { parser.determineCase(yytext); parser.addStatementTypeLocation('WITH', yylloc); return 'WITH'; }
+'WITH'                             { parser.determineCase(yytext); parser.addStatementTypeLocation('WITH', yylloc); return 'WITH'; }
+'WITHIN'                           { return 'WITHIN'; }
+'WITHOUT'                          { return 'WITHOUT'; }
+LIKE\s+PARQUET                     { this.begin('hdfs'); return 'LIKE_PARQUET'; }
+PARTITION\s+VALUE\s                { return 'PARTITION_VALUE'; }
+
+// Non-reserved Keywords
+'ARRAY'                            { return 'ARRAY'; }
+'DEFAULT'                          { return 'DEFAULT'; }
+'MAP'                              { return 'MAP'; }
+'OVER'                             { return 'OVER'; }
+'OWNER'                            { return 'OWNER'; }
+'ROLE'                             { return 'ROLE'; }
+'STRUCT'                           { return 'STRUCT'; }
+\[BROADCAST\]                      { return 'BROADCAST'; }
+\[NOSHUFFLE\]                      { return 'NOSHUFFLE'; }
+\[SHUFFLE\]                        { return 'SHUFFLE'; }
+
+'...'                              { return '...'; }
+'.'                                { return '.'; }
+'['                                { return '['; }
+']'                                { return ']'; }
+
+<between>'AND'                     { this.popState(); return 'BETWEEN_AND'; }
+
+// Reserved Keywords
+
+// Non-reserved Keywords
+
+
+// --- UDFs ---
+APPX_MEDIAN\s*\(                   { yy.lexer.unput('('); yytext = 'appx_median'; parser.addFunctionLocation(yylloc, yytext); return 'APPX_MEDIAN'; }
+AVG\s*\(                           { yy.lexer.unput('('); yytext = 'avg'; parser.addFunctionLocation(yylloc, yytext); return 'AVG'; }
+CAST\s*\(                          { yy.lexer.unput('('); yytext = 'cast'; parser.addFunctionLocation(yylloc, yytext); return 'CAST'; }
+COUNT\s*\(                         { yy.lexer.unput('('); yytext = 'count'; parser.addFunctionLocation(yylloc, yytext); return 'COUNT'; }
+EXTRACT\s*\(                       { yy.lexer.unput('('); yytext = 'extract'; parser.addFunctionLocation(yylloc, yytext); return 'EXTRACT'; }
+GROUP_CONCAT\s*\(                  { yy.lexer.unput('('); yytext = 'group_concat'; parser.addFunctionLocation(yylloc, yytext); return 'GROUP_CONCAT'; }
+MAX\s*\(                           { yy.lexer.unput('('); yytext = 'max'; parser.addFunctionLocation(yylloc, yytext); return 'MAX'; }
+MIN\s*\(                           { yy.lexer.unput('('); yytext = 'min'; parser.addFunctionLocation(yylloc, yytext); return 'MIN'; }
+NDV\s*\(                           { yy.lexer.unput('('); yytext = 'ndv'; parser.addFunctionLocation(yylloc, yytext); return 'NDV'; }
+STDDEV\s*\(                        { yy.lexer.unput('('); yytext = 'stddev'; parser.addFunctionLocation(yylloc, yytext); return 'STDDEV'; }
+STDDEV_POP\s*\(                    { yy.lexer.unput('('); yytext = 'stddev_pop'; parser.addFunctionLocation(yylloc, yytext); return 'STDDEV_POP'; }
+STDDEV_SAMP\s*\(                   { yy.lexer.unput('('); yytext = 'stddev_samp'; parser.addFunctionLocation(yylloc, yytext); return 'STDDEV_SAMP'; }
+SUM\s*\(                           { yy.lexer.unput('('); yytext = 'sum'; parser.addFunctionLocation(yylloc, yytext); return 'SUM'; }
+VAR_POP\s*\(                       { yy.lexer.unput('('); yytext = 'var_pop'; parser.addFunctionLocation(yylloc, yytext); return 'VAR_POP'; }
+VAR_SAMP\s*\(                      { yy.lexer.unput('('); yytext = 'var_samp'; parser.addFunctionLocation(yylloc, yytext); return 'VAR_SAMP'; }
+VARIANCE\s*\(                      { yy.lexer.unput('('); yytext = 'variance'; parser.addFunctionLocation(yylloc, yytext); return 'VARIANCE'; }
+VARIANCE_POP\s*\(                  { yy.lexer.unput('('); yytext = 'variance_pop'; parser.addFunctionLocation(yylloc, yytext); return 'VARIANCE_POP'; }
+VARIANCE_SAMP\s*\(                 { yy.lexer.unput('('); yytext = 'variance_samp'; parser.addFunctionLocation(yylloc, yytext); return 'VARIANCE_SAMP'; }
+
+// Analytical functions
+CUME_DIST\s*\(                     { yy.lexer.unput('('); yytext = 'cume_dist'; parser.addFunctionLocation(yylloc, yytext); return 'ANALYTIC'; }
+DENSE_RANK\s*\(                    { yy.lexer.unput('('); yytext = 'dense_rank'; parser.addFunctionLocation(yylloc, yytext); return 'ANALYTIC'; }
+FIRST_VALUE\s*\(                   { yy.lexer.unput('('); yytext = 'first_value'; parser.addFunctionLocation(yylloc, yytext); return 'ANALYTIC'; }
+LAG\s*\(                           { yy.lexer.unput('('); yytext = 'lag'; parser.addFunctionLocation(yylloc, yytext); return 'ANALYTIC'; }
+LAST_VALUE\s*\(                    { yy.lexer.unput('('); yytext = 'last_value'; parser.addFunctionLocation(yylloc, yytext); return 'ANALYTIC'; }
+LEAD\s*\(                          { yy.lexer.unput('('); yytext = 'lead'; parser.addFunctionLocation(yylloc, yytext); return 'ANALYTIC'; }
+NTILE\s*\(                         { yy.lexer.unput('('); yytext = 'ntile'; parser.addFunctionLocation(yylloc, yytext); return 'ANALYTIC'; }
+PERCENT_RANK\s*\(                  { yy.lexer.unput('('); yytext = 'percent_rank'; parser.addFunctionLocation(yylloc, yytext); return 'ANALYTIC'; }
+RANK\s*\(                          { yy.lexer.unput('('); yytext = 'rank'; parser.addFunctionLocation(yylloc, yytext); return 'ANALYTIC'; }
+ROW_NUMBER\s*\(                    { yy.lexer.unput('('); yytext = 'row_number'; parser.addFunctionLocation(yylloc, yytext); return 'ANALYTIC'; }
+SYSTEM\s*\(                        { yy.lexer.unput('('); yytext = 'system'; return 'SYSTEM'; }
+
+[0-9]+                                     { return 'UNSIGNED_INTEGER'; }
+[0-9]+(?:[YSL]|BD)?                        { return 'UNSIGNED_INTEGER'; }
+[0-9]+E                                    { return 'UNSIGNED_INTEGER_E'; }
+[A-Za-z0-9_]+                              { return 'REGULAR_IDENTIFIER'; }
+
+<hdfs>'\u2020'                             { parser.yy.cursorFound = true; return 'CURSOR'; }
+<hdfs>'\u2021'                             { parser.yy.cursorFound = true; return 'PARTIAL_CURSOR'; }
+<hdfs>\s+[']                               { return 'HDFS_START_QUOTE'; }
+<hdfs>[^'\u2020\u2021]+                    { parser.addFileLocation(yylloc, yytext); return 'HDFS_PATH'; }
+<hdfs>[']                                  { this.popState(); return 'HDFS_END_QUOTE'; }
+<hdfs><<EOF>>                              { return 'EOF'; }
+
+'&&'                                       { return 'AND'; }
+'||'                                       { return 'OR'; }
+
+'='                                        { return '='; }
+'<'                                        { return '<'; }
+'>'                                        { return '>'; }
+'!='                                       { return 'COMPARISON_OPERATOR'; }
+'<='                                       { return 'COMPARISON_OPERATOR'; }
+'>='                                       { return 'COMPARISON_OPERATOR'; }
+'<>'                                       { return 'COMPARISON_OPERATOR'; }
+'<=>'                                      { return 'COMPARISON_OPERATOR'; }
+
+'-'                                        { return '-'; }
+'*'                                        { return '*'; }
+'+'                                        { return 'ARITHMETIC_OPERATOR'; }
+'/'                                        { return 'ARITHMETIC_OPERATOR'; }
+'%'                                        { return 'ARITHMETIC_OPERATOR'; }
+'|'                                        { return 'ARITHMETIC_OPERATOR'; }
+'^'                                        { return 'ARITHMETIC_OPERATOR'; }
+'&'                                        { return 'ARITHMETIC_OPERATOR'; }
+
+','                                        { return ','; }
+'.'                                        { return '.'; }
+':'                                        { return ':'; }
+';'                                        { return ';'; }
+'~'                                        { return '~'; }
+'!'                                        { return '!'; }
+
+'('                                        { return '('; }
+')'                                        { return ')'; }
+'['                                        { return '['; }
+']'                                        { return ']'; }
+
+\$\{[^}]*\}                                { return 'VARIABLE_REFERENCE'; }
+
+\`                                         { this.begin('backtickedValue'); return 'BACKTICK'; }
+<backtickedValue>[^`]+                     {
+                                             if (parser.handleQuotedValueWithCursor(this, yytext, yylloc, '`')) {
+                                               return 'PARTIAL_VALUE';
+                                             }
+                                             return 'VALUE';
+                                           }
+<backtickedValue>\`                        { this.popState(); return 'BACKTICK'; }
+
+\'                                         { this.begin('singleQuotedValue'); return 'SINGLE_QUOTE'; }
+<singleQuotedValue>(?:\\\\|\\[']|[^'])+         {
+                                             if (parser.handleQuotedValueWithCursor(this, yytext, yylloc, '\'')) {
+                                               return 'PARTIAL_VALUE';
+                                             }
+                                             return 'VALUE';
+                                           }
+<singleQuotedValue>\'                      { this.popState(); return 'SINGLE_QUOTE'; }
+
+\"                                         { this.begin('doubleQuotedValue'); return 'DOUBLE_QUOTE'; }
+<doubleQuotedValue>(?:\\\\|\\["]|[^"])+         {
+                                             if (parser.handleQuotedValueWithCursor(this, yytext, yylloc, '"')) {
+                                               return 'PARTIAL_VALUE';
+                                             }
+                                             return 'VALUE';
+                                           }
+<doubleQuotedValue>\"                      { this.popState(); return 'DOUBLE_QUOTE'; }
+
+<<EOF>>                                    { return 'EOF'; }
+
+.                                          { /* To prevent console logging of unknown chars */ }
+<between>.                                 { }
+<hdfs>.                                    { }
+<backtickedValue>.                         { }
+<singleQuotedValue>.                       { }
+<doubleQuotedValue>.                       { }

+ 573 - 0
desktop/core/src/desktop/js/parse/jison/impala/sql_alter.jison

@@ -0,0 +1,573 @@
+// Licensed to Cloudera, Inc. under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  Cloudera, Inc. licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+DataDefinition
+ : AlterStatement
+ ;
+
+DataDefinition_EDIT
+ : AlterStatement_EDIT
+ ;
+
+AlterStatement
+ : AlterDatabase
+ | AlterTable
+ | AlterView
+ | CommentOn
+ ;
+
+AlterStatement_EDIT
+ : AlterDatabase_EDIT
+ | AlterTable_EDIT
+ | AlterView_EDIT
+ | CommentOn_EDIT
+ | 'ALTER' 'CURSOR'
+   {
+     parser.suggestKeywords(['TABLE', 'VIEW']);
+   }
+ ;
+
+AlterDatabase
+ : 'ALTER' DatabaseOrSchema RegularOrBacktickedIdentifier 'SET' 'OWNER' RoleOrUser RegularOrBacktickedIdentifier
+    {
+      parser.addDatabaseLocation(@3, [ { name: $3 } ]);
+    }
+ ;
+
+AlterDatabase_EDIT
+ : 'ALTER' DatabaseOrSchema 'CURSOR'
+   {
+     parser.suggestDatabases();
+   }
+ | 'ALTER' DatabaseOrSchema RegularOrBacktickedIdentifier 'CURSOR'
+   {
+     parser.addDatabaseLocation(@3, [ { name: $3 } ]);
+     parser.suggestKeywords(['SET OWNER']);
+   }
+ | 'ALTER' DatabaseOrSchema RegularOrBacktickedIdentifier 'SET' 'CURSOR'
+    {
+      parser.addDatabaseLocation(@3, [ { name: $3 } ]);
+      parser.suggestKeywords(['OWNER']);
+    }
+ | 'ALTER' DatabaseOrSchema RegularOrBacktickedIdentifier 'SET' 'OWNER' 'CURSOR'
+   {
+     parser.addDatabaseLocation(@3, [ { name: $3 } ]);
+     parser.suggestKeywords(['ROLE', 'USER']);
+   }
+ ;
+
+AlterTable
+ : AlterTableLeftSide 'ADD' OptionalIfNotExists PartitionSpec OptionalHdfsLocation OptionalPartitionSpecs OptionalCachedInOrUncached
+ | AlterTableLeftSide 'ADD' OptionalIfNotExists 'RANGE' 'PARTITION' RangePartitionSpec
+ | AlterTableLeftSide 'ADD' OptionalIfNotExists 'RANGE' 'PARTITION_VALUE' '=' UnsignedValueSpecification
+ | AlterTableLeftSide 'RENAME' 'TO' RegularOrBackTickedSchemaQualifiedName
+ | AlterTableLeftSide 'ALTER' OptionalColumn ColumnIdentifier 'SET' KuduStorageAttribute SetValue
+   {
+     parser.addColumnLocation($4.location, [ $4.identifier ]);
+   }
+ | AlterTableLeftSide 'ALTER' OptionalColumn ColumnIdentifier 'DROP' 'DEFAULT'
+   {
+     parser.addColumnLocation($4.location, [ $4.identifier ]);
+   }
+ | AlterTableLeftSide 'SET' 'COLUMN' 'STATS' ColumnIdentifier ParenthesizedStatsList
+   {
+     parser.addColumnLocation($5.location, [ $5.identifier ]);
+   }
+ | AlterTableLeftSide 'SET' 'OWNER' RoleOrUser RegularOrBacktickedIdentifier
+ | AlterTableLeftSide DropOperations
+ | AlterTableLeftSide OptionalPartitionOperations
+ | AlterTableLeftSide PartitionSpec OptionalPartitionOperations
+ | AlterTableLeftSide 'RECOVER' 'PARTITIONS'
+ ;
+
+AlterTable_EDIT
+ : AlterTableLeftSide_EDIT
+ | AlterTableLeftSide_EDIT 'ADD' OptionalIfNotExists PartitionSpec OptionalHdfsLocation OptionalPartitionSpecs OptionalCachedInOrUncached
+ | AlterTableLeftSide_EDIT 'RENAME' 'TO' RegularOrBackTickedSchemaQualifiedName
+ | AlterTableLeftSide_EDIT 'ALTER' OptionalColumn ColumnIdentifier 'SET' KuduStorageAttribute SetValue
+   {
+     parser.addColumnLocation($4.location, [ $4.identifier ]);
+   }
+ | AlterTableLeftSide_EDIT 'ALTER' OptionalColumn ColumnIdentifier 'DROP' 'DEFAULT'
+   {
+     parser.addColumnLocation($4.location, [ $4.identifier ]);
+   }
+ | AlterTableLeftSide_EDIT 'SET' 'COLUMN' 'STATS' ColumnIdentifier ParenthesizedStatsList
+   {
+     parser.addColumnLocation($5.location, [ $5.identifier ]);
+   }
+ | AlterTableLeftSide_EDIT 'SET' 'OWNER' RoleOrUser RegularOrBacktickedIdentifier
+ | AlterTableLeftSide_EDIT DropOperations
+ | AlterTableLeftSide_EDIT OptionalPartitionOperations
+ | AlterTableLeftSide_EDIT PartitionSpec OptionalPartitionOperations
+ | AlterTableLeftSide 'ADD' OptionalIfNotExists 'CURSOR'
+   {
+     if (!$3) {
+       parser.suggestKeywords([{ value: 'IF NOT EXISTS', weight: 4 }, { value: 'COLUMNS', weight: 3 }, { value: 'PARTITION', weight: 2 }, { value: 'RANGE PARTITION', weight: 1 }]);
+     } else {
+       parser.suggestKeywords([{ value: 'PARTITION', weight: 2 }, { value: 'RANGE PARTITION', weight: 1 }]);
+     }
+   }
+ | AlterTableLeftSide 'REPLACE' 'CURSOR'
+   {
+     parser.suggestKeywords(['COLUMNS']);
+   }
+ | AlterTableLeftSide 'ADD' OptionalIfNotExists_EDIT
+ | AlterTableLeftSide 'ADD' OptionalIfNotExists PartitionSpec HdfsLocation_EDIT OptionalPartitionSpecs OptionalCachedInOrUncached
+ | AlterTableLeftSide 'ADD' OptionalIfNotExists PartitionSpec OptionalHdfsLocation OptionalPartitionSpecs_EDIT OptionalCachedInOrUncached
+ | AlterTableLeftSide 'ADD' OptionalIfNotExists PartitionSpec OptionalHdfsLocation OptionalPartitionSpecs CachedIn_EDIT
+ | AlterTableLeftSide 'ADD' OptionalIfNotExists PartitionSpec OptionalHdfsLocation OptionalPartitionSpecs OptionalCachedInOrUncached 'CURSOR'
+   {
+     if (!$5 && !$6 && !$7) {
+       parser.suggestKeywords(['LOCATION', 'CACHED IN', 'UNCACHED']);
+     } else if (!$7) {
+       parser.suggestKeywords(['CACHED IN', 'UNCACHED']);
+     } else if ($7 && $7.suggestKeywords) {
+       parser.suggestKeywords($7.suggestKeywords);
+     }
+   }
+ | AlterTableLeftSide 'ADD' OptionalIfNotExists PartitionSpec_EDIT OptionalHdfsLocation OptionalPartitionSpecs OptionalCachedIn
+ | AlterTableLeftSide 'ADD' OptionalIfNotExists 'RANGE' 'CURSOR'
+   {
+     parser.suggestKeywords(['PARTITION']);
+   }
+ | AlterTableLeftSide 'ADD' OptionalIfNotExists 'RANGE' 'PARTITION' 'CURSOR'
+   {
+     parser.suggestKeywords(['VALUE']);
+   }
+ | AlterTableLeftSide 'ADD' OptionalIfNotExists 'RANGE' 'PARTITION_VALUE' 'CURSOR'
+   {
+     parser.suggestKeywords(['=']);
+   }
+ | AlterTableLeftSide 'ADD' OptionalIfNotExists 'RANGE' 'PARTITION' RangePartitionSpec_EDIT
+| AlterTableLeftSide 'ALTER' OptionalColumn 'CURSOR'
+   {
+     if (!$3) {
+       parser.suggestKeywords(['COLUMN']);
+     }
+     parser.suggestColumns();
+   }
+ | AlterTableLeftSide 'ALTER' OptionalColumn ColumnIdentifier 'CURSOR'
+   {
+     parser.suggestKeywords(['DROP DEFAULT', 'SET BLOCK_SIZE', 'SET COMMENT', 'SET COMPRESSION', 'SET DEFAULT',
+       'SET ENCODING']);
+     parser.addColumnLocation($4.location, [ $4.identifier ]);
+   }
+ | AlterTableLeftSide 'ALTER' OptionalColumn ColumnIdentifier 'DROP' 'CURSOR'
+   {
+     parser.suggestKeywords(['DEFAULT']);
+     parser.addColumnLocation($4.location, [ $4.identifier ]);
+   }
+ | AlterTableLeftSide 'ALTER' OptionalColumn ColumnIdentifier 'SET' 'CURSOR'
+   {
+     parser.suggestKeywords(['BLOCK_SIZE', 'COMMENT', 'COMPRESSION', 'DEFAULT', 'ENCODING']);
+     parser.addColumnLocation($4.location, [ $4.identifier ]);
+   }
+ | AlterTableLeftSide 'ALTER' OptionalColumn ColumnIdentifier 'SET' KuduStorageAttribute 'CURSOR'
+   {
+     parser.addColumnLocation($4.location, [ $4.identifier ]);
+   }
+ | AlterTableLeftSide 'SET' 'COLUMN' 'CURSOR'
+   {
+     parser.suggestKeywords(['STATS']);
+   }
+ | AlterTableLeftSide 'SET' 'COLUMN' 'STATS' 'CURSOR'
+   {
+     parser.suggestColumns();
+   }
+ | AlterTableLeftSide 'SET' 'COLUMN' 'STATS' ColumnIdentifier 'CURSOR'
+   {
+     parser.addColumnLocation($5.location, [ $5.identifier ]);
+   }
+ | AlterTableLeftSide 'SET' 'COLUMN' 'STATS' ColumnIdentifier ParenthesizedStatsList_EDIT
+   {
+     parser.addColumnLocation($5.location, [ $5.identifier ]);
+   }
+ | AlterTableLeftSide 'SET' 'OWNER' 'CURSOR'
+   {
+     parser.suggestKeywords(['ROLE', 'USER']);
+   }
+ | AlterTableLeftSide 'SET' 'OWNER' RoleOrUser 'CURSOR'
+ | AlterTableLeftSide OptionalPartitionOperations_EDIT
+ | AlterTableLeftSide DropOperations_EDIT
+ | AlterTableLeftSide 'CURSOR'
+   {
+     parser.suggestKeywords(['ADD COLUMNS', 'ADD PARTITION', 'ADD RANGE PARTITION', 'ALTER', 'ALTER COLUMN', 'CHANGE',
+       'DROP COLUMN', 'DROP PARTITION', 'DROP RANGE PARTITION', 'PARTITION', 'RECOVER PARTITIONS', 'RENAME TO',
+       'REPLACE COLUMNS', 'SET CACHED IN', 'SET COLUMN STATS', 'SET FILEFORMAT', 'SET LOCATION', 'SET OWNER',
+       'SET ROW FORMAT', 'SET SERDEPROPERTIES', 'SET TBLPROPERTIES', 'SET UNCACHED']);
+   }
+ | AlterTableLeftSide PartitionSpec 'CURSOR'
+   {
+     parser.suggestKeywords(['SET CACHED IN', 'SET FILEFORMAT', 'SET LOCATION', 'SET ROW FORMAT',
+       'SET SERDEPROPERTIES', 'SET TBLPROPERTIES', 'SET UNCACHED']);
+   }
+ | AlterTableLeftSide PartitionSpec AddOrReplace 'CURSOR'
+   {
+     parser.suggestKeywords(['COLUMNS']);
+   }
+ | AlterTableLeftSide PartitionSpec 'SET' 'CURSOR'
+   {
+     parser.suggestKeywords(['CACHED IN', 'FILEFORMAT', 'LOCATION', 'ROW FORMAT', 'SERDEPROPERTIES','TBLPROPERTIES', 'UNCACHED']);
+   }
+ | AlterTableLeftSide 'SET' 'CURSOR'
+   {
+     parser.suggestKeywords(['CACHED IN', 'COLUMN STATS', 'FILEFORMAT', 'LOCATION', 'OWNER ROLE', 'OWNER USER', 'ROW FORMAT', 'SERDEPROPERTIES', 'TBLPROPERTIES', 'UNCACHED']);
+   }
+ | AlterTableLeftSide PartitionSpec OptionalPartitionOperations_EDIT
+ | AlterTableLeftSide 'RENAME' 'CURSOR'
+   {
+     parser.suggestKeywords(['TO']);
+   }
+ | AlterTableLeftSide 'RENAME' 'TO' 'CURSOR'
+   {
+     parser.suggestDatabases({ appendDot: true });
+   }
+ | AlterTableLeftSide 'RECOVER' 'CURSOR'
+   {
+     parser.suggestKeywords(['PARTITIONS']);
+   }
+ ;
+
+KuduStorageAttribute
+ : 'BLOCK_SIZE'
+ | 'COMMENT'
+ | 'COMPRESSION'
+ | 'DEFAULT'
+ | 'ENCODING'
+ ;
+
+OptionalColumn
+ :
+ | 'COLUMN'
+ ;
+
+ParenthesizedStatsList
+ : '(' StatsList ')'
+ ;
+
+ParenthesizedStatsList_EDIT
+ : '(' StatsList_EDIT RightParenthesisOrError
+ ;
+
+StatsList
+ : StatsAssignment
+ | StatsList ',' StatsAssignment
+ ;
+
+StatsList_EDIT
+ : StatsAssignment_EDIT
+ | StatsList ',' StatsAssignment_EDIT
+ | StatsList ',' StatsAssignment_EDIT ',' StatsList
+ | StatsAssignment_EDIT ',' StatsList
+ ;
+
+StatsAssignment
+ : QuotedValue '=' QuotedValue
+ ;
+
+StatsAssignment_EDIT
+ : 'CURSOR'
+   {
+     parser.suggestIdentifiers(['\'avgSize\'', '\'maxSize\'', '\'numDVs\'', '\'numNulls\'']);
+   }
+ ;
+
+OptionalPartitionOperations
+ : 'SET' 'FILEFORMAT' FileFormat
+ | 'SET' HdfsLocation
+ | 'SET' 'TBLPROPERTIES' ParenthesizedPropertyAssignmentList
+ | 'SET' 'SERDEPROPERTIES' ParenthesizedPropertyAssignmentList
+ | 'SET' CachedIn OptionalWithReplication
+ | 'SET' 'ROW' 'FORMAT' RowFormat
+ | 'SET' 'UNCACHED'
+ | AddReplaceColumns
+ | 'CHANGE' ColumnIdentifier ColumnSpecification
+   {
+     parser.addColumnLocation($2.location, [ $2.identifier ]);
+   }
+ ;
+
+OptionalPartitionOperations_EDIT
+ : AddReplaceColumns_EDIT
+ | 'CHANGE' 'CURSOR'
+   {
+     parser.suggestColumns();
+   }
+ | 'CHANGE' ColumnIdentifier ColumnSpecification_EDIT
+   {
+     parser.addColumnLocation($2.location, [ $2.identifier ]);
+   }
+ | 'CHANGE' ColumnIdentifier ColumnSpecification 'CURSOR'
+   {
+     parser.addColumnLocation($2.location, [ $2.identifier ]);
+   }
+ | 'SET' 'FILEFORMAT' 'CURSOR'
+   {
+     parser.suggestFileFormats();
+   }
+ | 'SET' HdfsLocation_EDIT
+ | 'SET' CachedIn_EDIT
+ | 'SET' CachedIn OptionalWithReplication 'CURSOR'
+   {
+     if (!$3) {
+       parser.suggestKeywords(['WITH REPLICATION =']);
+     }
+   }
+ | 'SET' CachedIn WithReplication_EDIT
+ | 'SET' 'ROW' 'CURSOR'
+   {
+     parser.suggestKeywords(['FORMAT']);
+   }
+ | 'SET' 'ROW' 'FORMAT' 'CURSOR'
+   {
+     parser.suggestKeywords(['DELIMITED']);
+   }
+ | 'SET' 'ROW' 'FORMAT' RowFormat 'CURSOR'
+   {
+     if ($4.suggestKeywords) {
+       parser.suggestKeywords($4.suggestKeywords);
+     }
+   }
+ | 'SET' 'ROW' 'FORMAT' RowFormat_EDIT
+ ;
+
+AddReplaceColumns
+ : AddOrReplace 'COLUMNS' ParenthesizedColumnSpecificationList
+ ;
+
+AddReplaceColumns_EDIT
+ : AddOrReplace 'COLUMNS' ParenthesizedColumnSpecificationList_EDIT
+ | AddOrReplace 'COLUMNS' ParenthesizedColumnSpecificationList 'CURSOR'
+ ;
+
+ExchangePartitionSpec
+ : 'PARTITION' '(' OneOrMorePartitionSpecLists ')'
+ | 'PARTITION' '(' PartitionSpecList ')'
+ ;
+
+ExchangePartitionSpec_EDIT
+ : 'PARTITION' '(' OneOrMorePartitionSpecLists_EDIT RightParenthesisOrError
+ | 'PARTITION' '(' PartitionSpecList_EDIT RightParenthesisOrError
+ ;
+
+OneOrMorePartitionSpecLists
+ : '(' PartitionSpecList ')'
+ | OneOrMorePartitionSpecLists ',' '(' PartitionSpecList ')'
+ ;
+
+OneOrMorePartitionSpecLists_EDIT
+ : '(' PartitionSpecList_EDIT RightParenthesisOrError
+ | OneOrMorePartitionSpecLists ',' '(' PartitionSpecList_EDIT RightParenthesisOrError
+ ;
+
+DropOperations
+ : 'DROP' OptionalIfExists PartitionSpec
+ | 'DROP' OptionalIfExists 'RANGE'
+ | 'DROP' OptionalIfExists 'RANGE' 'PARTITION' RangePartitionSpec
+ | 'DROP' OptionalIfExists 'RANGE' 'PARTITION_VALUE' '=' UnsignedValueSpecification
+ | 'DROP' 'COLUMN' ColumnIdentifier
+   {
+     parser.addColumnLocation($3.location, [ $3.identifier ]);
+   }
+ ;
+
+DropOperations_EDIT
+ : 'DROP' OptionalIfExists 'CURSOR'
+   {
+     if (!$2) {
+       parser.suggestKeywords([{ value: 'COLUMN', weight: 1 }, { value: 'PARTITION', weight: 1 }, { value: 'RANGE PARTITION', weight: 1 }, { value: 'IF EXISTS', weight: 2 }]);
+       parser.suggestColumns();
+     } else {
+       parser.suggestKeywords(['PARTITION', 'RANGE PARTITION']);
+     }
+   }
+ | 'DROP' OptionalIfExists PartitionSpec_EDIT
+ | 'DROP' OptionalIfExists PartitionSpec 'CURSOR'
+ | 'DROP' OptionalIfExists_EDIT
+ | 'DROP' OptionalIfExists 'RANGE' 'CURSOR'
+   {
+     parser.suggestKeywords(['PARTITION']);
+   }
+ | 'DROP' OptionalIfExists 'RANGE' 'PARTITION' 'CURSOR'
+   {
+     parser.suggestKeywords(['VALUE']);
+   }
+ | 'DROP' OptionalIfExists 'RANGE' 'PARTITION_VALUE' 'CURSOR'
+   {
+     parser.suggestKeywords(['=']);
+   }
+ | 'DROP' OptionalIfExists 'RANGE' 'PARTITION' RangePartitionSpec_EDIT
+ | 'DROP' ColumnIdentifier_EDIT
+ | 'DROP' 'COLUMN' 'CURSOR'
+   {
+     parser.suggestColumns();
+   }
+ | 'DROP' 'COLUMN' ColumnIdentifier_EDIT
+ ;
+
+AlterTableLeftSide
+ : 'ALTER' AnyTable SchemaQualifiedTableIdentifier
+   {
+     parser.addTablePrimary($3);
+   }
+ ;
+
+AlterTableLeftSide_EDIT
+ : 'ALTER' AnyTable SchemaQualifiedTableIdentifier_EDIT
+   {
+     if (parser.yy.result.suggestTables) {
+       parser.yy.result.suggestTables.onlyTables = true;
+     }
+   }
+ | 'ALTER' AnyTable 'CURSOR'
+   {
+     parser.suggestTables({ onlyTables: true });
+     parser.suggestDatabases({ appendDot: true });
+   }
+ ;
+
+AddOrReplace
+ : 'ADD'
+ | 'REPLACE'
+ ;
+
+OptionalPartitionSpecs
+ :
+ | PartitionSpecWithLocationList
+ ;
+
+PartitionSpecWithLocationList
+ : PartitionSpecWithLocation
+ | PartitionSpecWithLocationList PartitionSpecWithLocation  -> $2
+ ;
+
+OptionalPartitionSpecs_EDIT
+ : PartitionSpecWithLocation_EDIT
+ | PartitionSpecWithLocation_EDIT PartitionSpecWithLocationList
+ | PartitionSpecWithLocationList PartitionSpecWithLocation_EDIT
+ | PartitionSpecWithLocationList PartitionSpecWithLocation_EDIT PartitionSpecWithLocationList
+ ;
+
+PartitionSpecWithLocation_EDIT
+ : PartitionSpec HdfsLocation_EDIT
+ | PartitionSpec_EDIT OptionalHdfsLocation
+ ;
+
+PartitionSpecWithLocation
+ : PartitionSpec OptionalHdfsLocation
+   {
+     if (!$2) {
+       $$ = { suggestKeywords: ['LOCATION'] };
+     }
+   }
+ ;
+
+AlterView
+ : AlterViewLeftSide 'SET' 'OWNER' RoleOrUser RegularOrBacktickedIdentifier
+ | AlterViewLeftSide 'AS' QuerySpecification
+ | AlterViewLeftSide 'RENAME' 'TO' RegularOrBacktickedIdentifier
+ | AlterViewLeftSide 'RENAME' 'TO' RegularOrBacktickedIdentifier '.' RegularOrBacktickedIdentifier
+ ;
+
+AlterView_EDIT
+ : AlterViewLeftSide_EDIT
+ | AlterViewLeftSide 'CURSOR'
+   {
+     parser.suggestKeywords(['AS', 'RENAME TO', 'SET OWNER']);
+   }
+ | AlterViewLeftSide 'SET' 'CURSOR'
+   {
+     parser.suggestKeywords(['OWNER ROLE', 'OWNER USER']);
+   }
+ | AlterViewLeftSide 'SET' 'OWNER' 'CURSOR'
+   {
+     parser.suggestKeywords(['ROLE', 'USER']);
+   }
+ | AlterViewLeftSide 'SET' 'OWNER' RoleOrUser 'CURSOR'
+ | AlterViewLeftSide 'AS' 'CURSOR'
+   {
+     parser.suggestKeywords(['SELECT']);
+   }
+ | AlterViewLeftSide 'AS' QuerySpecification_EDIT
+ | AlterViewLeftSide 'RENAME' 'CURSOR'
+   {
+     parser.suggestKeywords(['TO']);
+   }
+ | AlterViewLeftSide 'RENAME' 'TO' 'CURSOR'
+   {
+     parser.suggestDatabases({ appendDot: true });
+   }
+ ;
+
+
+AlterViewLeftSide
+ : 'ALTER' 'VIEW' SchemaQualifiedTableIdentifier
+   {
+     parser.addTablePrimary($3);
+   }
+ ;
+
+AlterViewLeftSide_EDIT
+ : 'ALTER' 'VIEW' SchemaQualifiedTableIdentifier_EDIT
+   {
+     if (parser.yy.result.suggestTables) {
+       parser.yy.result.suggestTables.onlyViews = true;
+     }
+   }
+ | 'ALTER' 'VIEW' 'CURSOR'
+   {
+     parser.suggestTables({ onlyViews: true });
+     parser.suggestDatabases({ appendDot: true });
+   }
+ ;
+
+CommentOn
+ : 'COMMENT' 'ON' 'DATABASE' RegularOrBacktickedIdentifier 'IS' NullableComment
+   {
+     parser.addDatabaseLocation(@4, [ { name: $4 } ]);
+   }
+ ;
+
+CommentOn_EDIT
+ : 'COMMENT' 'CURSOR'
+   {
+     parser.suggestKeywords(['ON DATABASE']);
+   }
+ | 'COMMENT' 'ON' 'CURSOR'
+   {
+     parser.suggestKeywords(['DATABASE']);
+   }
+ | 'COMMENT' 'ON' 'DATABASE' 'CURSOR'
+   {
+     parser.suggestDatabases();
+   }
+ | 'COMMENT' 'ON' 'DATABASE' RegularOrBacktickedIdentifier 'CURSOR'
+   {
+     parser.addDatabaseLocation(@4, [ { name: $4 } ]);
+     parser.suggestKeywords(['IS']);
+   }
+ | 'COMMENT' 'ON' 'DATABASE' RegularOrBacktickedIdentifier 'IS' 'CURSOR'
+   {
+     parser.addDatabaseLocation(@4, [ { name: $4 } ]);
+     parser.suggestKeywords(['NULL']);
+   }
+ ;
+
+NullableComment
+ : QuotedValue
+ | 'NULL'
+ ;

+ 164 - 0
desktop/core/src/desktop/js/parse/jison/impala/sql_analyze.jison

@@ -0,0 +1,164 @@
+// Licensed to Cloudera, Inc. under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  Cloudera, Inc. licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+DataDefinition
+ : RefreshStatement
+ | InvalidateStatement
+ | ComputeStatsStatement
+ ;
+
+DataDefinition_EDIT
+ : RefreshStatement_EDIT
+ | InvalidateStatement_EDIT
+ | ComputeStatsStatement_EDIT
+ ;
+
+RefreshStatement
+ : 'REFRESH' SchemaQualifiedTableIdentifier OptionalPartitionSpec
+   {
+     parser.addTablePrimary($2);
+   }
+ | 'REFRESH' 'FUNCTIONS' DatabaseIdentifier
+   {
+     parser.addDatabaseLocation(@3, [{ name: $3 }]);
+   }
+ | 'REFRESH' 'AUTHORIZATION'
+ ;
+
+RefreshStatement_EDIT
+ : 'REFRESH' 'CURSOR'
+   {
+     parser.suggestTables();
+     parser.suggestDatabases({ appendDot: true });
+     parser.suggestKeywords(['AUTHORIZATION', 'FUNCTIONS']);
+   }
+ | 'REFRESH' SchemaQualifiedTableIdentifier_EDIT OptionalPartitionSpec
+ | 'REFRESH' SchemaQualifiedTableIdentifier OptionalPartitionSpec 'CURSOR'
+   {
+     parser.addTablePrimary($2);
+     if (!$3) {
+       parser.suggestKeywords(['PARTITION']);
+     }
+   }
+ | 'REFRESH' SchemaQualifiedTableIdentifier OptionalPartitionSpec_EDIT
+ | 'REFRESH' 'FUNCTIONS' 'CURSOR'
+   {
+     parser.suggestDatabases();
+   }
+ ;
+
+InvalidateStatement
+ : 'INVALIDATE' 'METADATA'
+ | 'INVALIDATE' 'METADATA' SchemaQualifiedTableIdentifier
+   {
+     parser.addTablePrimary($3);
+   }
+ ;
+
+InvalidateStatement_EDIT
+ : 'INVALIDATE' 'CURSOR'
+   {
+     parser.suggestKeywords(['METADATA']);
+   }
+ | 'INVALIDATE' 'METADATA' 'CURSOR'
+   {
+     parser.suggestTables();
+     parser.suggestDatabases({ appendDot: true });
+   }
+ | 'INVALIDATE' 'METADATA' SchemaQualifiedTableIdentifier_EDIT
+ | 'INVALIDATE' 'CURSOR' SchemaQualifiedTableIdentifier
+   {
+     parser.addTablePrimary($3);
+     parser.suggestKeywords(['METADATA']);
+   }
+ ;
+
+ComputeStatsStatement
+ : 'COMPUTE' 'STATS' SchemaQualifiedTableIdentifier OptionalParenthesizedColumnList OptionalTableSample
+   {
+     parser.addTablePrimary($3);
+   }
+ | 'COMPUTE' 'INCREMENTAL' 'STATS' SchemaQualifiedTableIdentifier OptionalPartitionSpec
+   {
+     parser.addTablePrimary($4);
+   }
+ ;
+
+ComputeStatsStatement_EDIT
+ : 'COMPUTE' 'CURSOR'
+   {
+     parser.suggestKeywords(['STATS', 'INCREMENTAL STATS']);
+   }
+ | 'COMPUTE' 'STATS' 'CURSOR'
+   {
+     parser.suggestTables();
+     parser.suggestDatabases({ appendDot: true });
+   }
+ | 'COMPUTE' 'STATS' SchemaQualifiedTableIdentifier_EDIT
+ | 'COMPUTE' 'CURSOR' SchemaQualifiedTableIdentifier OptionalPartitionSpec
+   {
+     parser.addTablePrimary($3);
+     parser.suggestKeywords(['STATS', 'INCREMENTAL STATS']);
+   }
+ | 'COMPUTE' 'STATS' SchemaQualifiedTableIdentifier OptionalParenthesizedColumnList OptionalTableSample 'CURSOR'
+   {
+     parser.addTablePrimary($3);
+     if (!$5) {
+       parser.suggestKeywords(['TABLESAMPLE']);
+     } else if ($5.suggestKeywords) {
+       parser.suggestKeywords($5.suggestKeywords);
+     }
+   }
+ | 'COMPUTE' 'STATS' SchemaQualifiedTableIdentifier ParenthesizedColumnList_EDIT OptionalTableSample
+   {
+     parser.addTablePrimary($3);
+   }
+ | 'COMPUTE' 'STATS' SchemaQualifiedTableIdentifier OptionalParenthesizedColumnList OptionalTableSample_EDIT
+   {
+     parser.addTablePrimary($3);
+   }
+ | 'COMPUTE' 'CURSOR' 'STATS' SchemaQualifiedTableIdentifier OptionalPartitionSpec
+   {
+     parser.addTablePrimary($4);
+     parser.suggestKeywords(['INCREMENTAL']);
+   }
+ | 'COMPUTE' 'INCREMENTAL' 'CURSOR'
+   {
+     parser.suggestKeywords(['STATS']);
+   }
+ | 'COMPUTE' 'INCREMENTAL' 'CURSOR' SchemaQualifiedTableIdentifier OptionalPartitionSpec
+   {
+     parser.addTablePrimary($4);
+     parser.suggestKeywords(['STATS']);
+   }
+ | 'COMPUTE' 'INCREMENTAL' 'STATS' 'CURSOR'
+   {
+     parser.suggestTables();
+     parser.suggestDatabases({ appendDot: true });
+   }
+ | 'COMPUTE' 'INCREMENTAL' 'STATS' SchemaQualifiedTableIdentifier_EDIT OptionalPartitionSpec
+ | 'COMPUTE' 'INCREMENTAL' 'STATS' SchemaQualifiedTableIdentifier 'CURSOR' OptionalPartitionSpec
+   {
+     parser.addTablePrimary($4);
+     if (!$6) {
+       parser.suggestKeywords(['PARTITION']);
+     }
+   }
+ | 'COMPUTE' 'INCREMENTAL' 'STATS' SchemaQualifiedTableIdentifier PartitionSpec_EDIT
+   {
+     parser.addTablePrimary($4);
+   }
+ ;

+ 1284 - 0
desktop/core/src/desktop/js/parse/jison/impala/sql_create.jison

@@ -0,0 +1,1284 @@
+// Licensed to Cloudera, Inc. under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  Cloudera, Inc. licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+DataDefinition
+ : CreateStatement
+ ;
+
+DataDefinition_EDIT
+ : CreateStatement_EDIT
+ ;
+
+CreateStatement
+ : DatabaseDefinition
+ | TableDefinition
+ | ViewDefinition
+ | RoleDefinition
+ | FunctionDefinition
+ ;
+
+CreateStatement_EDIT
+ : DatabaseDefinition_EDIT
+ | TableDefinition_EDIT
+ | ViewDefinition_EDIT
+ | FunctionDefinition_EDIT
+ | AnyCreate OptionalExternal 'CURSOR'
+   {
+     if ($2) {
+       parser.suggestKeywords(['TABLE']);
+     } else {
+       parser.suggestKeywords(['AGGREGATE FUNCTION', 'DATABASE', 'EXTERNAL TABLE', 'FUNCTION', 'ROLE', 'SCHEMA', 'TABLE', 'VIEW']);
+     }
+   }
+ ;
+
+DatabaseDefinition
+ : AnyCreate DatabaseOrSchema OptionalIfNotExists
+ | AnyCreate DatabaseOrSchema OptionalIfNotExists RegularIdentifier DatabaseDefinitionOptionals
+   {
+     parser.addNewDatabaseLocation(@4, [{ name: $4 }]);
+   }
+ ;
+
+DatabaseDefinition_EDIT
+ : AnyCreate DatabaseOrSchema OptionalIfNotExists 'CURSOR'
+   {
+     if (!$3) {
+       parser.suggestKeywords(['IF NOT EXISTS']);
+     }
+   }
+ | AnyCreate DatabaseOrSchema OptionalIfNotExists_EDIT
+ | AnyCreate DatabaseOrSchema OptionalIfNotExists 'CURSOR' RegularIdentifier
+   {
+     if (!$3) {
+       parser.suggestKeywords(['IF NOT EXISTS']);
+     }
+     parser.addNewDatabaseLocation(@5, [{ name: $5 }]);
+   }
+ | AnyCreate DatabaseOrSchema OptionalIfNotExists_EDIT RegularIdentifier
+   {
+     parser.addNewDatabaseLocation(@4, [{ name: $4 }]);
+   }
+ | AnyCreate DatabaseOrSchema OptionalIfNotExists RegularIdentifier DatabaseDefinitionOptionals 'CURSOR'
+   {
+     parser.addNewDatabaseLocation(@4, [{ name: $4 }]);
+   }
+ ;
+
+DatabaseDefinitionOptionals
+ : OptionalComment OptionalHdfsLocation
+   {
+     var keywords = [];
+     if (!$2) {
+       keywords.push('LOCATION');
+     }
+     if (!$1 && !$2) {
+       keywords.push('COMMENT');
+     }
+     if (keywords.length > 0) {
+       parser.suggestKeywords(keywords);
+     }
+   }
+ ;
+
+DatabaseDefinitionOptionals_EDIT
+ : OptionalComment_INVALID OptionalHdfsLocation
+ | OptionalComment HdfsLocation_EDIT
+ ;
+
+OptionalComment
+ :
+ | Comment
+ ;
+
+Comment
+ : 'COMMENT' QuotedValue
+ ;
+
+OptionalComment_INVALID
+ : Comment_INVALID
+ ;
+
+Comment_INVALID
+ : 'COMMENT' SINGLE_QUOTE
+ | 'COMMENT' DOUBLE_QUOTE
+ | 'COMMENT' SINGLE_QUOTE VALUE
+ | 'COMMENT' DOUBLE_QUOTE VALUE
+ ;
+
+ParenthesizedPropertyAssignmentList
+ : '(' PropertyAssignmentList ')'
+ ;
+
+PropertyAssignmentList
+ : PropertyAssignment
+ | PropertyAssignmentList ',' PropertyAssignment
+ ;
+
+PropertyAssignment
+ : QuotedValue '=' UnsignedValueSpecification
+ ;
+
+TableDefinition
+ : AnyCreate OptionalExternal AnyTable OptionalIfNotExists TableDefinitionRightPart
+ ;
+
+TableDefinition_EDIT
+ : AnyCreate OptionalExternal AnyTable OptionalIfNotExists TableDefinitionRightPart_EDIT
+ | AnyCreate OptionalExternal AnyTable OptionalIfNotExists 'CURSOR'
+   {
+     if (!$4) {
+       parser.suggestKeywords(['IF NOT EXISTS']);
+     }
+   }
+ | AnyCreate OptionalExternal AnyTable OptionalIfNotExists_EDIT
+ ;
+
+TableDefinitionRightPart
+ : TableIdentifierAndOptionalColumnSpecification OptionalPartitionedBy OptionalSortBy OptionalComment
+   OptionalRowFormat OptionalWithSerdeproperties OptionalStoredAs
+   OptionalHdfsLocation OptionalCachedInOrUncached OptionalTblproperties OptionalAsSelectStatement
+ ;
+
+TableDefinitionRightPart_EDIT
+ : TableIdentifierAndOptionalColumnSpecification_EDIT OptionalPartitionedBy OptionalSortBy OptionalComment
+   OptionalRowFormat OptionalWithSerdeproperties OptionalStoredAs
+   OptionalHdfsLocation OptionalCachedInOrUncached OptionalTblproperties OptionalAsSelectStatement
+ | TableIdentifierAndOptionalColumnSpecification PartitionedBy_EDIT OptionalSortBy OptionalComment
+   OptionalRowFormat OptionalWithSerdeproperties OptionalStoredAs
+   OptionalHdfsLocation OptionalCachedInOrUncached OptionalTblproperties OptionalAsSelectStatement
+ | TableIdentifierAndOptionalColumnSpecification OptionalPartitionedBy SortBy_EDIT OptionalComment
+   OptionalRowFormat OptionalWithSerdeproperties OptionalStoredAs
+   OptionalHdfsLocation OptionalCachedInOrUncached OptionalTblproperties OptionalAsSelectStatement
+ | TableIdentifierAndOptionalColumnSpecification OptionalPartitionedBy OptionalSortBy OptionalComment
+   RowFormat_EDIT OptionalWithSerdeproperties OptionalStoredAs
+   OptionalHdfsLocation OptionalCachedInOrUncached OptionalTblproperties OptionalAsSelectStatement
+ | TableIdentifierAndOptionalColumnSpecification OptionalPartitionedBy OptionalSortBy OptionalComment
+   OptionalRowFormat WithSerdeproperties_EDIT OptionalStoredAs
+   OptionalHdfsLocation OptionalCachedInOrUncached OptionalTblproperties OptionalAsSelectStatement
+ | TableIdentifierAndOptionalColumnSpecification OptionalPartitionedBy OptionalSortBy OptionalComment
+   OptionalRowFormat OptionalWithSerdeproperties StoredAs_EDIT
+   OptionalHdfsLocation OptionalCachedInOrUncached OptionalTblproperties OptionalAsSelectStatement
+ | TableIdentifierAndOptionalColumnSpecification OptionalPartitionedBy OptionalSortBy OptionalComment
+   OptionalRowFormat OptionalWithSerdeproperties OptionalStoredAs
+   HdfsLocation_EDIT OptionalCachedInOrUncached OptionalTblproperties OptionalAsSelectStatement
+ | TableIdentifierAndOptionalColumnSpecification OptionalPartitionedBy OptionalSortBy OptionalComment
+   OptionalRowFormat OptionalWithSerdeproperties OptionalStoredAs
+   OptionalHdfsLocation CachedIn_EDIT OptionalTblproperties OptionalAsSelectStatement
+ | TableIdentifierAndOptionalColumnSpecification OptionalPartitionedBy OptionalSortBy OptionalComment
+   OptionalRowFormat OptionalWithSerdeproperties OptionalStoredAs
+   OptionalHdfsLocation CachedIn WithReplication_EDIT OptionalTblproperties OptionalAsSelectStatement
+ | TableIdentifierAndOptionalColumnSpecification OptionalPartitionedBy OptionalSortBy OptionalComment
+   OptionalRowFormat OptionalWithSerdeproperties OptionalStoredAs
+   OptionalHdfsLocation OptionalCachedInOrUncached OptionalTblproperties OptionalAsSelectStatement_EDIT
+ | TableIdentifierAndOptionalColumnSpecification OptionalPartitionedBy OptionalSortBy OptionalComment
+   OptionalRowFormat OptionalWithSerdeproperties OptionalStoredAs
+   OptionalHdfsLocation OptionalCachedInOrUncached OptionalTblproperties 'CURSOR'
+   {
+     var keywords = [];
+     if (!$1 && !$2 && !$3 && !$4 && !$5 && !$6 && !$7 && !$8 && !$9 && !$10) {
+       keywords.push({ value: 'LIKE', weight: 1 });
+       keywords.push({ value: 'LIKE PARQUET', weight: 1 });
+     } else {
+       if (!$2 && !$3 && !$4 && !$5 && !$6 && !$7 && !$8 && !$9 && !$10) {
+         keywords.push({ value: 'PARTITIONED BY', weight: 12 });
+         keywords.push({ value: 'PARTITION BY', weight: 12 });
+       }
+       if (!$3 && !$4 && !$5 && !$6 && !$7 && !$8 && !$9 && !$10) {
+         keywords.push({ value: 'SORT BY', weight: 11 });
+       }
+       if (!$4 && !$5 && !$6 && !$7 && !$8 && !$9 && !$10) {
+         keywords.push({ value: 'COMMENT', weight: 10 });
+       }
+       if (!$5 && !$6 && !$7 && !$8 && !$9 && !$10) {
+         keywords.push({ value: 'ROW FORMAT', weight: 7 });
+       } else if ($5 && $5.suggestKeywords && !$6 && !$7 && !$8 && !$9 && !$10 && !$10) {
+         keywords = keywords.concat(parser.createWeightedKeywords($5.suggestKeywords, 7));
+       }
+       if (!$6 && !$7 && !$8 && !$9 && !$10) {
+         keywords.push({ value: 'WITH SERDEPROPERTIES', weight: 6 });
+       }
+       if (!$7 && !$8 && !$9 && !$10) {
+         keywords.push({ value: 'STORED AS', weight: 5 });
+       }
+       if (!$8 && !$9 && !$10) {
+         keywords.push({ value: 'LOCATION', weight: 4 });
+       }
+       if (!$9 && !$10) {
+         keywords.push({ value: 'CACHED IN', weight: 3 }, { value: 'UNCACHED', weight: 3 });
+       } else if ($9 && $9.suggestKeywords && !$10) {
+         keywords = keywords.concat(parser.createWeightedKeywords($9.suggestKeywords, 3));
+       }
+       if (!$10) {
+         keywords.push({ value: 'TBLPROPERTIES', weight: 2 });
+       }
+       keywords.push({ value: 'AS', weight: 1 });
+     }
+
+     parser.suggestKeywords(keywords);
+   }
+ ;
+
+TableIdentifierAndOptionalColumnSpecification
+ : SchemaQualifiedIdentifier OptionalColumnSpecificationsOrLike
+   {
+     parser.addNewTableLocation(@1, $1, $2);
+     $$ = $2;
+   }
+ ;
+
+TableIdentifierAndOptionalColumnSpecification_EDIT
+ : SchemaQualifiedIdentifier OptionalColumnSpecificationsOrLike_EDIT
+ | SchemaQualifiedIdentifier_EDIT OptionalColumnSpecificationsOrLike
+ ;
+
+OptionalColumnSpecificationsOrLike
+ :
+ | ParenthesizedColumnSpecificationList
+ | 'LIKE_PARQUET' HdfsPath          -> []
+ | 'LIKE' SchemaQualifiedTableIdentifier    -> []
+ ;
+
+OptionalColumnSpecificationsOrLike_EDIT
+ : ParenthesizedColumnSpecificationList_EDIT
+ | 'LIKE_PARQUET' HdfsPath_EDIT
+ | 'LIKE' 'CURSOR'
+   {
+     parser.suggestTables();
+     parser.suggestDatabases({ appendDot: true });
+     parser.suggestKeywords(['PARQUET']);
+   }
+ | 'LIKE' SchemaQualifiedTableIdentifier_EDIT
+ ;
+
+ParenthesizedColumnSpecificationList
+ : '(' ColumnSpecificationList ')'                              -> $2
+ | '(' ColumnSpecificationList ',' PrimaryKeySpecification ')'  -> $2
+ ;
+
+ParenthesizedColumnSpecificationList_EDIT
+ : '(' ColumnSpecificationList_EDIT RightParenthesisOrError
+ | '(' ColumnSpecificationList ',' PrimaryKeySpecification_EDIT RightParenthesisOrError
+ | '(' ColumnSpecificationList ',' 'CURSOR' RightParenthesisOrError
+   {
+     parser.suggestKeywords(['PRIMARY KEY']);
+   }
+ ;
+
+ColumnSpecificationList
+ : ColumnSpecification                              -> [$1]
+ | ColumnSpecificationList ',' ColumnSpecification  -> $1.concat($3)
+ ;
+
+ColumnSpecificationList_EDIT
+ : ColumnSpecification_EDIT
+ | ColumnSpecification_EDIT ',' ColumnSpecificationList
+ | ColumnSpecificationList ',' ColumnSpecification_EDIT
+ | ColumnSpecificationList ',' ColumnSpecification_EDIT ',' ColumnSpecificationList
+ | ColumnSpecification 'CURSOR'
+   {
+     parser.checkForKeywords($1);
+   }
+ | ColumnSpecification 'CURSOR' ',' ColumnSpecificationList
+   {
+     parser.checkForKeywords($1);
+   }
+ | ColumnSpecificationList ',' ColumnSpecification 'CURSOR'
+   {
+     parser.checkForKeywords($3);
+   }
+ | ColumnSpecificationList ',' ColumnSpecification 'CURSOR' ',' ColumnSpecificationList
+   {
+     parser.checkForKeywords($3);
+   }
+ ;
+
+ColumnSpecification
+ : ColumnIdentifier ColumnDataType OptionalColumnOptions
+   {
+     $$ = $1;
+     $$.type = $2;
+     var keywords = [];
+     if (!$3['primary']) {
+       keywords.push('PRIMARY KEY');
+     }
+     if (!$3['encoding']) {
+       keywords.push('ENCODING');
+     }
+     if (!$3['compression']) {
+       keywords.push('COMPRESSION');
+     }
+     if (!$3['default']) {
+       keywords.push('DEFAULT');
+     }
+     if (!$3['block_size']) {
+       keywords.push('BLOCK_SIZE');
+     }
+     if (!$3['null']) {
+       keywords.push('NOT NULL');
+       keywords.push('NULL');
+     }
+     if (!$3['comment']) {
+       keywords.push('COMMENT');
+     }
+     if (keywords.length > 0) {
+       $$.suggestKeywords = keywords;
+     }
+   }
+ ;
+
+ColumnSpecification_EDIT
+ : ColumnIdentifier 'CURSOR' OptionalColumnOptions
+   {
+     parser.suggestKeywords(parser.getColumnDataTypeKeywords());
+   }
+ | ColumnIdentifier ColumnDataType_EDIT OptionalColumnOptions
+ | ColumnIdentifier ColumnDataType ColumnOptions_EDIT
+ ;
+
+OptionalColumnOptions
+ :                      -> {}
+ | ColumnOptions
+ ;
+
+ColumnOptions
+ : ColumnOption
+   {
+     $$ = {};
+     $$[$1] = true;
+   }
+ | ColumnOptions ColumnOption
+   {
+     $1[$2] = true;
+   }
+ ;
+
+ColumnOptions_EDIT
+ : ColumnOption_EDIT
+ | ColumnOption_EDIT ColumnOptions
+ | ColumnOptions ColumnOption_EDIT
+ | ColumnOptions ColumnOption_EDIT ColumnOptions
+ ;
+
+ColumnOption
+ : PrimaryKey                                        -> 'primary'
+ | 'ENCODING' RegularIdentifier                      -> 'encoding'
+ | 'COMPRESSION' RegularIdentifier                   -> 'compression'
+ | 'DEFAULT' NonParenthesizedValueExpressionPrimary  -> 'default'
+ | 'BLOCK_SIZE' UnsignedNumericLiteral               -> 'block_size'
+ | 'NOT' 'NULL'                                      -> 'null'
+ | 'NULL'                                            -> 'null'
+ | Comment                                           -> 'comment'
+ ;
+
+ColumnOption_EDIT
+ : PrimaryKey_EDIT
+ | 'NOT' 'CURSOR'
+   {
+     parser.suggestKeywords(['NULL']);
+   }
+ ;
+
+ColumnDataType
+ : PrimitiveType
+ | ArrayType
+ | MapType
+ | StructType
+ | ArrayType_INVALID
+ | MapType_INVALID
+ | StructType_INVALID
+ ;
+
+ColumnDataType_EDIT
+ : ArrayType_EDIT
+ | MapType_EDIT
+ | StructType_EDIT
+ ;
+
+ArrayType
+ : 'ARRAY' '<' ColumnDataType '>'
+ ;
+
+ArrayType_INVALID
+ : 'ARRAY' '<' '>'
+ ;
+
+ArrayType_EDIT
+ : 'ARRAY' '<' AnyCursor GreaterThanOrError
+   {
+     parser.suggestKeywords(parser.getColumnDataTypeKeywords());
+   }
+ | 'ARRAY' '<' ColumnDataType_EDIT GreaterThanOrError
+ ;
+
+MapType
+ : 'MAP' '<' PrimitiveType ',' ColumnDataType '>'
+ ;
+
+MapType_INVALID
+ : 'MAP' '<' '>'
+ ;
+
+MapType_EDIT
+ : 'MAP' '<' PrimitiveType ',' ColumnDataType_EDIT GreaterThanOrError
+ | 'MAP' '<' AnyCursor GreaterThanOrError
+   {
+     parser.suggestKeywords(parser.getTypeKeywords());
+   }
+ | 'MAP' '<' PrimitiveType ',' AnyCursor GreaterThanOrError
+   {
+     parser.suggestKeywords(parser.getColumnDataTypeKeywords());
+   }
+ | 'MAP' '<' ',' AnyCursor GreaterThanOrError
+   {
+     parser.suggestKeywords(parser.getColumnDataTypeKeywords());
+   }
+ ;
+
+StructType
+ : 'STRUCT' '<' StructDefinitionList '>'
+ ;
+
+StructType_INVALID
+ : 'STRUCT' '<' '>'
+ ;
+
+StructType_EDIT
+ : 'STRUCT' '<' StructDefinitionList_EDIT GreaterThanOrError
+ ;
+
+StructDefinitionList
+ : StructDefinition
+ | StructDefinitionList ',' StructDefinition
+ ;
+
+StructDefinitionList_EDIT
+ : StructDefinition_EDIT
+ | StructDefinition_EDIT Commas
+ | StructDefinition_EDIT Commas StructDefinitionList
+ | StructDefinitionList ',' StructDefinition_EDIT
+ | StructDefinitionList ',' StructDefinition_EDIT Commas StructDefinitionList
+ ;
+
+StructDefinition
+ : RegularOrBacktickedIdentifier ':' ColumnDataType OptionalComment
+ ;
+
+StructDefinition_EDIT
+ : Commas RegularOrBacktickedIdentifier ':' ColumnDataType 'CURSOR'
+   {
+     parser.suggestKeywords(['COMMENT']);
+   }
+ | Commas RegularOrBacktickedIdentifier ':' AnyCursor
+   {
+     parser.suggestKeywords(parser.getColumnDataTypeKeywords());
+   }
+ | Commas RegularOrBacktickedIdentifier ':' ColumnDataType_EDIT
+ | RegularOrBacktickedIdentifier ':' ColumnDataType 'CURSOR'
+   {
+     parser.suggestKeywords(['COMMENT']);
+   }
+ | RegularOrBacktickedIdentifier ':' AnyCursor
+   {
+     parser.suggestKeywords(parser.getColumnDataTypeKeywords());
+   }
+ | RegularOrBacktickedIdentifier ':' ColumnDataType_EDIT
+ ;
+
+ColumnDataTypeList
+ : ColumnDataType
+ | ColumnDataTypeList ',' ColumnDataType
+ ;
+
+ColumnDataTypeList_EDIT
+ : ColumnDataTypeListInner_EDIT
+ | ColumnDataTypeListInner_EDIT Commas
+ | ColumnDataTypeList ',' ColumnDataTypeListInner_EDIT
+ | ColumnDataTypeListInner_EDIT Commas ColumnDataTypeList
+ | ColumnDataTypeList ',' ColumnDataTypeListInner_EDIT Commas ColumnDataTypeList
+ ;
+
+ColumnDataTypeListInner_EDIT
+ : Commas AnyCursor
+   {
+     parser.suggestKeywords(parser.getColumnDataTypeKeywords());
+   }
+ | Commas ColumnDataType_EDIT
+ | AnyCursor
+   {
+     parser.suggestKeywords(parser.getColumnDataTypeKeywords());
+   }
+ | ColumnDataType_EDIT
+ ;
+
+GreaterThanOrError
+ : '>'
+ | error
+ ;
+
+PrimaryKeySpecification
+ : PrimaryKey ParenthesizedColumnList
+ ;
+
+PrimaryKeySpecification_EDIT
+ : PrimaryKey_EDIT
+ | PrimaryKey_EDIT ParenthesizedColumnList
+ | PrimaryKey ParenthesizedColumnList_EDIT
+ ;
+
+PrimaryKey
+ : 'PRIMARY' 'KEY'
+ ;
+
+PrimaryKey_EDIT
+ : 'PRIMARY' 'CURSOR'
+   {
+     parser.suggestKeywords(['KEY']);
+   }
+ ;
+
+OptionalPartitionedBy
+ :
+ | PartitionedBy
+ ;
+
+PartitionedBy
+ : 'PARTITIONED' 'BY' ParenthesizedColumnSpecificationList
+ | 'PARTITION' 'BY' HashClauses
+ | 'PARTITION' 'BY' HashClauses ',' RangeClause
+ | 'PARTITION' 'BY' RangeClause
+ ;
+
+PartitionedBy_EDIT
+ : 'PARTITIONED' 'CURSOR'
+   {
+     parser.suggestKeywords(['BY']);
+   }
+ | 'PARTITIONED' 'CURSOR' ParenthesizedColumnSpecificationList
+   {
+     parser.suggestKeywords(['BY']);
+   }
+ | 'PARTITIONED' 'BY' ParenthesizedColumnSpecificationList_EDIT
+ | 'PARTITIONED' ParenthesizedColumnSpecificationList_EDIT
+ | 'PARTITION' 'CURSOR'
+   {
+     parser.suggestKeywords(['BY']);
+   }
+ | 'PARTITION' 'BY' 'CURSOR'
+   {
+     parser.suggestKeywords(['HASH', 'RANGE']);
+   }
+ | 'PARTITION' 'BY' HashClauses_EDIT
+ | 'PARTITION' 'BY' RangeClause_EDIT
+ | 'PARTITION' 'BY' HashClauses ',' 'CURSOR'
+   {
+     parser.suggestKeywords(['HASH', 'RANGE']);
+   }
+ | 'PARTITION' 'BY' HashClauses ',' RangeClause_EDIT
+ | 'PARTITION' 'BY' HashClauses_EDIT ',' RangeClause
+ ;
+
+HashClauses
+ : HashClause
+ | HashClauses ',' HashClause
+ ;
+
+HashClauses_EDIT
+ : HashClause_EDIT
+ | HashClauses ',' HashClause_EDIT
+ | HashClauses ',' HashClause_EDIT ',' HashClauses
+ ;
+
+HashClause
+ : 'HASH' OptionalParenthesizedColumnList 'PARTITIONS' UnsignedNumericLiteral
+ ;
+
+HashClause_EDIT
+ : 'HASH' OptionalParenthesizedColumnList 'CURSOR'
+   {
+     parser.suggestKeywords(['PARTITIONS']);
+   }
+ | 'HASH' ParenthesizedColumnList_EDIT
+ | 'HASH' OptionalParenthesizedColumnList 'PARTITIONS' 'CURSOR'
+ | 'HASH' ParenthesizedColumnList_EDIT 'PARTITIONS' UnsignedNumericLiteral
+ ;
+
+RangeClause
+ : AnyRange ParenthesizedColumnList ParenthesizedPartitionValuesList
+ ;
+
+RangeClause_EDIT
+ : AnyRange 'CURSOR'
+ | AnyRange ParenthesizedColumnList_EDIT
+ | AnyRange ParenthesizedColumnList 'CURSOR'
+ | AnyRange ParenthesizedColumnList ParenthesizedPartitionValuesList_EDIT
+ | AnyRange ParenthesizedColumnList_EDIT ParenthesizedPartitionValuesList
+ ;
+
+OptionalSortBy
+ :
+ | SortBy
+ ;
+
+SortBy
+ : 'SORT' 'BY' ParenthesizedColumnList
+ ;
+
+SortBy_EDIT
+ : 'SORT' 'CURSOR'
+   {
+     parser.suggestKeywords(['BY']);
+   }
+ | 'SORT' 'BY' ParenthesizedColumnList_EDIT
+ ;
+
+ParenthesizedPartitionValuesList
+ : '(' PartitionValueList ')'
+ ;
+
+ParenthesizedPartitionValuesList_EDIT
+ : '(' 'CURSOR' RightParenthesisOrError
+   {
+     parser.suggestKeywords(['PARTITION']);
+   }
+ |'(' PartitionValueList_EDIT RightParenthesisOrError
+ ;
+
+PartitionValueList
+ : PartitionValue
+ | PartitionValueList ',' PartitionValue
+ ;
+
+PartitionValueList_EDIT
+ : PartitionValue_EDIT
+ | PartitionValueList ',' 'CURSOR'
+   {
+     parser.suggestKeywords(['PARTITION']);
+   }
+ | PartitionValueList ',' 'CURSOR' ',' PartitionValueList
+   {
+     parser.suggestKeywords(['PARTITION']);
+   }
+ | PartitionValueList ',' PartitionValue_EDIT
+ | PartitionValueList ',' PartitionValue_EDIT ',' PartitionValueList
+ ;
+
+PartitionValue
+ : 'PARTITION' ValueExpression LessThanOrEqualTo 'VALUES' LessThanOrEqualTo ValueExpression
+ | 'PARTITION' 'VALUES' LessThanOrEqualTo ValueExpression
+ | 'PARTITION' ValueExpression LessThanOrEqualTo 'VALUES'
+ | 'PARTITION_VALUE' '=' ValueExpression
+ ;
+
+PartitionValue_EDIT
+ : 'PARTITION' 'CURSOR'
+   {
+     parser.suggestKeywords(['VALUE', 'VALUES']);
+   }
+ | 'PARTITION_VALUE' 'CURSOR'
+   {
+     parser.suggestKeywords(['=']);
+   }
+ | 'PARTITION_VALUE' '=' 'CURSOR'
+   {
+     parser.suggestFunctions();
+   }
+ | 'PARTITION' ValueExpression_EDIT
+   {
+     if ($2.endsWithLessThanOrEqual) {
+      parser.suggestKeywords(['VALUES']);
+     }
+   }
+ | 'PARTITION' ValueExpression 'CURSOR'
+   {
+     parser.suggestKeywords(['<', '<=']);
+   }
+ | 'PARTITION' ValueExpression LessThanOrEqualTo 'CURSOR'
+   {
+     parser.suggestKeywords(['VALUES']);
+   }
+ | 'PARTITION' ValueExpression_EDIT LessThanOrEqualTo 'VALUES'
+ | 'PARTITION' ValueExpression LessThanOrEqualTo 'VALUES' 'CURSOR'
+   {
+     parser.suggestKeywords(['<', '<=']);
+   }
+ | 'PARTITION' ValueExpression LessThanOrEqualTo 'VALUES' LessThanOrEqualTo 'CURSOR'
+   {
+     parser.suggestFunctions();
+   }
+ | 'PARTITION' ValueExpression LessThanOrEqualTo 'VALUES' LessThanOrEqualTo ValueExpression_EDIT
+ | 'PARTITION' 'VALUES' 'CURSOR'
+   {
+     parser.suggestKeywords(['<', '<=']);
+   }
+ | 'PARTITION' 'VALUES' LessThanOrEqualTo 'CURSOR'
+   {
+     parser.suggestFunctions();
+   }
+ | 'PARTITION' 'VALUES' LessThanOrEqualTo ValueExpression_EDIT
+ ;
+
+LessThanOrEqualTo
+ : '<'
+ | 'COMPARISON_OPERATOR' // This is fine for autocompletion
+ ;
+
+ParenthesizedSortList
+ : '(' SortList ')'
+ ;
+
+ParenthesizedSortList_EDIT
+ : '(' SortList_EDIT RightParenthesisOrError
+ ;
+
+SortList
+ : SortIdentifier
+ | SortList ',' SortIdentifier
+ ;
+
+SortList_EDIT
+ : SortIdentifier_EDIT
+ | SortIdentifier_EDIT ',' SortList
+ | SortList ',' SortIdentifier_EDIT
+ | SortList ',' SortIdentifier_EDIT ',' SortList
+ ;
+
+SortIdentifier
+ : ColumnIdentifier OptionalAscOrDesc
+ ;
+
+SortIdentifier_EDIT
+ : ColumnIdentifier OptionalAscOrDesc 'CURSOR'
+   {
+     parser.checkForKeywords($2);
+   }
+ | ColumnIdentifier_EDIT OptionalAscOrDesc
+ | AnyCursor OptionalAscOrDesc
+   {
+     parser.suggestColumns();
+   }
+ ;
+
+OptionalRowFormat
+ :
+ | RowFormat
+ ;
+
+RowFormat
+ : 'ROW' 'FORMAT' RowFormat
+   {
+     $$ = $3
+   }
+ ;
+
+RowFormat_EDIT
+ : 'ROW' 'CURSOR'
+   {
+     parser.suggestKeywords(['FORMAT']);
+   }
+ | 'ROW' 'FORMAT' 'CURSOR'
+   {
+     parser.suggestKeywords(['DELIMITED']);
+   }
+ | 'ROW' 'FORMAT' RowFormat_EDIT
+ ;
+
+OptionalStoredAs
+ :           -> { suggestKeywords: ['STORED AS'] }
+ | StoredAs
+ ;
+
+StoredAs
+ : 'STORED' 'AS' FileFormat
+ ;
+
+StoredAs_EDIT
+ : 'STORED' 'CURSOR'
+   {
+     parser.suggestKeywords(['AS']);
+   }
+ | 'STORED' 'AS' 'CURSOR'
+   {
+     parser.suggestFileFormats();
+   }
+ ;
+
+FileFormat
+ : 'AVRO'
+ | 'KUDU'
+ | 'ORC'
+ | 'PARQUET'
+ | 'RCFILE'
+ | 'SEQUENCEFILE'
+ | 'TEXTFILE'
+ ;
+
+RowFormat
+ : 'DELIMITED' OptionalFieldsTerminatedBy OptionalLinesTerminatedBy
+   {
+     if (!$2 && !$3) {
+       $$ = { suggestKeywords: [{ value: 'FIELDS TERMINATED BY', weight: 2 }, { value: 'LINES TERMINATED BY', weight: 1 }] };
+     } else if ($2 && $2.suggestKeywords && !$3) {
+       $$ = { suggestKeywords: parser.createWeightedKeywords($2.suggestKeywords, 2).concat(['LINES TERMINATED BY']) };
+     } else if (!$3) {
+       $$ = { suggestKeywords: [{ value: 'LINES TERMINATED BY', weight: 1 }] };
+     }
+   }
+ ;
+
+RowFormat_EDIT
+ : 'DELIMITED' OptionalFieldsTerminatedBy_EDIT OptionalLinesTerminatedBy
+ | 'DELIMITED' OptionalFieldsTerminatedBy OptionalLinesTerminatedBy_EDIT
+ ;
+
+OptionalFieldsTerminatedBy
+ :
+ | 'FIELDS' 'TERMINATED' 'BY' SingleQuotedValue  -> { suggestKeywords: ['ESCAPED BY'] }
+ | 'FIELDS' 'TERMINATED' 'BY' SingleQuotedValue 'ESCAPED' 'BY' SingleQuotedValue
+ ;
+
+OptionalFieldsTerminatedBy_EDIT
+ : 'FIELDS' 'CURSOR'
+   {
+     parser.suggestKeywords(['TERMINATED BY']);
+   }
+ | 'FIELDS' 'TERMINATED' 'CURSOR'
+   {
+     parser.suggestKeywords(['BY']);
+   }
+ | 'FIELDS' 'TERMINATED' 'BY' SingleQuotedValue 'ESCAPED' 'CURSOR'
+   {
+     parser.suggestKeywords(['BY']);
+   }
+ ;
+
+OptionalLinesTerminatedBy
+ :
+ | 'LINES' 'TERMINATED' 'BY' SingleQuotedValue
+ ;
+
+OptionalLinesTerminatedBy_EDIT
+ : 'LINES' 'CURSOR'
+   {
+     parser.suggestKeywords(['TERMINATED BY']);
+   }
+ | 'LINES' 'TERMINATED' 'CURSOR'
+   {
+     parser.suggestKeywords(['BY']);
+   }
+ ;
+
+OptionalWithSerdeproperties
+ :
+ | WithSerdeproperties
+ ;
+
+WithSerdeproperties
+ : 'WITH' 'SERDEPROPERTIES' ParenthesizedPropertyAssignmentList
+ ;
+
+WithSerdeproperties_EDIT
+ : 'WITH' 'CURSOR'
+   {
+     parser.suggestKeywords(['SERDEPROPERTIES']);
+   }
+ | 'WITH' 'CURSOR' ParenthesizedPropertyAssignmentList
+   {
+     parser.suggestKeywords(['SERDEPROPERTIES']);
+   }
+ ;
+
+OptionalTblproperties
+ :
+ | TblProperties
+ ;
+
+TblProperties
+ : 'TBLPROPERTIES' ParenthesizedPropertyAssignmentList
+ ;
+
+OptionalAsSelectStatement
+ :
+ | 'AS' CommitLocations QuerySpecification
+ ;
+
+OptionalAsSelectStatement_EDIT
+ : 'AS' CommitLocations 'CURSOR'
+   {
+     parser.suggestKeywords(['SELECT']);
+   }
+ | 'AS' CommitLocations QuerySpecification_EDIT
+ ;
+
+CommitLocations
+ : /* empty */
+   {
+     parser.commitLocations();
+   }
+ ;
+
+ViewDefinition
+ : AnyCreate 'VIEW' OptionalIfNotExists SchemaQualifiedIdentifier OptionalParenthesizedViewColumnList OptionalComment 'AS' QuerySpecification
+ ;
+
+ViewDefinition_EDIT
+ : AnyCreate 'VIEW' OptionalIfNotExists 'CURSOR'
+   {
+     if (!$3) {
+       parser.suggestKeywords(['IF NOT EXISTS']);
+     }
+     parser.suggestDatabases({ appendDot: true });
+   }
+ | AnyCreate 'VIEW' OptionalIfNotExists 'CURSOR' SchemaQualifiedIdentifier OptionalParenthesizedViewColumnList OptionalComment 'AS' QuerySpecification
+   {
+     if (!$3) {
+       parser.suggestKeywords(['IF NOT EXISTS']);
+     }
+   }
+ | AnyCreate 'VIEW' OptionalIfNotExists_EDIT
+ | AnyCreate 'VIEW' OptionalIfNotExists SchemaQualifiedIdentifier ParenthesizedViewColumnList_EDIT OptionalComment
+ | AnyCreate 'VIEW' OptionalIfNotExists SchemaQualifiedIdentifier OptionalParenthesizedViewColumnList OptionalComment 'CURSOR'
+   {
+     var keywords = [{value: 'AS', weight: 1 }];
+     if (!$6) {
+       keywords.push({ value: 'COMMENT', weight: 3 });
+     }
+     parser.suggestKeywords(keywords);
+   }
+ | AnyCreate 'VIEW' OptionalIfNotExists SchemaQualifiedIdentifier OptionalParenthesizedViewColumnList OptionalComment 'AS' 'CURSOR'
+   {
+     parser.suggestKeywords(['SELECT']);
+   }
+ | AnyCreate 'VIEW' OptionalIfNotExists SchemaQualifiedIdentifier OptionalParenthesizedViewColumnList OptionalComment 'AS' QuerySpecification_EDIT
+ | AnyCreate 'VIEW' OptionalIfNotExists SchemaQualifiedIdentifier_EDIT OptionalParenthesizedViewColumnList OptionalComment 'AS' QuerySpecification
+ ;
+
+FunctionDefinition
+ : GenericFunctionDefinition
+ | AggregateFunctionDefinition
+ ;
+
+FunctionDefinition_EDIT
+ : GenericFunctionDefinition_EDIT
+ | AggregateFunctionDefinition_EDIT
+ ;
+
+GenericFunctionDefinition
+ : AnyCreate 'FUNCTION' OptionalIfNotExists SchemaQualifiedIdentifier ParenthesizedArgumentList ReturnType HdfsLocation SymbolDefinition
+ ;
+
+GenericFunctionDefinition_EDIT
+ : AnyCreate 'FUNCTION' OptionalIfNotExists 'CURSOR'
+   {
+     if (!$3) {
+       parser.suggestKeywords(['IF NOT EXISTS']);
+     }
+     parser.suggestDatabases({ appendDot: true });
+   }
+ | AnyCreate 'FUNCTION' OptionalIfNotExists 'CURSOR' SchemaQualifiedIdentifier ParenthesizedArgumentList ReturnType HdfsLocation SymbolDefinition
+   {
+     if (!$3) {
+       parser.suggestKeywords(['IF NOT EXISTS']);
+     }
+   }
+ | AnyCreate 'FUNCTION' OptionalIfNotExists SchemaQualifiedIdentifier ParenthesizedArgumentList 'CURSOR'
+   {
+     parser.suggestKeywords(['RETURNS']);
+   }
+ | AnyCreate 'FUNCTION' OptionalIfNotExists SchemaQualifiedIdentifier ParenthesizedArgumentList ReturnType 'CURSOR'
+   {
+     parser.suggestKeywords(['LOCATION']);
+   }
+ | AnyCreate 'FUNCTION' OptionalIfNotExists SchemaQualifiedIdentifier ParenthesizedArgumentList ReturnType HdfsLocation 'CURSOR'
+   {
+     parser.suggestKeywords(['SYMBOL']);
+   }
+ | AnyCreate 'FUNCTION' OptionalIfNotExists_EDIT
+ | AnyCreate 'FUNCTION' OptionalIfNotExists SchemaQualifiedIdentifier ParenthesizedArgumentList_EDIT
+ | AnyCreate 'FUNCTION' OptionalIfNotExists SchemaQualifiedIdentifier ParenthesizedArgumentList ReturnType_EDIT
+ | AnyCreate 'FUNCTION' OptionalIfNotExists SchemaQualifiedIdentifier ParenthesizedArgumentList ReturnType HdfsLocation_EDIT
+ | AnyCreate 'FUNCTION' OptionalIfNotExists_EDIT SchemaQualifiedIdentifier ParenthesizedArgumentList ReturnType HdfsLocation SymbolDefinition
+ | AnyCreate 'FUNCTION' OptionalIfNotExists SchemaQualifiedIdentifier ParenthesizedArgumentList_EDIT ReturnType HdfsLocation SymbolDefinition
+ | AnyCreate 'FUNCTION' OptionalIfNotExists SchemaQualifiedIdentifier ParenthesizedArgumentList ReturnType_EDIT HdfsLocation SymbolDefinition
+ | AnyCreate 'FUNCTION' OptionalIfNotExists SchemaQualifiedIdentifier ParenthesizedArgumentList ReturnType HdfsLocation_EDIT SymbolDefinition
+ ;
+
+AggregateFunctionDefinition
+ : AnyCreate 'AGGREGATE' 'FUNCTION' OptionalIfNotExists SchemaQualifiedIdentifier ParenthesizedArgumentList ReturnType
+   HdfsLocation OptionalInitFn UpdateFn MergeFn OptionalPrepareFn OptionalCloseFn OptionalSerializeFn OptionalFinalizeFn OptionalIntermediate
+ ;
+
+AggregateFunctionDefinition_EDIT
+ : AnyCreate 'AGGREGATE' 'CURSOR'
+   {
+     parser.suggestKeywords(['FUNCTION']);
+   }
+ | AnyCreate 'AGGREGATE' 'FUNCTION' OptionalIfNotExists 'CURSOR' SchemaQualifiedIdentifier ParenthesizedArgumentList ReturnType
+   HdfsLocation OptionalInitFn UpdateFn MergeFn OptionalPrepareFn OptionalCloseFn OptionalSerializeFn OptionalFinalizeFn OptionalIntermediate
+   {
+     if (!$4) {
+       parser.suggestKeywords(['IF NOT EXISTS']);
+     }
+   }
+ | AnyCreate 'AGGREGATE' 'FUNCTION' OptionalIfNotExists 'CURSOR'
+   {
+     if (!$4) {
+       parser.suggestKeywords(['IF NOT EXISTS']);
+     }
+     parser.suggestDatabases({ appendDot: true });
+   }
+ | AnyCreate 'AGGREGATE' 'FUNCTION' OptionalIfNotExists_EDIT
+ | AnyCreate 'AGGREGATE' 'FUNCTION' OptionalIfNotExists_EDIT SchemaQualifiedIdentifier ParenthesizedArgumentList ReturnType
+   HdfsLocation OptionalInitFn UpdateFn MergeFn OptionalPrepareFn OptionalCloseFn OptionalSerializeFn OptionalFinalizeFn OptionalIntermediate
+ | AnyCreate 'AGGREGATE' 'FUNCTION' OptionalIfNotExists SchemaQualifiedIdentifier ParenthesizedArgumentList_EDIT
+ | AnyCreate 'AGGREGATE' 'FUNCTION' OptionalIfNotExists SchemaQualifiedIdentifier ParenthesizedArgumentList_EDIT ReturnType
+   HdfsLocation OptionalInitFn UpdateFn MergeFn OptionalPrepareFn OptionalCloseFn OptionalSerializeFn OptionalFinalizeFn OptionalIntermediate
+ | AnyCreate 'AGGREGATE' 'FUNCTION' OptionalIfNotExists SchemaQualifiedIdentifier ParenthesizedArgumentList 'CURSOR'
+   {
+     parser.suggestKeywords(['RETURNS']);
+   }
+ | AnyCreate 'AGGREGATE' 'FUNCTION' OptionalIfNotExists SchemaQualifiedIdentifier ParenthesizedArgumentList ReturnType
+   'CURSOR'
+   {
+     parser.suggestKeywords(['LOCATION']);
+   }
+ | AnyCreate 'AGGREGATE' 'FUNCTION' OptionalIfNotExists SchemaQualifiedIdentifier ParenthesizedArgumentList ReturnType
+   HdfsLocation OptionalInitFn 'CURSOR'
+   {
+     if (!$9) {
+       parser.suggestKeywords([{value: 'INIT_FN', weight: 2 }, {value: 'UPDATE_FN', weight: 1 }]);
+     } else {
+       parser.suggestKeywords([{value: 'UPDATE_FN', weight: 1 }]);
+     }
+   }
+ | AnyCreate 'AGGREGATE' 'FUNCTION' OptionalIfNotExists SchemaQualifiedIdentifier ParenthesizedArgumentList ReturnType
+   HdfsLocation OptionalInitFn UpdateFn 'CURSOR'
+   {
+     parser.suggestKeywords(['MERGE_FN']);
+   }
+ | AnyCreate 'AGGREGATE' 'FUNCTION' OptionalIfNotExists SchemaQualifiedIdentifier ParenthesizedArgumentList ReturnType
+   HdfsLocation OptionalInitFn UpdateFn MergeFn OptionalPrepareFn OptionalCloseFn OptionalSerializeFn OptionalFinalizeFn OptionalIntermediate 'CURSOR'
+   {
+     if (!$12 && !$13 && !$14 && !$15 && !$16) {
+       parser.suggestKeywords([{value: 'PREPARE_FN', weight: 5 }, {value: 'CLOSE_FN', weight: 4 }, {value: 'SERIALIZE_FN', weight: 3 }, {value: 'FINALIZE_FN', weight: 2 }, {value: 'INTERMEDIATE', weight: 1 }]);
+     } else if ($12 && !$13 && !$14 && !$15 && !$16) {
+       parser.suggestKeywords([{value: 'CLOSE_FN', weight: 4 }, {value: 'SERIALIZE_FN', weight: 3 }, {value: 'FINALIZE_FN', weight: 2 }, {value: 'INTERMEDIATE', weight: 1 }]);
+     } else if ($13 && !$14 && !$15 && !$16) {
+       parser.suggestKeywords([{value: 'SERIALIZE_FN', weight: 3 }, {value: 'FINALIZE_FN', weight: 2 }, {value: 'INTERMEDIATE', weight: 1 }]);
+     } else if ($14 && !$15 && !$16) {
+       parser.suggestKeywords([{value: 'FINALIZE_FN', weight: 2 }, {value: 'INTERMEDIATE', weight: 1 }]);
+     } else if ($15 && !$16) {
+       parser.suggestKeywords([{value: 'INTERMEDIATE', weight: 1 }]);
+     }
+   }
+ | AnyCreate 'AGGREGATE' 'FUNCTION' OptionalIfNotExists SchemaQualifiedIdentifier ParenthesizedArgumentList ReturnType_EDIT
+ | AnyCreate 'AGGREGATE' 'FUNCTION' OptionalIfNotExists SchemaQualifiedIdentifier ParenthesizedArgumentList ReturnType
+   HdfsLocation_EDIT OptionalInitFn
+ | AnyCreate 'AGGREGATE' 'FUNCTION' OptionalIfNotExists SchemaQualifiedIdentifier ParenthesizedArgumentList ReturnType
+   HdfsLocation OptionalInitFn_EDIT
+ | AnyCreate 'AGGREGATE' 'FUNCTION' OptionalIfNotExists SchemaQualifiedIdentifier ParenthesizedArgumentList ReturnType
+   HdfsLocation OptionalInitFn UpdateFn_EDIT
+ | AnyCreate 'AGGREGATE' 'FUNCTION' OptionalIfNotExists SchemaQualifiedIdentifier ParenthesizedArgumentList ReturnType
+   HdfsLocation OptionalInitFn UpdateFn
+ | AnyCreate 'AGGREGATE' 'FUNCTION' OptionalIfNotExists SchemaQualifiedIdentifier ParenthesizedArgumentList ReturnType
+   HdfsLocation OptionalInitFn UpdateFn MergeFn_EDIT OptionalPrepareFn OptionalCloseFn OptionalSerializeFn OptionalFinalizeFn OptionalIntermediate
+ | AnyCreate 'AGGREGATE' 'FUNCTION' OptionalIfNotExists SchemaQualifiedIdentifier ParenthesizedArgumentList ReturnType
+   HdfsLocation OptionalInitFn UpdateFn MergeFn OptionalPrepareFn_EDIT OptionalCloseFn OptionalSerializeFn OptionalFinalizeFn OptionalIntermediate
+ | AnyCreate 'AGGREGATE' 'FUNCTION' OptionalIfNotExists SchemaQualifiedIdentifier ParenthesizedArgumentList ReturnType
+   HdfsLocation OptionalInitFn UpdateFn MergeFn OptionalPrepareFn OptionalCloseFn_EDIT  OptionalSerializeFn OptionalFinalizeFn OptionalIntermediate
+ | AnyCreate 'AGGREGATE' 'FUNCTION' OptionalIfNotExists SchemaQualifiedIdentifier ParenthesizedArgumentList ReturnType
+   HdfsLocation OptionalInitFn UpdateFn MergeFn OptionalPrepareFn OptionalCloseFn OptionalSerializeFn_EDIT OptionalFinalizeFn OptionalIntermediate
+ | AnyCreate 'AGGREGATE' 'FUNCTION' OptionalIfNotExists SchemaQualifiedIdentifier ParenthesizedArgumentList ReturnType
+   HdfsLocation OptionalInitFn UpdateFn MergeFn OptionalPrepareFn OptionalCloseFn OptionalSerializeFn OptionalFinalizeFn_EDIT OptionalIntermediate
+ | AnyCreate 'AGGREGATE' 'FUNCTION' OptionalIfNotExists SchemaQualifiedIdentifier ParenthesizedArgumentList ReturnType
+   HdfsLocation OptionalInitFn UpdateFn MergeFn OptionalPrepareFn OptionalCloseFn OptionalSerializeFn OptionalFinalizeFn Intermediate_EDIT
+ | AnyCreate 'AGGREGATE' 'FUNCTION' OptionalIfNotExists SchemaQualifiedIdentifier ParenthesizedArgumentList ReturnType_EDIT
+   HdfsLocation OptionalInitFn UpdateFn MergeFn OptionalPrepareFn OptionalCloseFn OptionalSerializeFn OptionalFinalizeFn OptionalIntermediate
+ | AnyCreate 'AGGREGATE' 'FUNCTION' OptionalIfNotExists SchemaQualifiedIdentifier ParenthesizedArgumentList ReturnType
+   HdfsLocation_EDIT OptionalInitFn UpdateFn MergeFn OptionalPrepareFn OptionalCloseFn OptionalSerializeFn OptionalFinalizeFn OptionalIntermediate
+ | AnyCreate 'AGGREGATE' 'FUNCTION' OptionalIfNotExists SchemaQualifiedIdentifier ParenthesizedArgumentList ReturnType
+   HdfsLocation OptionalInitFn_EDIT UpdateFn MergeFn OptionalPrepareFn OptionalCloseFn OptionalSerializeFn OptionalFinalizeFn OptionalIntermediate
+ | AnyCreate 'AGGREGATE' 'FUNCTION' OptionalIfNotExists SchemaQualifiedIdentifier ParenthesizedArgumentList ReturnType
+   HdfsLocation OptionalInitFn UpdateFn_EDIT MergeFn OptionalPrepareFn OptionalCloseFn OptionalSerializeFn OptionalFinalizeFn OptionalIntermediate
+ ;
+
+ParenthesizedArgumentList
+ : '(' ')'
+ | '(' ArgumentList OptionalVariableArguments')'
+ ;
+
+ParenthesizedArgumentList_EDIT
+ : '(' ArgumentList_EDIT RightParenthesisOrError
+   {
+     parser.suggestKeywords(parser.getTypeKeywords());
+   }
+ | '(' ArgumentList 'CURSOR' RightParenthesisOrError
+   {
+     parser.suggestKeywords(['...']);
+   }
+ ;
+
+ArgumentList
+ : PrimitiveType
+ | ArgumentList ',' PrimitiveType
+ ;
+
+ArgumentList_EDIT
+ : AnyCursor
+ | ArgumentList ',' AnyCursor
+ | AnyCursor ',' ArgumentList
+ | ArgumentList ',' AnyCursor ',' ArgumentList
+ ;
+
+OptionalVariableArguments
+ :
+ | '...'
+ ;
+
+ReturnType
+ : 'RETURNS' PrimitiveType
+ ;
+
+ReturnType_EDIT
+ : 'RETURNS' 'CURSOR'
+   {
+     parser.suggestKeywords(parser.getTypeKeywords());
+   }
+ ;
+
+SymbolDefinition
+ : 'SYMBOL' '=' SingleQuotedValue
+ ;
+
+OptionalInitFn
+ :
+ | 'INIT_FN' '=' FunctionReference
+ ;
+
+OptionalInitFn_EDIT
+ : 'INIT_FN' '=' FunctionReference_EDIT
+ ;
+
+UpdateFn
+ : 'UPDATE_FN' '=' FunctionReference
+ ;
+
+UpdateFn_EDIT
+ : 'UPDATE_FN' '=' FunctionReference_EDIT
+ ;
+
+MergeFn
+ : 'MERGE_FN' '=' FunctionReference
+ ;
+
+MergeFn_EDIT
+ : 'MERGE_FN' '=' FunctionReference_EDIT
+ ;
+
+OptionalPrepareFn
+ :
+ | 'PREPARE_FN' '=' FunctionReference
+ ;
+
+OptionalPrepareFn_EDIT
+ : 'PREPARE_FN' '=' FunctionReference_EDIT
+ ;
+
+OptionalCloseFn
+ :
+ | 'CLOSE_FN' '=' FunctionReference
+ ;
+
+OptionalCloseFn_EDIT
+ : 'CLOSE_FN' '=' FunctionReference_EDIT
+ ;
+
+OptionalSerializeFn
+ :
+ | 'SERIALIZE_FN' '=' FunctionReference
+ ;
+
+OptionalSerializeFn_EDIT
+ : 'SERIALIZE_FN' '=' FunctionReference_EDIT
+ ;
+
+OptionalFinalizeFn
+ :
+ | 'FINALIZE_FN' '=' FunctionReference
+ ;
+
+OptionalFinalizeFn_EDIT
+ : 'FINALIZE_FN' '=' FunctionReference_EDIT
+ ;
+
+OptionalIntermediate
+ :
+ | 'INTERMEDIATE' PrimitiveType
+ ;
+
+Intermediate_EDIT
+ : 'INTERMEDIATE' 'CURSOR'
+   {
+     parser.suggestKeywords(parser.getTypeKeywords());
+   }
+ ;
+
+FunctionReference
+ : SingleQuotedValue
+ ;
+
+FunctionReference_EDIT
+ : SingleQuotedValue_EDIT
+   {
+     parser.suggestFunctions();
+     parser.suggestAggregateFunctions();
+     parser.suggestAnalyticFunctions();
+   }
+ ;
+
+OptionalParenthesizedViewColumnList
+ :
+ | ParenthesizedViewColumnList
+ ;
+
+ParenthesizedViewColumnList
+ : '(' ViewColumnList ')'
+ ;
+
+ParenthesizedViewColumnList_EDIT
+ : '(' ViewColumnList_EDIT RightParenthesisOrError
+   {
+     if (!$2) {
+       parser.suggestKeywords(['COMMENT']);
+     }
+   }
+ ;
+
+ViewColumnList
+ : ColumnReference OptionalComment
+ | ViewColumnList ',' ColumnReference OptionalComment
+ ;
+
+ViewColumnList_EDIT
+ : ColumnReference OptionalComment 'CURSOR'                                        --> $2
+ | ColumnReference OptionalComment 'CURSOR' ',' ViewColumnList                     --> $2
+ | ViewColumnList ',' ColumnReference OptionalComment 'CURSOR'                     --> $4
+ | ViewColumnList ',' ColumnReference OptionalComment 'CURSOR' ',' ViewColumnList  --> $4
+ ;
+
+RoleDefinition
+ : AnyCreate 'ROLE' RegularIdentifier
+ ;

+ 504 - 0
desktop/core/src/desktop/js/parse/jison/impala/sql_drop.jison

@@ -0,0 +1,504 @@
+// Licensed to Cloudera, Inc. under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  Cloudera, Inc. licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+DataDefinition
+ : DropStatement
+ | HiveAbortStatement
+ ;
+
+DataDefinition_EDIT
+ : DropStatement_EDIT
+ | HiveAbortStatement_EDIT
+ ;
+
+DataManipulation
+ : HiveDeleteStatement
+ | ImpalaDeleteStatement
+ ;
+
+DataManipulation_EDIT
+ : HiveDeleteStatement_EDIT
+ | ImpalaDeleteStatement_EDIT
+ ;
+
+DropStatement
+ : DropDatabaseStatement
+ | DropFunctionStatement
+ | DropRoleStatement
+ | DropStatsStatement
+ | DropTableStatement
+ | DropIndexStatement
+ | DropMacroStatement
+ | DropViewStatement
+ | TruncateTableStatement
+ ;
+
+DropStatement_EDIT
+ : DropDatabaseStatement_EDIT
+ | DropFunctionStatement_EDIT
+ | DropStatsStatement_EDIT
+ | DropTableStatement_EDIT
+ | DropIndexStatement_EDIT
+ | DropMacroStatement_EDIT
+ | DropViewStatement_EDIT
+ | TruncateTableStatement_EDIT
+ | 'DROP' 'CURSOR'
+   {
+     if (parser.isHive()) {
+       parser.suggestKeywords(['DATABASE', 'FUNCTION', 'INDEX', 'ROLE', 'SCHEMA', 'TABLE', 'TEMPORARY FUNCTION', 'TEMPORARY MACRO', 'VIEW']);
+     } else if (parser.isImpala()) {
+       parser.suggestKeywords(['AGGREGATE FUNCTION', 'DATABASE', 'FUNCTION', 'INCREMENTAL STATS', 'ROLE', 'SCHEMA', 'STATS', 'TABLE', 'VIEW']);
+     } else {
+       parser.suggestKeywords(['ROLE', 'SCHEMA', 'TABLE', 'VIEW']);
+     }
+   }
+ ;
+
+DropDatabaseStatement
+ : 'DROP' DatabaseOrSchema OptionalIfExists RegularOrBacktickedIdentifier OptionalCascadeOrRestrict
+ ;
+
+DropDatabaseStatement_EDIT
+ : 'DROP' DatabaseOrSchema OptionalIfExists
+ | 'DROP' DatabaseOrSchema OptionalIfExists_EDIT
+ | 'DROP' DatabaseOrSchema OptionalIfExists 'CURSOR'
+   {
+     if (!$3) {
+       parser.suggestKeywords(['IF EXISTS']);
+     }
+     parser.suggestDatabases();
+   }
+ | 'DROP' DatabaseOrSchema OptionalIfExists RegularOrBacktickedIdentifier 'CURSOR'
+   {
+     if (parser.isHive() || parser.isImpala()) {
+       parser.suggestKeywords(['CASCADE', 'RESTRICT']);
+     }
+   }
+ | 'DROP' DatabaseOrSchema OptionalIfExists_EDIT RegularOrBacktickedIdentifier OptionalCascadeOrRestrict
+ | 'DROP' DatabaseOrSchema OptionalIfExists 'CURSOR' RegularOrBacktickedIdentifier OptionalCascadeOrRestrict
+   {
+     if (!$3) {
+       parser.suggestKeywords(['IF EXISTS']);
+     }
+   }
+ ;
+
+DropFunctionStatement
+ : DropImpalaFunction
+ | DropHiveFunction
+ ;
+
+DropFunctionStatement_EDIT
+ : DropImpalaFunction_EDIT
+ | DropHiveFunction_EDIT
+ ;
+
+// OptionalAggregate is no go for look ahead reasons
+DropImpalaFunction
+ : 'DROP' '<impala>FUNCTION' OptionalIfExists SchemaQualifiedIdentifier ParenthesizedArgumentList
+ | 'DROP' '<impala>AGGREGATE' '<impala>FUNCTION' OptionalIfExists SchemaQualifiedIdentifier ParenthesizedArgumentList
+ ;
+
+DropImpalaFunction_EDIT
+ : 'DROP' '<impala>FUNCTION' OptionalIfExists 'CURSOR'
+   {
+     if (!$3) {
+       parser.suggestKeywords(['IF EXISTS']);
+     }
+     parser.suggestDatabases({ appendDot: true });
+   }
+ | 'DROP' '<impala>AGGREGATE' '<impala>FUNCTION' OptionalIfExists 'CURSOR'
+   {
+     if (!$4) {
+       parser.suggestKeywords(['IF EXISTS']);
+     }
+     parser.suggestDatabases({ appendDot: true });
+   }
+ | 'DROP' '<impala>FUNCTION' OptionalIfExists 'CURSOR' SchemaQualifiedIdentifier ParenthesizedArgumentList
+   {
+     if (!$3) {
+       parser.suggestKeywords(['IF EXISTS']);
+     }
+   }
+ | 'DROP' '<impala>FUNCTION' OptionalIfExists_EDIT
+ | 'DROP' 'CURSOR' '<impala>FUNCTION' OptionalIfExists SchemaQualifiedIdentifier ParenthesizedArgumentList
+   {
+     parser.suggestKeywords(['AGGREGATE']);
+   }
+ | 'DROP' '<impala>FUNCTION' OptionalIfExists SchemaQualifiedIdentifier ParenthesizedArgumentList_EDIT
+ | 'DROP' '<impala>AGGREGATE' 'CURSOR'
+   {
+     parser.suggestKeywords(['FUNCTION']);
+   }
+ | 'DROP' '<impala>AGGREGATE' '<impala>FUNCTION' OptionalIfExists 'CURSOR' SchemaQualifiedIdentifier ParenthesizedArgumentList
+   {
+     if (!$4) {
+       parser.suggestKeywords(['IF EXISTS']);
+     }
+   }
+ | 'DROP' '<impala>AGGREGATE' '<impala>FUNCTION' OptionalIfExists_EDIT
+ | 'DROP' '<impala>AGGREGATE' '<impala>FUNCTION' OptionalIfExists SchemaQualifiedIdentifier ParenthesizedArgumentList_EDIT
+ | 'DROP' '<impala>FUNCTION' OptionalIfExists SchemaQualifiedIdentifier_EDIT ParenthesizedArgumentList
+ | 'DROP' '<impala>AGGREGATE' '<impala>FUNCTION' OptionalIfExists SchemaQualifiedIdentifier_EDIT ParenthesizedArgumentList
+ ;
+
+DropHiveFunction
+ : 'DROP' '<hive>FUNCTION' OptionalIfExists SchemaQualifiedIdentifier
+ | 'DROP' '<hive>TEMPORARY' '<hive>FUNCTION' OptionalIfExists RegularIdentifier
+ ;
+
+DropHiveFunction_EDIT
+ : 'DROP' '<hive>FUNCTION' OptionalIfExists 'CURSOR'
+   {
+     if (!$3) {
+       parser.suggestKeywords(['IF EXISTS']);
+     }
+   }
+ | 'DROP' '<hive>FUNCTION' OptionalIfExists 'CURSOR' SchemaQualifiedIdentifier
+   {
+     if (!$3) {
+       parser.suggestKeywords(['IF EXISTS']);
+     }
+   }
+ | 'DROP' '<hive>FUNCTION' OptionalIfExists_EDIT
+ | 'DROP' '<hive>FUNCTION' OptionalIfExists_EDIT SchemaQualifiedIdentifier
+ | 'DROP' '<hive>FUNCTION' OptionalIfExists SchemaQualifiedIdentifier_EDIT
+ | 'DROP' '<hive>TEMPORARY' '<hive>FUNCTION' OptionalIfExists 'CURSOR'
+   {
+     if (!$4) {
+       parser.suggestKeywords(['IF EXISTS']);
+     }
+   }
+ | 'DROP' '<hive>TEMPORARY' '<hive>FUNCTION' OptionalIfExists_EDIT
+ ;
+
+DropRoleStatement
+ : 'DROP' 'ROLE' RegularIdentifier
+ ;
+
+DropStatsStatement
+ : 'DROP' '<impala>STATS' SchemaQualifiedTableIdentifier
+   {
+     parser.addTablePrimary($3);
+   }
+ | 'DROP' '<impala>INCREMENTAL' '<impala>STATS' SchemaQualifiedTableIdentifier PartitionSpec
+   {
+     parser.addTablePrimary($4);
+   }
+ ;
+
+DropStatsStatement_EDIT
+ : 'DROP' '<impala>STATS' 'CURSOR'
+   {
+     parser.suggestTables();
+     parser.suggestDatabases({ appendDot: true });
+   }
+ | 'DROP' '<impala>STATS' SchemaQualifiedTableIdentifier_EDIT
+ | 'DROP' 'CURSOR' '<impala>STATS' SchemaQualifiedTableIdentifier
+   {
+     parser.addTablePrimary($4);
+     parser.suggestKeywords(['INCREMENTAL']);
+   }
+ | 'DROP' 'CURSOR' '<impala>STATS' SchemaQualifiedTableIdentifier PartitionSpec
+   {
+     parser.addTablePrimary($4);
+     parser.suggestKeywords(['INCREMENTAL']);
+   }
+ | 'DROP' '<impala>INCREMENTAL' 'CURSOR'
+   {
+     parser.suggestKeywords(['STATS']);
+   }
+ | 'DROP' '<impala>INCREMENTAL' '<impala>STATS' 'CURSOR'
+   {
+     parser.suggestTables();
+     parser.suggestDatabases({ appendDot: true });
+   }
+ | 'DROP' '<impala>INCREMENTAL' '<impala>STATS' SchemaQualifiedTableIdentifier_EDIT
+ | 'DROP' '<impala>INCREMENTAL' '<impala>STATS' SchemaQualifiedTableIdentifier_EDIT PartitionSpec
+ | 'DROP' '<impala>INCREMENTAL' '<impala>STATS' SchemaQualifiedTableIdentifier 'CURSOR'
+   {
+     parser.addTablePrimary($4);
+     parser.suggestKeywords(['PARTITION']);
+   }
+ | 'DROP' '<impala>INCREMENTAL' '<impala>STATS' SchemaQualifiedTableIdentifier PartitionSpec_EDIT
+   {
+     parser.addTablePrimary($4);
+   }
+ ;
+
+DropTableStatement
+ : 'DROP' AnyTable OptionalIfExists SchemaQualifiedTableIdentifier OptionalPurge
+   {
+     parser.addTablePrimary($4);
+   }
+ ;
+
+DropTableStatement_EDIT
+ : 'DROP' AnyTable OptionalIfExists_EDIT
+ | 'DROP' AnyTable OptionalIfExists 'CURSOR'
+   {
+     if (!$3) {
+       parser.suggestKeywords(['IF EXISTS']);
+     }
+     parser.suggestTables({ onlyTables: true });
+     parser.suggestDatabases({
+       appendDot: true
+     });
+   }
+ | 'DROP' AnyTable OptionalIfExists SchemaQualifiedTableIdentifier_EDIT OptionalPurge
+   {
+     if (parser.yy.result.suggestTables) {
+       parser.yy.result.suggestTables.onlyTables = true;
+     }
+   }
+ | 'DROP' AnyTable OptionalIfExists_EDIT SchemaQualifiedTableIdentifier OptionalPurge
+ | 'DROP' AnyTable OptionalIfExists SchemaQualifiedTableIdentifier OptionalPurge 'CURSOR'
+   {
+     parser.addTablePrimary($4);
+     if (!$5) {
+       parser.suggestKeywords(['PURGE']);
+     }
+   }
+ ;
+
+OptionalPurge
+ :
+ | 'PURGE'
+ | '<hive>PURGE'
+ ;
+
+
+DropIndexStatement
+ : 'DROP' '<hive>INDEX' OptionalIfExists RegularOrBacktickedIdentifier 'ON' SchemaQualifiedTableIdentifier
+   {
+     parser.addTablePrimary($6);
+   }
+ ;
+
+DropIndexStatement_EDIT
+ : 'DROP' '<hive>INDEX' OptionalIfExists 'CURSOR'
+   {
+     parser.suggestKeywords(['IF EXISTS']);
+   }
+ | 'DROP' '<hive>INDEX' OptionalIfExists_EDIT
+ | 'DROP' '<hive>INDEX' OptionalIfExists RegularOrBacktickedIdentifier 'CURSOR'
+   {
+     parser.suggestKeywords(['ON']);
+   }
+ | 'DROP' '<hive>INDEX' OptionalIfExists RegularOrBacktickedIdentifier 'ON' 'CURSOR'
+   {
+     parser.suggestTables();
+     parser.suggestDatabases({ appendDot: true });
+   }
+ | 'DROP' '<hive>INDEX' OptionalIfExists RegularOrBacktickedIdentifier 'ON' SchemaQualifiedTableIdentifier_EDIT
+ ;
+
+DropMacroStatement
+ : 'DROP' '<hive>TEMPORARY' '<hive>MACRO' OptionalIfExists RegularIdentifier
+ ;
+
+DropMacroStatement_EDIT
+ : 'DROP' '<hive>TEMPORARY' 'CURSOR'
+   {
+     parser.suggestKeywords(['FUNCTION', 'MACRO']);
+   }
+ | 'DROP' '<hive>TEMPORARY' '<hive>MACRO' OptionalIfExists 'CURSOR'
+   {
+     if (!$4) {
+       parser.suggestKeywords(['IF EXISTS']);
+     }
+   }
+ | 'DROP' '<hive>TEMPORARY' '<hive>MACRO' OptionalIfExists_EDIT
+ ;
+
+DropViewStatement
+ : 'DROP' 'VIEW' OptionalIfExists SchemaQualifiedTableIdentifier
+   {
+     parser.addTablePrimary($4);
+   }
+ ;
+
+DropViewStatement_EDIT
+ : 'DROP' 'VIEW' OptionalIfExists 'CURSOR'
+   {
+     if (!$3) {
+       parser.suggestKeywords(['IF EXISTS']);
+     }
+     parser.suggestTables({ onlyViews: true });
+     parser.suggestDatabases({ appendDot: true });
+   }
+ | 'DROP' 'VIEW' OptionalIfExists 'CURSOR' SchemaQualifiedTableIdentifier
+   {
+     parser.addTablePrimary($5);
+     if (!$3) {
+       parser.suggestKeywords(['IF EXISTS']);
+     }
+   }
+ | 'DROP' 'VIEW' OptionalIfExists_EDIT
+ | 'DROP' 'VIEW' OptionalIfExists_EDIT SchemaQualifiedTableIdentifier
+   {
+     parser.addTablePrimary($4);
+   }
+ | 'DROP' 'VIEW' OptionalIfExists SchemaQualifiedTableIdentifier_EDIT
+   {
+     if (parser.yy.result.suggestTables) {
+       parser.yy.result.suggestTables.onlyViews = true;
+     }
+   }
+ ;
+
+TruncateTableStatement
+ : 'TRUNCATE' AnyTable OptionalIfExists SchemaQualifiedTableIdentifier OptionalPartitionSpec
+   {
+     parser.addTablePrimary($4);
+   }
+ ;
+
+TruncateTableStatement_EDIT
+ : 'TRUNCATE' 'CURSOR'
+   {
+     parser.suggestKeywords(['TABLE']);
+   }
+ | 'TRUNCATE' AnyTable OptionalIfExists 'CURSOR' OptionalPartitionSpec
+   {
+     parser.suggestTables();
+     parser.suggestDatabases({ appendDot: true });
+     if (parser.isImpala() && !$3) {
+       parser.suggestKeywords(['IF EXISTS']);
+     }
+   }
+ | 'TRUNCATE' AnyTable OptionalIfExists_EDIT OptionalPartitionSpec
+ | 'TRUNCATE' AnyTable OptionalIfExists SchemaQualifiedTableIdentifier_EDIT OptionalPartitionSpec
+ | 'TRUNCATE' AnyTable OptionalIfExists SchemaQualifiedTableIdentifier OptionalPartitionSpec 'CURSOR'
+   {
+     parser.addTablePrimary($4);
+     if (parser.isHive() && !$5) {
+       parser.suggestKeywords(['PARTITION']);
+     }
+   }
+ | 'TRUNCATE' AnyTable OptionalIfExists SchemaQualifiedTableIdentifier OptionalPartitionSpec_EDIT
+   {
+     parser.addTablePrimary($4);
+   }
+ | 'TRUNCATE' AnyTable OptionalIfExists 'CURSOR' SchemaQualifiedTableIdentifier OptionalPartitionSpec
+   {
+     parser.addTablePrimary($4);
+     if (parser.isImpala() && !$3) {
+       parser.suggestKeywords(['IF EXISTS']);
+     }
+   }
+ | 'TRUNCATE' AnyTable OptionalIfExists_EDIT SchemaQualifiedTableIdentifier OptionalPartitionSpec
+ ;
+
+HiveDeleteStatement
+ : '<hive>DELETE' 'FROM' SchemaQualifiedTableIdentifier OptionalWhereClause
+   {
+     parser.addTablePrimary($3);
+   }
+ ;
+
+HiveDeleteStatement_EDIT
+ : '<hive>DELETE' 'CURSOR'
+   {
+     parser.suggestKeywords(['FROM']);
+   }
+ | '<hive>DELETE' 'FROM' 'CURSOR'
+   {
+     parser.suggestTables();
+     parser.suggestDatabases({ appendDot: true });
+   }
+ | '<hive>DELETE' 'FROM' SchemaQualifiedTableIdentifier 'CURSOR' OptionalWhereClause
+   {
+     parser.addTablePrimary($3);
+     if (!$5) {
+       parser.suggestKeywords(['WHERE']);
+     }
+   }
+ | '<hive>DELETE' 'FROM' SchemaQualifiedTableIdentifier_EDIT OptionalWhereClause
+ | '<hive>DELETE' 'FROM' SchemaQualifiedTableIdentifier WhereClause_EDIT
+   {
+     parser.addTablePrimary($3);
+   }
+ ;
+
+ImpalaDeleteStatement
+ : '<impala>DELETE' OptionalImpalaDeleteTableRef 'FROM' TableReference OptionalWhereClause
+ ;
+
+ImpalaDeleteStatement_EDIT
+ : '<impala>DELETE' OptionalImpalaDeleteTableRef 'CURSOR'
+   {
+     parser.suggestKeywords(['FROM']);
+     if (parser.isImpala() && !$2) {
+       parser.suggestTables();
+       parser.suggestDatabases({ appendDot: true });
+     }
+   }
+ | '<impala>DELETE' ImpalaDeleteTableRef_EDIT
+ | '<impala>DELETE' OptionalImpalaDeleteTableRef 'FROM' 'CURSOR'
+   {
+     parser.suggestTables();
+     parser.suggestDatabases({ appendDot: true });
+   }
+ | '<impala>DELETE' OptionalImpalaDeleteTableRef 'FROM' TableReference 'CURSOR' OptionalWhereClause
+   {
+     var keywords = [{ value: 'FULL JOIN', weight: 1 }, { value: 'FULL OUTER JOIN', weight: 1 }, { value: 'JOIN', weight: 1 }, { value: 'LEFT JOIN', weight: 1 }, { value: 'LEFT OUTER JOIN', weight: 1 }, { value: 'RIGHT JOIN', weight: 1 }, { value: 'RIGHT OUTER JOIN', weight: 1 }, { value: 'INNER JOIN', weight: 1 },  { value: 'LEFT ANTI JOIN', weight: 1 }, { value: 'LEFT SEMI JOIN', weight: 1 }, { value: 'RIGHT ANTI JOIN', weight: 1 }, { value: 'RIGHT SEMI JOIN', weight: 1 }];
+     if (!$6) {
+       keywords.push({ value: 'WHERE', weight: 3 });
+     }
+     if ($4.suggestJoinConditions) {
+       parser.suggestJoinConditions($4.suggestJoinConditions);
+     }
+     if ($4.suggestJoins) {
+       parser.suggestJoins($4.suggestJoins);
+     }
+     if ($4.suggestKeywords) {
+       keywords = keywords.concat(parser.createWeightedKeywords($4.suggestKeywords, 2));
+     }
+     if (keywords.length > 0) {
+       parser.suggestKeywords(keywords);
+     }
+   }
+ | '<impala>DELETE' ImpalaDeleteTableRef_EDIT 'FROM'
+ | '<impala>DELETE' ImpalaDeleteTableRef_EDIT 'FROM' TableReference OptionalWhereClause
+ | '<impala>DELETE' OptionalImpalaDeleteTableRef 'FROM' TableReference_EDIT OptionalWhereClause
+ | '<impala>DELETE' OptionalImpalaDeleteTableRef 'FROM' TableReference WhereClause_EDIT
+ ;
+
+OptionalImpalaDeleteTableRef
+ :
+ | TableReference
+ ;
+
+ImpalaDeleteTableRef_EDIT
+ : TableReference_EDIT
+ ;
+
+HiveAbortStatement
+ : '<hive>ABORT' '<hive>TRANSACTIONS' TransactionIdList
+ ;
+
+HiveAbortStatement_EDIT
+ : '<hive>ABORT' 'CURSOR'
+   {
+     parser.suggestKeywords(['TRANSACTIONS']);
+   }
+ ;
+
+TransactionIdList
+ : UnsignedNumericLiteral
+ | TransactionIdList ',' UnsignedNumericLiteral
+ ;

+ 190 - 0
desktop/core/src/desktop/js/parse/jison/impala/sql_error.jison

@@ -0,0 +1,190 @@
+// Licensed to Cloudera, Inc. under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  Cloudera, Inc. licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+SqlStatements
+ : error
+ | NonStartingToken error // Having just ': error' does not work for some reason, jison bug?
+ ;
+
+SqlStatement_EDIT
+ : AnyCursor error
+   {
+     if (parser.isHive()) {
+       parser.suggestDdlAndDmlKeywords(['EXPLAIN', 'FROM']);
+     } else if (parser.isImpala()) {
+       parser.suggestDdlAndDmlKeywords(['EXPLAIN']);
+     } else {
+       parser.suggestDdlAndDmlKeywords();
+     }
+   }
+ ;
+
+SelectStatement
+ : 'SELECT' OptionalAllOrDistinct OptionalStraightJoin SelectList_ERROR TableExpression
+ | 'SELECT' OptionalAllOrDistinct OptionalStraightJoin SelectList TableExpression_ERROR
+ ;
+
+SelectStatement_EDIT
+ : 'SELECT' OptionalAllOrDistinct OptionalStraightJoin SelectList_ERROR_EDIT TableExpression
+   {
+     parser.selectListNoTableSuggest($4, $2);
+   }
+ | 'SELECT' OptionalAllOrDistinct OptionalStraightJoin SelectList_ERROR TableExpression_EDIT
+ ;
+
+SelectList_ERROR
+ : ErrorList
+ | SelectList ',' ErrorList
+ | ErrorList ',' SelectList ',' ErrorList
+ | ErrorList ',' SelectList
+ | SelectList ',' ErrorList ',' SelectList
+ ;
+
+SelectList_ERROR_EDIT
+ : ErrorList ',' SelectList_EDIT                               -> $3
+ | SelectList ',' ErrorList ',' SelectList_EDIT                -> $5
+ | ErrorList ',' SelectList ',' ErrorList ',' SelectList_EDIT  -> $7
+ | ErrorList ',' AnyCursor
+   {
+     $$ = { cursorAtStart : false, suggestFunctions: true, suggestColumns: true, suggestAggregateFunctions: true };
+   }
+ | SelectList ',' ErrorList ',' AnyCursor
+   {
+     $$ = { cursorAtStart : false, suggestFunctions: true, suggestColumns: true, suggestAggregateFunctions: true };
+   }
+ | ErrorList ',' SelectList ',' Errors ',' AnyCursor
+   {
+     $$ = { cursorAtStart : true, suggestFunctions: true, suggestColumns: true, suggestAggregateFunctions: true };
+   }
+ ;
+
+SetSpecification
+ : 'SET' SetOption '=' error
+ ;
+
+ErrorList
+ : error
+ | Errors ',' error
+ ;
+
+LateralView
+ : '<hive>LATERAL' '<hive>VIEW' OptionalOuter ArbitraryFunction RegularOrBacktickedIdentifier '<hive>AS' error  -> { }
+ | '<hive>LATERAL' '<hive>VIEW' OptionalOuter ArbitraryFunction error                                           -> { }
+ | '<hive>LATERAL' '<hive>VIEW' OptionalOuter error                                                               -> { }
+ | '<hive>LATERAL' error                                                                                          -> { }
+ ;
+
+JoinType_EDIT
+ : 'FULL' 'CURSOR' error
+   {
+     parser.suggestKeywords(['JOIN', 'OUTER JOIN']);
+   }
+ | 'LEFT' 'CURSOR' error
+   {
+     if (parser.isHive()) {
+       parser.suggestKeywords(['JOIN', 'OUTER JOIN', 'SEMI JOIN']);
+     } else if (parser.isImpala()) {
+       parser.suggestKeywords(['ANTI JOIN', 'INNER JOIN', 'JOIN', 'OUTER JOIN', 'SEMI JOIN']);
+     } else {
+       parser.suggestKeywords(['JOIN', 'OUTER JOIN']);
+     }
+   }
+ | 'RIGHT' 'CURSOR' error
+   {
+     if (parser.isImpala()) {
+       parser.suggestKeywords(['ANTI JOIN', 'INNER JOIN', 'JOIN', 'OUTER JOIN', 'SEMI JOIN']);
+     } else {
+       parser.suggestKeywords(['JOIN', 'OUTER JOIN']);
+     }
+   }
+ ;
+
+OptionalSelectConditions_EDIT
+ : WhereClause error 'CURSOR' OptionalGroupByClause OptionalHavingClause OptionalWindowClause OptionalOrderByClause OptionalClusterOrDistributeBy OptionalLimitClause OptionalOffsetClause
+   {
+     $$ = {
+       suggestKeywords: parser.getKeywordsForOptionalsLR([$4, $5, $6, $7, $8, $9, $10], [{ value: 'GROUP BY', weight: 8 }, { value: 'HAVING', weight: 7 }, { value: 'WINDOW', weight: 6 }, { value: 'ORDER BY', weight: 5 }, [{ value: 'CLUSTER BY', weight: 4 }, { value: 'DISTRIBUTE BY', weight: 4 }, { value: 'SORT BY', weight: 4 }], { value: 'LIMIT', weight: 3 }, { value: 'OFFSET', weight: 2 }], [true, true, parser.isHive(), true, parser.isHive(), true, parser.isImpala()]),
+       cursorAtEnd: !$4 && !$5 && !$6 && !$7 && !$8 && !$9 && !$10
+     };
+   }
+ | OptionalWhereClause OptionalGroupByClause HavingClause error 'CURSOR' OptionalWindowClause OptionalOrderByClause OptionalClusterOrDistributeBy OptionalLimitClause OptionalOffsetClause
+   {
+     $$ = {
+       suggestKeywords: parser.getKeywordsForOptionalsLR([$6, $7, $8, $9, $10], [{ value: 'WINDOW', weight: 6 }, { value: 'ORDER BY', weight: 5 }, [{ value: 'CLUSTER BY', weight: 4 }, { value: 'DISTRIBUTE BY', weight: 4 }, { value: 'SORT BY', weight: 4 }], { value: 'LIMIT', weight: 3 }, { value: 'OFFSET', weight: 2 }], [parser.isHive(), true, parser.isHive(), true, parser.isImpala()]),
+       cursorAtEnd: !$6 && !$7 && !$8 && !$9 && !$10
+     }
+   }
+ | OptionalWhereClause OptionalGroupByClause OptionalHavingClause WindowClause error 'CURSOR' OptionalOrderByClause OptionalClusterOrDistributeBy OptionalLimitClause OptionalOffsetClause
+   {
+     $$ = {
+       suggestKeywords: parser.getKeywordsForOptionalsLR([$7, $8, $9, $10], [{ value: 'ORDER BY', weight: 5 }, [{ value: 'CLUSTER BY', weight: 4 }, { value: 'DISTRIBUTE BY', weight: 4 }, { value: 'SORT BY', weight: 4 }], { value: 'LIMIT', weight: 3 }, { value: 'OFFSET', weight: 2 }], [true, parser.isHive(), true, parser.isImpala()]),
+       cursorAtEnd: !$7 && !$8 && !$9 && !$10
+     }
+   }
+ | OptionalWhereClause OptionalGroupByClause OptionalHavingClause OptionalWindowClause OrderByClause error 'CURSOR' OptionalClusterOrDistributeBy OptionalLimitClause OptionalOffsetClause
+   {
+     $$ = {
+       suggestKeywords: parser.getKeywordsForOptionalsLR([$8, $9, $10], [[{ value: 'CLUSTER BY', weight: 4 }, { value: 'DISTRIBUTE BY', weight: 4 }, { value: 'SORT BY', weight: 4 }], { value: 'LIMIT', weight: 3 }, { value: 'OFFSET', weight: 2 }], [parser.isHive(), true, parser.isImpala()]),
+       cursorAtEnd: !$8 && !$9 && !$10
+     }
+   }
+ | OptionalWhereClause OptionalGroupByClause OptionalHavingClause OptionalWindowClause OptionalOrderByClause ClusterOrDistributeBy error 'CURSOR' OptionalLimitClause OptionalOffsetClause
+   {
+     $$ = {
+       suggestKeywords: parser.getKeywordsForOptionalsLR([$9, $10], [{ value: 'LIMIT', weight: 3 }, { value: 'OFFSET', weight: 2 }], [true, parser.isImpala()]),
+       cursorAtEnd: !$9 && !$10
+     }
+   }
+ | OptionalWhereClause OptionalGroupByClause OptionalHavingClause OptionalWindowClause OptionalOrderByClause OptionalClusterOrDistributeBy LimitClause error 'CURSOR' OptionalOffsetClause
+   {
+     $$ = {
+       suggestKeywords: parser.getKeywordsForOptionalsLR([$10], [{ value: 'OFFSET', weight: 2 }], [parser.isImpala()]),
+       cursorAtEnd: !$10
+     }
+   }
+ ;
+
+OptionalSelectConditions_EDIT
+ : WhereClause error GroupByClause_EDIT OptionalHavingClause OptionalWindowClause OptionalOrderByClause OptionalClusterOrDistributeBy OptionalLimitClause OptionalOffsetClause
+ | WhereClause error OptionalGroupByClause HavingClause_EDIT OptionalWindowClause OptionalOrderByClause OptionalClusterOrDistributeBy OptionalLimitClause OptionalOffsetClause
+ | WhereClause error OptionalGroupByClause OptionalHavingClause WindowClause_EDIT OptionalOrderByClause OptionalClusterOrDistributeBy OptionalLimitClause OptionalOffsetClause
+ | WhereClause error OptionalGroupByClause OptionalHavingClause OptionalWindowClause OrderByClause_EDIT OptionalClusterOrDistributeBy OptionalLimitClause OptionalOffsetClause
+ | WhereClause error OptionalGroupByClause OptionalHavingClause OptionalWindowClause OptionalOrderByClause ClusterOrDistributeBy_EDIT OptionalLimitClause OptionalOffsetClause
+ | WhereClause error OptionalGroupByClause OptionalHavingClause OptionalWindowClause OptionalOrderByClause OptionalClusterOrDistributeBy LimitClause_EDIT OptionalOffsetClause
+ | WhereClause error OptionalGroupByClause OptionalHavingClause OptionalWindowClause OptionalOrderByClause OptionalClusterOrDistributeBy OptionalLimitClause OffsetClause_EDIT
+ | OptionalWhereClause GroupByClause error HavingClause_EDIT OptionalWindowClause OptionalOrderByClause OptionalClusterOrDistributeBy OptionalLimitClause OptionalOffsetClause
+ | OptionalWhereClause GroupByClause error OptionalHavingClause WindowClause_EDIT OptionalOrderByClause OptionalClusterOrDistributeBy OptionalLimitClause OptionalOffsetClause
+ | OptionalWhereClause GroupByClause error OptionalHavingClause OptionalWindowClause OrderByClause_EDIT OptionalClusterOrDistributeBy OptionalLimitClause OptionalOffsetClause
+ | OptionalWhereClause GroupByClause error OptionalHavingClause OptionalWindowClause OptionalOrderByClause ClusterOrDistributeBy_EDIT OptionalLimitClause OptionalOffsetClause
+ | OptionalWhereClause GroupByClause error OptionalHavingClause OptionalWindowClause OptionalOrderByClause OptionalClusterOrDistributeBy LimitClause_EDIT OptionalOffsetClause
+ | OptionalWhereClause GroupByClause error OptionalHavingClause OptionalWindowClause OptionalOrderByClause OptionalClusterOrDistributeBy OptionalLimitClause OffsetClause_EDIT
+ | OptionalWhereClause OptionalGroupByClause HavingClause error WindowClause_EDIT OptionalOrderByClause OptionalClusterOrDistributeBy OptionalLimitClause OptionalOffsetClause
+ | OptionalWhereClause OptionalGroupByClause HavingClause error OptionalWindowClause OrderByClause_EDIT OptionalClusterOrDistributeBy OptionalLimitClause OptionalOffsetClause
+ | OptionalWhereClause OptionalGroupByClause HavingClause error OptionalWindowClause OptionalOrderByClause ClusterOrDistributeBy_EDIT OptionalLimitClause OptionalOffsetClause
+ | OptionalWhereClause OptionalGroupByClause HavingClause error OptionalWindowClause OptionalOrderByClause OptionalClusterOrDistributeBy LimitClause_EDIT OptionalOffsetClause
+ | OptionalWhereClause OptionalGroupByClause HavingClause error OptionalWindowClause OptionalOrderByClause OptionalClusterOrDistributeBy OptionalLimitClause OffsetClause_EDIT
+ | OptionalWhereClause OptionalGroupByClause OptionalHavingClause WindowClause error OrderByClause_EDIT OptionalClusterOrDistributeBy OptionalLimitClause OptionalOffsetClause
+ | OptionalWhereClause OptionalGroupByClause OptionalHavingClause WindowClause error OptionalOrderByClause ClusterOrDistributeBy_EDIT OptionalLimitClause OptionalOffsetClause
+ | OptionalWhereClause OptionalGroupByClause OptionalHavingClause WindowClause error OptionalOrderByClause OptionalClusterOrDistributeBy LimitClause_EDIT OptionalOffsetClause
+ | OptionalWhereClause OptionalGroupByClause OptionalHavingClause WindowClause error OptionalOrderByClause OptionalClusterOrDistributeBy OptionalLimitClause OffsetClause_EDIT
+ | OptionalWhereClause OptionalGroupByClause OptionalHavingClause OptionalWindowClause OrderByClause error ClusterOrDistributeBy_EDIT OptionalLimitClause OptionalOffsetClause
+ | OptionalWhereClause OptionalGroupByClause OptionalHavingClause OptionalWindowClause OrderByClause error OptionalClusterOrDistributeBy LimitClause_EDIT OptionalOffsetClause
+ | OptionalWhereClause OptionalGroupByClause OptionalHavingClause OptionalWindowClause OrderByClause error OptionalClusterOrDistributeBy OptionalLimitClause OffsetClause_EDIT
+ ;
+
+DatabaseDefinition_EDIT
+ : AnyCreate DatabaseOrSchema OptionalIfNotExists RegularIdentifier DatabaseDefinitionOptionals_EDIT error
+ ;

+ 519 - 0
desktop/core/src/desktop/js/parse/jison/impala/sql_grant.jison

@@ -0,0 +1,519 @@
+// Licensed to Cloudera, Inc. under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  Cloudera, Inc. licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+DataDefinition
+ : GrantStatement
+ | RevokeStatement
+ ;
+
+DataDefinition_EDIT
+ : GrantStatement_EDIT
+ | RevokeStatement_EDIT
+ ;
+
+GrantStatement
+ : '<hive>GRANT' HivePrivilegeTypeList OptionalOnSpecification 'TO' PrincipalSpecificationList OptionalWithGrantOption
+ | '<hive>GRANT' UserOrRoleList 'TO' PrincipalSpecificationList OptionalWithAdminOption
+ | '<hive>GRANT' '<hive>ROLE' UserOrRoleList 'TO' PrincipalSpecificationList OptionalWithAdminOption
+ | '<impala>GRANT' '<impala>ROLE' RegularOrBacktickedIdentifier 'TO' '<impala>GROUP' RegularOrBacktickedIdentifier
+ | '<impala>GRANT' ImpalaPrivilegeType 'ON' ImpalaObjectSpecification 'TO' RegularOrBacktickedIdentifier OptionalWithGrantOption
+ | '<impala>GRANT' ImpalaPrivilegeType 'ON' ImpalaObjectSpecification 'TO' '<impala>ROLE' RegularOrBacktickedIdentifier OptionalWithGrantOption
+ ;
+
+GrantStatement_EDIT
+ : '<hive>GRANT' 'CURSOR'
+   {
+     parser.suggestKeywords(['ALL', 'ALTER', 'CREATE', 'DELETE', 'DROP', 'INDEX', 'INSERT', 'LOCK', 'ROLE', 'SELECT', 'UPDATE']);
+   }
+ | '<hive>GRANT' HivePrivilegeTypeList_EDIT OptionalOnSpecification
+ | '<hive>GRANT' HivePrivilegeTypeList OnSpecification_EDIT
+ | '<hive>GRANT' HivePrivilegeTypeList OptionalOnSpecification 'CURSOR'
+   {
+     if (!$3) {
+       parser.suggestKeywords(['ON', 'TO']);
+     } else {
+       parser.suggestKeywords(['TO']);
+     }
+   }
+ | '<hive>GRANT' HivePrivilegeTypeList OptionalOnSpecification 'TO' 'CURSOR'
+   {
+     parser.suggestKeywords(['GROUP', 'ROLE', 'USER']);
+   }
+ | '<hive>GRANT' HivePrivilegeTypeList OptionalOnSpecification 'TO' PrincipalSpecificationList_EDIT
+ | '<hive>GRANT' HivePrivilegeTypeList OptionalOnSpecification 'TO' PrincipalSpecificationList OptionalWithGrantOption 'CURSOR'
+   {
+     if (!$6) {
+       parser.suggestKeywords(['WITH GRANT OPTION']);
+     }
+   }
+ | '<hive>GRANT' HivePrivilegeTypeList OptionalOnSpecification 'TO' PrincipalSpecificationList WithGrantOption_EDIT
+ | '<hive>GRANT' UserOrRoleList 'CURSOR'
+   {
+     parser.suggestKeywords(['TO']);
+   }
+ | '<hive>GRANT' UserOrRoleList 'TO' 'CURSOR'
+   {
+     parser.suggestKeywords(['GROUP', 'ROLE', 'USER']);
+   }
+ | '<hive>GRANT' UserOrRoleList 'TO' PrincipalSpecificationList_EDIT
+ | '<hive>GRANT' UserOrRoleList 'TO' PrincipalSpecificationList OptionalWithAdminOption 'CURSOR'
+   {
+     if (!$5) {
+       parser.suggestKeywords(['WITH ADMIN OPTION']);
+     }
+   }
+ | '<hive>GRANT' UserOrRoleList 'TO' PrincipalSpecificationList WithAdminOption_EDIT
+ | '<hive>GRANT' '<hive>ROLE' UserOrRoleList 'TO' 'CURSOR'
+   {
+     parser.suggestKeywords(['GROUP', 'ROLE', 'USER']);
+   }
+ | '<hive>GRANT' '<hive>ROLE' UserOrRoleList 'TO' PrincipalSpecificationList_EDIT
+ | '<hive>GRANT' '<hive>ROLE' UserOrRoleList 'TO' PrincipalSpecificationList OptionalWithAdminOption 'CURSOR'
+   {
+     if (!$6) {
+       parser.suggestKeywords(['WITH ADMIN OPTION']);
+     }
+   }
+ | '<hive>GRANT' '<hive>ROLE' UserOrRoleList 'TO' PrincipalSpecificationList WithAdminOption_EDIT
+ | '<impala>GRANT' 'CURSOR'
+   {
+     parser.suggestKeywords(['ALL', 'ALTER', 'CREATE', 'DROP', 'INSERT', 'REFRESH', 'ROLE', 'SELECT']);
+   }
+ | '<impala>GRANT' '<impala>ROLE' RegularOrBacktickedIdentifier 'CURSOR'
+   {
+     parser.suggestKeywords(['TO GROUP']);
+   }
+ | '<impala>GRANT' '<impala>ROLE' RegularOrBacktickedIdentifier 'TO' 'CURSOR'
+   {
+     parser.suggestKeywords(['GROUP']);
+   }
+ | '<impala>GRANT' ImpalaPrivilegeType_EDIT
+ | '<impala>GRANT' ImpalaPrivilegeType 'CURSOR'
+   {
+     if ($2.isCreate) {
+       parser.suggestKeywords(['ON DATABASE', 'ON SERVER']);
+     } else {
+       parser.suggestKeywords(['ON DATABASE', 'ON SERVER', 'ON TABLE', 'ON URI']);
+     }
+   }
+ | '<impala>GRANT' ImpalaPrivilegeType 'ON' 'CURSOR'
+   {
+     if ($2.isCreate) {
+        parser.suggestKeywords(['DATABASE', 'SERVER']);
+     } else {
+        parser.suggestKeywords(['DATABASE', 'SERVER', 'TABLE', 'URI']);
+     }
+   }
+ | '<impala>GRANT' ImpalaPrivilegeType 'ON' ImpalaObjectSpecification_EDIT
+ | '<impala>GRANT' ImpalaPrivilegeType 'ON' ImpalaObjectSpecification 'CURSOR'
+   {
+     parser.suggestKeywords(['TO']);
+   }
+ | '<impala>GRANT' ImpalaPrivilegeType 'ON' ImpalaObjectSpecification 'TO' 'CURSOR'
+   {
+     parser.suggestKeywords(['ROLE']);
+   }
+ | '<impala>GRANT' ImpalaPrivilegeType 'ON' ImpalaObjectSpecification 'TO' RegularOrBacktickedIdentifier OptionalWithGrantOption 'CURSOR'
+   {
+     if (!$7) {
+       parser.suggestKeywords(['WITH GRANT OPTION']);
+     }
+   }
+ | '<impala>GRANT' ImpalaPrivilegeType 'ON' ImpalaObjectSpecification 'TO' RegularOrBacktickedIdentifier WithGrantOption_EDIT
+ | '<impala>GRANT' ImpalaPrivilegeType 'ON' ImpalaObjectSpecification 'TO' '<impala>ROLE' RegularOrBacktickedIdentifier OptionalWithGrantOption 'CURSOR'
+   {
+     if (!$8) {
+       parser.suggestKeywords(['WITH GRANT OPTION']);
+     }
+   }
+ | '<impala>GRANT' ImpalaPrivilegeType 'ON' ImpalaObjectSpecification 'TO' '<impala>ROLE' RegularOrBacktickedIdentifier WithGrantOption_EDIT
+ ;
+
+OptionalOnSpecification
+ :
+ | 'ON' HiveObjectSpecification
+ ;
+
+OnSpecification_EDIT
+ : 'ON' 'CURSOR'
+   {
+     parser.suggestKeywords(['DATABASE', 'TABLE']);
+     parser.suggestTables();
+     parser.suggestDatabases({ appendDot: true });
+   }
+ | 'ON' HiveObjectSpecification_EDIT
+ ;
+
+HiveObjectSpecification
+ : 'DATABASE' RegularOrBacktickedIdentifier
+ | '<hive>TABLE' SchemaQualifiedTableIdentifier
+   {
+     parser.addTablePrimary($2);
+   }
+ | SchemaQualifiedTableIdentifier
+   {
+     parser.addTablePrimary($1);
+   }
+ ;
+
+HiveObjectSpecification_EDIT
+ : 'DATABASE' 'CURSOR'
+   {
+     parser.suggestDatabases();
+   }
+ | '<hive>TABLE' 'CURSOR'
+   {
+     parser.suggestTables();
+     parser.suggestDatabases({ appendDot: true });
+   }
+ | '<hive>TABLE' SchemaQualifiedTableIdentifier_EDIT
+ | SchemaQualifiedTableIdentifier_EDIT
+ ;
+
+ImpalaObjectSpecification
+ : 'DATABASE' RegularOrBacktickedIdentifier
+   {
+     parser.addDatabaseLocation(@2, [ { name: $2 } ]);
+   }
+ | '<impala>TABLE' SchemaQualifiedTableIdentifier
+   {
+     parser.addTablePrimary($2);
+   }
+ | '<impala>SERVER' RegularOrBacktickedIdentifier
+ | '<impala>URI' RegularOrBacktickedIdentifier
+ ;
+
+ImpalaObjectSpecification_EDIT
+ : 'DATABASE' 'CURSOR'
+   {
+     parser.suggestDatabases();
+   }
+ | '<impala>TABLE' 'CURSOR'
+   {
+     parser.suggestTables();
+     parser.suggestDatabases({ appendDot: true });
+   }
+ | '<impala>TABLE' SchemaQualifiedTableIdentifier_EDIT
+ ;
+
+HivePrivilegeTypeList
+ : HivePrivilegeTypeWithOptionalColumn
+   {
+     if ($1.toUpperCase() === 'ALL') {
+       $$ = { singleAll: true };
+     }
+   }
+ | HivePrivilegeTypeList ',' HivePrivilegeTypeWithOptionalColumn
+ ;
+
+HivePrivilegeTypeList_EDIT
+ : HivePrivilegeTypeWithOptionalColumn_EDIT
+ | HivePrivilegeTypeList ',' HivePrivilegeTypeWithOptionalColumn_EDIT
+ | HivePrivilegeTypeWithOptionalColumn_EDIT ',' HivePrivilegeTypeList
+ | HivePrivilegeTypeList ',' HivePrivilegeTypeWithOptionalColumn_EDIT ',' HivePrivilegeTypeList
+ | 'CURSOR' ',' HivePrivilegeTypeList
+   {
+     parser.suggestKeywords(['ALL', 'ALTER', 'CREATE', 'DELETE', 'DROP', 'INDEX', 'INSERT', 'LOCK', 'SELECT', 'SHOW_DATABASE', 'UPDATE']);
+   }
+ | HivePrivilegeTypeList ',' 'CURSOR'
+   {
+     parser.suggestKeywords(['ALL', 'ALTER', 'CREATE', 'DELETE', 'DROP', 'INDEX', 'INSERT', 'LOCK', 'SELECT', 'SHOW_DATABASE', 'UPDATE']);
+   }
+ | HivePrivilegeTypeList ',' 'CURSOR' ',' HivePrivilegeTypeList
+   {
+     parser.suggestKeywords(['ALL', 'ALTER', 'CREATE', 'DELETE', 'DROP', 'INDEX', 'INSERT', 'LOCK', 'SELECT', 'SHOW_DATABASE', 'UPDATE']);
+   }
+ ;
+
+HivePrivilegeTypeWithOptionalColumn
+ : HivePrivilegeType OptionalParenthesizedColumnList
+ ;
+
+HivePrivilegeTypeWithOptionalColumn_EDIT
+ : HivePrivilegeType ParenthesizedColumnList_EDIT
+ ;
+
+HivePrivilegeType
+ : '<hive>INSERT'
+ | 'SELECT'
+ | 'UPDATE'
+ | '<hive>DELETE'
+ | 'ALTER'
+ | '<hive>CREATE'
+ | 'DROP'
+ | '<hive>INDEX'
+ | '<hive>LOCK'
+ | '<hive>SHOW_DATABASE'
+ | '<hive>ALL'
+ ;
+
+ImpalaPrivilegeType
+ : 'ALL'
+ | 'ALTER'
+ | '<impala>CREATE'  --> { isCreate: true }
+ | 'DROP'
+ | '<impala>INSERT'
+ | '<impala>REFRESH'
+ | 'SELECT' OptionalParenthesizedColumnList
+ ;
+
+ImpalaPrivilegeType_EDIT
+ : 'SELECT' ParenthesizedColumnList_EDIT
+ ;
+
+PrincipalSpecificationList
+ : PrincipalSpecification
+ | PrincipalSpecificationList ',' PrincipalSpecification
+ ;
+
+PrincipalSpecificationList_EDIT
+ : PrincipalSpecificationList ',' 'CURSOR'
+   {
+     parser.suggestKeywords(['GROUP', 'ROLE', 'USER']);
+   }
+ | 'CURSOR' ',' PrincipalSpecificationList
+   {
+     parser.suggestKeywords(['GROUP', 'ROLE', 'USER']);
+   }
+ | PrincipalSpecificationList ',' 'CURSOR' ',' PrincipalSpecificationList
+   {
+     parser.suggestKeywords(['GROUP', 'ROLE', 'USER']);
+   }
+ ;
+
+PrincipalSpecification
+ : '<hive>USER' RegularOrBacktickedIdentifier
+ | 'GROUP' RegularOrBacktickedIdentifier
+ | '<hive>ROLE' RegularOrBacktickedIdentifier
+ ;
+
+PrincipalSpecification_EDIT
+ : '<hive>USER' 'CURSOR'
+ | 'GROUP' 'CURSOR'
+ | '<hive>ROLE' 'CURSOR'
+ ;
+
+UserOrRoleList
+ : RegularOrBacktickedIdentifier
+ | UserOrRoleList ',' RegularOrBacktickedIdentifier
+ ;
+
+OptionalWithGrantOption
+ :
+ | '<hive>WITH' '<hive>GRANT' 'OPTION'
+ | '<impala>WITH' '<impala>GRANT' 'OPTION'
+ ;
+
+WithGrantOption_EDIT
+ : AnyWith 'CURSOR'
+   {
+     parser.suggestKeywords(['GRANT OPTION']);
+   }
+ | '<hive>WITH' '<hive>GRANT' 'CURSOR'
+   {
+     parser.suggestKeywords(['OPTION']);
+   }
+ | '<impala>WITH' '<impala>GRANT' 'CURSOR'
+   {
+     parser.suggestKeywords(['OPTION']);
+   }
+ ;
+
+OptionalWithAdminOption
+ :
+ | '<hive>WITH' '<hive>ADMIN' 'OPTION'
+ ;
+
+WithAdminOption_EDIT
+ : '<hive>WITH' 'CURSOR'
+   {
+     parser.suggestKeywords(['ADMIN OPTION']);
+   }
+ | '<hive>WITH' '<hive>ADMIN' 'CURSOR'
+   {
+     parser.suggestKeywords(['OPTION']);
+   }
+ ;
+
+RevokeStatement
+ : '<hive>REVOKE' HivePrivilegeTypeList OptionalOnSpecification 'FROM' PrincipalSpecificationList
+ | '<hive>REVOKE' '<hive>GRANT' 'OPTION' '<hive>FOR' HivePrivilegeTypeList OptionalOnSpecification 'FROM' PrincipalSpecificationList
+ | '<hive>REVOKE' UserOrRoleList 'FROM' PrincipalSpecificationList
+ | '<hive>REVOKE' '<hive>ROLE' UserOrRoleList 'FROM' PrincipalSpecificationList
+ | '<hive>REVOKE' '<hive>ADMIN' 'OPTION' '<hive>FOR' UserOrRoleList 'FROM' PrincipalSpecificationList
+ | '<hive>REVOKE' '<hive>ADMIN' 'OPTION' '<hive>FOR' '<hive>ROLE' UserOrRoleList 'FROM' PrincipalSpecificationList
+ | '<hive>REVOKE' '<hive>ALL' PrivilegesOrGrantOption 'FROM' UserOrRoleList
+ | '<impala>REVOKE' '<impala>ROLE' RegularOrBacktickedIdentifier 'FROM' '<impala>GROUP' RegularOrBacktickedIdentifier
+ | '<impala>REVOKE' ImpalaPrivilegeType 'ON' ImpalaObjectSpecification 'FROM' RegularOrBacktickedIdentifier
+ | '<impala>REVOKE' ImpalaPrivilegeType 'ON' ImpalaObjectSpecification 'FROM' '<impala>ROLE' RegularOrBacktickedIdentifier
+ ;
+
+RevokeStatement_EDIT
+ : '<hive>REVOKE' 'CURSOR'
+   {
+     parser.suggestKeywords(['ADMIN OPTION FOR', 'ALL', 'ALL GRANT OPTION FROM', 'ALL PRIVILEGES FROM', 'ALTER', 'CREATE', 'DELETE', 'DROP', 'GRANT OPTION FOR', 'INDEX', 'INSERT', 'LOCK', 'ROLE', 'SELECT', 'UPDATE']);
+   }
+ | '<hive>REVOKE' HivePrivilegeTypeList_EDIT
+ | '<hive>REVOKE' HivePrivilegeTypeList OnSpecification_EDIT
+ | '<hive>REVOKE' HivePrivilegeTypeList OptionalOnSpecification 'CURSOR'
+   {
+     if (!$3) {
+       if ($2.singleAll) {
+         parser.suggestKeywords(['FROM', 'GRANT OPTION', 'ON', 'PRIVILEGES FROM']);
+       } else {
+         parser.suggestKeywords(['FROM', 'ON']);
+       }
+     } else {
+       parser.suggestKeywords(['FROM']);
+     }
+   }
+ | '<hive>REVOKE' HivePrivilegeTypeList OptionalOnSpecification 'FROM' 'CURSOR'
+   {
+     parser.suggestKeywords(['GROUP', 'ROLE', 'USER']);
+   }
+ | '<hive>REVOKE' HivePrivilegeTypeList OptionalOnSpecification 'FROM' PrincipalSpecificationList_EDIT
+ | '<hive>REVOKE' '<hive>GRANT' 'CURSOR'
+   {
+     parser.suggestKeywords(['OPTION FOR']);
+   }
+ | '<hive>REVOKE' '<hive>GRANT' 'OPTION' 'CURSOR'
+   {
+     parser.suggestKeywords(['FOR']);
+   }
+ | '<hive>REVOKE' '<hive>GRANT' 'OPTION' '<hive>FOR' 'CURSOR'
+   {
+     parser.suggestKeywords(['ALL', 'ALTER', 'CREATE', 'DELETE', 'DROP', 'INDEX', 'INSERT', 'LOCK', 'SELECT', 'SHOW_DATABASE', 'UPDATE']);
+   }
+ | '<hive>REVOKE' '<hive>GRANT' 'OPTION' '<hive>FOR' HivePrivilegeTypeList_EDIT
+ | '<hive>REVOKE' '<hive>GRANT' 'OPTION' '<hive>FOR' HivePrivilegeTypeList OnSpecification_EDIT
+ | '<hive>REVOKE' '<hive>GRANT' 'OPTION' '<hive>FOR' HivePrivilegeTypeList OptionalOnSpecification 'CURSOR'
+   {
+     if (!$6) {
+       parser.suggestKeywords(['FROM', 'ON']);
+     } else {
+       parser.suggestKeywords(['FROM']);
+     }
+   }
+ | '<hive>REVOKE' '<hive>GRANT' 'OPTION' '<hive>FOR' HivePrivilegeTypeList OptionalOnSpecification 'FROM' 'CURSOR'
+   {
+     parser.suggestKeywords(['GROUP', 'ROLE', 'USER']);
+   }
+ | '<hive>REVOKE' '<hive>GRANT' 'OPTION' '<hive>FOR' HivePrivilegeTypeList OptionalOnSpecification 'FROM' PrincipalSpecificationList_EDIT
+ | '<hive>REVOKE' UserOrRoleList 'CURSOR'
+   {
+     if ($2.toUpperCase() === 'ADMIN') {
+       parser.suggestKeywords(['FROM', 'OPTION FOR']);
+     } else {
+       parser.suggestKeywords(['FROM']);
+     }
+   }
+ | '<hive>REVOKE' UserOrRoleList 'FROM' 'CURSOR'
+   {
+     parser.suggestKeywords(['GROUP', 'ROLE', 'USER']);
+   }
+ | '<hive>REVOKE' UserOrRoleList 'FROM' PrincipalSpecificationList_EDIT
+ | '<hive>REVOKE' '<hive>ROLE' UserOrRoleList 'CURSOR'
+   {
+     parser.suggestKeywords(['FROM']);
+   }
+ | '<hive>REVOKE' '<hive>ROLE' UserOrRoleList 'FROM' 'CURSOR'
+   {
+     parser.suggestKeywords(['GROUP', 'ROLE', 'USER']);
+   }
+ | '<hive>REVOKE' '<hive>ROLE' UserOrRoleList 'FROM' PrincipalSpecificationList_EDIT
+
+ | '<hive>REVOKE' '<hive>ADMIN' 'OPTION' 'CURSOR'
+   {
+     parser.suggestKeywords(['FOR']);
+   }
+ | '<hive>REVOKE' '<hive>ADMIN' 'OPTION' '<hive>FOR' 'CURSOR'
+   {
+     parser.suggestKeywords(['ROLE']);
+   }
+ | '<hive>REVOKE' '<hive>ADMIN' 'OPTION' '<hive>FOR' UserOrRoleList 'CURSOR'
+   {
+     parser.suggestKeywords(['FROM']);
+   }
+ | '<hive>REVOKE' '<hive>ADMIN' 'OPTION' '<hive>FOR' UserOrRoleList 'FROM' 'CURSOR'
+   {
+     parser.suggestKeywords(['GROUP', 'ROLE', 'USER']);
+   }
+ | '<hive>REVOKE' '<hive>ADMIN' 'OPTION' '<hive>FOR' UserOrRoleList 'FROM' PrincipalSpecificationList_EDIT
+ | '<hive>REVOKE' '<hive>ADMIN' 'OPTION' '<hive>FOR' '<hive>ROLE' UserOrRoleList 'CURSOR'
+   {
+     parser.suggestKeywords(['FROM']);
+   }
+ | '<hive>REVOKE' '<hive>ADMIN' 'OPTION' '<hive>FOR' '<hive>ROLE' UserOrRoleList 'FROM' 'CURSOR'
+   {
+     parser.suggestKeywords(['GROUP', 'ROLE', 'USER']);
+   }
+ | '<hive>REVOKE' '<hive>ADMIN' 'OPTION' '<hive>FOR' '<hive>ROLE' UserOrRoleList 'FROM' PrincipalSpecificationList_EDIT
+ | '<hive>REVOKE' '<hive>ALL' PrivilegesOrGrantOption_EDIT
+ | '<hive>REVOKE' '<hive>ALL' PrivilegesOrGrantOption 'CURSOR'
+   {
+     parser.suggestKeywords(['FROM']);
+   }
+ | '<impala>REVOKE' 'CURSOR'
+   {
+     parser.suggestKeywords(['ALL', 'ALTER', 'CREATE', 'DROP', 'INSERT', 'REFRESH', 'ROLE', 'SELECT']);
+   }
+ | '<impala>REVOKE' '<impala>ROLE' RegularOrBacktickedIdentifier 'CURSOR'
+   {
+     parser.suggestKeywords(['FROM GROUP']);
+   }
+ | '<impala>REVOKE' '<impala>ROLE' RegularOrBacktickedIdentifier 'FROM' 'CURSOR'
+   {
+     parser.suggestKeywords(['GROUP']);
+   }
+ | '<impala>REVOKE' ImpalaPrivilegeType_EDIT
+ | '<impala>REVOKE' ImpalaPrivilegeType 'CURSOR'
+   {
+     if ($2.isCreate) {
+       parser.suggestKeywords(['ON DATABASE', 'ON SERVER']);
+     } else {
+       parser.suggestKeywords(['ON DATABASE', 'ON SERVER', 'ON TABLE', 'ON URI']);
+     }
+   }
+ | '<impala>REVOKE' ImpalaPrivilegeType 'ON' 'CURSOR'
+   {
+     if ($2.isCreate) {
+       parser.suggestKeywords(['DATABASE', 'SERVER']);
+     } else {
+       parser.suggestKeywords(['DATABASE', 'SERVER', 'TABLE', 'URI']);
+     }
+   }
+ | '<impala>REVOKE' ImpalaPrivilegeType 'ON' ImpalaObjectSpecification_EDIT
+ | '<impala>REVOKE' ImpalaPrivilegeType 'ON' ImpalaObjectSpecification 'CURSOR'
+   {
+     parser.suggestKeywords(['FROM']);
+   }
+ | '<impala>REVOKE' ImpalaPrivilegeType 'ON' ImpalaObjectSpecification 'FROM' 'CURSOR'
+   {
+     parser.suggestKeywords(['ROLE']);
+   }
+ ;
+
+PrivilegesOrGrantOption
+ : '<hive>PRIVILEGES'
+ | '<hive>GRANT' 'OPTION'
+ ;
+
+PrivilegesOrGrantOption_EDIT
+ : '<hive>GRANT' 'CURSOR'
+   {
+     parser.suggestKeywords(['OPTION']);
+   }
+ ;

+ 762 - 0
desktop/core/src/desktop/js/parse/jison/impala/sql_insert.jison

@@ -0,0 +1,762 @@
+// Licensed to Cloudera, Inc. under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  Cloudera, Inc. licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+DataManipulation
+ : InsertStatement
+ ;
+
+InsertStatement
+ : HiveInsertStatement
+ | InsertValuesStatement
+ | ImpalaInsertOrUpsertStatement
+ | CommonTableExpression HiveInsertStatement
+ | CommonTableExpression ImpalaInsertOrUpsertStatement
+ | HiveMergeStatement
+ ;
+
+DataManipulation_EDIT
+ : HiveInsertStatement_EDIT
+ | InsertValuesStatement_EDIT
+ | ImpalaInsertOrUpsertStatement_EDIT
+ | CommonTableExpression HiveInsertStatement_EDIT
+   {
+     parser.addCommonTableExpressions($1);
+   }
+ | CommonTableExpression_EDIT HiveInsertStatement
+ | CommonTableExpression ImpalaInsertOrUpsertStatement_EDIT
+   {
+     parser.addCommonTableExpressions($1);
+   }
+ | CommonTableExpression_EDIT ImpalaInsertOrUpsertStatement
+ | HiveMergeStatement_EDIT
+ ;
+
+HiveInsertStatement
+ : HiveInsertWithoutQuery QuerySpecification
+ | FromClause HiveInserts
+ | FromClause SelectWithoutTableExpression OptionalSelectConditions
+ ;
+
+HiveInsertStatement_EDIT
+ : HiveInsertWithoutQuery_EDIT
+ | HiveInsertWithoutQuery 'CURSOR'
+   {
+     var keywords = [];
+     if ($1.suggestKeywords) {
+       keywords = parser.createWeightedKeywords($1.suggestKeywords, 2).concat([{ value: 'SELECT', weight: 1}]);
+     } else {
+       keywords = ['SELECT'];
+     }
+     if ($1.addValues) {
+       keywords.push({ weight: 1.1, value: 'VALUES' });
+     }
+     if (keywords.length > 0) {
+       parser.suggestKeywords(keywords);
+     }
+   }
+ | HiveInsertWithoutQuery_EDIT QuerySpecification
+ | HiveInsertWithoutQuery QuerySpecification_EDIT
+ | FromClause HiveInserts_EDIT
+   {
+     if (!$2.keepTables) {
+       delete parser.yy.result.suggestTables;
+       delete parser.yy.result.suggestDatabases;
+     }
+   }
+ | FromClause_EDIT
+ | FromClause_EDIT HiveInserts
+ | FromClause_EDIT SelectWithoutTableExpression OptionalSelectConditions
+ | FromClause 'CURSOR'
+   {
+     parser.suggestKeywords(['INSERT INTO', 'INSERT OVERWRITE', 'SELECT']);
+   }
+ | FromClause SelectWithoutTableExpression_EDIT OptionalSelectConditions
+   {
+     if ($2.cursorAtEnd) {
+       parser.checkForSelectListKeywords($2);
+       var keywords = parser.yy.result.suggestKeywords || [];
+       if ($3.suggestKeywords) {
+         keywords = keywords.concat($3.suggestKeywords);
+       }
+       if (keywords.length > 0) {
+         parser.suggestKeywords(keywords);
+       }
+     }
+     delete parser.yy.result.suggestTables;
+     delete parser.yy.result.suggestDatabases;
+   }
+ | FromClause SelectWithoutTableExpression OptionalSelectConditions_EDIT
+   {
+     if ($3.cursorAtStart) {
+       parser.checkForSelectListKeywords($2.tableExpression);
+     }
+   }
+ ;
+
+HiveInsertWithoutQuery
+ : '<hive>INSERT' '<hive>OVERWRITE' OptionalHiveTable SchemaQualifiedTableIdentifier OptionalPartitionSpec OptionalIfNotExists
+   {
+     $4.owner = 'insert';
+     parser.addTablePrimary($4);
+     if (!$5 && !$6) {
+       $$ = { suggestKeywords: ['PARTITION'] }
+     } else if (!$6) {
+       $$ = { suggestKeywords: ['IF NOT EXISTS'] }
+     }
+   }
+ | '<hive>INSERT' '<hive>OVERWRITE' '<hive>LOCAL' '<hive>DIRECTORY' HdfsPath OptionalInsertRowFormat OptionalStoredAs
+   {
+     if (!$6 && !$7) {
+       $$ = { suggestKeywords: [{ value: 'ROW FORMAT', weight: 2 }, { value: 'STORED AS', weight: 1}] };
+     } else if (!$7) {
+       $$ = { suggestKeywords: ['STORED AS'] };
+     }
+   }
+ | '<hive>INSERT' '<hive>OVERWRITE_DIRECTORY' HdfsPath OptionalInsertRowFormat OptionalStoredAs
+    {
+      if (!$4 && !$5) {
+        $$ = { suggestKeywords: [{ value: 'ROW FORMAT', weight: 2 }, { value: 'STORED AS', weight: 1}] };
+      } else if (!$5) {
+        $$ = { suggestKeywords: ['STORED AS'] };
+      }
+    }
+  | '<hive>INSERT' 'INTO' OptionalHiveTable SchemaQualifiedTableIdentifier OptionalPartitionSpec OptionalParenthesizedColumnList
+   {
+     $4.owner = 'insert';
+     parser.addTablePrimary($4);
+     if (!$5 && !$6) {
+       $$ = { suggestKeywords: ['PARTITION'], addValues: true };
+     } else if (!$6) {
+       $$ = { addValues: true };
+     }
+   }
+ ;
+
+HiveInsertWithoutQuery_EDIT
+ : '<hive>INSERT' 'CURSOR'
+   {
+     parser.suggestKeywords(['OVERWRITE', 'INTO']);
+   }
+ | '<hive>INSERT' '<hive>OVERWRITE' OptionalHiveTable 'CURSOR'
+   {
+     if (!$3) {
+       parser.suggestKeywords(['DIRECTORY', 'LOCAL DIRECTORY', 'TABLE']);
+     }
+     parser.suggestTables();
+     parser.suggestDatabases({ appendDot: true });
+     $$ = { keepTables: true }
+   }
+ | '<hive>INSERT' '<hive>OVERWRITE' OptionalHiveTable SchemaQualifiedTableIdentifier_EDIT OptionalPartitionSpec OptionalParenthesizedColumnList
+   {
+     $$ = { keepTables: true }
+   }
+ | '<hive>INSERT' '<hive>OVERWRITE' OptionalHiveTable SchemaQualifiedTableIdentifier OptionalPartitionSpec_EDIT OptionalIfNotExists
+   {
+     $4.owner = 'insert';
+     parser.addTablePrimary($4);
+     if (parser.yy.result.suggestColumns) {
+       parser.yy.result.suggestColumns.owner = 'insert';
+     }
+   }
+ | '<hive>INSERT' '<hive>OVERWRITE' OptionalHiveTable SchemaQualifiedTableIdentifier OptionalPartitionSpec OptionalIfNotExists_EDIT
+   {
+     $4.owner = 'insert';
+     parser.addTablePrimary($4);
+   }
+ | '<hive>INSERT' '<hive>OVERWRITE' '<hive>LOCAL' 'CURSOR'
+   {
+     parser.suggestKeywords(['DIRECTORY']);
+   }
+ | '<hive>INSERT' '<hive>OVERWRITE' '<hive>LOCAL' '<hive>DIRECTORY' HdfsPath_EDIT OptionalInsertRowFormat OptionalStoredAs
+ | '<hive>INSERT' '<hive>OVERWRITE' '<hive>LOCAL' '<hive>DIRECTORY' HdfsPath OptionalInsertRowFormat_EDIT OptionalStoredAs
+ | '<hive>INSERT' '<hive>OVERWRITE' '<hive>LOCAL' '<hive>DIRECTORY' HdfsPath OptionalInsertRowFormat StoredAs_EDIT
+ | '<hive>INSERT' '<hive>OVERWRITE_DIRECTORY' HdfsPath_EDIT OptionalInsertRowFormat OptionalStoredAs  // DIRECTORY is a non-reserved keyword
+ | '<hive>INSERT' '<hive>OVERWRITE_DIRECTORY' HdfsPath OptionalInsertRowFormat_EDIT OptionalStoredAs
+ | '<hive>INSERT' '<hive>OVERWRITE_DIRECTORY' HdfsPath OptionalInsertRowFormat StoredAs_EDIT
+ | '<hive>INSERT' 'INTO' OptionalHiveTable 'CURSOR'
+   {
+     if (!$3) {
+       parser.suggestKeywords(['TABLE']);
+     }
+     parser.suggestTables();
+     parser.suggestDatabases({ appendDot: true });
+     $$ = { keepTables: true }
+   }
+ | '<hive>INSERT' 'INTO' OptionalHiveTable SchemaQualifiedTableIdentifier_EDIT OptionalPartitionSpec OptionalParenthesizedColumnList
+   {
+     $$ = { keepTables: true }
+   }
+ | '<hive>INSERT' 'INTO' OptionalHiveTable SchemaQualifiedTableIdentifier OptionalPartitionSpec_EDIT OptionalParenthesizedColumnList
+   {
+     $4.owner = 'insert';
+     parser.addTablePrimary($4);
+     if (parser.yy.result.suggestColumns) {
+       parser.yy.result.suggestColumns.owner = 'insert';
+     }
+   }
+ | '<hive>INSERT' 'INTO' OptionalHiveTable SchemaQualifiedTableIdentifier OptionalPartitionSpec OptionalParenthesizedColumnList_EDIT
+   {
+     $4.owner = 'insert';
+     parser.addTablePrimary($4);
+     if (parser.yy.result.suggestColumns) {
+       parser.yy.result.suggestColumns.owner = 'insert';
+     }
+   }
+ ;
+
+HiveInserts
+ : HiveInsert
+ | HiveInserts HiveInsert
+ ;
+
+HiveInserts_EDIT
+ : HiveInsert_EDIT
+ | HiveInserts HiveInsert_EDIT
+ | HiveInsert_EDIT HiveInserts
+ | HiveInserts HiveInsert_EDIT HiveInserts
+ ;
+
+// TODO: Verify Hive unions in insert
+HiveInsert
+ : HiveInsertWithoutQuery SelectWithoutTableExpression OptionalSelectConditions
+ ;
+
+HiveInsert_EDIT
+ : HiveInsertWithoutQuery_EDIT
+ | HiveInsertWithoutQuery_EDIT SelectWithoutTableExpression OptionalSelectConditions
+ | HiveInsertWithoutQuery 'CURSOR'
+   {
+     if ($1.suggestKeywords) {
+       parser.suggestKeywords(parser.createWeightedKeywords($1.suggestKeywords, 2).concat([{ value: 'SELECT', weight: 1}]));
+     } else {
+       parser.suggestKeywords(['SELECT']);
+     }
+   }
+ | HiveInsertWithoutQuery SelectWithoutTableExpression_EDIT OptionalSelectConditions
+   {
+     if ($2.cursorAtEnd) {
+       parser.checkForSelectListKeywords($2);
+       var keywords = parser.yy.result.suggestKeywords || [];
+       if ($3.suggestKeywords) {
+         keywords = keywords.concat($3.suggestKeywords);
+       }
+       if (keywords.length > 0) {
+         parser.suggestKeywords(keywords);
+       }
+     }
+   }
+ | HiveInsertWithoutQuery SelectWithoutTableExpression OptionalSelectConditions_EDIT
+ ;
+
+InsertValuesStatement
+ : '<hive>INSERT' 'INTO' OptionalHiveTable SchemaQualifiedTableIdentifier OptionalPartitionSpec 'VALUES' InsertValuesList
+   {
+     $4.owner = 'insert';
+     parser.addTablePrimary($4);
+   }
+ | 'INSERT' 'INTO' OptionalTable SchemaQualifiedTableIdentifier 'VALUES' InsertValuesList
+   {
+     $4.owner = 'insert';
+     parser.addTablePrimary($4);
+   }
+ ;
+
+InsertValuesStatement_EDIT
+ : 'INSERT' 'CURSOR'
+   {
+     parser.suggestKeywords(['INTO']);
+   }
+ | 'INSERT' 'INTO' OptionalTable 'CURSOR'
+   {
+     if (!$3) {
+       parser.suggestKeywords(['TABLE']);
+     }
+     parser.suggestTables();
+     parser.suggestDatabases({ appendDot: true });
+   }
+ | 'INSERT' 'INTO' OptionalTable SchemaQualifiedTableIdentifier_EDIT
+ | 'INSERT' 'INTO' OptionalTable SchemaQualifiedTableIdentifier 'CURSOR'
+   {
+     $4.owner = 'insert';
+     parser.addTablePrimary($4);
+     parser.suggestKeywords(['VALUES']);
+   }
+ | 'INSERT' 'INTO' OptionalTable SchemaQualifiedTableIdentifier_EDIT 'VALUES' InsertValuesList
+ ;
+
+InsertValuesList
+ : ParenthesizedRowValuesList
+ | RowValuesList ',' ParenthesizedRowValuesList
+ ;
+
+ParenthesizedRowValuesList
+ : '(' InValueList ')'
+ ;
+
+OptionalTable
+ :
+ | 'TABLE'
+ ;
+
+OptionalInsertRowFormat
+ :
+ | 'ROW' '<hive>FORMAT' [deleted]
+ ;
+
+OptionalInsertRowFormat_EDIT
+ : 'ROW' 'CURSOR'
+   {
+     parser.suggestKeywords(['FORMAT DELIMITED']);
+   }
+ | 'ROW' '<hive>FORMAT' 'CURSOR'
+   {
+     parser.suggestKeywords(['DELIMITED']);
+   }
+ | 'ROW' '<hive>FORMAT' [deleted]
+ ;
+
+SelectWithoutTableExpression
+ : 'SELECT' OptionalAllOrDistinct OptionalStraightJoin SelectList  -> { selectList: $4 }
+ ;
+
+SelectWithoutTableExpression_EDIT
+ : 'SELECT' OptionalAllOrDistinct OptionalStraightJoin SelectList 'CURSOR'
+   {
+     $$ = $4;
+     $$.cursorAtEnd = true;
+   }
+ | 'SELECT' OptionalAllOrDistinct OptionalStraightJoin SelectList_EDIT
+   {
+     parser.selectListNoTableSuggest($4, $2);
+   }
+ | 'SELECT' OptionalAllOrDistinct OptionalStraightJoin 'CURSOR'
+   {
+     var keywords = parser.getSelectListKeywords();
+     if (!$2 || $2 === 'ALL') {
+       parser.suggestAggregateFunctions();
+       parser.suggestAnalyticFunctions();
+     }
+     if (!$3 && !$2) {
+       keywords.push({ value: 'ALL', weight: 2 });
+       keywords.push({ value: 'DISTINCT', weight: 2 });
+     }
+     if (parser.isImpala() && !$3) {
+       keywords.push({ value: 'STRAIGHT_JOIN', weight: 1 });
+     }
+     parser.suggestKeywords(keywords);
+     parser.suggestFunctions();
+     parser.suggestColumns();
+   }
+ ;
+
+OptionalHiveTable
+ :
+ | '<hive>TABLE'
+ ;
+
+ImpalaInsertOrUpsertStatement
+ : ImpalaInsertOrUpsertStatementWithoutCTE
+ ;
+
+ImpalaInsertOrUpsertStatement_EDIT
+ : ImpalaInsertOrUpsertStatementWithoutCTE_EDIT
+ ;
+
+ImpalaInsertOrUpsertStatementWithoutCTE
+ : ImpalaInsertOrUpsertLeftPart OptionalImpalaShuffleOrNoShuffle SelectStatement OptionalUnions
+ | ImpalaInsertOrUpsertLeftPart 'VALUES' ImpalaRowValuesLists
+ ;
+
+ImpalaInsertOrUpsertStatementWithoutCTE_EDIT
+ : ImpalaInsertOrUpsertLeftPart_EDIT
+ | ImpalaInsertOrUpsertLeftPart OptionalImpalaShuffleOrNoShuffle 'CURSOR'
+   {
+     var keywords = $1.suggestKeywords && !$2 ? parser.createWeightedKeywords($1.suggestKeywords, 2) : [];
+     if (!$2) {
+       keywords = keywords.concat(['[NOSHUFFLE]', '[SHUFFLE]', 'SELECT', 'VALUES'])
+     } else {
+       keywords = keywords.concat(['SELECT'])
+     }
+     parser.suggestKeywords(keywords);
+   }
+ | ImpalaInsertOrUpsertLeftPart_EDIT OptionalImpalaShuffleOrNoShuffle SelectStatement OptionalUnions
+ | ImpalaInsertOrUpsertLeftPart OptionalImpalaShuffleOrNoShuffle SelectStatement_EDIT OptionalUnions
+ | ImpalaInsertOrUpsertLeftPart OptionalImpalaShuffleOrNoShuffle SelectStatement OptionalUnions_EDIT
+ | ImpalaInsertOrUpsertLeftPart_EDIT 'VALUES' ImpalaRowValuesLists
+ | ImpalaInsertOrUpsertLeftPart 'VALUES' ImpalaRowValuesLists_EDIT
+ ;
+
+ImpalaInsertOrUpsertLeftPart
+ : ImpalaUpsertStatementLeftPart
+ | ImpalaInsertLeftPart
+ ;
+
+ImpalaInsertOrUpsertLeftPart_EDIT
+ : ImpalaUpsertStatementLeftPart_EDIT
+ | ImpalaInsertLeftPart_EDIT
+ ;
+
+ImpalaUpsertStatementLeftPart
+ : '<impala>UPSERT' 'INTO' OptionalImpalaTable SchemaQualifiedTableIdentifier OptionalParenthesizedColumnList
+   {
+     $4.owner = 'upsert';
+     parser.addTablePrimary($4);
+   }
+ ;
+
+ImpalaUpsertStatementLeftPart_EDIT
+ : '<impala>UPSERT' 'CURSOR'
+   {
+     parser.suggestKeywords(['INTO']);
+   }
+ | '<impala>UPSERT' 'INTO' OptionalImpalaTable 'CURSOR'
+   {
+     if (!$3) {
+       parser.suggestKeywords(['TABLE']);
+     }
+     parser.suggestTables();
+     parser.suggestDatabases({ appendDot: true });
+   }
+ | '<impala>UPSERT' 'INTO' OptionalImpalaTable 'CURSOR' SchemaQualifiedTableIdentifier OptionalParenthesizedColumnList
+   {
+     if (!$3) {
+       parser.suggestKeywords(['TABLE']);
+     }
+     $5.owner = 'upsert';
+     parser.addTablePrimary($5);
+   }
+ | '<impala>UPSERT' 'INTO' OptionalImpalaTable SchemaQualifiedTableIdentifier_EDIT OptionalParenthesizedColumnList
+ | '<impala>UPSERT' 'INTO' OptionalImpalaTable SchemaQualifiedTableIdentifier OptionalParenthesizedColumnList_EDIT
+   {
+     $4.owner = 'upsert';
+     parser.addTablePrimary($4);
+     if (parser.yy.result.suggestColumns) {
+       parser.yy.result.suggestColumns.owner = 'upsert';
+     }
+   }
+ ;
+
+
+ImpalaInsertLeftPart
+ : '<impala>INSERT' IntoOrOverwrite OptionalImpalaTable SchemaQualifiedTableIdentifier OptionalParenthesizedColumnList OptionalPartitionSpec
+   {
+     $4.owner = 'insert';
+     parser.addTablePrimary($4);
+     if (!$6) {
+       $$ = { suggestKeywords: ['PARTITION'] };
+     }
+   }
+ ;
+
+ImpalaInsertLeftPart_EDIT
+ : '<impala>INSERT' 'CURSOR'
+   {
+     parser.suggestKeywords(['INTO', 'OVERWRITE']);
+   }
+ | '<impala>INSERT' IntoOrOverwrite OptionalImpalaTable 'CURSOR'
+   {
+     if (!$3) {
+       parser.suggestKeywords(['TABLE']);
+     }
+     parser.suggestTables();
+     parser.suggestDatabases({ appendDot: true });
+   }
+ | '<impala>INSERT' IntoOrOverwrite OptionalImpalaTable 'CURSOR' SchemaQualifiedTableIdentifier OptionalParenthesizedColumnList OptionalPartitionSpec
+   {
+     if (!$3) {
+       parser.suggestKeywords(['TABLE']);
+     }
+     $5.owner = 'insert';
+     parser.addTablePrimary($5);
+   }
+ | '<impala>INSERT' IntoOrOverwrite OptionalImpalaTable SchemaQualifiedTableIdentifier_EDIT OptionalParenthesizedColumnList OptionalPartitionSpec
+ | '<impala>INSERT' IntoOrOverwrite OptionalImpalaTable SchemaQualifiedTableIdentifier OptionalParenthesizedColumnList_EDIT OptionalPartitionSpec
+   {
+     $4.owner = 'insert';
+     parser.addTablePrimary($4);
+     if (parser.yy.result.suggestColumns) {
+       parser.yy.result.suggestColumns.owner = 'insert';
+     }
+   }
+ | '<impala>INSERT' IntoOrOverwrite OptionalImpalaTable SchemaQualifiedTableIdentifier OptionalParenthesizedColumnList OptionalPartitionSpec_EDIT
+   {
+     $4.owner = 'insert';
+     parser.addTablePrimary($4);
+     if (parser.yy.result.suggestColumns) {
+       parser.yy.result.suggestColumns.owner = 'insert';
+     }
+   }
+ ;
+
+IntoOrOverwrite
+ : 'INTO'
+ | '<impala>OVERWRITE'
+ ;
+
+OptionalImpalaTable
+ :
+ | '<impala>TABLE'
+ ;
+
+OptionalImpalaShuffleOrNoShuffle
+ :
+ | '<impala>SHUFFLE'
+ | '<impala>NOSHUFFLE'
+ ;
+
+ImpalaRowValuesLists
+ : ParenthesizedImpalaRowValuesList
+ | ImpalaRowValuesLists ',' ParenthesizedImpalaRowValuesList
+ ;
+
+ImpalaRowValuesLists_EDIT
+ : ParenthesizedImpalaRowValuesList_EDIT
+ | ImpalaRowValuesLists ',' ParenthesizedImpalaRowValuesList_EDIT
+ | ImpalaRowValuesLists ',' ParenthesizedImpalaRowValuesList_EDIT ',' ImpalaRowValuesLists
+ | ParenthesizedImpalaRowValuesList_EDIT ',' ImpalaRowValuesLists
+ ;
+
+ParenthesizedImpalaRowValuesList
+ : '(' ValueExpressionList ')'
+ ;
+
+ParenthesizedImpalaRowValuesList_EDIT
+ : '(' AnyCursor RightParenthesisOrError
+   {
+     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']);
+   }
+ ;

+ 291 - 0
desktop/core/src/desktop/js/parse/jison/impala/sql_load.jison

@@ -0,0 +1,291 @@
+// Licensed to Cloudera, Inc. under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  Cloudera, Inc. licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+DataManipulation
+ : LoadStatement
+ | ImportStatement
+ | ExportStatement
+ ;
+
+DataManipulation_EDIT
+ : LoadStatement_EDIT
+ | ImportStatement_EDIT
+ | ExportStatement_EDIT
+ ;
+
+LoadStatement
+ : AnyLoad AnyData OptionalHiveLocal AnyInpath HdfsPath OptionalOverwrite 'INTO' AnyTable SchemaQualifiedTableIdentifier OptionalPartitionSpec
+   {
+     parser.addTablePrimary($9);
+   }
+ ;
+
+LoadStatement_EDIT
+ : AnyLoad 'CURSOR'
+   {
+     if (parser.isHive()) {
+       parser.suggestKeywords(['DATA LOCAL INPATH', 'DATA INPATH']);
+     } else if (parser.isImpala()) {
+       parser.suggestKeywords(['DATA INPATH']);
+     }
+   }
+ | AnyLoad AnyData OptionalHiveLocal 'CURSOR'
+   {
+     if (parser.isHive() && !$3) {
+       parser.suggestKeywords(['INPATH', 'LOCAL INPATH']);
+     } else {
+       parser.suggestKeywords(['INPATH']);
+     }
+   }
+ | AnyLoad AnyData OptionalHiveLocal AnyInpath HdfsPath_EDIT OptionalOverwrite
+ | AnyLoad AnyData OptionalHiveLocal AnyInpath HdfsPath OptionalOverwrite 'CURSOR'
+   {
+     if (!$6) {
+       parser.suggestKeywords(['OVERWRITE INTO TABLE', 'INTO TABLE']);
+     } else {
+       parser.suggestKeywords(['INTO TABLE']);
+     }
+   }
+ | AnyLoad AnyData OptionalHiveLocal AnyInpath HdfsPath OptionalOverwrite 'INTO' 'CURSOR'
+   {
+     parser.suggestKeywords([ 'TABLE' ]);
+   }
+ | AnyLoad AnyData OptionalHiveLocal AnyInpath HdfsPath OptionalOverwrite 'INTO' AnyTable 'CURSOR'
+   {
+     parser.suggestTables();
+     parser.suggestDatabases({ appendDot: true });
+   }
+ | AnyLoad AnyData OptionalHiveLocal AnyInpath HdfsPath OptionalOverwrite 'INTO' AnyTable SchemaQualifiedTableIdentifier_EDIT OptionalPartitionSpec
+ | AnyLoad AnyData OptionalHiveLocal AnyInpath HdfsPath OptionalOverwrite 'INTO' AnyTable SchemaQualifiedTableIdentifier OptionalPartitionSpec 'CURSOR'
+   {
+     parser.addTablePrimary($9);
+     if (!$10) {
+       parser.suggestKeywords(['PARTITION']);
+     }
+   }
+ | AnyLoad AnyData OptionalHiveLocal AnyInpath HdfsPath OptionalOverwrite 'INTO' AnyTable SchemaQualifiedTableIdentifier OptionalPartitionSpec_EDIT
+   {
+     parser.addTablePrimary($9);
+   }
+ | AnyLoad AnyData OptionalHiveLocal AnyInpath HdfsPath_EDIT OptionalOverwrite 'INTO' AnyTable SchemaQualifiedTableIdentifier OptionalPartitionSpec
+   {
+     parser.addTablePrimary($9);
+   }
+ ;
+
+OptionalOverwrite
+ :
+ | '<hive>OVERWRITE'
+ | '<impala>OVERWRITE'
+ ;
+
+OptionalHiveLocal
+ :
+ | '<hive>LOCAL'
+ ;
+
+AnyLoad
+ : '<hive>LOAD'
+ | '<impala>LOAD'
+ ;
+
+AnyData
+ : '<hive>DATA'
+ | '<impala>DATA'
+ ;
+
+AnyInpath
+ : '<hive>INPATH'
+ | '<impala>INPATH'
+ ;
+
+ImportStatement
+ : '<hive>IMPORT' OptionalTableWithPartition PushHdfsLexerState 'FROM' HdfsPath OptionalHdfsLocation
+ ;
+
+ImportStatement_EDIT
+ : '<hive>IMPORT' 'CURSOR' OptionalTableWithPartition
+   {
+     if (!$3) {
+       parser.suggestKeywords(['EXTERNAL TABLE', 'FROM', 'TABLE']);
+     } else if (!$3.hasExternal) {
+       parser.suggestKeywords(['EXTERNAL']);
+     }
+   }
+ | '<hive>IMPORT' TableWithPartition 'CURSOR'
+   {
+     if ($2.suggestKeywords) {
+        parser.suggestKeywords(parser.createWeightedKeywords($2.suggestKeywords, 2).concat(['FROM']));
+      } else {
+        parser.suggestKeywords(['FROM']);
+      }
+   }
+ | '<hive>IMPORT' TableWithPartition_EDIT
+ | '<hive>IMPORT' OptionalTableWithPartition PushHdfsLexerState 'FROM' HdfsPath_EDIT OptionalHdfsLocation
+ | '<hive>IMPORT' OptionalTableWithPartition PushHdfsLexerState 'FROM' HdfsPath HdfsLocation_EDIT
+ | '<hive>IMPORT' OptionalTableWithPartition PushHdfsLexerState 'FROM' HdfsPath OptionalHdfsLocation 'CURSOR'
+   {
+     if (!$6) {
+       parser.suggestKeywords(['LOCATION']);
+     }
+   }
+ | '<hive>IMPORT' 'CURSOR' OptionalTableWithPartition PushHdfsLexerState 'FROM' HdfsPath OptionalHdfsLocation
+   {
+     if (!$3) {
+       parser.suggestKeywords(['EXTERNAL TABLE', 'TABLE']);
+     } else if (!$3.hasExternal) {
+       parser.suggestKeywords(['EXTERNAL']);
+     }
+   }
+| '<hive>IMPORT' TableWithPartition_EDIT PushHdfsLexerState 'FROM' HdfsPath OptionalHdfsLocation
+ | '<hive>IMPORT' TableWithPartition 'CURSOR' PushHdfsLexerState 'FROM' HdfsPath OptionalHdfsLocation
+    {
+      if ($2.suggestKeywords) {
+        parser.suggestKeywords(parser.createWeightedKeywords($2.suggestKeywords, 2).concat(['FROM']));
+      }
+    }
+ ;
+
+OptionalTableWithPartition
+ :
+ | TableWithPartition
+ ;
+
+TableWithPartition
+ : '<hive>EXTERNAL' '<hive>TABLE' SchemaQualifiedTableIdentifier OptionalPartitionSpec
+   {
+     parser.addTablePrimary($3);
+     if (!$4) {
+       $$ = { hasExternal: true, suggestKeywords: ['PARTITION'] };
+     } else {
+       $$ = { hasExternal: true }
+     }
+   }
+ | '<hive>TABLE' SchemaQualifiedTableIdentifier OptionalPartitionSpec
+   {
+     parser.addTablePrimary($2);
+     if (!$3) {
+       $$ = { suggestKeywords: ['PARTITION'] };
+     }
+   }
+ ;
+
+TableWithPartition_EDIT
+ : '<hive>EXTERNAL' 'CURSOR'
+   {
+     parser.suggestKeywords(['TABLE']);
+   }
+ | '<hive>EXTERNAL' '<hive>TABLE' 'CURSOR'
+   {
+     parser.suggestTables();
+     parser.suggestDatabases({ appendDot: true });
+   }
+ | '<hive>EXTERNAL' '<hive>TABLE' SchemaQualifiedTableIdentifier_EDIT OptionalPartitionSpec
+ | '<hive>EXTERNAL' '<hive>TABLE' SchemaQualifiedTableIdentifier PartitionSpec_EDIT
+   {
+     parser.addTablePrimary($3);
+   }
+ | '<hive>TABLE' 'CURSOR'
+   {
+     parser.suggestTables();
+     parser.suggestDatabases({ appendDot: true });
+   }
+
+ | '<hive>TABLE' SchemaQualifiedTableIdentifier_EDIT OptionalPartitionSpec
+ | '<hive>TABLE' SchemaQualifiedTableIdentifier PartitionSpec_EDIT
+   {
+     parser.addTablePrimary($3);
+   }
+ ;
+
+ExportStatement
+ : '<hive>EXPORT' '<hive>TABLE' SchemaQualifiedTableIdentifier OptionalPartitionSpec PushHdfsLexerState 'TO' HdfsPath
+   {
+     parser.addTablePrimary($3);
+   }
+ | '<hive>EXPORT' '<hive>TABLE' SchemaQualifiedTableIdentifier OptionalPartitionSpec PushHdfsLexerState 'TO' HdfsPath '<hive>FOR' '<hive>REPLICATION' '(' QuotedValue ')'
+   {
+     parser.addTablePrimary($3);
+   }
+ ;
+
+ExportStatement_EDIT
+ : '<hive>EXPORT' 'CURSOR'
+   {
+     parser.suggestKeywords(['TABLE']);
+   }
+ | '<hive>EXPORT' '<hive>TABLE' 'CURSOR'
+   {
+     parser.suggestTables();
+     parser.suggestDatabases({ appendDot: true });
+   }
+ | '<hive>EXPORT' '<hive>TABLE' SchemaQualifiedTableIdentifier_EDIT
+ | '<hive>EXPORT' '<hive>TABLE' SchemaQualifiedTableIdentifier OptionalPartitionSpec 'CURSOR'
+   {
+     parser.addTablePrimary($3);
+     if (!$4) {
+       parser.suggestKeywords([{ weight: 2, value: 'PARTITION' }, { weight: 1, value: 'TO' }]);
+     } else {
+       parser.suggestKeywords([ 'TO' ]);
+     }
+   }
+ | '<hive>EXPORT' '<hive>TABLE' SchemaQualifiedTableIdentifier PartitionSpec_EDIT
+   {
+     parser.addTablePrimary($3);
+   }
+ | '<hive>EXPORT' '<hive>TABLE' SchemaQualifiedTableIdentifier OptionalPartitionSpec PushHdfsLexerState 'TO' HdfsPath_EDIT
+   {
+     parser.addTablePrimary($3);
+   }
+ | '<hive>EXPORT' '<hive>TABLE' SchemaQualifiedTableIdentifier OptionalPartitionSpec PushHdfsLexerState 'TO' HdfsPath 'CURSOR'
+   {
+     parser.addTablePrimary($3);
+     parser.suggestKeywords(['FOR replication()']);
+   }
+ | '<hive>EXPORT' '<hive>TABLE' SchemaQualifiedTableIdentifier OptionalPartitionSpec PushHdfsLexerState 'TO' HdfsPath '<hive>FOR' 'CURSOR'
+   {
+     parser.addTablePrimary($3);
+     parser.suggestKeywords(['replication()']);
+   }
+ | '<hive>EXPORT' '<hive>TABLE' SchemaQualifiedTableIdentifier_EDIT OptionalPartitionSpec PushHdfsLexerState 'TO' HdfsPath
+ | '<hive>EXPORT' '<hive>TABLE' SchemaQualifiedTableIdentifier_EDIT OptionalPartitionSpec PushHdfsLexerState 'TO' HdfsPath '<hive>FOR' '<hive>REPLICATION' '(' QuotedValue ')'
+ | '<hive>EXPORT' '<hive>TABLE' SchemaQualifiedTableIdentifier OptionalPartitionSpec 'CURSOR' PushHdfsLexerState 'TO' HdfsPath
+   {
+     parser.addTablePrimary($3);
+     if (!$4) {
+       parser.suggestKeywords(['PARTITION']);
+     }
+   }
+ | '<hive>EXPORT' '<hive>TABLE' SchemaQualifiedTableIdentifier OptionalPartitionSpec 'CURSOR' PushHdfsLexerState 'TO' HdfsPath '<hive>FOR' '<hive>REPLICATION' '(' QuotedValue ')'
+   {
+     parser.addTablePrimary($3);
+     if (!$4) {
+       parser.suggestKeywords(['PARTITION']);
+     }
+   }
+ | '<hive>EXPORT' '<hive>TABLE' SchemaQualifiedTableIdentifier PartitionSpec_EDIT PushHdfsLexerState 'TO' HdfsPath
+   {
+     parser.addTablePrimary($3);
+   }
+ | '<hive>EXPORT' '<hive>TABLE' SchemaQualifiedTableIdentifier PartitionSpec_EDIT PushHdfsLexerState 'TO' HdfsPath '<hive>FOR' '<hive>REPLICATION' '(' QuotedValue ')'
+   {
+     parser.addTablePrimary($3);
+   }
+ | '<hive>EXPORT' '<hive>TABLE' SchemaQualifiedTableIdentifier OptionalPartitionSpec PushHdfsLexerState 'TO' HdfsPath_EDIT '<hive>FOR' '<hive>REPLICATION' '(' QuotedValue ')'
+   {
+     parser.addTablePrimary($3);
+   }
+ ;

+ 4503 - 0
desktop/core/src/desktop/js/parse/jison/impala/sql_main.jison

@@ -0,0 +1,4503 @@
+// Licensed to Cloudera, Inc. under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  Cloudera, Inc. licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+SqlSyntax
+ : NewStatement SqlStatements EOF
+ ;
+
+SqlAutocomplete
+ : NewStatement SqlStatements EOF
+   {
+     return parser.yy.result;
+   }
+ | NewStatement SqlStatements_EDIT EOF
+   {
+     return parser.yy.result;
+   }
+ ;
+
+NewStatement
+ : /* empty */
+   {
+     parser.prepareNewStatement();
+   }
+ ;
+
+SqlStatements
+ :
+ | SqlStatement
+   {
+     parser.addStatementLocation(@1);
+   }
+ | SqlStatements ';' NewStatement SqlStatements
+ ;
+
+SqlStatements_EDIT
+ : SqlStatement_EDIT
+   {
+     parser.addStatementLocation(@1);
+   }
+ | SqlStatement_EDIT ';' NewStatement SqlStatements
+   {
+     parser.addStatementLocation(@1);
+   }
+ | SqlStatements ';' NewStatement SqlStatement_EDIT
+   {
+     parser.addStatementLocation(@4);
+   }
+ | SqlStatements ';' NewStatement SqlStatement_EDIT ';' NewStatement SqlStatements
+   {
+     parser.addStatementLocation(@4);
+   }
+ ;
+
+SqlStatement
+ : DataDefinition
+ | DataManipulation
+ | QuerySpecification
+ | ExplainClause DataDefinition
+ | ExplainClause DataManipulation
+ | ExplainClause QuerySpecification
+ ;
+
+SqlStatement_EDIT
+ : AnyCursor
+   {
+     if (parser.isHive()) {
+       parser.suggestDdlAndDmlKeywords(['EXPLAIN', 'FROM']);
+     } else if (parser.isImpala()) {
+       parser.suggestDdlAndDmlKeywords(['EXPLAIN']);
+     } else {
+       parser.suggestDdlAndDmlKeywords();
+     }
+   }
+ | CommonTableExpression 'CURSOR'
+   {
+     if (parser.isHive() || parser.isImpala()) {
+       parser.suggestKeywords(['INSERT', 'SELECT']);
+     } else {
+       parser.suggestKeywords(['SELECT']);
+     }
+   }
+ | ExplainClause_EDIT
+ | DataDefinition_EDIT
+ | DataManipulation_EDIT
+ | QuerySpecification_EDIT
+ | SetSpecification_EDIT
+ | ExplainClause DataDefinition_EDIT
+ | ExplainClause DataManipulation_EDIT
+ | ExplainClause QuerySpecification_EDIT
+ | ExplainClause_EDIT DataDefinition
+ | ExplainClause_EDIT DataManipulation
+ | ExplainClause_EDIT QuerySpecification
+ ;
+
+NonReservedKeyword
+ : '<hive>ABORT'
+ | '<hive>ADD'
+ | '<hive>ADMIN'
+ | '<hive>AFTER'
+ | '<hive>ANALYZE'
+ | '<hive>ARCHIVE'
+ | '<hive>AVRO'
+ | '<hive>BUCKET'
+ | '<hive>BUCKETS'
+ | '<hive>CASCADE'
+ | '<hive>CHANGE'
+ | '<hive>CLUSTERED'
+ | '<hive>COLLECTION'
+ | '<hive>COLUMNS'
+ | '<hive>COMMENT'
+ | '<hive>COMPACT'
+ | '<hive>COMPACTIONS'
+ | '<hive>COMPUTE'
+ | '<hive>CONCATENATE'
+ | '<hive>DATA'
+ | '<hive>DATABASES'
+ | '<hive>DBPROPERTIES'
+ | '<hive>DEFERRED'
+ | '<hive>DEFINED'
+ | '<hive>DELIMITED'
+ | '<hive>DEPENDENCY'
+ | '<hive>DIRECTORY'
+ | '<hive>DISABLE'
+ | '<hive>DOUBLE_PRECISION'
+ | '<hive>ENABLE'
+ | '<hive>ESCAPED'
+ | '<hive>EXCHANGE'
+ | '<hive>EXPLAIN'
+ | '<hive>EXPORT'
+ | '<hive>FIELDS'
+ | '<hive>FILE'
+ | '<hive>FILEFORMAT'
+ | '<hive>FIRST'
+ | '<hive>FORMAT'
+ | '<hive>FUNCTIONS'
+ | '<hive>INPATH'
+ | '<hive>INPUTFORMAT'
+ | '<hive>JAR'
+ | '<hive>JSONFILE'
+ | '<hive>IDXPROPERTIES'
+ | '<hive>ITEMS'
+ | '<hive>KEY'
+ | '<hive>KEYS'
+ | '<hive>LINES'
+ | '<hive>LOAD'
+ | '<hive>LOCATION'
+ | '<hive>LOCKS'
+ | '<hive>MATCHED'
+ | '<hive>METADATA'
+ | '<hive>MERGE'
+ | '<hive>MSCK'
+ | '<hive>NOSCAN'
+ | '<hive>NOVALIDATE'
+ | '<hive>NO_DROP'
+ | '<hive>OFFLINE'
+ | '<hive>ORC'
+ | '<hive>OUTPUTFORMAT'
+ | '<hive>OVERWRITE'
+ | '<hive>OWNER'
+ | '<hive>PARQUET'
+ | '<hive>PARTITIONED'
+ | '<hive>PARTITIONS'
+ | '<hive>PERCENT'
+ | '<hive>PRIVILEGES'
+ | '<hive>PURGE'
+ | '<hive>RCFILE'
+ | '<hive>REBUILD'
+ | '<hive>RELOAD'
+ | '<hive>RELY'
+ | '<hive>NORELY'
+ | '<hive>REPAIR'
+ | '<hive>REPLICATION'
+ | '<hive>RECOVER'
+ | '<hive>RENAME'
+ | '<hive>REPLACE'
+ | '<hive>RESTRICT'
+ | '<hive>ROLE'
+ | '<hive>ROLES'
+ | '<hive>SCHEMAS'
+ | '<hive>SEQUENCEFILE'
+ | '<hive>SERDE'
+ | '<hive>SERDEPROPERTIES'
+ | '<hive>SETS'
+ | '<hive>SHOW'
+ | '<hive>SORTED'
+ | '<hive>STATISTICS'
+ | '<hive>STORED'
+ | '<hive>STRING'
+ | '<hive>TABLES'
+ | '<hive>TBLPROPERTIES'
+ | '<hive>TEMPORARY'
+ | '<hive>TERMINATED'
+ | '<hive>TEXTFILE'
+ | '<hive>TIMESTAMP'
+ | '<hive>TINYINT'
+ | '<hive>TOUCH'
+ | '<hive>TRANSACTIONAL'
+ | '<hive>TRANSACTIONS'
+ | '<hive>UNARCHIVE'
+ | '<hive>UNIONTYPE'
+ | '<hive>USE'
+ | '<hive>USER'
+ | '<hive>VIEW'
+ | '<hive>WAIT'
+ | '<hive>DAY'
+ | '<hive>HOUR'
+ | '<hive>MINUTE'
+ | '<hive>MONTH'
+ | '<hive>QUARTER'
+ | '<hive>SECOND'
+ | '<hive>WEEK'
+ | '<hive>YEAR'
+// | '<hive>ASC'      // These cause conflicts, we could use a separate lexer state for DESCRIBE, ALTER, GRANT, REVOKE and SHOW
+// | '<hive>CLUSTER'
+// | '<hive>DESC'
+// | '<hive>DISTRIBUTE'
+// | '<hive>FORMATTED'
+// | '<hive>FUNCTION'
+// | '<hive>INDEX'
+// | '<hive>INDEXES'
+// | '<hive>LOCK'
+// | '<hive>SCHEMA'
+// | '<hive>SHOW_DATABASE'
+// | '<hive>SORT'
+ ;
+
+NonReservedKeyword
+ : '<impala>DEFAULT'
+ | '<impala>KEY'
+ | '<impala>OWNER'
+ | '<impala>SERVER'
+ | '<impala>URI'
+ ;
+
+NonReservedKeyword
+ : 'ROLE'
+ | 'OPTION'
+ | 'STRUCT'
+ ;
+
+RegularIdentifier
+ : 'REGULAR_IDENTIFIER'
+ | 'VARIABLE_REFERENCE'
+ | NonReservedKeyword
+ ;
+
+ExplainClause
+ : '<hive>EXPLAIN' OptionalHiveExplainTypes
+ | '<impala>EXPLAIN'
+ ;
+
+ExplainClause_EDIT
+ : '<hive>EXPLAIN' OptionalHiveExplainTypes 'CURSOR'
+   {
+     if (!$2) {
+       parser.suggestDdlAndDmlKeywords([{ value: 'AUTHORIZATION', weight: 2 }, { value: 'DEPENDENCY', weight: 2 }, { value: 'EXTENDED', weight: 2 }]);
+     } else {
+       parser.suggestDdlAndDmlKeywords();
+     }
+   }
+ | '<impala>EXPLAIN' 'CURSOR'
+   {
+     parser.suggestDdlAndDmlKeywords();
+   }
+ ;
+
+OptionalHiveExplainTypes
+ :
+ | '<hive>AUTHORIZATION'
+ | '<hive>DEPENDENCY'
+ | '<hive>EXTENDED'
+ ;
+
+// This is a work-around for error handling when a statement starts with some token that the parser can understand but
+// it's not a valid statement (see ErrorStatement). It contains everything except valid starting tokens ('SELECT', 'USE' etc.)
+NonStartingToken
+ : '<hive>.'
+ | '<hive>['
+ | '<hive>]'
+ | '<hive>ADMIN'
+ | '<hive>ALL'
+ | '<hive>AS'
+ | '<hive>ASC'
+ | '<hive>AUTHORIZATION'
+ | '<hive>AVRO'
+ | '<hive>BINARY'
+ | '<hive>BUCKET'
+ | '<hive>BUCKETS'
+ | '<hive>CACHE'
+ | '<hive>CLUSTER'
+ | '<hive>CLUSTERED'
+ | '<hive>COLLECT_LIST'
+ | '<hive>COLLECT_SET'
+ | '<hive>COLLECTION'
+ | '<hive>COLUMNS'
+ | '<hive>COMMENT'
+ | '<hive>COMPACTIONS'
+ | '<hive>COMPUTE'
+ | '<hive>CONF'
+ | '<hive>CONSTRAINT'
+ | '<hive>CORR'
+ | '<hive>COVAR_POP'
+ | '<hive>COVAR_SAMP'
+ | '<hive>CUBE'
+ | '<hive>CURRENT'
+ | '<hive>DATA'
+ | '<hive>DATABASES'
+ | '<hive>DATE'
+ | '<hive>DAY'
+ | '<hive>DAYOFWEEK'
+ | '<hive>DBPROPERTIES'
+ | '<hive>DEFERRED'
+ | '<hive>DEFINED'
+ | '<hive>DELIMITED'
+ | '<hive>DEPENDENCY'
+ | '<hive>DESC'
+ | '<hive>DIRECTORY'
+ | '<hive>DISTRIBUTE'
+ | '<hive>DISTRIBUTED'
+ | '<hive>DOUBLE_PRECISION' |'<hive>ESCAPED'
+ | '<hive>EXTENDED'
+ | '<hive>EXTERNAL'
+ | '<hive>FIELDS'
+ | '<hive>FILE'
+ | '<hive>FOR'
+ | '<hive>FOREIGN'
+ | '<hive>FORMAT'
+ | '<hive>FORMATTED'
+ | '<hive>FUNCTION'
+ | '<hive>FUNCTIONS'
+ | '<hive>GRANT'
+ | '<hive>GROUPING'
+ | '<hive>HISTOGRAM_NUMERIC'
+ | '<hive>HOUR'
+ | '<hive>IDXPROPERTIES'
+ | '<hive>INDEX'
+ | '<hive>INDEXES'
+ | '<hive>INPATH'
+ | '<hive>INPUTFORMAT'
+ | '<hive>ITEMS'
+ | '<hive>JAR'
+ | '<hive>JSONFILE'
+ | '<hive>KEY'
+ | '<hive>KEYS'
+ | '<hive>LATERAL'
+ | '<hive>LINES'
+ | '<hive>LOCAL'
+ | '<hive>LOCATION'
+ | '<hive>LOCK'
+ | '<hive>LOCKS'
+ | '<hive>MACRO'
+ | '<hive>MATCHED'
+ | '<hive>METADATA'
+ | '<hive>MINUTE'
+ | '<hive>MONTH'
+ | '<hive>NONE'
+ | '<hive>NORELY'
+ | '<hive>NOSCAN'
+ | '<hive>NOVALIDATE'
+ | '<hive>NTILE'
+ | '<hive>OF'
+ | '<hive>ORC'
+ | '<hive>OUT'
+ | '<hive>OUTPUTFORMAT'
+ | '<hive>OVERWRITE'
+ | '<hive>OWNER'
+ | '<hive>PARQUET'
+ | '<hive>PARTITION'
+ | '<hive>PARTITIONED'
+ | '<hive>PARTITIONS'
+ | '<hive>PERCENT'
+ | '<hive>PERCENTILE'
+ | '<hive>PERCENTILE_APPROX'
+ | '<hive>PRIMARY'
+ | '<hive>PRIVILEGES'
+ | '<hive>QUARTER'
+ | '<hive>RCFILE'
+ | '<hive>REBUILD'
+ | '<hive>REFERENCES'
+ | '<hive>RELY'
+ | '<hive>REPAIR'
+ | '<hive>REPLICATION' |'<hive>ROLLUP'
+ | '<hive>ROLE'
+ | '<hive>ROLES'
+ | '<hive>SCHEMA'
+ | '<hive>SCHEMAS'
+ | '<hive>SECOND'
+ | '<hive>SEQUENCEFILE'
+ | '<hive>SERDE'
+ | '<hive>SERDEPROPERTIES'
+ | '<hive>SETS'
+ | '<hive>SHOW_DATABASE'
+ | '<hive>SORTED'
+ | '<hive>STATISTICS'
+ | '<hive>STORED'
+ | '<hive>STORED_AS_DIRECTORIES'
+ | '<hive>STRING'
+ | '<hive>TABLE'
+ | '<hive>TABLES'
+ | '<hive>TABLESAMPLE'
+ | '<hive>TBLPROPERTIES'
+ | '<hive>TEMPORARY'
+ | '<hive>TERMINATED'
+ | '<hive>TEXTFILE'
+ | '<hive>TIMESTAMP' |'<hive>USER'
+ | '<hive>TINYINT'
+ | '<hive>TRANSACTIONAL'
+ | '<hive>TRANSACTIONS'
+ | '<hive>UNIONTYPE'
+ | '<hive>USING'
+ | '<hive>VIEW'
+ | '<hive>VIEWS'
+ | '<hive>WAIT'
+ | '<hive>WEEK'
+ | '<hive>WINDOW'
+ | '<hive>YEAR'
+ | '<impala>.'
+ | '<impala>...'
+ | '<impala>['
+ | '<impala>]'
+ | '<impala>AGGREGATE'
+ | '<impala>ALLOCATE'
+ | '<impala>ANALYTIC'
+ | '<impala>ANTI'
+ | '<impala>ANY'
+ | '<impala>APPX_MEDIAN'
+ | '<impala>ARE'
+ | '<impala>ARRAY_AGG'
+ | '<impala>ARRAY_MAX_CARDINALITY'
+ | '<impala>ASENSITIVE'
+ | '<impala>ASYMMETRIC'
+ | '<impala>AT'
+ | '<impala>ATOMIC'
+ | '<impala>AUTHORIZATION'
+ | '<impala>AVRO'
+ | '<impala>BEGIN_FRAME'
+ | '<impala>BEGIN_PARTITION'
+ | '<impala>BLOB'
+ | '<impala>BLOCK_SIZE'
+ | '<impala>BOTH'
+ | '<impala>BROADCAST'
+ | '<impala>CACHED'
+ | '<impala>CALLED'
+ | '<impala>CARDINALITY'
+ | '<impala>CASCADE'
+ | '<impala>CASCADED'
+ | '<impala>CHARACTER'
+ | '<impala>CLOB'
+ | '<impala>CLOSE_FN'
+ | '<impala>COLLATE'
+ | '<impala>COLLECT'
+ | '<impala>COLUMN'
+ | '<impala>COMMIT'
+ | '<impala>CONDITION'
+ | '<impala>CONNECT'
+ | '<impala>CONSTRAINT'
+ | '<impala>CONTAINS'
+ | '<impala>CONVERT'
+ | '<impala>COPY'
+ | '<impala>CORR'
+ | '<impala>CORRESPONDING'
+ | '<impala>COVAR_POP'
+ | '<impala>COVAR_SAMP'
+ | '<impala>CUBE'
+ | '<impala>CURRENT'
+ | '<impala>CURRENT_DATE'
+ | '<impala>CURRENT_DEFAULT_TRANSFORM_GROUP'
+ | '<impala>CURRENT_PATH'
+ | '<impala>CURRENT_ROLE'
+ | '<impala>CURRENT_ROW'
+ | '<impala>CURRENT_SCHEMA'
+ | '<impala>CURRENT_TIME'
+ | '<impala>CURRENT_TRANSFORM_GROUP_FOR_TYPE'
+ | '<impala>CURSOR'
+ | '<impala>CYCLE'
+ | '<impala>DATA'
+ | '<impala>DATABASES'
+ | '<impala>DEALLOCATE'
+ | '<impala>DEC'
+ | '<impala>DECFLOAT'
+ | '<impala>DECLARE'
+ | '<impala>DEFINE'
+ | '<impala>DELETE'
+ | '<impala>DELIMITED'
+ | '<impala>DEREF'
+ | '<impala>DETERMINISTIC'
+ | '<impala>DISCONNECT'
+ | '<impala>DYNAMIC'
+ | '<impala>EACH'
+ | '<impala>ELEMENT'
+ | '<impala>EMPTY'
+ | '<impala>END_FRAME'
+ | '<impala>END_PARTITION'
+ | '<impala>EQUALS'
+ | '<impala>ESCAPE'
+ | '<impala>ESCAPED'
+ | '<impala>EVERY'
+ | '<impala>EXCEPT'
+ | '<impala>EXEC'
+ | '<impala>EXECUTE'
+ | '<impala>EXTENDED'
+ | '<impala>EXTERNAL'
+ | '<impala>EXTRACT'
+ | '<impala>FETCH'
+ | '<impala>FIELDS'
+ | '<impala>FILES'
+ | '<impala>FILTER'
+ | '<impala>FINALIZE_FN'
+ | '<impala>FIRST'
+ | '<impala>FOR'
+ | '<impala>FOREIGN'
+ | '<impala>FORMAT'
+ | '<impala>FORMATTED'
+ | '<impala>FRAME_ROW'
+ | '<impala>FREE'
+ | '<impala>FUNCTION'
+ | '<impala>FUNCTIONS'
+ | '<impala>FUSION'
+ | '<impala>GET'
+ | '<impala>GLOBAL'
+ | '<impala>GRANT'
+ | '<impala>GROUP'
+ | '<impala>GROUP_CONCAT'
+ | '<impala>GROUPING'
+ | '<impala>GROUPS'
+ | '<impala>HASH'
+ | '<impala>HOLD'
+ | '<impala>IGNORE'
+ | '<impala>ILIKE'
+ | '<impala>INCREMENTAL'
+ | '<impala>INDICATOR'
+ | '<impala>INIT_FN'
+ | '<impala>INITIAL'
+ | '<impala>INOUT'
+ | '<impala>INPATH'
+ | '<impala>INSENSITIVE'
+ | '<impala>INTERMEDIATE'
+ | '<impala>INTERSECT'
+ | '<impala>INTERSECTION'
+ | '<impala>INTERVAL'
+ | '<impala>IREGEXP'
+ | '<impala>JSON_ARRAY'
+ | '<impala>JSON_ARRAYAGG'
+ | '<impala>JSON_EXISTS'
+ | '<impala>JSON_OBJECT'
+ | '<impala>JSON_OBJECTAGG'
+ | '<impala>JSON_QUERY'
+ | '<impala>JSON_TABLE'
+ | '<impala>JSON_TABLE_PRIMITIVE'
+ | '<impala>JSON_VALUE'
+ | '<impala>KEY'
+ | '<impala>KUDU'
+ | '<impala>LARGE'
+ | '<impala>LAST'
+ | '<impala>LATERAL'
+ | '<impala>LEADING'
+ | '<impala>LIKE_REGEX'
+ | '<impala>LIMIT'
+ | '<impala>LINES'
+ | '<impala>LISTAGG'
+ | '<impala>LOCAL'
+ | '<impala>LOCALTIMESTAMP'
+ | '<impala>LOCATION'
+ | '<impala>MATCH'
+ | '<impala>MATCH_NUMBER'
+ | '<impala>MATCH_RECOGNIZE'
+ | '<impala>MATCHES'
+ | '<impala>MERGE'
+ | '<impala>MERGE_FN'
+ | '<impala>METHOD'
+ | '<impala>MODIFIES'
+ | '<impala>MULTISET'
+ | '<impala>NATIONAL'
+ | '<impala>NATURAL'
+ | '<impala>NCHAR'
+ | '<impala>NCLOB'
+ | '<impala>NDV'
+ | '<impala>NO'
+ | '<impala>NONE'
+ | '<impala>NORMALIZE'
+ | '<impala>NOSHUFFLE'
+ | '<impala>NTH_VALUE'
+ | '<impala>NULLS'
+ | '<impala>NUMERIC'
+ | '<impala>OCCURRENCES_REGEX'
+ | '<impala>OCTET_LENGTH'
+ | '<impala>OF'
+ | '<impala>OMIT'
+ | '<impala>ONE'
+ | '<impala>ONLY'
+ | '<impala>OUT'
+ | '<impala>OVER'
+ | '<impala>OVERLAPS'
+ | '<impala>OVERLAY'
+ | '<impala>OWNER'
+ | '<impala>PARQUET'
+ | '<impala>PARTITIONED'
+ | '<impala>PARTITIONS'
+ | '<impala>PATTERN'
+ | '<impala>PER'
+ | '<impala>PERCENT'
+ | '<impala>PERCENTILE_CONT'
+ | '<impala>PERCENTILE_DISC'
+ | '<impala>PORTION'
+ | '<impala>POSITION'
+ | '<impala>POSITION_REGEX'
+ | '<impala>PRECEDES'
+ | '<impala>PREPARE'
+ | '<impala>PREPARE_FN'
+ | '<impala>PRIMARY'
+ | '<impala>PROCEDURE'
+ | '<impala>PTF'
+ | '<impala>RANGE'
+ | '<impala>RCFILE'
+ | '<impala>READS'
+ | '<impala>REAL'
+ | '<impala>RECOVER'
+ | '<impala>RECURSIVE'
+ | '<impala>REF'
+ | '<impala>REFERENCES'
+ | '<impala>REFERENCING'
+ | '<impala>REGR_AVGX'
+ | '<impala>REGR_AVGY'
+ | '<impala>REGR_COUNT'
+ | '<impala>REGR_INTERCEPT'
+ | '<impala>REGR_R2REGR_SLOPE'
+ | '<impala>REGR_SXX'
+ | '<impala>REGR_SXY'
+ | '<impala>REGR_SYY'
+ | '<impala>RELEASE'
+ | '<impala>REPEATABLE'
+ | '<impala>REPLICATION'
+ | '<impala>RESTRICT'
+ | '<impala>RETURNS'
+ | '<impala>ROLE'
+ | '<impala>ROLES'
+ | '<impala>ROLLBACK'
+ | '<impala>ROLLUP'
+ | '<impala>RUNNING'
+ | '<impala>SAVEPOINT'
+ | '<impala>SCHEMAS'
+ | '<impala>SCOPE'
+ | '<impala>SCROLL'
+ | '<impala>SEARCH'
+ | '<impala>SEEK'
+ | '<impala>SENSITIVE'
+ | '<impala>SEQUENCEFILE'
+ | '<impala>SERDEPROPERTIES'
+ | '<impala>SERIALIZE_FN'
+ | '<impala>SERVER'
+ | '<impala>SHUFFLE'
+ | '<impala>SIMILAR'
+ | '<impala>SKIP'
+ | '<impala>SOME'
+ | '<impala>SORT'
+ | '<impala>SPECIFIC'
+ | '<impala>SPECIFICTYPE'
+ | '<impala>SQLEXCEPTION'
+ | '<impala>SQLSTATE'
+ | '<impala>SQLWARNING'
+ | '<impala>STATIC'
+ | '<impala>STATS'
+ | '<impala>STDDEV'
+ | '<impala>STORED'
+ | '<impala>STRAIGHT_JOIN'
+ | '<impala>SUBMULTISET'
+ | '<impala>SUBSET'
+ | '<impala>SUBSTRING_REGEX'
+ | '<impala>SUCCEEDS'
+ | '<impala>SYMBOL'
+ | '<impala>SYMMETRIC'
+ | '<impala>SYSTEM_TIME'
+ | '<impala>SYSTEM_USER'
+ | '<impala>TABLE'
+ | '<impala>TABLES'
+ | '<impala>TABLESAMPLE'
+ | '<impala>TBLPROPERTIES'
+ | '<impala>TERMINATED'
+ | '<impala>TEXTFILE'
+ | '<impala>TIMEZONE_HOUR'
+ | '<impala>TIMEZONE_MINUTE'
+ | '<impala>TRAILING'
+ | '<impala>TRANSLATE_REGEX'
+ | '<impala>TRANSLATION'
+ | '<impala>TREAT'
+ | '<impala>TRIGGER'
+ | '<impala>TRIM_ARRAY'
+ | '<impala>UESCAPE'
+ | '<impala>UNIQUE'
+ | '<impala>UNNEST'
+ | '<impala>UPDATE_FN'
+ | '<impala>URI'
+ | '<impala>USER'
+ | '<impala>USING'
+ | '<impala>VALUE_OF'
+ | '<impala>VARBINARY'
+ | '<impala>VARCHAR'
+ | '<impala>VARIANCE_POP'
+ | '<impala>VARIANCE_SAMP'
+ | '<impala>VARYING'
+ | '<impala>VERSIONING'
+ | '<impala>WHENEVER'
+ | '<impala>WIDTH_BUCKET'
+ | '<impala>WINDOW'
+ | '<impala>WITHIN'
+ | '<impala>WITHOUT'
+ | '!'
+ | '('
+ | ')'
+ | '*'
+ | ','
+ | '-'
+ | '.'
+ | '<'
+ | '='
+ | '>'
+ | '['
+ | ']'
+ | '~'
+ | 'ALL'
+ | 'ANALYTIC'
+ | 'AND'
+ | 'ARITHMETIC_OPERATOR'
+ | 'ARRAY'
+ | 'AS'
+ | 'ASC'
+ | 'AVG'
+ | 'BACKTICK'
+ | 'BETWEEN'
+ | 'BIGINT'
+ | 'BOOLEAN'
+ | 'BY'
+ | 'CASE'
+ | 'CAST'
+ | 'CHAR'
+ | 'COMPARISON_OPERATOR'
+ | 'COUNT'
+ | 'CROSS'
+ | 'CURRENT'
+ | 'DATABASE'
+ | 'DECIMAL'
+ | 'DESC'
+ | 'DISTINCT'
+ | 'DOUBLE'
+ | 'DOUBLE_QUOTE'
+ | 'ELSE'
+ | 'END'
+ | 'EXISTS'
+ | 'FALSE'
+ | 'FLOAT'
+ | 'FOLLOWING'
+ | 'FROM'
+ | 'FULL'
+ | 'GROUP'
+ | 'HAVING'
+ | 'HDFS_START_QUOTE'
+ | 'IF'
+ | 'IN'
+ | 'INNER'
+ | 'INT'
+ | 'INTO'
+ | 'IS'
+ | 'JOIN'
+ | 'LEFT'
+ | 'LIKE'
+ | 'LIMIT'
+ | 'MAP'
+ | 'MAX'
+ | 'MIN'
+ | 'NOT'
+ | 'NULL'
+ | 'ON'
+ | 'OPTION'
+ | 'OR'
+ | 'ORDER'
+ | 'OUTER'
+ | 'OVER'
+ | 'PARTITION'
+ | 'PRECEDING'
+ | 'PURGE'
+ | 'RANGE'
+ | 'REGEXP'
+ | 'REGULAR_IDENTIFIER'
+ | 'RIGHT'
+ | 'RLIKE'
+ | 'ROLE'
+ | 'ROW'
+ | 'ROWS'
+ | 'SCHEMA'
+ | 'SEMI'
+ | 'SET'
+ | 'SINGLE_QUOTE'
+ | 'SMALLINT'
+ | 'STDDEV_POP'
+ | 'STDDEV_SAMP'
+ | 'STRING'
+ | 'STRUCT'
+ | 'SUM'
+ | 'TABLE'
+ | 'THEN'
+ | 'TIMESTAMP'
+ | 'TINYINT'
+ | 'TRUE'
+ | 'UNION'
+ | 'UNSIGNED_INTEGER'
+ | 'UNSIGNED_INTEGER_E'
+ | 'VALUES'
+ | 'VAR_POP'
+ | 'VAR_SAMP'
+ | 'VARCHAR'
+ | 'VARIABLE_REFERENCE'
+ | 'VARIANCE'
+ | 'WHEN'
+ | 'WHERE'
+ ;
+
+DataDefinition
+ : DescribeStatement
+ ;
+
+DataDefinition_EDIT
+ : DescribeStatement_EDIT
+ ;
+
+// ===================================== Commonly used constructs =====================================
+
+AggregateOrAnalytic
+ : '<impala>AGGREGATE'
+ | '<impala>ANALYTIC'
+ ;
+
+Commas
+ : ','
+ | Commas ','
+ ;
+
+AnyCreate
+ : 'CREATE'
+ | '<hive>CREATE'
+ | '<impala>CREATE'
+ ;
+
+AnyCursor
+ : 'CURSOR'
+ | 'PARTIAL_CURSOR'
+ ;
+
+AnyDot
+ : '.'
+ | '<impala>.'
+ | '<hive>.'
+ ;
+
+AnyFromOrIn
+ : 'FROM'
+ | 'IN'
+ ;
+
+AnyGroup
+ : 'GROUP'
+ | '<hive>GROUP'
+ | '<impala>GROUP'
+ ;
+
+AnyPartition
+ : 'PARTITION'
+ | '<hive>PARTITION'
+ ;
+
+AnyTable
+ : 'TABLE'
+ | '<hive>TABLE'
+ | '<impala>TABLE'
+ ;
+
+AnyWith
+ : 'WITH'
+ | '<hive>WITH'
+ | '<impala>WITH'
+ ;
+
+DatabaseOrSchema
+ : 'DATABASE'
+ | 'SCHEMA'
+ | '<hive>SCHEMA'
+ ;
+
+FromOrIn
+ : 'FROM'
+ | 'IN'
+ ;
+
+HiveIndexOrIndexes
+ : '<hive>INDEX'
+ | '<hive>INDEXES'
+ ;
+
+HiveOrImpalaCreate
+ : '<hive>CREATE'
+ | '<impala>CREATE'
+ ;
+
+HiveOrImpalaDatabasesOrSchemas
+ : '<hive>DATABASES'
+ | '<hive>SCHEMAS'
+ | '<impala>DATABASES'
+ | '<impala>SCHEMAS'
+ ;
+
+HiveOrImpalaLeftSquareBracket
+ : '<hive>['
+ | '<impala>['
+ ;
+
+HiveOrImpalaLocation
+ : '<hive>LOCATION'
+ | '<impala>LOCATION'
+ ;
+
+HiveOrImpalaRightSquareBracket
+ : '<hive>]'
+ | '<impala>]'
+ ;
+
+HiveOrImpalaTables
+ : '<hive>TABLES'
+ | '<impala>TABLES'
+ ;
+
+HiveRoleOrUser
+ : '<hive>ROLE'
+ | '<hive>USER'
+ ;
+
+RoleOrUser
+ : '<impala>ROLE'
+ | '<impala>USER'
+ ;
+
+SingleQuotedValue
+ : 'SINGLE_QUOTE' 'VALUE' 'SINGLE_QUOTE'  -> $2
+ | 'SINGLE_QUOTE' 'SINGLE_QUOTE'          -> ''
+ ;
+
+SingleQuotedValue_EDIT
+ : 'SINGLE_QUOTE' 'PARTIAL_VALUE'
+ ;
+
+DoubleQuotedValue
+ : 'DOUBLE_QUOTE' 'VALUE' 'DOUBLE_QUOTE'  -> $2
+ | 'DOUBLE_QUOTE' 'DOUBLE_QUOTE'          -> ''
+ ;
+
+DoubleQuotedValue_EDIT
+ : 'DOUBLE_QUOTE' 'PARTIAL_VALUE'
+ ;
+
+QuotedValue
+ : SingleQuotedValue
+ | DoubleQuotedValue
+ ;
+
+QuotedValue_EDIT
+ : SingleQuotedValue_EDIT
+ | DoubleQuotedValue_EDIT
+ ;
+
+OptionalAggregateOrAnalytic
+ :
+ | AggregateOrAnalytic
+ ;
+
+OptionalHiveExtended
+ :
+ | '<hive>EXTENDED'
+ ;
+
+OptionalHiveExtendedOrFormatted
+ :
+ | '<hive>EXTENDED'
+ | '<hive>FORMATTED'
+ ;
+
+OptionalExternal
+ :
+ | '<hive>EXTERNAL'
+ | '<impala>EXTERNAL'
+ ;
+
+OptionalImpalaExtendedOrFormatted
+ :
+ | '<impala>EXTENDED'
+ | '<impala>FORMATTED'
+ ;
+
+OptionallyFormattedIndex
+ : '<hive>FORMATTED' HiveIndexOrIndexes
+ | HiveIndexOrIndexes
+ ;
+
+OptionallyFormattedIndex_EDIT
+ : '<hive>FORMATTED' 'CURSOR'
+   {
+     parser.suggestKeywords(['INDEX', 'INDEXES']);
+   }
+ | 'CURSOR' HiveIndexOrIndexes
+   {
+     parser.suggestKeywords(['FORMATTED']);
+   }
+ ;
+
+OptionalFromDatabase
+ :
+ | FromOrIn DatabaseIdentifier
+ ;
+
+OptionalFromDatabase_EDIT
+ : FromOrIn DatabaseIdentifier_EDIT
+ ;
+
+OptionalCascade
+ :
+ | '<hive>CASCADE'
+ ;
+
+OptionalCascadeOrRestrict
+ :
+ | '<hive>CASCADE'
+ | '<impala>CASCADE'
+ | '<hive>RESTRICT'
+ | '<impala>RESTRICT'
+ ;
+
+OptionalHiveCascadeOrRestrict
+ :
+ | '<hive>CASCADE'
+ | '<hive>RESTRICT'
+ ;
+
+OptionalIfExists
+ :
+ | 'IF' 'EXISTS'
+   {
+     parser.yy.correlatedSubQuery = false;
+   }
+ ;
+
+OptionalIfExists_EDIT
+ : 'IF' 'CURSOR'
+   {
+     parser.suggestKeywords(['EXISTS']);
+   }
+ ;
+
+OptionalIfNotExists
+ :
+ | 'IF' 'NOT' 'EXISTS'
+   {
+     parser.yy.correlatedSubQuery = false;
+   }
+ ;
+
+OptionalIfNotExists_EDIT
+ : 'IF' 'CURSOR'
+   {
+     parser.suggestKeywords(['NOT EXISTS']);
+   }
+ | 'IF' 'NOT' 'CURSOR'
+   {
+     parser.suggestKeywords(['EXISTS']);
+   }
+ ;
+
+OptionalInDatabase
+ :
+ | 'IN' DatabaseIdentifier
+ | 'IN' DatabaseIdentifier_EDIT
+ ;
+
+OptionalPartitionSpec
+ :
+ | PartitionSpec
+ ;
+
+OptionalPartitionSpec_EDIT
+ : PartitionSpec_EDIT
+ ;
+
+PartitionSpec
+ : AnyPartition '(' PartitionSpecList ')'
+ ;
+
+PartitionSpec_EDIT
+ : AnyPartition '(' PartitionSpecList_EDIT RightParenthesisOrError
+ ;
+
+RangePartitionSpec
+ : UnsignedValueSpecification RangePartitionComparisonOperator 'VALUES' RangePartitionComparisonOperator UnsignedValueSpecification
+ ;
+
+RangePartitionSpec_EDIT
+ : UnsignedValueSpecification 'CURSOR'
+   {
+     parser.suggestKeywords(['<', '<=', '<>', '=', '>', '>=']);
+   }
+ | UnsignedValueSpecification RangePartitionComparisonOperator 'CURSOR'
+   {
+     parser.suggestKeywords(['VALUES']);
+   }
+ | UnsignedValueSpecification RangePartitionComparisonOperator 'VALUES' 'CURSOR'
+   {
+     parser.suggestKeywords(['<', '<=', '<>', '=', '>', '>=']);
+   }
+ | UnsignedValueSpecification 'CURSOR' 'VALUES' RangePartitionComparisonOperator UnsignedValueSpecification
+   {
+     parser.suggestKeywords(['<', '<=', '<>', '=', '>', '>=']);
+   }
+ | UnsignedValueSpecification RangePartitionComparisonOperator 'CURSOR' RangePartitionComparisonOperator UnsignedValueSpecification
+   {
+     parser.suggestKeywords(['VALUES']);
+   }
+ | UnsignedValueSpecification RangePartitionComparisonOperator 'VALUES' 'CURSOR' UnsignedValueSpecification
+   {
+     parser.suggestKeywords(['<', '<=', '<>', '=', '>', '>=']);
+   }
+ ;
+
+RangePartitionComparisonOperator
+ : 'COMPARISON_OPERATOR'
+ | '='
+ | '<'
+ | '>'
+ ;
+
+ConfigurationName
+ : RegularIdentifier
+ | 'CURSOR'
+ | ConfigurationName '<hive>.' RegularIdentifier
+ | ConfigurationName '<hive>.' 'PARTIAL_CURSOR'
+ ;
+
+PartialBacktickedOrAnyCursor
+ : AnyCursor
+ | PartialBacktickedIdentifier
+ ;
+
+PartialBacktickedOrCursor
+ : 'CURSOR'
+ | PartialBacktickedIdentifier
+ ;
+
+PartialBacktickedOrPartialCursor
+ : 'PARTIAL_CURSOR'
+ | PartialBacktickedIdentifier
+ ;
+
+PartialBacktickedIdentifier
+ : 'BACKTICK' 'PARTIAL_VALUE'
+ ;
+
+RightParenthesisOrError
+ : ')'
+ | error
+ ;
+
+OptionalParenthesizedColumnList
+ :
+ | ParenthesizedColumnList
+ ;
+
+OptionalParenthesizedColumnList_EDIT
+ : ParenthesizedColumnList_EDIT
+ ;
+
+ParenthesizedColumnList
+ : '(' ColumnList ')'
+ ;
+
+ParenthesizedColumnList_EDIT
+ : '(' ColumnList_EDIT RightParenthesisOrError
+ | '(' AnyCursor RightParenthesisOrError
+   {
+     parser.suggestColumns();
+   }
+ ;
+
+ColumnList
+ : ColumnIdentifier
+ | ColumnList ',' ColumnIdentifier
+ ;
+
+ColumnList_EDIT
+ : ColumnIdentifier_EDIT
+ | ColumnList ',' AnyCursor
+   {
+     parser.suggestColumns();
+   }
+ | ColumnList ',' ColumnIdentifier_EDIT
+ | ColumnIdentifier_EDIT ',' ColumnList
+ | ColumnList ',' ColumnIdentifier_EDIT ',' ColumnList
+ | ColumnList ',' AnyCursor ',' ColumnList
+   {
+     parser.suggestColumns();
+   }
+ ;
+
+ParenthesizedSimpleValueList
+ : '(' SimpleValueList ')'
+ ;
+
+SimpleValueList
+ : UnsignedValueSpecification
+ | SimpleValueList ',' UnsignedValueSpecification
+ ;
+
+SchemaQualifiedTableIdentifier
+ : RegularOrBacktickedIdentifier
+   {
+     parser.addTableLocation(@1, [ { name: $1 } ]);
+     $$ = { identifierChain: [ { name: $1 } ] };
+   }
+ | RegularOrBacktickedIdentifier AnyDot RegularOrBacktickedIdentifier
+   {
+     parser.addDatabaseLocation(@1, [ { name: $1 } ]);
+     parser.addTableLocation(@3, [ { name: $1 }, { name: $3 } ]);
+     $$ = { identifierChain: [ { name: $1 }, { name: $3 } ] };
+   }
+ | RegularOrBacktickedIdentifier AnyDot RegularOrBacktickedIdentifier ImpalaFields
+   {
+     // This is a special case for Impala expression like "SELECT | FROM db.table.col"
+     $$ = { identifierChain: [ { name: $1 }, { name: $3 } ].concat($4) };
+   }
+ ;
+
+SchemaQualifiedTableIdentifier_EDIT
+ : PartialBacktickedIdentifier
+   {
+     parser.suggestTables();
+     parser.suggestDatabases({ appendDot: true });
+   }
+ | PartialBacktickedIdentifier AnyDot RegularOrBacktickedIdentifier
+   {
+     parser.suggestDatabases();
+     $$ = { identifierChain: [{ name: $1 }] };
+   }
+ | RegularOrBacktickedIdentifier AnyDot PartialBacktickedOrPartialCursor
+   {
+     // In Impala you can have statements like 'SELECT ... FROM testTable t, t.|'
+     parser.suggestTablesOrColumns($1);
+   }
+ | RegularOrBacktickedIdentifier AnyDot RegularOrBacktickedIdentifier ImpalaFields_EDIT
+   {
+     // TODO: switch to suggestColumns, it's currently handled in sqlAutocompleter2.js
+     // Issue is that suggestColumns is deleted if no tables are defined and this is
+     // Impala only cases like "SELECT | FROM db.table.col"
+     parser.suggestTables({ identifierChain: [{ name: $1 }, { name: $3 }].concat($4) });
+   }
+ ;
+
+ImpalaFields
+ : ImpalaField               -> [$1]
+ | ImpalaFields ImpalaField
+   {
+     $1.push($2);
+   }
+ ;
+
+ImpalaFields_EDIT
+ : ImpalaField_EDIT                            -> []
+ | ImpalaFields ImpalaField_EDIT               -> $1
+ | ImpalaFields ImpalaField_EDIT ImpalaFields  -> $1
+ | ImpalaField_EDIT ImpalaFields               -> []
+ ;
+
+ImpalaField
+ : '<impala>.' RegularOrBacktickedIdentifier  -> { name: $2 }
+ ;
+
+ImpalaField_EDIT
+ : '<impala>.' PartialBacktickedOrPartialCursor
+ ;
+
+SchemaQualifiedIdentifier
+ : RegularOrBacktickedIdentifier                                       -> [{ name: $1 }]
+ | RegularOrBacktickedIdentifier AnyDot RegularOrBacktickedIdentifier  -> [{ name: $1 }, { name: $2 }]
+ ;
+
+SchemaQualifiedIdentifier_EDIT
+ : PartialBacktickedIdentifier
+   {
+     parser.suggestDatabases({ appendDot: true });
+   }
+ | PartialBacktickedIdentifier AnyDot RegularOrBacktickedIdentifier
+   {
+     parser.suggestDatabases();
+     $$ = { identifierChain: [{ name: $1 }] };
+   }
+ | RegularOrBacktickedIdentifier AnyDot PartialBacktickedOrPartialCursor
+ ;
+
+DatabaseIdentifier
+ : RegularOrBacktickedIdentifier
+ ;
+
+DatabaseIdentifier_EDIT
+ : PartialBacktickedOrCursor
+   {
+     parser.suggestDatabases();
+   }
+ ;
+
+PartitionSpecList
+ : PartitionExpression
+ | PartitionSpecList ',' PartitionExpression
+ ;
+
+PartitionSpecList_EDIT
+ : PartitionExpression_EDIT
+ | PartitionSpecList ',' PartitionExpression_EDIT
+ | PartitionExpression_EDIT ',' PartitionSpecList
+ | PartitionSpecList ',' PartitionExpression_EDIT ',' PartitionSpecList
+ ;
+
+PartitionExpression
+ : ColumnIdentifier '=' ValueExpression
+ | ColumnIdentifier // Hive allows partial partition specs in some cases
+ ;
+
+PartitionExpression_EDIT
+ : ColumnIdentifier '=' ValueExpression_EDIT
+ | ColumnIdentifier '=' AnyCursor
+   {
+     parser.valueExpressionSuggest();
+   }
+ | PartialBacktickedIdentifier '=' ValueExpression
+   {
+     parser.suggestColumns();
+   }
+ | AnyCursor
+   {
+     parser.suggestColumns();
+   }
+ ;
+
+OptionalHdfsLocation
+ :
+ | HdfsLocation
+ ;
+
+HdfsLocation
+ : HiveOrImpalaLocation HdfsPath
+ ;
+
+HdfsLocation_EDIT
+ : HiveOrImpalaLocation HdfsPath_EDIT
+ ;
+
+OptionalCachedInOrUncached
+ :
+ | CachedIn OptionalWithReplication
+   {
+     if (!$2) {
+       $$ = { suggestKeywords: ['WITH REPLICATION ='] };
+     }
+   }
+ | '<impala>UNCACHED'
+ ;
+
+
+OptionalCachedIn
+ :
+ | CachedIn OptionalWithReplication
+   {
+     if (!$2) {
+       $$ = { suggestKeywords: ['WITH REPLICATION ='] };
+     }
+   }
+ ;
+
+CachedIn
+ : '<impala>CACHED' 'IN' QuotedValue
+ ;
+
+CachedIn_EDIT
+ : '<impala>CACHED' 'CURSOR'
+   {
+     parser.suggestKeywords(['IN']);
+   }
+ ;
+
+OptionalWithReplication
+ :
+ | WithReplication
+ ;
+
+WithReplication
+ : '<impala>WITH' '<impala>REPLICATION' '=' SignedInteger
+ ;
+
+WithReplication_EDIT
+ : '<impala>WITH' 'CURSOR'
+   {
+     parser.suggestKeywords(['REPLICATION =']);
+   }
+ | '<impala>WITH' '<impala>REPLICATION' 'CURSOR'
+   {
+     parser.suggestKeywords(['=']);
+   }
+ ;
+
+RegularOrBacktickedIdentifier
+ : RegularIdentifier
+ | 'BACKTICK' 'VALUE' 'BACKTICK'  -> $2
+ | 'BACKTICK' 'BACKTICK'          -> ''
+ ;
+
+// TODO: Same as SchemaQualifiedTableIdentifier?
+RegularOrBackTickedSchemaQualifiedName
+ : RegularOrBacktickedIdentifier
+   {
+     parser.addTableLocation(@1, [ { name: $1 } ]);
+     $$ = { identifierChain: [ { name: $1 } ] };
+   }
+ | RegularOrBacktickedIdentifier AnyDot RegularOrBacktickedIdentifier
+   {
+     parser.addDatabaseLocation(@1, [ { name: $1 } ]);
+     parser.addTableLocation(@3, [ { name: $1 }, { name: $3 } ]);
+     $$ = { identifierChain: [ { name: $1 }, { name: $3 } ] };
+   }
+ ;
+
+RegularOrBackTickedSchemaQualifiedName_EDIT
+ : PartialBacktickedIdentifier
+   {
+     parser.suggestTables();
+     parser.suggestDatabases({ prependDot: true });
+   }
+ | RegularOrBacktickedIdentifier AnyDot PartialBacktickedOrPartialCursor
+   {
+     parser.suggestTablesOrColumns($1);
+   }
+ ;
+
+
+LocalOrSchemaQualifiedName
+ : RegularOrBackTickedSchemaQualifiedName
+ | RegularOrBackTickedSchemaQualifiedName RegularOrBacktickedIdentifier  -> { identifierChain: $1.identifierChain, alias: $2 }
+ ;
+
+LocalOrSchemaQualifiedName_EDIT
+ : RegularOrBackTickedSchemaQualifiedName_EDIT
+ | RegularOrBackTickedSchemaQualifiedName_EDIT RegularOrBacktickedIdentifier
+ ;
+
+ColumnReference
+ : BasicIdentifierChain
+   {
+     parser.yy.locations[parser.yy.locations.length - 1].type = 'column';
+   }
+ | BasicIdentifierChain AnyDot '*'
+   {
+     parser.addAsteriskLocation(@3, $1.concat({ asterisk: true }));
+   }
+ ;
+
+ColumnReference_EDIT
+ : BasicIdentifierChain_EDIT
+ ;
+
+BasicIdentifierChain
+ : ColumnIdentifier
+   {
+     $$ = [ $1.identifier ];
+     parser.yy.firstChainLocation = parser.addUnknownLocation($1.location, [ $1.identifier ]);
+   }
+ | BasicIdentifierChain AnyDot ColumnIdentifier
+   {
+     if (parser.yy.firstChainLocation) {
+       parser.yy.firstChainLocation.firstInChain = true;
+       delete parser.yy.firstChainLocation;
+     }
+     $1.push($3.identifier);
+     parser.addUnknownLocation($3.location, $1.concat());
+   }
+ ;
+
+// TODO: Merge with DerivedColumnChain_EDIT ( issue is starting with PartialBacktickedOrPartialCursor)
+BasicIdentifierChain_EDIT
+ : ColumnIdentifier_EDIT
+   {
+     if ($1.insideKey) {
+       parser.suggestKeyValues({ identifierChain: [ $1.identifier ] });
+       parser.suggestColumns();
+       parser.suggestFunctions();
+     }
+   }
+ | BasicIdentifierChain AnyDot ColumnIdentifier_EDIT
+   {
+     if ($3.insideKey) {
+       parser.suggestKeyValues({ identifierChain: $1.concat([ $3.identifier ]) });
+       parser.suggestColumns();
+       parser.suggestFunctions();
+     }
+   }
+ | BasicIdentifierChain AnyDot ColumnIdentifier_EDIT AnyDot BasicIdentifierChain
+ | ColumnIdentifier_EDIT AnyDot BasicIdentifierChain
+ | BasicIdentifierChain AnyDot PartialBacktickedOrPartialCursor
+   {
+     parser.suggestColumns({
+       identifierChain: $1
+     });
+     $$ = { suggestKeywords: [{ value: '*', weight: 10000 }] };
+   }
+ | BasicIdentifierChain AnyDot PartialBacktickedOrPartialCursor AnyDot BasicIdentifierChain
+   {
+     parser.suggestColumns({
+       identifierChain: $1
+     });
+     $$ = { suggestKeywords: [{ value: '*', weight: 10000 }] };
+   }
+ ;
+
+DerivedColumnChain
+ : ColumnIdentifier  -> [ $1.identifier ]
+ | DerivedColumnChain AnyDot ColumnIdentifier
+   {
+     $1.push($3.identifier);
+   }
+ ;
+
+DerivedColumnChain_EDIT
+ : ColumnIdentifier_EDIT
+   {
+     if ($1.insideKey) {
+       parser.suggestKeyValues({ identifierChain: [ $1.identifier ] });
+       parser.suggestColumns();
+       parser.suggestFunctions();
+     }
+   }
+ | DerivedColumnChain AnyDot ColumnIdentifier_EDIT
+   {
+     if ($3.insideKey) {
+       parser.suggestKeyValues({ identifierChain: $1.concat([ $3.identifier ]) });
+       parser.suggestColumns();
+       parser.suggestFunctions();
+     }
+   }
+ | DerivedColumnChain AnyDot ColumnIdentifier_EDIT AnyDot DerivedColumnChain
+   {
+     if ($3.insideKey) {
+       parser.suggestKeyValues({ identifierChain: $1.concat([ $3.identifier ]) });
+       parser.suggestColumns();
+       parser.suggestFunctions();
+     }
+   }
+ | ColumnIdentifier_EDIT AnyDot DerivedColumnChain
+   {
+     if ($1.insideKey) {
+       parser.suggestKeyValues({ identifierChain: [ $1.identifier ] });
+       parser.suggestColumns();
+       parser.suggestFunctions();
+     }
+   }
+ | PartialBacktickedIdentifierOrPartialCursor
+   {
+     parser.suggestColumns();
+   }
+ | DerivedColumnChain AnyDot PartialBacktickedIdentifierOrPartialCursor
+   {
+     parser.suggestColumns({ identifierChain: $1 });
+   }
+ | DerivedColumnChain AnyDot PartialBacktickedIdentifierOrPartialCursor AnyDot DerivedColumnChain
+   {
+     parser.suggestColumns({ identifierChain: $1 });
+   }
+ | PartialBacktickedIdentifierOrPartialCursor AnyDot DerivedColumnChain
+   {
+     parser.suggestColumns();
+   }
+ ;
+
+ColumnIdentifier
+ : RegularOrBacktickedIdentifier                                                                               -> { identifier: { name: $1 }, location: @1 };
+ | RegularOrBacktickedIdentifier HiveOrImpalaLeftSquareBracket ValueExpression HiveOrImpalaRightSquareBracket  -> { identifier: { name: $1, keySet: true }, location: @1 }
+ | RegularOrBacktickedIdentifier HiveOrImpalaLeftSquareBracket HiveOrImpalaRightSquareBracket                  -> { identifier: { name: $1, keySet: true }, location: @1 }
+ ;
+
+ColumnIdentifier_EDIT
+ : RegularOrBacktickedIdentifier HiveOrImpalaLeftSquareBracket AnyCursor HiveOrImpalaRightSquareBracketOrError             -> { identifier: { name: $1 }, insideKey: true }
+ | RegularOrBacktickedIdentifier HiveOrImpalaLeftSquareBracket ValueExpression_EDIT HiveOrImpalaRightSquareBracketOrError  -> { identifier: { name: $1 }};
+ ;
+
+PartialBacktickedIdentifierOrPartialCursor
+ : PartialBacktickedIdentifier
+ | 'PARTIAL_CURSOR'
+ ;
+
+HiveOrImpalaRightSquareBracketOrError
+ : HiveOrImpalaRightSquareBracket
+ | error
+ ;
+
+// TODO: Support | DECIMAL(precision, scale)  -- (Note: Available in Hive 0.13.0 and later)
+PrimitiveType
+ : 'TINYINT'
+ | '<hive>TINYINT'
+ | 'SMALLINT'
+ | 'INT'
+ | 'BIGINT'
+ | 'BOOLEAN'
+ | 'FLOAT'
+ | 'DOUBLE'
+ | '<hive>DOUBLE_PRECISION'
+ | '<impala>REAL'
+ | 'STRING'
+ | '<hive>STRING'
+ | 'DECIMAL' OptionalTypePrecision
+ | 'CHAR' OptionalTypeLength
+ | 'VARCHAR' OptionalTypeLength
+ | 'TIMESTAMP'
+ | '<hive>TIMESTAMP'
+ | '<hive>BINARY'
+ | '<hive>DATE'
+ ;
+
+OptionalTypeLength
+ :
+ | '(' 'UNSIGNED_INTEGER' ')'
+ ;
+
+OptionalTypePrecision
+ :
+ | '(' 'UNSIGNED_INTEGER' ')'
+ | '(' 'UNSIGNED_INTEGER' ',' 'UNSIGNED_INTEGER' ')'
+ ;
+
+// ===================================== DESCRIBE statement =====================================
+
+DescribeStatement
+ : HiveDescribeStatement
+ | ImpalaDescribeStatement
+ ;
+
+DescribeStatement_EDIT
+ : HiveDescribeStatement_EDIT
+ | ImpalaDescribeStatement_EDIT
+ ;
+
+HiveDescribeStatement
+ : '<hive>DESCRIBE' OptionalHiveExtendedOrFormatted SchemaQualifiedTableIdentifier DerivedColumnChain OptionalPartitionSpec
+   {
+     parser.addTablePrimary($3);
+     parser.addColumnLocation(@4, $4);
+   }
+ | '<hive>DESCRIBE' OptionalHiveExtendedOrFormatted SchemaQualifiedTableIdentifier OptionalPartitionSpec
+   {
+     parser.addTablePrimary($3);
+   }
+ | '<hive>DESCRIBE' DatabaseOrSchema OptionalHiveExtended DatabaseIdentifier
+   {
+     parser.addDatabaseLocation(@4, [{ name: $4 }]);
+   }
+ | '<hive>DESCRIBE' '<hive>FUNCTION' OptionalHiveExtended RegularIdentifier
+ ;
+
+HiveDescribeStatement_EDIT
+ : '<hive>DESCRIBE' OptionalHiveExtendedOrFormatted SchemaQualifiedTableIdentifier_EDIT OptionalPartitionSpec
+ | '<hive>DESCRIBE' OptionalHiveExtendedOrFormatted SchemaQualifiedTableIdentifier DerivedColumnChain_EDIT OptionalPartitionSpec
+   {
+     parser.addTablePrimary($3);
+   }
+ | '<hive>DESCRIBE' OptionalHiveExtendedOrFormatted 'CURSOR' SchemaQualifiedTableIdentifier DerivedColumnChain OptionalPartitionSpec
+   {
+     if (!$2) {
+       parser.suggestKeywords(['EXTENDED', 'FORMATTED']);
+     }
+   }
+ | '<hive>DESCRIBE' OptionalHiveExtendedOrFormatted 'CURSOR' SchemaQualifiedTableIdentifier OptionalPartitionSpec
+   {
+     if (!$2) {
+       parser.suggestKeywords(['EXTENDED', 'FORMATTED']);
+     }
+   }
+ | '<hive>DESCRIBE' OptionalHiveExtendedOrFormatted SchemaQualifiedTableIdentifier 'CURSOR' OptionalPartitionSpec
+   {
+     parser.addTablePrimary($3);
+     parser.suggestColumns();
+     if (!$5) {
+       parser.suggestKeywords(['PARTITION']);
+     }
+   }
+ | '<hive>DESCRIBE' OptionalHiveExtendedOrFormatted SchemaQualifiedTableIdentifier DerivedColumnChain 'CURSOR' OptionalPartitionSpec
+   {
+     if (!$6) {
+       parser.suggestKeywords(['PARTITION']);
+     }
+   }
+ | '<hive>DESCRIBE' OptionalHiveExtendedOrFormatted SchemaQualifiedTableIdentifier DerivedColumnChain OptionalPartitionSpec_EDIT
+ | '<hive>DESCRIBE' OptionalHiveExtendedOrFormatted SchemaQualifiedTableIdentifier OptionalPartitionSpec_EDIT
+
+ | '<hive>DESCRIBE' OptionalHiveExtendedOrFormatted 'CURSOR'
+   {
+     if (!$2) {
+       parser.suggestKeywords(['DATABASE', 'EXTENDED', 'FORMATTED', 'FUNCTION', 'SCHEMA']);
+     }
+     parser.suggestTables();
+     parser.suggestDatabases({ appendDot: true });
+    }
+ | '<hive>DESCRIBE' DatabaseOrSchema OptionalHiveExtended DatabaseIdentifier_EDIT
+   {
+     if (!$3) {
+       parser.suggestKeywords(['EXTENDED']);
+     }
+   }
+ | '<hive>DESCRIBE' DatabaseOrSchema OptionalHiveExtended 'CURSOR' DatabaseIdentifier
+    {
+      if (!$3) {
+        parser.suggestKeywords(['EXTENDED']);
+      }
+    }
+ | '<hive>DESCRIBE' '<hive>FUNCTION' OptionalHiveExtended 'CURSOR'
+   {
+     if (!$3) {
+       parser.suggestKeywords(['EXTENDED']);
+     }
+   }
+ | '<hive>DESCRIBE' '<hive>FUNCTION' OptionalHiveExtended 'CURSOR' RegularIdentifier
+    {
+      if (!$3) {
+        parser.suggestKeywords(['EXTENDED']);
+      }
+    }
+ ;
+
+ImpalaDescribeStatement
+ : '<impala>DESCRIBE' OptionalImpalaExtendedOrFormatted SchemaQualifiedTableIdentifier
+   {
+     parser.addTablePrimary($3);
+   }
+ | '<impala>DESCRIBE' 'DATABASE' OptionalImpalaExtendedOrFormatted DatabaseIdentifier
+   {
+     parser.addDatabaseLocation(@4, [{ name: $4 }]);
+   }
+ ;
+
+ImpalaDescribeStatement_EDIT
+ : '<impala>DESCRIBE' OptionalImpalaExtendedOrFormatted 'CURSOR'
+   {
+     if (!$2) {
+       parser.suggestKeywords([{ value: 'DATABASE', weight: 2 }, { value: 'EXTENDED', weight: 1 }, { value: 'FORMATTED', weight: 1 }]);
+     }
+     parser.suggestTables();
+     parser.suggestDatabases({ appendDot: true });
+   }
+ | '<impala>DESCRIBE' OptionalImpalaExtendedOrFormatted SchemaQualifiedTableIdentifier_EDIT
+ | '<impala>DESCRIBE' OptionalImpalaExtendedOrFormatted 'CURSOR' SchemaQualifiedTableIdentifier
+   {
+     parser.addTablePrimary($4);
+     if (!$2) {
+       parser.suggestKeywords([{ value: 'DATABASE', weight: 2 }, { value: 'EXTENDED', weight: 1 }, { value: 'FORMATTED', weight: 1 }]);
+     }
+   }
+ | '<impala>DESCRIBE' 'DATABASE' OptionalImpalaExtendedOrFormatted 'CURSOR'
+   {
+     if (!$3) {
+       parser.suggestKeywords(['EXTENDED', 'FORMATTED']);
+     }
+     parser.suggestDatabases();
+   }
+ | '<impala>DESCRIBE' 'DATABASE' OptionalImpalaExtendedOrFormatted 'CURSOR' DatabaseIdentifier
+    {
+      if (!$3) {
+        parser.suggestKeywords(['EXTENDED', 'FORMATTED']);
+      }
+      parser.addDatabaseLocation(@5, [{ name: $5 }]);
+    }
+ ;
+
+// ===================================== SELECT statement =====================================
+
+QuerySpecification
+ : SelectStatement OptionalUnions                                   -> $1
+ | CommonTableExpression SelectStatement OptionalUnions
+ | CommonTableExpression '(' QuerySpecification ')' OptionalUnions  -> $3
+ ;
+
+QuerySpecification_EDIT
+ : SelectStatement_EDIT OptionalUnions
+ | SelectStatement OptionalUnions_EDIT
+ | CommonTableExpression '(' QuerySpecification_EDIT ')'
+   {
+     parser.addCommonTableExpressions($1);
+   }
+ | CommonTableExpression SelectStatement_EDIT OptionalUnions
+   {
+     parser.addCommonTableExpressions($1);
+   }
+ | CommonTableExpression SelectStatement OptionalUnions_EDIT
+   {
+     parser.addCommonTableExpressions($1);
+   }
+ | CommonTableExpression_EDIT
+ | CommonTableExpression_EDIT '(' QuerySpecification ')'
+ | CommonTableExpression_EDIT SelectStatement OptionalUnions
+ ;
+
+SelectStatement
+ : 'SELECT' OptionalAllOrDistinct OptionalStraightJoin SelectList
+   {
+     parser.addClauseLocation('selectList', parser.firstDefined($3, @3, $2, @2, $1, @1), @4);
+     $$ = { selectList: $4 };
+   }
+ | 'SELECT' OptionalAllOrDistinct OptionalStraightJoin SelectList TableExpression
+   {
+     parser.addClauseLocation('selectList', parser.firstDefined($3, @3, $2, @2, $1, @1), @4);
+     $$ = { selectList: $4, tableExpression: $5 }
+   }
+ ;
+
+OptionalUnions
+ :
+ | Unions
+ ;
+
+OptionalUnions_EDIT
+ : Unions_EDIT
+ ;
+
+Unions
+ : UnionClause
+ | Unions UnionClause
+ ;
+
+Unions_EDIT
+ : UnionClause_EDIT
+ | Unions UnionClause_EDIT
+ | UnionClause_EDIT Unions
+ | Unions UnionClause_EDIT Unions
+ ;
+
+UnionClause
+ : 'UNION' NewStatement OptionalAllOrDistinct SelectStatement
+ ;
+
+UnionClause_EDIT
+ : 'UNION' NewStatement 'CURSOR'
+   {
+     parser.suggestKeywords(['ALL', 'DISTINCT', 'SELECT']);
+   }
+ | 'UNION' NewStatement 'CURSOR' SelectStatement
+   {
+     parser.suggestKeywords(['ALL', 'DISTINCT']);
+   }
+ | 'UNION' NewStatement OptionalAllOrDistinct SelectStatement_EDIT
+ ;
+
+SelectStatement_EDIT
+ : 'SELECT' OptionalAllOrDistinct OptionalStraightJoin SelectList_EDIT
+   {
+     parser.addClauseLocation('selectList', parser.firstDefined($3, @3, $2, @2, $1, @1), @4);
+     if ($4.cursorAtStart) {
+       var keywords = parser.getSelectListKeywords();
+       if (!$3 && !$2) {
+         keywords.push({ value: 'ALL', weight: 2 });
+         keywords.push({ value: 'DISTINCT', weight: 2 });
+       }
+       if (parser.isImpala() && !$3) {
+         keywords.push({ value: 'STRAIGHT_JOIN', weight: 1 });
+       }
+       parser.suggestKeywords(keywords);
+     } else {
+       parser.checkForSelectListKeywords($4);
+     }
+     if ($4.suggestFunctions) {
+       parser.suggestFunctions();
+     }
+     if ($4.suggestColumns) {
+       parser.suggestColumns({ identifierChain: [], source: 'select' });
+     }
+     if ($4.suggestTables) {
+       parser.suggestTables({ prependQuestionMark: true, prependFrom: true });
+     }
+     if ($4.suggestDatabases) {
+       parser.suggestDatabases({ prependQuestionMark: true, prependFrom: true, appendDot: true });
+     }
+     if ($4.suggestAggregateFunctions && (!$2 || $2 === 'ALL')) {
+       parser.suggestAggregateFunctions();
+       parser.suggestAnalyticFunctions();
+     }
+   }
+ | 'SELECT' OptionalAllOrDistinct OptionalStraightJoin 'CURSOR'
+   {
+     parser.addClauseLocation('selectList', parser.firstDefined($3, @3, $2, @2, $1, @1), @4, true);
+     var keywords = parser.getSelectListKeywords();
+     if (!$2 || $2 === 'ALL') {
+       parser.suggestAggregateFunctions();
+       parser.suggestAnalyticFunctions();
+     }
+     if (!$3 && !$2) {
+       keywords.push({ value: 'ALL', weight: 2 });
+       keywords.push({ value: 'DISTINCT', weight: 2 });
+     }
+     if (parser.isImpala() && !$3) {
+       keywords.push({ value: 'STRAIGHT_JOIN', weight: 1 });
+     }
+     parser.suggestKeywords(keywords);
+     parser.suggestFunctions();
+     parser.suggestColumns({ identifierChain: [], source: 'select' });
+     parser.suggestTables({ prependQuestionMark: true, prependFrom: true });
+     parser.suggestDatabases({ prependQuestionMark: true, prependFrom: true, appendDot: true });
+   }
+ | 'SELECT' OptionalAllOrDistinct OptionalStraightJoin SelectList TableExpression_EDIT
+   {
+     parser.addClauseLocation('selectList', parser.firstDefined($3, @3, $2, @2, $1, @1), @4);
+   }
+ | 'SELECT' OptionalAllOrDistinct OptionalStraightJoin SelectList_EDIT TableExpression
+   {
+     parser.addClauseLocation('selectList', parser.firstDefined($3, @3, $2, @2, $1, @1), @4);
+     parser.selectListNoTableSuggest($4, $2);
+     if (parser.yy.result.suggestColumns) {
+       parser.yy.result.suggestColumns.source = 'select';
+     }
+   }
+ | 'SELECT' OptionalAllOrDistinct OptionalStraightJoin 'CURSOR' TableExpression
+   {
+     parser.addClauseLocation('selectList', parser.firstDefined($3, @3, $2, @2, $1, @1), @4, true);
+     var keywords = parser.getSelectListKeywords();
+     if (!$2 || $2 === 'ALL') {
+       parser.suggestAggregateFunctions();
+       parser.suggestAnalyticFunctions();
+     }
+     if (!$3 && !$2) {
+       keywords.push({ value: 'ALL', weight: 2 });
+       keywords.push({ value: 'DISTINCT', weight: 2 });
+     }
+     if (parser.isImpala() && !$3) {
+       keywords.push({ value: 'STRAIGHT_JOIN', weight: 1 });
+     }
+     parser.suggestKeywords(keywords);
+     parser.suggestFunctions();
+     parser.suggestColumns({ identifierChain: [], source: 'select' });
+     parser.suggestTables({ prependQuestionMark: true, prependFrom: true });
+     parser.suggestDatabases({ prependQuestionMark: true, prependFrom: true, appendDot: true });
+   }
+ | 'SELECT' OptionalAllOrDistinct OptionalStraightJoin SelectList 'CURSOR' TableExpression
+   {
+     parser.addClauseLocation('selectList', parser.firstDefined($3, @3, $2, @2, $1, @1), @4);
+     parser.checkForSelectListKeywords($4);
+   }
+ | 'SELECT' OptionalAllOrDistinct OptionalStraightJoin SelectList 'CURSOR' ',' TableExpression
+   {
+     parser.addClauseLocation('selectList', parser.firstDefined($3, @3, $2, @2, $1, @1), @4);
+     parser.checkForSelectListKeywords($4);
+   }
+ | 'SELECT' OptionalAllOrDistinct OptionalStraightJoin SelectList 'CURSOR'
+   {
+     parser.addClauseLocation('selectList', parser.firstDefined($3, @3, $2, @2, $1, @1), @4);
+     parser.checkForSelectListKeywords($4);
+     var keywords = ['FROM'];
+     if (parser.yy.result.suggestKeywords) {
+       keywords = parser.yy.result.suggestKeywords.concat(keywords);
+     }
+     parser.suggestKeywords(keywords);
+     parser.suggestTables({ prependFrom: true });
+     parser.suggestDatabases({ prependFrom: true, appendDot: true });
+   }
+ ;
+
+OptionalStraightJoin
+ :
+ | '<impala>STRAIGHT_JOIN'
+ ;
+
+CommonTableExpression
+ : AnyWith WithQueries  -> $2
+ ;
+
+CommonTableExpression_EDIT
+ : AnyWith WithQueries_EDIT
+ ;
+
+WithQueries
+ : WithQuery                   -> [$1]
+ | WithQueries ',' WithQuery   -> $1.concat([$3]);
+ ;
+
+WithQueries_EDIT
+ : WithQuery_EDIT
+ | WithQueries ',' WithQuery_EDIT
+   {
+     parser.addCommonTableExpressions($1);
+   }
+ | WithQuery_EDIT ',' WithQueries
+ | WithQueries ',' WithQuery_EDIT ',' WithQueries
+   {
+     parser.addCommonTableExpressions($1);
+   }
+ ;
+
+WithQuery
+ : RegularOrBacktickedIdentifier 'AS' '(' TableSubQueryInner ')'
+   {
+     parser.addCteAliasLocation(@1, $1);
+     $4.alias = $1;
+     $$ = $4;
+   }
+ ;
+
+WithQuery_EDIT
+ : RegularOrBacktickedIdentifier 'CURSOR'
+   {
+     parser.suggestKeywords(['AS']);
+   }
+ | RegularOrBacktickedIdentifier 'AS' '(' AnyCursor RightParenthesisOrError
+   {
+     parser.suggestKeywords(['SELECT']);
+   }
+ | RegularOrBacktickedIdentifier 'AS' '(' TableSubQueryInner_EDIT RightParenthesisOrError
+ ;
+
+OptionalAllOrDistinct
+ :
+ | '<hive>ALL'
+ | 'ALL'
+ | 'DISTINCT'
+ ;
+
+TableExpression
+ : FromClause OptionalSelectConditions
+   {
+     parser.addClauseLocation('whereClause', @1, $2.whereClauseLocation);
+     parser.addClauseLocation('limitClause', $2.limitClausePreceding || @1, $2.limitClauseLocation);
+   }
+ ;
+
+TableExpression_EDIT
+ : FromClause_EDIT OptionalSelectConditions
+   {
+     parser.addClauseLocation('whereClause', @1, $2.whereClauseLocation);
+     parser.addClauseLocation('limitClause', $2.limitClausePreceding || @1, $2.limitClauseLocation);
+   }
+ | FromClause 'CURSOR' OptionalSelectConditions OptionalJoins
+   {
+     var keywords = [];
+
+     parser.addClauseLocation('whereClause', @1, $3.whereClauseLocation);
+     parser.addClauseLocation('limitClause', $2.limitClausePreceding || @1, $2.limitClauseLocation);
+
+     if ($1) {
+       if (!$1.hasLateralViews && typeof $1.tableReferenceList.hasJoinCondition !== 'undefined' && !$1.tableReferenceList.hasJoinCondition) {
+         keywords.push({ value: 'ON', weight: 3 });
+         if (parser.isImpala()) {
+           keywords.push({ value: 'USING', weight: 3 });
+         }
+       }
+       if ($1.suggestKeywords) {
+         keywords = parser.createWeightedKeywords($1.suggestKeywords, 3);
+       }
+       if ($1.tableReferenceList.suggestJoinConditions) {
+         parser.suggestJoinConditions($1.tableReferenceList.suggestJoinConditions);
+       }
+       if ($1.tableReferenceList.suggestJoins) {
+         parser.suggestJoins($1.tableReferenceList.suggestJoins);
+       }
+       if (!$1.hasLateralViews && $1.tableReferenceList.suggestKeywords) {
+         keywords = keywords.concat(parser.createWeightedKeywords($1.tableReferenceList.suggestKeywords, 3));
+       }
+
+       // Lower the weights for 'TABLESAMPLE' and 'LATERAL VIEW'
+       keywords.forEach(function (keyword) {
+         if (keyword.value === 'TABLESAMPLE' || keyword.value === 'LATERAL VIEW') {
+           keyword.weight = 1.1;
+         }
+       });
+
+       if (!$1.hasLateralViews && $1.tableReferenceList.types) {
+         var veKeywords = parser.getValueExpressionKeywords($1.tableReferenceList);
+         keywords = keywords.concat(veKeywords.suggestKeywords);
+         if (veKeywords.suggestColRefKeywords) {
+           parser.suggestColRefKeywords(veKeywords.suggestColRefKeywords);
+           parser.addColRefIfExists($1.tableReferenceList);
+         }
+       }
+     }
+
+     if ($3.empty && $4 && $4.joinType.toUpperCase() === 'JOIN') {
+       keywords = keywords.concat(['FULL', 'FULL OUTER', 'LEFT', 'LEFT OUTER', 'RIGHT', 'RIGHT OUTER']);
+       if (parser.isHive()) {
+         keywords = keywords.concat(['CROSS', 'INNER', 'LEFT SEMI']);
+       } else if (parser.isImpala()) {
+         keywords = keywords.concat(['ANTI', 'CROSS', 'INNER', 'LEFT ANTI', 'LEFT INNER', 'LEFT SEMI', 'OUTER', 'RIGHT ANTI', 'RIGHT INNER', 'RIGHT SEMI', 'SEMI']);
+       } else {
+         keywords.push('INNER');
+       }
+       parser.suggestKeywords(keywords);
+       return;
+     }
+
+     if ($3.suggestKeywords) {
+       keywords = keywords.concat(parser.createWeightedKeywords($3.suggestKeywords, 2));
+     }
+
+     if ($3.suggestFilters) {
+       parser.suggestFilters($3.suggestFilters);
+     }
+     if ($3.suggestGroupBys) {
+       parser.suggestGroupBys($3.suggestGroupBys);
+     }
+     if ($3.suggestOrderBys) {
+       parser.suggestOrderBys($3.suggestOrderBys);
+     }
+
+     if ($3.empty) {
+       keywords.push({ value: 'UNION', weight: 2.11 });
+     }
+
+     keywords = keywords.concat([
+       { value: 'FULL JOIN', weight: 1 },
+       { value: 'FULL OUTER JOIN', weight: 1 },
+       { value: 'JOIN', weight: 1 },
+       { value: 'LEFT JOIN', weight: 1 },
+       { value: 'LEFT OUTER JOIN', weight: 1 },
+       { value: 'RIGHT JOIN', weight: 1 },
+       { value: 'RIGHT OUTER JOIN', weight: 1 }
+     ]);
+     if (parser.isHive()) {
+       keywords = keywords.concat([
+         { value: 'CROSS JOIN', weight: 1 },
+         { value: 'INNER JOIN', weight: 1 },
+         { value: 'LEFT SEMI JOIN', weight: 1 }
+       ]);
+     } else if (parser.isImpala()) {
+       keywords = keywords.concat([
+         { value: 'ANTI JOIN', weight: 1 },
+         { value: 'INNER JOIN', weight: 1 },
+         { value: 'LEFT ANTI JOIN', weight: 1 },
+         { value: 'LEFT INNER JOIN', weight: 1 },
+         { value: 'LEFT SEMI JOIN', weight: 1 },
+         { value: 'OUTER JOIN', weight: 1 },
+         { value: 'RIGHT ANTI JOIN', weight: 1 },
+         { value: 'RIGHT INNER JOIN', weight: 1 },
+         { value: 'RIGHT SEMI JOIN', weight: 1 },
+         { value: 'SEMI JOIN', weight: 1 }
+       ]);
+     } else {
+       keywords.push({ value: 'INNER JOIN', weight: 1 });
+     }
+     parser.suggestKeywords(keywords);
+  }
+ | FromClause OptionalSelectConditions_EDIT OptionalJoins
+   {
+     // A couple of things are going on here:
+     // - If there are no SelectConditions (WHERE, GROUP BY, etc.) we should suggest complete join options
+     // - If there's an OptionalJoin at the end, i.e. 'SELECT * FROM foo | JOIN ...' we should suggest
+     //   different join types
+     // - The FromClause could end with a valueExpression, in which case we should suggest keywords like '='
+     //   or 'AND' based on type
+
+     if (!$2) {
+       parser.addClauseLocation('whereClause', @1);
+       parser.addClauseLocation('limitClause', @1);
+       return;
+     }
+     parser.addClauseLocation('whereClause', @1, $2.whereClauseLocation);
+     parser.addClauseLocation('limitClause', $2.limitClausePreceding || @1, $2.limitClauseLocation);
+     var keywords = [];
+
+     if ($2.suggestColRefKeywords) {
+       parser.suggestColRefKeywords($2.suggestColRefKeywords);
+       parser.addColRefIfExists($2);
+     }
+
+     if ($2.suggestKeywords && $2.suggestKeywords.length) {
+       keywords = keywords.concat(parser.createWeightedKeywords($2.suggestKeywords, 2));
+     }
+
+     if ($2.cursorAtEnd) {
+       keywords.push({ value: 'UNION', weight: 2.11 });
+     }
+     parser.suggestKeywords(keywords);
+   }
+ ;
+
+OptionalJoins
+ :
+ | Joins
+ | Joins_INVALID
+ ;
+
+FromClause
+ : 'FROM' TableReferenceList OptionalLateralViews
+   {
+     if (parser.isHive()) {
+       $$ = { tableReferenceList : $2, suggestKeywords: ['LATERAL VIEW'] }
+     } else {
+       $$ = { tableReferenceList : $2 }
+     }
+     if (parser.isHive() && $3) {
+       parser.yy.lateralViews = $3.lateralViews;
+       $$.hasLateralViews = true;
+       if ($3.suggestKeywords) {
+         $$.suggestKeywords = $$.suggestKeywords.concat($3.suggestKeywords);
+       }
+     }
+   }
+ ;
+
+FromClause_EDIT
+ : 'FROM' 'CURSOR'
+   {
+       parser.suggestTables();
+       parser.suggestDatabases({ appendDot: true });
+   }
+ | 'FROM' TableReferenceList_EDIT OptionalLateralViews
+   {
+     if ($3) {
+       parser.yy.lateralViews = $3.lateralViews;
+     }
+   }
+ | 'FROM' TableReferenceList OptionalLateralViews_EDIT
+ ;
+
+OptionalSelectConditions
+ : OptionalWhereClause OptionalGroupByClause OptionalHavingClause OptionalWindowClause OptionalOrderByClause OptionalClusterOrDistributeBy OptionalLimitClause OptionalOffsetClause
+   {
+     var keywords = parser.getKeywordsForOptionalsLR(
+       [$1, $2, $3, $4, $5, $6, $6, $7, $8],
+       [{ value: 'WHERE', weight: 9 }, { value: 'GROUP BY', weight: 8 }, { value: 'HAVING', weight: 7 }, { value: 'WINDOW', weight: 6 }, { value: 'ORDER BY', weight: 5 }, [{ value: 'CLUSTER BY', weight: 4 }, { value: 'DISTRIBUTE BY', weight: 4 }], { value: 'SORT BY', weight: 4 }, { value: 'LIMIT', weight: 3 }, { value: 'OFFSET', weight: 2 }],
+       [true, true, true, parser.isHive(), true, parser.isHive(), parser.isHive() && !$5, true, parser.isImpala()]);
+
+     if (keywords.length > 0) {
+       $$ = { suggestKeywords: keywords, empty: !$1 && !$2 && !$3 && !$4 && !$5 && !$6 && !$7 && !$8 };
+     } else {
+       $$ = {};
+     }
+
+     $$.whereClauseLocation = $1 ? @1 : undefined;
+     $$.limitClausePreceding = parser.firstDefined($6, @6, $5, @5, $4, @4, $3, @3, $2, @2, $1, @1);
+     $$.limitClauseLocation = $7 ? @7 : undefined;
+
+     if (!$1 && !$2 && !$3 && !$4 && !$5 && !$6 && !$7 && !$8) {
+       $$.suggestFilters = { prefix: 'WHERE', tablePrimaries: parser.yy.latestTablePrimaries.concat() };
+     }
+     if (!$2 && !$3 && !$4 && !$5 && !$6 && !$7 && !$8) {
+       $$.suggestGroupBys = { prefix: 'GROUP BY', tablePrimaries: parser.yy.latestTablePrimaries.concat() };
+     }
+     if (!$5 && !$6 && !$7 && !$8) {
+       $$.suggestOrderBys = { prefix: 'ORDER BY', tablePrimaries: parser.yy.latestTablePrimaries.concat() };
+     }
+   }
+ ;
+
+OptionalSelectConditions_EDIT
+ : WhereClause_EDIT OptionalGroupByClause OptionalHavingClause OptionalWindowClause OptionalOrderByClause OptionalClusterOrDistributeBy OptionalLimitClause OptionalOffsetClause
+   {
+     if (parser.yy.result.suggestColumns) {
+       parser.yy.result.suggestColumns.source = 'where';
+     }
+   }
+ | OptionalWhereClause GroupByClause_EDIT OptionalHavingClause OptionalWindowClause OptionalOrderByClause OptionalClusterOrDistributeBy OptionalLimitClause OptionalOffsetClause
+   {
+     if (parser.yy.result.suggestColumns) {
+       parser.yy.result.suggestColumns.source = 'group by';
+     }
+   }
+ | OptionalWhereClause OptionalGroupByClause HavingClause_EDIT OptionalWindowClause OptionalOrderByClause OptionalClusterOrDistributeBy OptionalLimitClause OptionalOffsetClause
+ | OptionalWhereClause OptionalGroupByClause OptionalHavingClause WindowClause_EDIT OptionalOrderByClause OptionalClusterOrDistributeBy OptionalLimitClause OptionalOffsetClause
+ | OptionalWhereClause OptionalGroupByClause OptionalHavingClause OptionalWindowClause OrderByClause_EDIT OptionalClusterOrDistributeBy OptionalLimitClause OptionalOffsetClause
+   {
+     if (parser.yy.result.suggestColumns) {
+       parser.yy.result.suggestColumns.source = 'order by';
+     }
+   }
+ | OptionalWhereClause OptionalGroupByClause OptionalHavingClause OptionalWindowClause OptionalOrderByClause ClusterOrDistributeBy_EDIT OptionalLimitClause OptionalOffsetClause
+ | OptionalWhereClause OptionalGroupByClause OptionalHavingClause OptionalWindowClause OptionalOrderByClause OptionalClusterOrDistributeBy LimitClause_EDIT OptionalOffsetClause
+ | OptionalWhereClause OptionalGroupByClause OptionalHavingClause OptionalWindowClause OptionalOrderByClause OptionalClusterOrDistributeBy OptionalLimitClause OffsetClause_EDIT
+ ;
+
+OptionalSelectConditions_EDIT
+ : WhereClause 'CURSOR' OptionalGroupByClause OptionalHavingClause OptionalWindowClause OptionalOrderByClause OptionalClusterOrDistributeBy OptionalLimitClause OptionalOffsetClause
+   {
+     var keywords = parser.getKeywordsForOptionalsLR(
+       [$3, $4, $5, $6, $7, $7, $8, $9],
+       [{ value: 'GROUP BY', weight: 8 }, { value: 'HAVING', weight: 7 }, { value: 'WINDOW', weight: 6 }, { value: 'ORDER BY', weight: 5 }, [{ value: 'CLUSTER BY', weight: 4 }, { value: 'DISTRIBUTE BY', weight: 4 }], { value: 'SORT BY', weight: 4 }, { value: 'LIMIT', weight: 3 }, { value: 'OFFSET', weight: 2 }],
+       [true, true, parser.isHive(), true, parser.isHive(), parser.isHive() && !$6, true, parser.isImpala()]);
+     if ($1.suggestKeywords) {
+       keywords = keywords.concat(parser.createWeightedKeywords($1.suggestKeywords, 1));
+     }
+     $$ = parser.getValueExpressionKeywords($1, keywords);
+     $$.cursorAtEnd = !$3 && !$4 && !$5 && !$6 && !$7 && !$8 && !$9;
+     if ($1.columnReference) {
+       $$.columnReference = $1.columnReference;
+     }
+     if (!$3) {
+       parser.suggestGroupBys({ prefix: 'GROUP BY', tablePrimaries: parser.yy.latestTablePrimaries.concat() });
+     }
+     if (!$3 && !$4 && !$5 && !$6) {
+       parser.suggestOrderBys({ prefix: 'ORDER BY', tablePrimaries: parser.yy.latestTablePrimaries.concat() });
+     }
+     $$.whereClauseLocation = $1 ? @1 : undefined;
+     $$.limitClausePreceding = parser.firstDefined($7, @7, $6, @6, $5, @5, $4, @4, $3, @3, $1, @1);
+     $$.limitClauseLocation = $8 ? @8 : undefined;
+   }
+ | OptionalWhereClause GroupByClause 'CURSOR' OptionalHavingClause OptionalWindowClause OptionalOrderByClause OptionalClusterOrDistributeBy OptionalLimitClause OptionalOffsetClause
+   {
+     var keywords = parser.getKeywordsForOptionalsLR(
+       [$4, $5, $6, $7, $7, $8, $9],
+       [{ value: 'HAVING', weight: 7 }, { value: 'WINDOW', weight: 6 }, { value: 'ORDER BY', weight: 5 }, [{ value: 'CLUSTER BY', weight: 4 }, { value: 'DISTRIBUTE BY', weight: 4 }], { value: 'SORT BY', weight: 4 }, { value: 'LIMIT', weight: 3 }, { value: 'OFFSET', weight: 2 }],
+       [true, parser.isHive(), true, parser.isHive(), parser.isHive() && !$6, true, parser.isImpala()]);
+     if ($2.suggestKeywords) {
+       keywords = keywords.concat(parser.createWeightedKeywords($2.suggestKeywords, 8));
+     }
+     if ($2.valueExpression) {
+       $$ = parser.getValueExpressionKeywords($2.valueExpression, keywords);
+       if ($2.valueExpression.columnReference) {
+         $$.columnReference = $2.valueExpression.columnReference;
+       }
+     } else {
+       $$ = { suggestKeywords: keywords };
+     }
+     $$.cursorAtEnd = !$4 && !$5 && !$6 && !$7 && !$8 && !$9;
+     if (!$4 && !$5 && !$6) {
+       parser.suggestOrderBys({ prefix: 'ORDER BY', tablePrimaries: parser.yy.latestTablePrimaries.concat() });
+     }
+     $$.whereClauseLocation = $1 ? @1 : undefined;
+     $$.limitClausePreceding = parser.firstDefined($7, @7, $6, @6, $5, @5, $4, @4, $2, @2);
+     $$.limitClauseLocation = $8 ? @8 : undefined;
+   }
+ | OptionalWhereClause OptionalGroupByClause HavingClause 'CURSOR' OptionalWindowClause OptionalOrderByClause OptionalClusterOrDistributeBy OptionalLimitClause OptionalOffsetClause
+   {
+     var keywords = parser.getKeywordsForOptionalsLR(
+       [$5, $6, $7, $7, $8, $9],
+       [{ value: 'WINDOW', weight: 6 }, { value: 'ORDER BY', weight: 5 }, [{ value: 'CLUSTER BY', weight: 4 }, { value: 'DISTRIBUTE BY', weight: 4 }], { value: 'SORT BY', weight: 4 }, { value: 'LIMIT', weight: 3 }, { value: 'OFFSET', weight: 2 }],
+       [parser.isHive(), true, parser.isHive(), parser.isHive() && !$6, true, parser.isImpala()]);
+     $$ = { suggestKeywords: keywords, cursorAtEnd: !$5 && !$6 && !$7 && !$8 && !$9 };
+     if (!$5 && !$6) {
+       parser.suggestOrderBys({ prefix: 'ORDER BY', tablePrimaries: parser.yy.latestTablePrimaries.concat() });
+     }
+     $$.whereClauseLocation = $1 ? @1 : undefined;
+     $$.limitClausePreceding = parser.firstDefined($7, @7, $6, @6, $5, @5, $3, @3);
+     $$.limitClauseLocation = $8 ? @8 : undefined;
+   }
+ | OptionalWhereClause OptionalGroupByClause OptionalHavingClause WindowClause 'CURSOR' OptionalOrderByClause OptionalClusterOrDistributeBy OptionalLimitClause OptionalOffsetClause
+   {
+     var keywords = parser.getKeywordsForOptionalsLR([$6, $7, $8, $9], [{ value: 'ORDER BY', weight: 5 }, [{ value: 'CLUSTER BY', weight: 4 }, { value: 'DISTRIBUTE BY', weight: 4 }, { value: 'SORT BY', weight: 4 }], { value: 'LIMIT', weight: 3 }, { value: 'OFFSET', weight: 2 }], [true, parser.isHive(), true, parser.isImpala()]);
+     $$ = { suggestKeywords: keywords, cursorAtEnd: !$6 && !$7 && !$8 && !$9 };
+     if (!$6) {
+       parser.suggestOrderBys({ prefix: 'ORDER BY', tablePrimaries: parser.yy.latestTablePrimaries.concat() });
+     }
+     $$.whereClauseLocation = $1 ? @1 : undefined;
+     $$.limitClausePreceding = parser.firstDefined($7, @7, $6, @6, $4, @4);
+     $$.limitClauseLocation = $8 ? @8 : undefined;
+   }
+ | OptionalWhereClause OptionalGroupByClause OptionalHavingClause OptionalWindowClause OrderByClause 'CURSOR' OptionalClusterOrDistributeBy OptionalLimitClause OptionalOffsetClause
+   {
+     var keywords = parser.getKeywordsForOptionalsLR([$7, $8, $9], [[{ value: 'CLUSTER BY', weight: 4 }, { value: 'DISTRIBUTE BY', weight: 4 }], { value: 'LIMIT', weight: 3 }, { value: 'OFFSET', weight: 2 }], [parser.isHive(), true, parser.isImpala()]);
+     if ($5.suggestKeywords) {
+       keywords = keywords.concat(parser.createWeightedKeywords($5.suggestKeywords, 5));
+     }
+     $$ = { suggestKeywords: keywords, cursorAtEnd: !$7 && !$8 && !$9 };
+     $$.whereClauseLocation = $1 ? @1 : undefined;
+     $$.limitClausePreceding = parser.firstDefined($7, @7, $5, @5);
+     $$.limitClauseLocation = $8 ? @8 : undefined;
+   }
+ | OptionalWhereClause OptionalGroupByClause OptionalHavingClause OptionalWindowClause OptionalOrderByClause ClusterOrDistributeBy 'CURSOR' OptionalLimitClause OptionalOffsetClause
+   {
+     var keywords = parser.getKeywordsForOptionalsLR([$8, $9], [{ value: 'LIMIT', weight: 3 }, { value: 'OFFSET', weight: 2 }], [true, parser.isImpala()]);
+     if ($6.suggestKeywords) {
+       keywords = keywords.concat(parser.createWeightedKeywords($6.suggestKeywords, 4));
+     }
+     $$ = { suggestKeywords: keywords, cursorAtEnd: !$8 && !$9 };
+     $$.whereClauseLocation = $1 ? @1 : undefined;
+     $$.limitClausePreceding = @6;
+     $$.limitClauseLocation = $8 ? @8 : undefined;
+   }
+ | OptionalWhereClause OptionalGroupByClause OptionalHavingClause OptionalWindowClause OptionalOrderByClause OptionalClusterOrDistributeBy LimitClause 'CURSOR' OptionalOffsetClause
+   {
+     var keywords = parser.getKeywordsForOptionalsLR([$9], [{ value: 'OFFSET', weight: 2 }], [parser.isImpala()]);
+     $$ = { suggestKeywords: keywords, cursorAtEnd: !$9 };
+     $$.whereClauseLocation = $1 ? @1 : undefined;
+     $$.limitClausePreceding = parser.firstDefined($6, @6, $5, @5, $4, @4, $3, @3, $2, @2, $1, @1);
+     $$.limitClauseLocation = $7 ? @7 : undefined;
+   }
+ ;
+
+OptionalWhereClause
+ :
+ | WhereClause
+ ;
+
+WhereClause
+ : 'WHERE' SearchCondition  -> $2
+ ;
+
+WhereClause_EDIT
+ : 'WHERE' SearchCondition_EDIT
+   {
+     if ($2.suggestFilters) {
+       parser.suggestFilters({ tablePrimaries: parser.yy.latestTablePrimaries.concat() });
+     }
+   }
+ | 'WHERE' 'CURSOR'
+   {
+     parser.suggestFunctions();
+     parser.suggestColumns();
+     parser.suggestKeywords(['EXISTS', 'NOT EXISTS']);
+     parser.suggestFilters({ tablePrimaries: parser.yy.latestTablePrimaries.concat() });
+   }
+ ;
+
+OptionalGroupByClause
+ :
+ | GroupByClause
+ ;
+
+GroupByClause
+ : AnyGroup 'BY' GroupByColumnList OptionalHiveGroupingSetsCubeOrRollup
+   {
+     $$ = { valueExpression: $4 ? false : $3 };
+     if (!$4 && parser.isHive()) {
+       $$.suggestKeywords = ['GROUPING SETS', 'WITH CUBE', 'WITH ROLLUP'];
+     }
+   }
+ ;
+
+GroupByClause_EDIT
+ : AnyGroup 'BY' GroupByColumnList_EDIT OptionalHiveGroupingSetsCubeOrRollup
+   {
+     parser.suggestSelectListAliases();
+   }
+ | AnyGroup 'BY' 'CURSOR' OptionalHiveGroupingSetsCubeOrRollup
+   {
+     parser.valueExpressionSuggest();
+     parser.suggestSelectListAliases();
+     parser.suggestGroupBys({ tablePrimaries: parser.yy.latestTablePrimaries.concat() });
+   }
+ | AnyGroup 'CURSOR'
+   {
+     parser.suggestKeywords(['BY']);
+     parser.suggestGroupBys({ prefix: 'BY', tablePrimaries: parser.yy.latestTablePrimaries.concat() });
+   }
+ | AnyGroup 'BY' GroupByColumnList OptionalHiveGroupingSetsCubeOrRollup_EDIT
+ ;
+
+OptionalHiveGroupingSetsCubeOrRollup
+ :
+ | HiveGroupingSets
+ | '<hive>WITH' '<hive>CUBE'
+ | '<hive>WITH' '<hive>ROLLUP'
+ ;
+
+OptionalHiveGroupingSetsCubeOrRollup_EDIT
+ : HiveGroupingSets_EDIT
+ | '<hive>WITH' 'CURSOR'
+   {
+     parser.suggestKeywords(['CUBE', 'ROLLUP']);
+   }
+ ;
+
+HiveGroupingSets
+ : '<hive>GROUPING' '<hive>SETS' '(' ColumnGroupingSets ')'
+ ;
+
+HiveGroupingSets_EDIT
+ : '<hive>GROUPING' 'CURSOR'
+   {
+     parser.suggestKeywords(['SETS']);
+   }
+ | '<hive>GROUPING' '<hive>SETS' '(' ColumnGroupingSets_EDIT RightParenthesisOrError
+ ;
+
+ColumnGroupingSets
+ :
+ | ColumnReference
+ | ColumnGroupingSets ',' ColumnGroupingSets
+ | '(' ColumnGroupingSets ')'
+ ;
+
+ColumnGroupingSets_EDIT
+ : ColumnGroupingSet_EDIT
+ | ColumnGroupingSet_EDIT ',' ColumnGroupingSets
+ | ColumnGroupingSets ',' ColumnGroupingSet_EDIT
+ | ColumnGroupingSets ',' ColumnGroupingSet_EDIT ',' ColumnGroupingSets
+ | '(' ColumnGroupingSets_EDIT RightParenthesisOrError
+ ;
+
+ColumnGroupingSet_EDIT
+ : AnyCursor
+   {
+     parser.suggestColumns();
+   }
+ | ColumnReference_EDIT
+ ;
+
+GroupByColumnList
+ : ValueExpression
+ | GroupByColumnList ',' ValueExpression  -> $3
+ ;
+
+GroupByColumnList_EDIT
+ : ValueExpression_EDIT
+ | 'CURSOR' ValueExpression
+   {
+     parser.valueExpressionSuggest();
+   }
+ | 'CURSOR' ',' GroupByColumnList
+   {
+     parser.valueExpressionSuggest();
+   }
+ | ValueExpression_EDIT ',' GroupByColumnList
+ | GroupByColumnList ',' GroupByColumnListPartTwo_EDIT
+ | GroupByColumnList ',' GroupByColumnListPartTwo_EDIT ','
+ | GroupByColumnList ',' GroupByColumnListPartTwo_EDIT ',' GroupByColumnList
+ ;
+
+GroupByColumnListPartTwo_EDIT
+ : ValueExpression_EDIT
+ | AnyCursor ValueExpression
+   {
+     parser.valueExpressionSuggest();
+   }
+ | AnyCursor
+   {
+     parser.valueExpressionSuggest();
+   }
+ ;
+
+OptionalOrderByClause
+ :
+ | OrderByClause
+ ;
+
+OrderByClause
+ : 'ORDER' 'BY' OrderByColumnList  -> $3
+ ;
+
+OrderByClause_EDIT
+ : 'ORDER' 'BY' OrderByColumnList_EDIT
+   {
+     if ($3.emptyOrderBy) {
+       parser.suggestOrderBys({ tablePrimaries: parser.yy.latestTablePrimaries.concat() });
+     }
+   }
+ | 'ORDER' 'CURSOR'
+   {
+     parser.suggestKeywords(['BY']);
+     parser.suggestOrderBys({ prefix: 'BY', tablePrimaries: parser.yy.latestTablePrimaries.concat() });
+   }
+ ;
+
+OrderByColumnList
+ : OrderByIdentifier
+ | OrderByColumnList ',' OrderByIdentifier  -> $3
+ ;
+
+OrderByColumnList_EDIT
+ : OrderByIdentifier_EDIT
+ | 'CURSOR' OrderByIdentifier
+   {
+     $$ = { emptyOrderBy: false }
+     parser.valueExpressionSuggest();
+     parser.suggestAnalyticFunctions();
+     parser.suggestSelectListAliases();
+   }
+ | OrderByColumnList ',' OrderByIdentifier_EDIT                        -> { emptyOrderBy: false }
+ | OrderByColumnList ',' OrderByIdentifier_EDIT ','                    -> { emptyOrderBy: false }
+ | OrderByColumnList ',' OrderByIdentifier_EDIT ',' OrderByColumnList  -> { emptyOrderBy: false }
+ ;
+
+OrderByIdentifier
+ : ValueExpression OptionalAscOrDesc OptionalImpalaNullsFirstOrLast  -> parser.mergeSuggestKeywords($2, $3)
+ ;
+
+OrderByIdentifier_EDIT
+ : ValueExpression_EDIT OptionalAscOrDesc OptionalImpalaNullsFirstOrLast
+   {
+     parser.suggestSelectListAliases();
+   }
+ | ValueExpression OptionalAscOrDesc OptionalImpalaNullsFirstOrLast_EDIT
+ | AnyCursor OptionalAscOrDesc OptionalImpalaNullsFirstOrLast
+   {
+     $$ = { emptyOrderBy: true }
+     parser.valueExpressionSuggest();
+     parser.suggestAnalyticFunctions();
+     parser.suggestSelectListAliases();
+   }
+ ;
+
+OptionalAscOrDesc
+ :
+  {
+    $$ = { suggestKeywords: ['ASC', 'DESC'] };
+  }
+ | 'ASC'
+ | '<hive>ASC'
+ | 'DESC'
+ | '<hive>DESC'
+ ;
+
+OptionalImpalaNullsFirstOrLast
+ :
+  {
+    if (parser.isImpala()) {
+      $$ = { suggestKeywords: ['NULLS FIRST', 'NULLS LAST'] };
+    } else {
+      $$ = {};
+    }
+  }
+ | '<impala>NULLS' '<impala>FIRST'
+ | '<impala>NULLS' '<impala>LAST'
+ ;
+
+OptionalImpalaNullsFirstOrLast_EDIT
+ : '<impala>NULLS' 'CURSOR'
+   {
+     parser.suggestKeywords(['FIRST', 'LAST']);
+   }
+ ;
+
+OptionalClusterOrDistributeBy
+ :
+ | ClusterOrDistributeBy
+ ;
+
+ClusterOrDistributeBy
+ : ClusterByClause
+ | DistributeByClause               -> { suggestKeywords: ['SORT BY'] }
+ | DistributeByClause SortByClause
+ | SortByClause
+ ;
+
+ClusterOrDistributeBy_EDIT
+ : ClusterByClause_EDIT
+ | DistributeByClause_EDIT
+ | DistributeByClause SortByClause_EDIT
+ | DistributeByClause_EDIT SortByClause
+ | SortByClause_EDIT
+ ;
+
+ClusterByClause
+ : '<hive>CLUSTER' 'BY' ColumnList
+ ;
+
+ClusterByClause_EDIT
+ : '<hive>CLUSTER' 'CURSOR'
+   {
+     suggestKeywords: ['BY'];
+   }
+ | '<hive>CLUSTER' 'BY' 'CURSOR'
+   {
+     parser.suggestColumns();
+     parser.suggestSelectListAliases();
+   }
+ | '<hive>CLUSTER' 'BY' ColumnList_EDIT
+   {
+     parser.suggestSelectListAliases();
+   }
+ ;
+
+DistributeByClause
+ : '<hive>DISTRIBUTE' 'BY' ColumnList
+ ;
+
+DistributeByClause_EDIT
+ : '<hive>DISTRIBUTE' 'CURSOR'
+   {
+     suggestKeywords: ['BY'];
+   }
+ | '<hive>DISTRIBUTE' 'BY' 'CURSOR'
+   {
+     parser.suggestColumns();
+     parser.suggestSelectListAliases();
+   }
+ | '<hive>DISTRIBUTE' 'BY' ColumnList_EDIT
+   {
+     parser.suggestSelectListAliases();
+   }
+ ;
+
+SortByClause
+ : '<hive>SORT' 'BY' SortByList  -> $3
+ ;
+
+SortByClause_EDIT
+ : '<hive>SORT' 'CURSOR'
+   {
+     suggestKeywords: ['BY'];
+   }
+ | '<hive>SORT' 'BY' SortByList_EDIT
+   {
+     parser.suggestSelectListAliases();
+   }
+ ;
+
+SortByList
+ : SortByIdentifier
+ | SortByList ',' SortByIdentifier  -> $3
+ ;
+
+SortByList_EDIT
+ : SortByIdentifier_EDIT
+ | SortByIdentifier_EDIT ',' SortByList
+ | SortByList ',' SortByIdentifier_EDIT
+ | SortByList ',' SortByIdentifier_EDIT ',' SortByList
+ ;
+
+SortByIdentifier
+ : ColumnIdentifier OptionalAscOrDesc
+   {
+     parser.addColumnLocation($1.location, [ $1.identifier ]);
+     $$ = $2;
+   }
+ ;
+
+SortByIdentifier_EDIT
+ : ColumnIdentifier_EDIT OptionalAscOrDesc
+ | AnyCursor OptionalAscOrDesc
+   {
+     parser.suggestColumns();
+   }
+ ;
+
+OptionalLimitClause
+ :
+ | LimitClause
+ ;
+
+LimitClause
+ : 'LIMIT' UnsignedNumericLiteral
+ | 'LIMIT' UnsignedNumericLiteral ',' UnsignedNumericLiteral
+ | 'LIMIT' 'VARIABLE_REFERENCE'
+ | 'LIMIT' 'VARIABLE_REFERENCE' ',' 'VARIABLE_REFERENCE'
+ | '<impala>LIMIT' ValueExpression
+ ;
+
+LimitClause_EDIT
+ : 'LIMIT' 'CURSOR'
+ | '<impala>LIMIT' 'CURSOR'
+   {
+     parser.suggestFunctions({ types: ['BIGINT'] });
+   }
+ | '<impala>LIMIT' ValueExpression_EDIT
+   {
+     delete parser.yy.result.suggestColumns;
+   }
+ ;
+
+OptionalOffsetClause
+ :
+ | OffsetClause
+ ;
+
+OffsetClause
+ : '<impala>OFFSET' ValueExpression
+ ;
+
+OffsetClause_EDIT
+ : '<impala>OFFSET' 'CURSOR'
+   {
+     parser.suggestFunctions({ types: ['BIGINT'] });
+   }
+ | '<impala>OFFSET' ValueExpression_EDIT
+   {
+     delete parser.yy.result.suggestColumns;
+   }
+ ;
+
+SearchCondition
+ : ValueExpression
+ ;
+
+SearchCondition_EDIT
+ : ValueExpression_EDIT
+ ;
+
+ValueExpression
+ : NonParenthesizedValueExpressionPrimary
+ ;
+
+ValueExpression_EDIT
+ : NonParenthesizedValueExpressionPrimary_EDIT
+ ;
+
+ValueExpression_EDIT
+ : ValueExpression 'NOT' 'CURSOR'
+   {
+     if (parser.isImpala()) {
+       parser.suggestKeywords(['BETWEEN', 'EXISTS', 'IN', 'ILIKE', 'IREGEXP', 'LIKE', 'REGEXP', 'RLIKE']);
+     } else {
+       parser.suggestKeywords(['BETWEEN', 'EXISTS', 'IN', 'LIKE', 'REGEXP', 'RLIKE']);
+     }
+     $$ = { types: [ 'BOOLEAN' ] };
+   }
+ ;
+
+ValueExpressionList
+ : ValueExpression
+   {
+     $1.position = 1;
+   }
+ | ValueExpressionList ',' ValueExpression
+   {
+     $3.position = $1.position + 1;
+     $$ = $3;
+   }
+ ;
+
+ValueExpressionList_EDIT
+ : ValueExpression_EDIT
+   {
+     $1.position = 1;
+   }
+ | ValueExpressionList ',' ValueExpression_EDIT
+   {
+     $1.position += 1;
+   }
+ | ValueExpression_EDIT ',' ValueExpressionList
+   {
+     $1.position = 1;
+   }
+ | ValueExpressionList ',' ValueExpression_EDIT ',' ValueExpressionList
+   {
+     $1.position += 1;
+   }
+ | ValueExpressionList ',' AnyCursor
+   {
+     parser.valueExpressionSuggest();
+     $1.position += 1;
+   }
+ | ValueExpressionList ',' AnyCursor ',' ValueExpressionList
+   {
+     parser.valueExpressionSuggest();
+     $1.position += 1;
+   }
+ | ValueExpressionList 'CURSOR' ',' ValueExpressionList
+   {
+     parser.suggestValueExpressionKeywords($1);
+   }
+ | AnyCursor ',' ValueExpressionList
+   {
+     parser.valueExpressionSuggest();
+     $$ = { cursorAtStart : true, position: 1 };
+   }
+ | AnyCursor ','
+   {
+     parser.valueExpressionSuggest();
+     $$ = { cursorAtStart : true, position: 1 };
+   }
+ | ',' AnyCursor
+   {
+     parser.valueExpressionSuggest();
+     $$ = { position: 2 };
+   }
+ | ',' AnyCursor ',' ValueExpressionList
+   {
+     parser.valueExpressionSuggest();
+     $$ = { position: 2 };
+   }
+ ;
+
+InValueList
+ : NonParenthesizedValueExpressionPrimary
+ | InValueList ',' NonParenthesizedValueExpressionPrimary
+ ;
+
+NonParenthesizedValueExpressionPrimary
+ : UnsignedValueSpecification
+ | ColumnOrArbitraryFunctionRef             -> { types: ['COLREF'], columnReference: $1.chain }
+ | ColumnOrArbitraryFunctionRef ArbitraryFunctionRightPart
+   {
+     // We need to handle arbitrary UDFs here instead of inside UserDefinedFunction or there will be a conflict
+     // with columnReference for functions like: db.udf(foo)
+     var fn = $1.chain[$1.chain.length - 1].name.toLowerCase();
+     $1.lastLoc.type = 'function';
+     $1.lastLoc.function = fn;
+     $1.lastLoc.location = {
+       first_line: $1.lastLoc.location.first_line,
+       last_line: $1.lastLoc.location.last_line,
+       first_column: $1.lastLoc.location.first_column,
+       last_column: $1.lastLoc.location.last_column - 1
+     }
+     if ($1.lastLoc !== $1.firstLoc) {
+        $1.firstLoc.type = 'database';
+     } else {
+       delete $1.lastLoc.identifierChain;
+     }
+     if ($2.expression) {
+       $$ = { function: fn, expression: $2.expression, types: parser.findReturnTypes(fn) }
+     } else {
+       $$ = { function: fn, types: parser.findReturnTypes(fn) }
+     }
+   }
+ | ArbitraryFunctionName ArbitraryFunctionRightPart
+  {
+    parser.addFunctionLocation(@1, $1);
+    if ($2.expression) {
+      $$ = { function: $1, expression: $2.expression, types: parser.findReturnTypes($1) }
+    } else {
+      $$ = { function: $1, types: parser.findReturnTypes($1) }
+    }
+  }
+ | UserDefinedFunction
+ | 'NULL'                      -> { types: [ 'NULL' ] }
+ | ImpalaInterval              -> { types: [ 'TIMESTAMP' ] }
+ ;
+
+NonParenthesizedValueExpressionPrimary_EDIT
+ : UnsignedValueSpecification_EDIT
+ | ColumnOrArbitraryFunctionRef_EDIT
+   {
+     if ($1.suggestKeywords) {
+       $$ = { types: ['COLREF'], columnReference: $1, suggestKeywords: $1.suggestKeywords };
+     } else {
+       $$ = { types: ['COLREF'], columnReference: $1 };
+     }
+   }
+ | ColumnOrArbitraryFunctionRef ArbitraryFunctionRightPart_EDIT
+   {
+     var fn = $1.chain[$1.chain.length - 1].name.toLowerCase();
+     $1.lastLoc.type = 'function';
+     $1.lastLoc.function = fn;
+     $1.lastLoc.location = {
+       first_line: $1.lastLoc.location.first_line,
+       last_line: $1.lastLoc.location.last_line,
+       first_column: $1.lastLoc.location.first_column,
+       last_column: $1.lastLoc.location.last_column - 1
+     }
+     if ($1.lastLoc !== $1.firstLoc) {
+        $1.firstLoc.type = 'database';
+     } else {
+       delete $1.lastLoc.identifierChain;
+     }
+     if ($2.position) {
+       parser.applyArgumentTypesToSuggestions(fn, $2.position);
+     }
+     $$ = { types: parser.findReturnTypes(fn) };
+   }
+ | ArbitraryFunctionName ArbitraryFunctionRightPart_EDIT
+   {
+     parser.addFunctionLocation(@1, $1);
+     if ($2.position) {
+       parser.applyArgumentTypesToSuggestions($1, $2.position);
+     }
+     $$ = { types: parser.findReturnTypes($1) };
+   }
+ | UserDefinedFunction_EDIT
+ | ImpalaInterval_EDIT
+ ;
+
+ColumnOrArbitraryFunctionRef
+ : BasicIdentifierChain
+   {
+     var lastLoc = parser.yy.locations[parser.yy.locations.length - 1];
+     if (lastLoc.type !== 'variable') {
+       lastLoc.type = 'column';
+     }
+     // used for function references with db prefix
+     var firstLoc = parser.yy.locations[parser.yy.locations.length - $1.length];
+     $$ = { chain: $1, firstLoc: firstLoc, lastLoc: lastLoc }
+   }
+ | BasicIdentifierChain AnyDot '*'
+   {
+     parser.addAsteriskLocation(@3, $1.concat({ asterisk: true }));
+   }
+ ;
+
+ColumnOrArbitraryFunctionRef_EDIT
+ : BasicIdentifierChain_EDIT
+ ;
+
+ImpalaInterval
+ : '<impala>INTERVAL' SignedInteger RegularIdentifier
+ ;
+
+ImpalaInterval_EDIT
+ : '<impala>INTERVAL' SignedInteger 'CURSOR'
+   {
+     parser.suggestKeywords(['DAYS', 'HOURS', 'MICROSECONDS', 'MILLISECONDS', 'MINUTES', 'MONTHS', 'NANOSECONDS', 'SECONDS', 'WEEKS', 'YEARS']);
+   }
+ ;
+
+SignedInteger
+ : UnsignedNumericLiteral
+ | '-' UnsignedNumericLiteral
+ | '+' UnsignedNumericLiteral
+ ;
+
+UnsignedValueSpecification
+ : UnsignedLiteral
+ ;
+
+UnsignedValueSpecification_EDIT
+ : UnsignedLiteral_EDIT
+   {
+     parser.suggestValues($1);
+   }
+ ;
+
+UnsignedLiteral
+ : UnsignedNumericLiteral  -> { types: [ 'NUMBER' ] }
+ | GeneralLiteral
+ ;
+
+UnsignedLiteral_EDIT
+ : GeneralLiteral_EDIT
+ ;
+
+UnsignedNumericLiteral
+ : ExactNumericLiteral
+ | ApproximateNumericLiteral
+ ;
+
+ExactNumericLiteral
+ : 'UNSIGNED_INTEGER'
+ | 'UNSIGNED_INTEGER' AnyDot                     -> $1 + $2
+ | 'UNSIGNED_INTEGER' AnyDot 'UNSIGNED_INTEGER'  -> $1 + $2 + $3
+ | AnyDot 'UNSIGNED_INTEGER'                     -> $1 + $2
+ ;
+
+ApproximateNumericLiteral
+ : UNSIGNED_INTEGER_E 'UNSIGNED_INTEGER'
+ | AnyDot UNSIGNED_INTEGER_E 'UNSIGNED_INTEGER'
+ | 'UNSIGNED_INTEGER' AnyDot UNSIGNED_INTEGER_E 'UNSIGNED_INTEGER'
+ ;
+
+GeneralLiteral
+ : SingleQuotedValue
+   {
+     if (/\$\{[^}]*\}/.test($1)) {
+       parser.addVariableLocation(@1, $1);
+       $$ = { types: [ 'STRING' ], columnReference: [{ name: $1 }] }
+     } else {
+       $$ = { types: [ 'STRING' ] }
+     }
+   }
+ | DoubleQuotedValue
+   {
+     if (/\$\{[^}]*\}/.test($1)) {
+       parser.addVariableLocation(@1, $1);
+       $$ = { types: [ 'STRING' ], columnReference: [{ name: $1 }] }
+     } else {
+       $$ = { types: [ 'STRING' ] }
+     }
+   }
+ | TruthValue         -> { types: [ 'BOOLEAN' ] }
+ ;
+
+GeneralLiteral_EDIT
+ : SingleQuotedValue_EDIT
+  {
+    $$ = { partialQuote: '\'', missingEndQuote: parser.yy.missingEndQuote };
+  }
+ | DoubleQuotedValue_EDIT
+  {
+    $$ = { partialQuote: '"', missingEndQuote: parser.yy.missingEndQuote };
+  }
+ ;
+
+TruthValue
+ : 'TRUE'
+ | 'FALSE'
+ ;
+
+OptionalNot
+ :
+ | 'NOT'
+ ;
+
+SelectSpecification
+ : ValueExpression OptionalCorrelationName
+   {
+     if ($2) {
+       parser.addColumnAliasLocation($2.location, $2.alias, @1);
+       $$ = { valueExpression: $1, alias: $2.alias };
+       if (!parser.yy.selectListAliases) {
+         parser.yy.selectListAliases = [];
+       }
+       parser.yy.selectListAliases.push({ name: $2.alias, types: $1.types || ['T'] });
+     } else {
+       $$ = { valueExpression: $1 }
+     }
+   }
+ | '*'
+   {
+     parser.addAsteriskLocation(@1, [{ asterisk: true }]);
+     $$ = { asterisk: true }
+   }
+ ;
+
+SelectSpecification_EDIT
+ : ValueExpression_EDIT OptionalCorrelationName
+   {
+     if ($2) {
+       parser.addColumnAliasLocation($2.location, $2.alias, @1);
+     }
+   }
+
+ | AnyCursor 'AS' RegularOrBacktickedIdentifier
+   {
+     parser.suggestFunctions();
+     parser.suggestColumns();
+     parser.addColumnAliasLocation(@3, $3, @1);
+     $$ = { suggestAggregateFunctions: true };
+   }
+ | ValueExpression OptionalCorrelationName_EDIT  -> $2
+ ;
+
+SelectList
+ : SelectSpecification                 -> [ $1 ]
+ | SelectList ',' SelectSpecification
+   {
+     $1.push($3);
+   }
+ ;
+
+SelectList_EDIT
+ : SelectSpecification_EDIT
+ | 'CURSOR' SelectList
+   {
+     $$ = { cursorAtStart : true, suggestFunctions: true, suggestColumns: true, suggestAggregateFunctions: true };
+   }
+ | 'CURSOR' ',' SelectList
+   {
+     $$ = { cursorAtStart : true, suggestFunctions: true, suggestColumns: true, suggestAggregateFunctions: true };
+   }
+ | SelectSpecification_EDIT ',' SelectList
+ | SelectList 'CURSOR' SelectList
+   {
+     parser.checkForSelectListKeywords($1);
+   }
+ | SelectList 'CURSOR' ',' SelectList
+   {
+     parser.checkForSelectListKeywords($1);
+   }
+ | SelectList ',' AnyCursor
+   {
+     $$ = { suggestKeywords: parser.getSelectListKeywords(), suggestTables: true, suggestDatabases: true, suggestFunctions: true, suggestColumns: true, suggestAggregateFunctions: true };
+   }
+ | SelectList ',' SelectSpecification_EDIT                 -> $3
+ | SelectList ',' AnyCursor SelectList
+   {
+     $$ = { suggestKeywords: parser.getSelectListKeywords(), suggestFunctions: true, suggestColumns: true, suggestAggregateFunctions: true,  };
+   }
+ | SelectList ',' AnyCursor ','
+   {
+     $$ = { suggestKeywords: parser.getSelectListKeywords(), suggestFunctions: true, suggestColumns: true, suggestAggregateFunctions: true,  };
+   }
+ | SelectList ',' SelectSpecification_EDIT ','             -> $3
+ | SelectList ',' AnyCursor ',' SelectList
+   {
+     $$ = { suggestKeywords: parser.getSelectListKeywords(), suggestFunctions: true, suggestColumns: true, suggestAggregateFunctions: true,  };
+   }
+ | SelectList ',' SelectSpecification_EDIT ',' SelectList  -> $3
+ ;
+
+TableReferenceList
+ : TableReference
+ | TableReferenceList ',' TableReference  -> $3
+ ;
+
+TableReferenceList_EDIT
+ : TableReference_EDIT
+ | TableReference_EDIT ',' TableReference
+ | TableReferenceList ',' TableReference_EDIT
+ | TableReferenceList ',' TableReference_EDIT ',' TableReferenceList
+ | TableReferenceList ',' AnyCursor
+   {
+       parser.suggestTables();
+       parser.suggestDatabases({ appendDot: true });
+   }
+ ;
+
+TableReference
+ : TablePrimaryOrJoinedTable
+ ;
+
+TableReference_EDIT
+ : TablePrimaryOrJoinedTable_EDIT
+ ;
+
+TablePrimaryOrJoinedTable
+ : TablePrimary
+   {
+     $$ = $1;
+
+     if (parser.yy.latestTablePrimaries.length > 0) {
+       var idx = parser.yy.latestTablePrimaries.length - 1;
+       var tables = [];
+       do {
+         var tablePrimary = parser.yy.latestTablePrimaries[idx];
+         if (!tablePrimary.subQueryAlias) {
+           tables.unshift(tablePrimary.alias ? { identifierChain: tablePrimary.identifierChain, alias: tablePrimary.alias } : { identifierChain: tablePrimary.identifierChain })
+         }
+         idx--;
+       } while (idx >= 0 && tablePrimary.join && !tablePrimary.subQueryAlias)
+
+       if (tables.length > 0) {
+         $$.suggestJoins = {
+           prependJoin: true,
+           tables: tables
+         };
+       }
+      }
+   }
+ | JoinedTable
+ ;
+
+TablePrimaryOrJoinedTable_EDIT
+ : TablePrimary_EDIT
+ | JoinedTable_EDIT
+ ;
+
+JoinedTable
+ : TablePrimary Joins  -> $2
+ ;
+
+JoinedTable_EDIT
+ : TablePrimary Joins_EDIT
+ | TablePrimary_EDIT Joins
+ ;
+
+Joins
+ : JoinType OptionalImpalaBroadcastOrShuffle TablePrimary OptionalJoinCondition
+   {
+     if ($4 && $4.valueExpression) {
+       $$ = $4.valueExpression;
+     } else {
+       $$ = {};
+     }
+     $$.joinType = $1;
+     if ($4.noJoinCondition) {
+       $$.suggestJoinConditions = { prependOn: true, tablePrimaries: parser.yy.latestTablePrimaries.concat() }
+     }
+     if ($4.suggestKeywords) {
+       $$.suggestKeywords = $4.suggestKeywords;
+     }
+     if (parser.yy.latestTablePrimaries.length > 0) {
+        parser.yy.latestTablePrimaries[parser.yy.latestTablePrimaries.length - 1].join = true;
+     }
+   }
+ | Joins JoinType OptionalImpalaBroadcastOrShuffle TablePrimary OptionalJoinCondition
+   {
+     if ($5 && $5.valueExpression) {
+       $$ = $5.valueExpression;
+     } else {
+       $$ = {};
+     }
+     $$.joinType = $1;
+     if ($5.noJoinCondition) {
+       $$.suggestJoinConditions = { prependOn: true, tablePrimaries: parser.yy.latestTablePrimaries.concat() }
+     }
+     if ($5.suggestKeywords) {
+       $$.suggestKeywords = $5.suggestKeywords;
+     }
+     if (parser.yy.latestTablePrimaries.length > 0) {
+       parser.yy.latestTablePrimaries[parser.yy.latestTablePrimaries.length - 1].join = true;
+     }
+   }
+ ;
+
+Joins_INVALID
+ : JoinType OptionalImpalaBroadcastOrShuffle                                           -> { joinType: $1 }
+ | JoinType OptionalImpalaBroadcastOrShuffle Joins                                     -> { joinType: $1 }
+ ;
+
+OptionalImpalaBroadcastOrShuffle
+ :
+ | '<impala>BROADCAST'
+ | '<impala>SHUFFLE'
+ ;
+
+Join_EDIT
+ : JoinType_EDIT OptionalImpalaBroadcastOrShuffle TablePrimary OptionalJoinCondition
+   {
+     if ($1.suggestKeywords) {
+       parser.suggestKeywords($1.suggestKeywords);
+     }
+   }
+ | JoinType_EDIT OptionalImpalaBroadcastOrShuffle
+   {
+     if ($1.suggestKeywords) {
+       parser.suggestKeywords($1.suggestKeywords);
+     }
+   }
+ | JoinType OptionalImpalaBroadcastOrShuffle TablePrimary_EDIT OptionalJoinCondition
+ | JoinType OptionalImpalaBroadcastOrShuffle TablePrimary JoinCondition_EDIT
+ | JoinType OptionalImpalaBroadcastOrShuffle 'CURSOR' OptionalJoinCondition
+   {
+     if (!$2 && parser.isImpala()) {
+       parser.suggestKeywords(['[BROADCAST]', '[SHUFFLE]']);
+     }
+     if (!$2 && parser.yy.latestTablePrimaries.length > 0) {
+       var idx = parser.yy.latestTablePrimaries.length - 1;
+       var tables = [];
+       do {
+         var tablePrimary = parser.yy.latestTablePrimaries[idx];
+         if (!tablePrimary.subQueryAlias) {
+           tables.unshift(tablePrimary.alias ? { identifierChain: tablePrimary.identifierChain, alias: tablePrimary.alias } : { identifierChain: tablePrimary.identifierChain })
+         }
+         idx--;
+       } while (idx >= 0 && tablePrimary.join && !tablePrimary.subQueryAlias)
+
+       if (tables.length > 0) {
+         parser.suggestJoins({
+           prependJoin: false,
+           joinType: $1,
+           tables: tables
+         })
+       }
+     }
+     parser.suggestTables();
+     parser.suggestDatabases({
+       appendDot: true
+     });
+   }
+ ;
+
+Joins_EDIT
+ : Join_EDIT
+ | Join_EDIT Joins
+ | Joins Join_EDIT
+ | Joins Join_EDIT Joins
+ ;
+
+JoinType
+ : 'JOIN'                         -> 'JOIN'
+ | '<impala>ANTI' 'JOIN'          -> 'ANTI JOIN'
+ | 'CROSS' 'JOIN'                 -> 'CROSS JOIN'
+ | 'INNER' 'JOIN'                 -> 'INNER JOIN'
+ | 'OUTER' 'JOIN'                 -> 'OUTER JOIN'
+ | 'SEMI' 'JOIN'                  -> 'SEMI JOIN'
+ | 'FULL' 'JOIN'                  -> 'FULL JOIN'
+ | 'FULL' 'OUTER' 'JOIN'          -> 'FULL OUTER JOIN'
+ | 'LEFT' 'JOIN'                  -> 'LEFT JOIN'
+ | 'LEFT' '<impala>ANTI' 'JOIN'   -> 'LEFT ANTI JOIN'
+ | 'LEFT' 'INNER' 'JOIN'          -> 'LEFT INNER JOIN'
+ | 'LEFT' 'OUTER' 'JOIN'          -> 'LEFT OUTER JOIN'
+ | 'LEFT' 'SEMI' 'JOIN'           -> 'LEFT SEMI JOIN'
+ | 'RIGHT' 'JOIN'                 -> 'RIGHT JOIN'
+ | 'RIGHT' '<impala>ANTI' 'JOIN'  -> 'RIGHT ANTI JOIN'
+ | 'RIGHT' 'INNER' 'JOIN'         -> 'RIGHT OUTER JOIN'
+ | 'RIGHT' 'OUTER' 'JOIN'         -> 'RIGHT OUTER JOIN'
+ | 'RIGHT' 'SEMI' 'JOIN'          -> 'RIGHT SEMI JOIN'
+ ;
+
+JoinType_EDIT
+ : '<impala>ANTI' 'CURSOR'          -> { suggestKeywords: ['JOIN'] }
+ | 'CROSS' 'CURSOR'                 -> { suggestKeywords: ['JOIN'] }
+ | 'INNER' 'CURSOR'                 -> { suggestKeywords: ['JOIN'] }
+ | 'OUTER' 'CURSOR'                 -> { suggestKeywords: ['JOIN'] }
+ | 'SEMI' 'CURSOR'                  -> { suggestKeywords: ['JOIN'] }
+ | 'FULL' 'OUTER' 'CURSOR'          -> { suggestKeywords: ['JOIN'] }
+ | 'FULL' 'CURSOR' 'JOIN'           -> { suggestKeywords: ['OUTER'] }
+ | 'LEFT' '<impala>ANTI' 'CURSOR'   -> { suggestKeywords: ['JOIN'] }
+ | 'LEFT' 'INNER' 'CURSOR'          -> { suggestKeywords: ['JOIN'] }
+ | 'LEFT' 'OUTER' 'CURSOR'          -> { suggestKeywords: ['JOIN'] }
+ | 'LEFT' 'SEMI' 'CURSOR'           -> { suggestKeywords: ['JOIN'] }
+ | 'LEFT' 'CURSOR' 'JOIN'           -> { suggestKeywords: parser.isImpala() ? ['ANTI', 'INNER', 'OUTER', 'SEMI'] : parser.isHive() ? ['OUTER', 'SEMI'] : ['OUTER'] }
+ | 'RIGHT' '<impala>ANTI' 'CURSOR'  -> { suggestKeywords: ['JOIN'] }
+ | 'RIGHT' 'INNER' 'CURSOR'         -> { suggestKeywords: ['JOIN'] }
+ | 'RIGHT' 'OUTER' 'CURSOR'         -> { suggestKeywords: ['JOIN'] }
+ | 'RIGHT' 'SEMI' 'CURSOR'          -> { suggestKeywords: ['JOIN'] }
+ | 'RIGHT' 'CURSOR' 'JOIN'          -> { suggestKeywords: parser.isImpala() ? ['ANTI', 'INNER', 'OUTER', 'SEMI'] : ['OUTER'] }
+ ;
+
+OptionalJoinCondition
+ :                                       -> { noJoinCondition: true, suggestKeywords: parser.isImpala() ? ['ON', 'USING'] : ['ON'] }
+ | 'ON' ValueExpression                  -> { valueExpression: $2 }
+ | '<impala>USING' '(' UsingColList ')'  -> {}
+ ;
+
+UsingColList
+ : RegularOrBacktickedIdentifier
+ | UsingColList ',' RegularOrBacktickedIdentifier
+ ;
+
+JoinCondition_EDIT
+ : 'ON' ValueExpression_EDIT
+ | 'ON' 'CURSOR'
+   {
+     parser.valueExpressionSuggest();
+     parser.suggestJoinConditions({ prependOn: false });
+   }
+ ;
+
+TablePrimary
+ : TableOrQueryName OptionalHiveTableSample OptionalCorrelationName OptionalTableSample
+   {
+     $$ = {
+       primary: $1
+     }
+     if ($1.identifierChain) {
+       if ($3) {
+         $1.alias = $3.alias
+         parser.addTableAliasLocation($3.location, $3.alias, $1.identifierChain);
+       }
+       parser.addTablePrimary($1);
+     }
+     var keywords = [];
+     if ($4 && $4.suggestKeywords) {
+       keywords = $4.suggestKeywords;
+     } else {
+       // Right-to-left for cursor after TablePrimary
+       keywords = parser.getKeywordsForOptionalsLR([$4, $3, $2], [{ value: 'TABLESAMPLE', weight: 1 }, { value: 'AS', weight: 2 }, { value: 'TABLESAMPLE', weight: 3 }], [parser.isImpala(), true, parser.isHive()]);
+     }
+     if (keywords.length > 0) {
+       $$.suggestKeywords = keywords;
+     }
+   }
+ | DerivedTable OptionalCorrelationName OptionalTableSample
+   {
+     $$ = {
+       primary: $1
+     };
+
+     if ($2) {
+       $$.primary.alias = $2.alias;
+       parser.addTablePrimary({ subQueryAlias: $2.alias });
+       parser.addSubqueryAliasLocation($2.location, $2.alias, $1.identifierChain);
+     }
+
+     var keywords = [];
+     if ($3 && $3.suggestKeywords) {
+       keywords = $3.suggestKeywords;
+     } else {
+       keywords = parser.getKeywordsForOptionalsLR([$3, $2], [{ value: 'TABLESAMPLE', weight: 1 }, { value: 'AS', weight: 2 }], [parser.isImpala(), true]);
+     }
+     if (keywords.length > 0) {
+       $$.suggestKeywords = keywords;
+     }
+   }
+ ;
+
+TablePrimary_EDIT
+ : TableOrQueryName_EDIT OptionalHiveTableSample OptionalCorrelationName OptionalTableSample
+   {
+     if ($3) {
+       parser.addTableAliasLocation($3.location, $3.alias, $1.identifierChain);
+     }
+   }
+ | TableOrQueryName OptionalHiveTableSample_EDIT OptionalCorrelationName OptionalTableSample
+   {
+     if ($3) {
+       $1.alias = $3.alias;
+       parser.addTableAliasLocation($3.location, $3.alias, $1.identifierChain);
+     }
+     parser.addTablePrimary($1);
+   }
+ | TableOrQueryName OptionalHiveTableSample OptionalCorrelationName OptionalTableSample_EDIT
+   {
+     if ($3) {
+       $1.alias = $3.alias;
+       parser.addTableAliasLocation($3.location, $3.alias, $1.identifierChain);
+     }
+     parser.addTablePrimary($1);
+   }
+ | DerivedTable_EDIT OptionalCorrelationName OptionalTableSample
+   {
+     if ($2) {
+       parser.addTablePrimary({ subQueryAlias: $2.alias });
+       parser.addSubqueryAliasLocation($2.location, $2.alias);
+     }
+   }
+ | DerivedTable OptionalCorrelationName_EDIT OptionalTableSample
+ ;
+
+TableOrQueryName
+ : SchemaQualifiedTableIdentifier
+ ;
+
+TableOrQueryName_EDIT
+ : SchemaQualifiedTableIdentifier_EDIT
+ ;
+
+DerivedTable
+ : TableSubQuery
+ ;
+
+DerivedTable_EDIT
+ : TableSubQuery_EDIT
+ ;
+
+OptionalHiveTableSample
+ :
+ | '<hive>TABLESAMPLE' '(' '<hive>BUCKET' 'UNSIGNED_INTEGER' '<hive>OUT' '<hive>OF' 'UNSIGNED_INTEGER' OptionalOnColumn ')'
+ | '<hive>TABLESAMPLE' '(' ExactNumericLiteral '<hive>PERCENT' ')'
+ | '<hive>TABLESAMPLE' '(' ExactNumericLiteral 'ROWS' ')'
+ | '<hive>TABLESAMPLE' '(' 'REGULAR_IDENTIFIER' ')'
+ ;
+
+OptionalHiveTableSample_EDIT
+ : '<hive>TABLESAMPLE' '(' AnyCursor RightParenthesisOrError
+   {
+     parser.suggestKeywords(['BUCKET']);
+   }
+ | '<hive>TABLESAMPLE' '(' '<hive>BUCKET' 'UNSIGNED_INTEGER' 'CURSOR' RightParenthesisOrError
+   {
+     parser.suggestKeywords(['OUT OF']);
+   }
+ | '<hive>TABLESAMPLE' '(' '<hive>BUCKET' 'UNSIGNED_INTEGER' '<hive>OUT' 'CURSOR' RightParenthesisOrError
+   {
+     parser.suggestKeywords(['OF']);
+   }
+ | '<hive>TABLESAMPLE' '(' '<hive>BUCKET' 'UNSIGNED_INTEGER' '<hive>OUT' '<hive>OF' 'UNSIGNED_INTEGER' OptionalOnColumn 'CURSOR' RightParenthesisOrError
+   {
+     if (!$8) {
+       parser.suggestKeywords(['ON']);
+     }
+   }
+ | '<hive>TABLESAMPLE' '(' '<hive>BUCKET' 'UNSIGNED_INTEGER' '<hive>OUT' '<hive>OF' 'UNSIGNED_INTEGER' OptionalOnColumn_EDIT RightParenthesisOrError
+ | '<hive>TABLESAMPLE' '(' ExactNumericLiteral 'CURSOR' RightParenthesisOrError
+   {
+     if ($3.indexOf('.') === -1 ) {
+       parser.suggestKeywords(['PERCENT', 'ROWS']);
+     } else {
+       parser.suggestKeywords(['PERCENT']);
+     }
+   }
+ ;
+
+OptionalTableSample
+ :
+ | '<impala>TABLESAMPLE' '<impala>SYSTEM' '(' 'UNSIGNED_INTEGER' ')'                                                  --> { suggestKeywords: ['REPEATABLE()'] }
+ | '<impala>TABLESAMPLE' '<impala>SYSTEM' '(' 'UNSIGNED_INTEGER' ')' '<impala>REPEATABLE' '(' 'UNSIGNED_INTEGER' ')'
+ ;
+
+OptionalTableSample_EDIT
+ : '<impala>TABLESAMPLE' 'CURSOR'
+   {
+     parser.suggestKeywords(['SYSTEM()']);
+   }
+ ;
+
+OptionalOnColumn
+ :
+ | 'ON' ValueExpression
+ ;
+
+OptionalOnColumn_EDIT
+ : 'ON' 'CURSOR'
+   {
+     parser.valueExpressionSuggest();
+   }
+ | 'ON' ValueExpression_EDIT
+ ;
+
+PushQueryState
+ :
+   {
+     parser.pushQueryState();
+   }
+ ;
+
+PopQueryState
+ :
+   {
+     parser.popQueryState();
+   }
+ ;
+
+TableSubQuery
+ : '(' TableSubQueryInner ')'  -> $2
+ | '(' DerivedTable OptionalCorrelationName ')'
+   {
+     if ($3) {
+       $2.alias = $3.alias;
+       parser.addTablePrimary({ subQueryAlias: $3.alias });
+       parser.addSubqueryAliasLocation($3.location, $3.alias, $2.identifierChain);
+     }
+     $$ = $2;
+   }
+ ;
+
+TableSubQuery_EDIT
+ : '(' TableSubQueryInner_EDIT RightParenthesisOrError
+ | '(' AnyCursor RightParenthesisOrError
+   {
+     parser.suggestKeywords(['SELECT']);
+   }
+ ;
+
+TableSubQueryInner
+ : PushQueryState SubQuery
+   {
+     var subQuery = parser.getSubQuery($2);
+     subQuery.columns.forEach(function (column) {
+       parser.expandIdentifierChain({ wrapper: column });
+       delete column.linked;
+     });
+     parser.popQueryState(subQuery);
+     $$ = subQuery;
+   }
+ ;
+
+TableSubQueryInner_EDIT
+ : PushQueryState SubQuery_EDIT PopQueryState
+ ;
+
+SubQuery
+ : QueryExpression
+ ;
+
+SubQuery_EDIT
+ : QueryExpression_EDIT
+ ;
+
+QueryExpression
+ : QueryExpressionBody
+ ;
+
+QueryExpression_EDIT
+ : QueryExpressionBody_EDIT
+ ;
+
+QueryExpressionBody
+ : NonJoinQueryExpression
+ ;
+
+QueryExpressionBody_EDIT
+ : NonJoinQueryExpression_EDIT
+ ;
+
+NonJoinQueryExpression
+ : NonJoinQueryTerm
+ ;
+
+NonJoinQueryExpression_EDIT
+ : NonJoinQueryTerm_EDIT
+ ;
+
+NonJoinQueryTerm
+ : NonJoinQueryPrimary
+ ;
+
+NonJoinQueryTerm_EDIT
+ : NonJoinQueryPrimary_EDIT
+ ;
+
+NonJoinQueryPrimary
+ : SimpleTable
+ ;
+
+NonJoinQueryPrimary_EDIT
+ : SimpleTable_EDIT
+ ;
+
+SimpleTable
+ : QuerySpecification
+ ;
+
+SimpleTable_EDIT
+ : QuerySpecification_EDIT
+ ;
+
+OptionalCorrelationName
+ :
+ | RegularOrBacktickedIdentifier        -> { alias: $1, location: @1 }
+ | QuotedValue                          -> { alias: $1, location: @1 }
+ | 'AS' RegularOrBacktickedIdentifier  -> { alias: $2, location: @2 }
+ | 'AS' QuotedValue                    -> { alias: $2, location: @2 }
+ ;
+
+OptionalCorrelationName_EDIT
+ : PartialBacktickedIdentifier
+ | QuotedValue_EDIT
+ | 'AS' PartialBacktickedIdentifier
+ | 'AS' QuotedValue_EDIT
+ | 'AS' 'CURSOR'
+ ;
+
+OptionalLateralViews
+ :
+ | OptionalLateralViews LateralView
+   {
+     if ($1 && $2.lateralView) {
+       $1.lateralViews.push($2.lateralView);
+       $$ = $1;
+     } else if ($2.lateralView) {
+       $$ = { lateralViews: [ $2.lateralView ] };
+     }
+     if ($2.suggestKeywords) {
+       $$.suggestKeywords = $2.suggestKeywords
+     }
+   }
+ ;
+
+OptionalLateralViews_EDIT
+ : OptionalLateralViews LateralView_EDIT OptionalLateralViews
+ ;
+
+UserDefinedFunction
+ : AggregateFunction OptionalOverClause
+   {
+     if (!$2) {
+       $1.suggestKeywords = ['OVER'];
+     }
+   }
+ | AnalyticFunction OverClause
+ | CastFunction
+ | HiveExtractFunction
+ | ImpalaExtractFunction
+ ;
+
+UserDefinedFunction_EDIT
+ : AggregateFunction_EDIT
+ | AggregateFunction OptionalOverClause_EDIT
+ | AnalyticFunction_EDIT
+ | AnalyticFunction_EDIT OverClause
+ | AnalyticFunction 'CURSOR'
+   {
+     parser.suggestKeywords(['OVER']);
+   }
+ | AnalyticFunction OverClause_EDIT
+ | CastFunction_EDIT
+ | HiveExtractFunction_EDIT
+ | ImpalaExtractFunction_EDIT
+ ;
+
+ArbitraryFunction
+ : RegularIdentifier ArbitraryFunctionRightPart
+   {
+     parser.addFunctionLocation(@1, $1);
+     if ($2.expression) {
+       $$ = { function: $1, expression: $2.expression, types: parser.findReturnTypes($1) }
+     } else {
+       $$ = { function: $1, types: parser.findReturnTypes($1) }
+     }
+   }
+ | ArbitraryFunctionName ArbitraryFunctionRightPart
+   {
+     parser.addFunctionLocation(@1, $1);
+     if ($2.expression) {
+       $$ = { function: $1, expression: $2.expression, types: parser.findReturnTypes($1) }
+     } else {
+       $$ = { function: $1, types: parser.findReturnTypes($1) }
+     }
+   }
+ ;
+
+ArbitraryFunction_EDIT
+ : RegularIdentifier ArbitraryFunctionRightPart_EDIT
+   {
+     parser.addFunctionLocation(@1, $1);
+     if ($2.position) {
+       parser.applyArgumentTypesToSuggestions($1, $2.position);
+     }
+     $$ = { types: parser.findReturnTypes($1) };
+   }
+ | ArbitraryFunctionName ArbitraryFunctionRightPart_EDIT
+   {
+     parser.addFunctionLocation(@1, $1);
+     if ($2.position) {
+       parser.applyArgumentTypesToSuggestions($1, $2.position);
+     }
+     $$ = { types: parser.findReturnTypes($1) };
+   }
+ ;
+
+ArbitraryFunctionName
+ : 'IF'
+ | 'ARRAY'
+ | '<hive>BINARY'
+ | 'MAP'
+ | '<impala>REPLACE'
+ | 'TRUNCATE'
+ | '<impala>USER'
+ ;
+
+ArbitraryFunctionRightPart
+ : '(' ')'
+ | '(' ValueExpressionList ')'  -> { expression: $2 }
+ ;
+
+ArbitraryFunctionRightPart_EDIT
+ : '(' AnyCursor RightParenthesisOrError
+   {
+     parser.valueExpressionSuggest();
+     $$ = { position: 1 }
+   }
+ | '(' ValueExpressionList 'CURSOR' RightParenthesisOrError
+   {
+     parser.suggestValueExpressionKeywords($3);
+   }
+ | '(' ValueExpressionList_EDIT RightParenthesisOrError      -> $2
+ ;
+
+AggregateFunction
+ : CountFunction
+ | SumFunction
+ | OtherAggregateFunction
+ ;
+
+AggregateFunction_EDIT
+ : CountFunction_EDIT
+ | SumFunction_EDIT
+ | OtherAggregateFunction_EDIT
+ ;
+
+AnalyticFunction
+ : 'ANALYTIC' '(' ')'                      -> { types: parser.findReturnTypes($1) }
+ | 'ANALYTIC' '(' ValueExpressionList ')'  -> { function: $1, expression: $2, types: parser.findReturnTypes($1) }
+ ;
+
+AnalyticFunction_EDIT
+ : 'ANALYTIC' '(' AnyCursor RightParenthesisOrError
+   {
+     parser.valueExpressionSuggest();
+     parser.applyArgumentTypesToSuggestions($1, 1);
+     $$ = { types: parser.findReturnTypes($1) };
+   }
+ | 'ANALYTIC' '(' ValueExpressionList 'CURSOR' RightParenthesisOrError
+   {
+     parser.suggestValueExpressionKeywords($3);
+     $$ = { types: parser.findReturnTypes($1) };
+   }
+ | 'ANALYTIC' '(' ValueExpressionList_EDIT RightParenthesisOrError
+   {
+     parser.applyArgumentTypesToSuggestions($1, $3.position);
+     $$ = { types: parser.findReturnTypes($1) };
+   }
+ ;
+
+OptionalOverClause
+ :
+ | OverClause
+ ;
+
+OptionalOverClause_EDIT
+ : OverClause_EDIT
+ ;
+
+OverClause
+ : 'OVER' RegularOrBacktickedIdentifier
+ | 'OVER' WindowExpression
+ | '<impala>OVER' RegularOrBacktickedIdentifier
+ | '<impala>OVER' WindowExpression
+ ;
+
+OverClause_EDIT
+ : 'OVER' WindowExpression_EDIT
+ | '<impala>OVER' WindowExpression_EDIT
+ ;
+
+WindowExpression
+ : '(' OptionalPartitionBy OptionalOrderByAndWindow ')'
+ ;
+
+WindowExpression_EDIT
+ : '(' PartitionBy_EDIT OptionalOrderByAndWindow RightParenthesisOrError
+   {
+     if (parser.yy.result.suggestFunctions) {
+       parser.suggestAggregateFunctions();
+     }
+   }
+ | '(' OptionalPartitionBy OptionalOrderByAndWindow_EDIT RightParenthesisOrError
+   {
+     if (parser.yy.result.suggestFunctions) {
+       parser.suggestAggregateFunctions();
+     }
+   }
+ | '(' AnyCursor OptionalPartitionBy OptionalOrderByAndWindow RightParenthesisOrError
+   {
+     if (!$3 && !$4) {
+       parser.suggestKeywords([{ value: 'PARTITION BY', weight: 2 }, { value: 'ORDER BY', weight: 1 }]);
+     } else if (!$3) {
+       parser.suggestKeywords(['PARTITION BY']);
+     }
+   }
+ | '(' AnyPartition 'BY' ValueExpressionList 'CURSOR' OptionalOrderByAndWindow RightParenthesisOrError
+    {
+      if (!$6) {
+        parser.suggestValueExpressionKeywords($4, [{ value: 'ORDER BY', weight: 2 }]);
+      } else {
+        parser.suggestValueExpressionKeywords($4);
+      }
+    }
+  ;
+
+OptionalPartitionBy
+ :
+ | PartitionBy
+ ;
+
+PartitionBy
+ : AnyPartition 'BY' ValueExpressionList  -> $3
+ ;
+
+PartitionBy_EDIT
+ : AnyPartition 'CURSOR'
+   {
+     parser.suggestKeywords(['BY']);
+   }
+ | AnyPartition 'BY' 'CURSOR'
+   {
+     parser.valueExpressionSuggest();
+   }
+ | AnyPartition 'BY' ValueExpressionList_EDIT
+ ;
+
+OptionalOrderByAndWindow
+ :
+ | OrderByClause OptionalWindowSpec
+ ;
+
+OptionalOrderByAndWindow_EDIT
+  : OrderByClause_EDIT
+    {
+      // Only allowed in last order by
+      delete parser.yy.result.suggestAnalyticFunctions;
+    }
+  | OrderByClause 'CURSOR' OptionalWindowSpec
+    {
+      var keywords = [];
+      if ($1.suggestKeywords) {
+        keywords = parser.createWeightedKeywords($1.suggestKeywords, 2);
+      }
+      if (!$3) {
+        keywords = keywords.concat([{ value: 'RANGE BETWEEN', weight: 1 }, { value: 'ROWS BETWEEN', weight: 1 }]);
+      }
+      parser.suggestKeywords(keywords);
+    }
+  | OrderByClause WindowSpec_EDIT
+  ;
+
+OptionalWindowSpec
+ :
+ | WindowSpec
+ ;
+
+WindowSpec
+ : RowsOrRange 'BETWEEN' PopLexerState OptionalCurrentOrPreceding OptionalAndFollowing
+ | RowsOrRange 'UNBOUNDED' PopLexerState OptionalCurrentOrPreceding OptionalAndFollowing
+ ;
+
+WindowSpec_EDIT
+ : RowsOrRange 'CURSOR'
+   {
+     parser.suggestKeywords(parser.isHive() ? ['BETWEEN', 'UNBOUNDED'] : ['BETWEEN']);
+   }
+ | RowsOrRange 'BETWEEN' PopLexerState OptionalCurrentOrPreceding OptionalAndFollowing 'CURSOR'
+   {
+     if (!$4 && !$5) {
+       parser.suggestKeywords(['CURRENT ROW', 'UNBOUNDED PRECEDING']);
+     } else if (!$5) {
+       parser.suggestKeywords(['AND']);
+     }
+   }
+ | RowsOrRange 'BETWEEN' PopLexerState OptionalCurrentOrPreceding_EDIT OptionalAndFollowing
+ | RowsOrRange 'BETWEEN' PopLexerState OptionalCurrentOrPreceding OptionalAndFollowing_EDIT
+ | RowsOrRange 'UNBOUNDED' PopLexerState OptionalCurrentOrPreceding 'CURSOR'
+   {
+     if (!$4 && parser.isHive()) {
+       parser.suggestKeywords(['PRECEDING']);
+     }
+   }
+ | RowsOrRange 'UNBOUNDED' PopLexerState OptionalCurrentOrPreceding_EDIT
+ ;
+
+PopLexerState
+ :
+  {
+    lexer.popState();
+  }
+ ;
+
+PushHdfsLexerState
+ :
+  {
+    lexer.begin('hdfs');
+  }
+ ;
+
+HdfsPath
+ : 'HDFS_START_QUOTE' 'HDFS_PATH' 'HDFS_END_QUOTE'
+ ;
+
+HdfsPath_EDIT
+ : 'HDFS_START_QUOTE' 'HDFS_PATH' 'PARTIAL_CURSOR' 'HDFS_PATH' 'HDFS_END_QUOTE'
+    {
+      parser.suggestHdfs({ path: $2 });
+    }
+ | 'HDFS_START_QUOTE' 'HDFS_PATH' 'PARTIAL_CURSOR' 'HDFS_END_QUOTE'
+   {
+     parser.suggestHdfs({ path: $2 });
+   }
+ | 'HDFS_START_QUOTE' 'HDFS_PATH' 'PARTIAL_CURSOR'
+    {
+      parser.suggestHdfs({ path: $2 });
+    }
+ | 'HDFS_START_QUOTE' 'PARTIAL_CURSOR' 'HDFS_END_QUOTE'
+   {
+     parser.suggestHdfs({ path: '' });
+   }
+ | 'HDFS_START_QUOTE' 'PARTIAL_CURSOR'
+    {
+      parser.suggestHdfs({ path: '' });
+    }
+ ;
+
+RowsOrRange
+ : 'ROWS'
+ | AnyRange
+ ;
+
+OptionalCurrentOrPreceding
+ :
+ | IntegerOrUnbounded 'PRECEDING'
+ | AnyCurrent 'ROW'
+ ;
+
+OptionalCurrentOrPreceding_EDIT
+ : IntegerOrUnbounded 'CURSOR'
+   {
+     parser.suggestKeywords(['PRECEDING']);
+   }
+ | AnyCurrent 'CURSOR'
+   {
+     parser.suggestKeywords(['ROW']);
+   }
+ ;
+
+AnyCurrent
+ : 'CURRENT'
+ | '<hive>CURRENT'
+ | '<impala>CURRENT'
+ ;
+
+AnyRange
+ : 'RANGE'
+ | '<impala>RANGE'
+ ;
+
+OptionalAndFollowing
+ :
+ | 'AND' AnyCurrent 'ROW'
+ | 'AND' IntegerOrUnbounded 'FOLLOWING'
+ ;
+
+OptionalAndFollowing_EDIT
+ : 'AND' 'CURSOR'
+   {
+     parser.suggestKeywords(['CURRENT ROW', 'UNBOUNDED FOLLOWING']);
+   }
+ | 'AND' AnyCurrent 'CURSOR'
+   {
+     parser.suggestKeywords(['ROW']);
+   }
+ | 'AND' IntegerOrUnbounded 'CURSOR'
+   {
+     parser.suggestKeywords(['FOLLOWING']);
+   }
+ ;
+
+IntegerOrUnbounded
+ : 'UNSIGNED_INTEGER'
+ | 'UNBOUNDED'
+ ;
+
+OptionalHavingClause
+ :
+ | HavingClause
+ ;
+
+HavingClause
+ : 'HAVING' ValueExpression
+ ;
+
+HavingClause_EDIT
+ : 'HAVING' 'CURSOR'
+   {
+     parser.valueExpressionSuggest();
+     parser.suggestAggregateFunctions();
+     parser.suggestSelectListAliases(true);
+   }
+ | 'HAVING' ValueExpression_EDIT
+   {
+     parser.suggestAggregateFunctions();
+     parser.suggestSelectListAliases(true);
+   }
+ ;
+
+OptionalWindowClause
+ :
+ | WindowClause
+ ;
+
+WindowClause
+ : '<hive>WINDOW' RegularOrBacktickedIdentifier '<hive>AS' WindowExpression
+ ;
+
+WindowClause_EDIT
+ : '<hive>WINDOW' RegularOrBacktickedIdentifier 'CURSOR'
+   {
+     parser.suggestKeywords(['AS']);
+   }
+ | '<hive>WINDOW' RegularOrBacktickedIdentifier '<hive>AS' WindowExpression_EDIT
+ ;
+
+CastFunction
+ : 'CAST' '(' ValueExpression 'AS' PrimitiveType ')'  -> { types: [ $5.toUpperCase() ] }
+ | 'CAST' '(' ')'                                      -> { types: [ 'T' ] }
+ ;
+
+CastFunction_EDIT
+ : 'CAST' '(' AnyCursor 'AS' PrimitiveType RightParenthesisOrError
+   {
+     parser.valueExpressionSuggest();
+     $$ = { types: [ $5.toUpperCase() ] };
+   }
+ | 'CAST' '(' AnyCursor 'AS' RightParenthesisOrError
+   {
+     parser.valueExpressionSuggest();
+     $$ = { types: [ 'T' ] };
+   }
+ | 'CAST' '(' AnyCursor RightParenthesisOrError
+   {
+     parser.valueExpressionSuggest();
+     $$ = { types: [ 'T' ] };
+   }
+ | 'CAST' '(' ValueExpression_EDIT 'AS' PrimitiveType RightParenthesisOrError  -> { types: [ $5.toUpperCase() ] }
+ | 'CAST' '(' ValueExpression_EDIT 'AS' RightParenthesisOrError                -> { types: [ 'T' ] }
+ | 'CAST' '(' ValueExpression_EDIT RightParenthesisOrError                      -> { types: [ 'T' ] }
+ | 'CAST' '(' ValueExpression 'CURSOR' PrimitiveType RightParenthesisOrError
+   {
+     parser.suggestValueExpressionKeywords($3, [{ value: 'AS', weight: 2 }]);
+     $$ =  { types: [ $5.toUpperCase() ] };
+   }
+ | 'CAST' '(' ValueExpression 'CURSOR' RightParenthesisOrError
+   {
+     parser.suggestValueExpressionKeywords($3, [{ value: 'AS', weight: 2 }]);
+     $$ = { types: [ 'T' ] };
+   }
+ | 'CAST' '(' ValueExpression 'AS' 'CURSOR' RightParenthesisOrError
+   {
+     parser.suggestKeywords(parser.getTypeKeywords());
+     $$ = { types: [ 'T' ] };
+   }
+ | 'CAST' '(' 'AS' 'CURSOR' RightParenthesisOrError
+   {
+     parser.suggestKeywords(parser.getTypeKeywords());
+     $$ = { types: [ 'T' ] };
+   }
+ ;
+
+CountFunction
+ : 'COUNT' '(' '*' ')'                                        -> { types: parser.findReturnTypes($1) }
+ | 'COUNT' '(' ')'                                            -> { types: parser.findReturnTypes($1) }
+ | 'COUNT' '(' OptionalAllOrDistinct ValueExpressionList ')'  -> { types: parser.findReturnTypes($1) }
+ ;
+
+CountFunction_EDIT
+ : 'COUNT' '(' OptionalAllOrDistinct AnyCursor RightParenthesisOrError
+   {
+     parser.valueExpressionSuggest();
+     var keywords = parser.getSelectListKeywords();
+     if (!$3) {
+       keywords.push('DISTINCT');
+       if (parser.isImpala()) {
+         keywords.push('ALL');
+       }
+       if (parser.yy.result.suggestKeywords) {
+         keywords = parser.yy.result.suggestKeywords.concat(keywords);
+       }
+     }
+     parser.suggestKeywords(keywords);
+     $$ = { types: parser.findReturnTypes($1) };
+   }
+ | 'COUNT' '(' OptionalAllOrDistinct ValueExpressionList 'CURSOR' RightParenthesisOrError
+   {
+     parser.suggestValueExpressionKeywords($4);
+     $$ = { types: parser.findReturnTypes($1) };
+   }
+ | 'COUNT' '(' OptionalAllOrDistinct ValueExpressionList_EDIT RightParenthesisOrError
+   {
+     if ($4.cursorAtStart) {
+       var keywords = parser.getSelectListKeywords();
+       if (!$3) {
+         keywords.push('DISTINCT');
+         if (parser.isImpala()) {
+           keywords.push('ALL');
+         }
+       }
+       parser.suggestKeywords(keywords);
+     }
+     $$ = { types: parser.findReturnTypes($1) };
+   }
+ ;
+
+HiveExtractFunction
+ : '<hive>EXTRACT' '(' HiveDateField 'FROM' ValueExpression ')'  -> { types: ['INT'] }
+ ;
+
+HiveExtractFunction_EDIT
+ : '<hive>EXTRACT' '(' AnyCursor RightParenthesisOrError
+   {
+     parser.suggestKeywords(['DAY', 'DAYOFWEEK', 'HOUR', 'MINUTE', 'MONTH', 'QUARTER', 'SECOND', 'WEEK', 'YEAR']);
+     $$ = { types: ['INT'] }
+   }
+ | '<hive>EXTRACT' '(' HiveDateField 'CURSOR' RightParenthesisOrError
+   {
+     parser.suggestKeywords(['FROM']);
+     $$ = { types: ['INT'] }
+   }
+ | '<hive>EXTRACT' '(' HiveDateField 'FROM' 'CURSOR' RightParenthesisOrError
+   {
+     parser.valueExpressionSuggest();
+     $$ = { types: ['INT'] }
+   }
+ | '<hive>EXTRACT' '(' HiveDateField 'FROM' ValueExpression_EDIT RightParenthesisOrError  -> { types: ['INT'] }
+ | '<hive>EXTRACT' '(' AnyCursor 'FROM' ValueExpression RightParenthesisOrError
+   {
+      parser.suggestKeywords(['DAY', 'DAYOFWEEK', 'HOUR', 'MINUTE', 'MONTH', 'QUARTER', 'SECOND', 'WEEK', 'YEAR']);
+      $$ = { types: ['INT'] }
+   }
+ | '<hive>EXTRACT' '(' HiveDateField 'CURSOR' ValueExpression RightParenthesisOrError
+   {
+     parser.suggestKeywords(['FROM']);
+     $$ = { types: ['INT'] }
+   }
+ ;
+
+HiveDateField
+ : '<hive>DAY'
+ | '<hive>DAYOFWEEK'
+ | '<hive>HOUR'
+ | '<hive>MINUTE'
+ | '<hive>MONTH'
+ | '<hive>QUARTER'
+ | '<hive>SECOND'
+ | '<hive>WEEK'
+ | '<hive>YEAR'
+ ;
+
+OtherAggregateFunction
+ : OtherAggregateFunction_Type '(' OptionalAllOrDistinct ')'                      -> { types: parser.findReturnTypes($1) }
+ | OtherAggregateFunction_Type '(' OptionalAllOrDistinct ValueExpressionList ')'  -> { types: parser.findReturnTypes($1) }
+ ;
+
+OtherAggregateFunction_EDIT
+ : OtherAggregateFunction_Type '(' OptionalAllOrDistinct AnyCursor RightParenthesisOrError
+   {
+     parser.valueExpressionSuggest();
+     var keywords = parser.getSelectListKeywords(true);
+     if (!$3) {
+       if ($1.toLowerCase() === 'group_concat') {
+         keywords.push('ALL');
+       } else if (parser.isImpala()) {
+         keywords.push('ALL');
+         keywords.push('DISTINCT');
+       } else {
+         keywords.push('DISTINCT');
+       }
+     }
+     if (parser.yy.result.suggestKeywords) {
+       keywords = parser.yy.result.suggestKeywords.concat(keywords);
+     }
+     parser.suggestKeywords(keywords);
+     parser.applyArgumentTypesToSuggestions($1, 1);
+     $$ = { types: parser.findReturnTypes($1) };
+   }
+ | OtherAggregateFunction_Type '(' OptionalAllOrDistinct ValueExpressionList 'CURSOR' RightParenthesisOrError
+   {
+     parser.suggestValueExpressionKeywords($4);
+     $$ = { types: parser.findReturnTypes($1) };
+   }
+ | OtherAggregateFunction_Type '(' OptionalAllOrDistinct ValueExpressionList_EDIT RightParenthesisOrError
+   {
+     if ($4.cursorAtStart) {
+       var keywords = parser.getSelectListKeywords(true);
+       if (!$3) {
+         if ($1.toLowerCase() === 'group_concat') {
+           keywords.push('ALL');
+         } else if (parser.isImpala()) {
+           keywords.push('ALL');
+           keywords.push('DISTINCT');
+         } else {
+           keywords.push('DISTINCT');
+         }
+       }
+       if (parser.yy.result.suggestKeywords) {
+         keywords = parser.yy.result.suggestKeywords.concat(keywords);
+       }
+       parser.suggestKeywords(keywords);
+     }
+     if (parser.yy.result.suggestFunctions && !parser.yy.result.suggestFunctions.types) {
+       parser.applyArgumentTypesToSuggestions($1, $4.position);
+     }
+     $$ = { types: parser.findReturnTypes($1) };
+   }
+ ;
+
+OtherAggregateFunction_Type
+ : '<impala>APPX_MEDIAN'
+ | 'AVG'
+ | '<hive>COLLECT_SET'
+ | '<hive>COLLECT_LIST'
+ | '<hive>CORR'
+ | '<hive>COVAR_POP'
+ | '<hive>COVAR_SAMP'
+ | '<impala>GROUP_CONCAT'
+ | '<hive>HISTOGRAM_NUMERIC'
+ | '<impala>STDDEV'
+ | 'STDDEV_POP'
+ | 'STDDEV_SAMP'
+ | 'MAX'
+ | 'MIN'
+ | '<impala>NDV'
+ | '<hive>NTILE'
+ | '<hive>PERCENTILE'
+ | '<hive>PERCENTILE_APPROX'
+ | 'VARIANCE'
+ | '<impala>VARIANCE_POP'
+ | '<impala>VARIANCE_SAMP'
+ | 'VAR_POP'
+ | 'VAR_SAMP'
+ ;
+
+ImpalaExtractFunction
+ : '<impala>EXTRACT' '(' ValueExpression FromOrComma ValueExpression ')'
+ | '<impala>EXTRACT' '(' ')'
+ ;
+
+ImpalaExtractFunction_EDIT
+ : '<impala>EXTRACT' '(' AnyCursor FromOrComma ValueExpression RightParenthesisOrError
+   {
+     parser.valueExpressionSuggest();
+     parser.applyTypeToSuggestions($4.toLowerCase() === 'from' ? ['STRING'] : ['TIMESTAMP']);
+     $$ = { types: parser.findReturnTypes($1) };
+   }
+ | '<impala>EXTRACT' '(' AnyCursor FromOrComma RightParenthesisOrError
+   {
+     parser.valueExpressionSuggest();
+     parser.applyTypeToSuggestions($4.toLowerCase() === 'from' ? ['STRING'] : ['TIMESTAMP']);
+     $$ = { types: parser.findReturnTypes($1) };
+   }
+ | '<impala>EXTRACT' '(' AnyCursor RightParenthesisOrError
+   {
+     parser.valueExpressionSuggest();
+     parser.applyTypeToSuggestions(['STRING', 'TIMESTAMP']);
+     $$ = { types: parser.findReturnTypes($1) };
+   }
+ | '<impala>EXTRACT' '(' ValueExpression_EDIT FromOrComma ValueExpression RightParenthesisOrError
+   {
+     parser.applyTypeToSuggestions($4.toLowerCase() === 'from' ? ['STRING'] : ['TIMESTAMP']);
+     $$ = { types: parser.findReturnTypes($1) };
+   }
+ | '<impala>EXTRACT' '(' ValueExpression_EDIT FromOrComma RightParenthesisOrError
+   {
+     parser.applyTypeToSuggestions($4.toLowerCase() === 'from' ? ['STRING'] : ['TIMESTAMP']);
+     $$ = { types: parser.findReturnTypes($1) };
+   }
+ | '<impala>EXTRACT' '(' ValueExpression_EDIT RightParenthesisOrError
+   {
+     parser.applyTypeToSuggestions(['STRING', 'TIMESTAMP']);
+     $$ = { types: parser.findReturnTypes($1) };
+   }
+ | '<impala>EXTRACT' '(' ValueExpression FromOrComma AnyCursor RightParenthesisOrError
+   {
+     parser.valueExpressionSuggest();
+     parser.applyTypeToSuggestions($4.toLowerCase() === 'from' ? ['TIMESTAMP'] : ['STRING']);
+     $$ = { types: parser.findReturnTypes($1) };
+   }
+ | '<impala>EXTRACT' '(' FromOrComma AnyCursor RightParenthesisOrError
+   {
+     parser.valueExpressionSuggest();
+     parser.applyTypeToSuggestions($4.toLowerCase() === 'from' ? ['TIMESTAMP'] : ['STRING']);
+     $$ = { types: parser.findReturnTypes($1) };
+   }
+ | '<impala>EXTRACT' '(' ValueExpression FromOrComma ValueExpression_EDIT RightParenthesisOrError
+   {
+     parser.applyTypeToSuggestions($4.toLowerCase() === 'from' ? ['TIMESTAMP'] : ['STRING']);
+     $$ = { types: parser.findReturnTypes($1) };
+   }
+ | '<impala>EXTRACT' '(' FromOrComma ValueExpression_EDIT RightParenthesisOrError
+   {
+    parser.applyTypeToSuggestions($4.toLowerCase() === 'from' ? ['TIMESTAMP'] : ['STRING']);
+     $$ = { types: parser.findReturnTypes($1) };
+   }
+ | '<impala>EXTRACT' '(' ValueExpression 'CURSOR' ValueExpression RightParenthesisOrError
+   {
+     if ($3.types[0] === 'STRING') {
+       parser.suggestValueExpressionKeywords($3, ['FROM']);
+     } else {
+       parser.suggestValueExpressionKeywords($3);
+     }
+     $$ = { types: parser.findReturnTypes($1) };
+   }
+ | '<impala>EXTRACT' '(' ValueExpression 'CURSOR' RightParenthesisOrError
+   {
+     if ($3.types[0] === 'STRING') {
+       parser.suggestValueExpressionKeywords($3, ['FROM']);
+     } else {
+       parser.suggestValueExpressionKeywords($3);
+     }
+     $$ = { types: parser.findReturnTypes($1) };
+   }
+ ;
+
+FromOrComma
+ : 'FROM'
+ | ','
+ ;
+
+SumFunction
+ : 'SUM' '(' OptionalAllOrDistinct ValueExpression ')'  -> { types: parser.findReturnTypes($1) }
+ | 'SUM' '(' ')'                                        -> { types: parser.findReturnTypes($1) }
+ ;
+
+SumFunction_EDIT
+ : 'SUM' '(' OptionalAllOrDistinct AnyCursor RightParenthesisOrError
+   {
+     parser.valueExpressionSuggest();
+     parser.applyArgumentTypesToSuggestions($1, 1);
+     var keywords = parser.getSelectListKeywords(true);
+     if (!$3) {
+       keywords.push('DISTINCT');
+       if (parser.isImpala()) {
+         keywords.push('ALL');
+       }
+     }
+     if (parser.yy.result.suggestKeywords) {
+       keywords = parser.yy.result.suggestKeywords.concat(keywords);
+     }
+     parser.suggestKeywords(keywords);
+     $$ = { types: parser.findReturnTypes($1) };
+   }
+ | 'SUM' '(' OptionalAllOrDistinct ValueExpression 'CURSOR' RightParenthesisOrError
+   {
+     parser.suggestValueExpressionKeywords($4);
+     $$ = { types: parser.findReturnTypes($1) };
+   }
+ | 'SUM' '(' OptionalAllOrDistinct ValueExpression_EDIT RightParenthesisOrError
+   {
+     if (parser.yy.result.suggestFunctions && ! parser.yy.result.suggestFunctions.types) {
+       parser.applyArgumentTypesToSuggestions($1, 1);
+     }
+     $$ = { types: parser.findReturnTypes($1) };
+   }
+ ;
+
+LateralView
+ : '<hive>LATERAL' '<hive>VIEW' OptionalOuter ArbitraryFunction RegularOrBacktickedIdentifier LateralViewColumnAliases  -> { lateralView: { udtf: $4, tableAlias: $5, columnAliases: $6 }}
+ | '<hive>LATERAL' '<hive>VIEW' OptionalOuter ArbitraryFunction RegularOrBacktickedIdentifier
+   {
+     if ($4.function.toLowerCase() === 'explode') {
+       $$ = { lateralView: { udtf: $4, tableAlias: $5, columnAliases: ['key', 'value'] }, suggestKeywords: ['AS'] };
+     } else if ($4.function.toLowerCase() === 'posexplode') {
+       $$ = { lateralView: { udtf: $4, tableAlias: $5, columnAliases: ['pos', 'val'] }, suggestKeywords: ['AS'] };
+     } else {
+       $$ = { lateralView: { udtf: $4, tableAlias: $5, columnAliases: [] }, suggestKeywords: ['AS'] };
+     }
+   }
+ | '<hive>LATERAL' '<hive>VIEW' OptionalOuter ArbitraryFunction LateralViewColumnAliases                                -> { lateralView: { udtf: $4, columnAliases: $5 }}
+ ;
+
+LateralView_EDIT
+ : '<hive>LATERAL' '<hive>VIEW' OptionalOuter ArbitraryFunction_EDIT
+ | '<hive>LATERAL' '<hive>VIEW' OptionalOuter ArbitraryFunction_EDIT RegularOrBacktickedIdentifier
+ | '<hive>LATERAL' '<hive>VIEW' OptionalOuter ArbitraryFunction_EDIT RegularOrBacktickedIdentifier LateralViewColumnAliases
+ | '<hive>LATERAL' '<hive>VIEW' OptionalOuter ArbitraryFunction RegularOrBacktickedIdentifier LateralViewColumnAliases_EDIT
+ | '<hive>LATERAL' '<hive>VIEW' OptionalOuter ArbitraryFunction PartialBacktickedOrCursor
+ | '<hive>LATERAL' '<hive>VIEW' OptionalOuter ArbitraryFunction PartialBacktickedOrCursor LateralViewColumnAliases
+ | '<hive>LATERAL' '<hive>VIEW' OptionalOuter 'CURSOR'
+   {
+     if (!$3) {
+       parser.suggestKeywords([{ value: 'OUTER', weight: 2 }, { value: 'explode', weight: 1 }, { value: 'posexplode', weight: 1 }]);
+     } else {
+       parser.suggestKeywords(['explode', 'posexplode']);
+     }
+   }
+ | '<hive>LATERAL' 'CURSOR'
+   {
+     parser.suggestKeywords(['VIEW']);
+   }
+ ;
+
+OptionalOuter
+ :
+ | 'OUTER'
+ ;
+
+LateralViewColumnAliases
+ : '<hive>AS' RegularOrBacktickedIdentifier                                    -> [ $2 ]
+ | '<hive>AS' RegularOrBacktickedIdentifier ',' RegularOrBacktickedIdentifier  -> [ $2, $4 ]
+ ;
+
+LateralViewColumnAliases_EDIT
+ : '<hive>AS' PartialBacktickedOrCursor
+ | '<hive>AS' RegularOrBacktickedIdentifier ',' PartialBacktickedOrAnyCursor
+ ;

+ 67 - 0
desktop/core/src/desktop/js/parse/jison/impala/sql_set.jison

@@ -0,0 +1,67 @@
+// Licensed to Cloudera, Inc. under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  Cloudera, Inc. licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+DataDefinition
+ : SetRoleStatement
+ | SetSpecification
+ ;
+
+DataDefinition_EDIT
+ : SetRoleStatement_EDIT
+ | 'SET' 'CURSOR'
+   {
+     parser.suggestSetOptions();
+     if (parser.isHive()) {
+       parser.suggestKeywords(['ROLE']);
+     }
+     if (parser.isImpala()) {
+       parser.suggestKeywords(['ALL']);
+     }
+   }
+ ;
+
+SetSpecification
+ : 'SET' SetOption '=' SetValue
+ | 'SET' 'ALL'
+ ;
+
+SetOption
+ : RegularIdentifier
+ | SetOption AnyDot RegularIdentifier
+ ;
+
+SetValue
+ : RegularIdentifier
+ | SignedInteger
+ | SignedInteger RegularIdentifier
+ | QuotedValue
+ | 'TRUE'
+ | 'FALSE'
+ | 'NULL'
+ ;
+
+SetRoleStatement
+ : 'SET' '<hive>ROLE' RegularIdentifier
+ | 'SET' '<hive>ROLE' '<hive>ALL'
+ | 'SET' '<hive>ROLE' '<hive>NONE'
+ ;
+
+SetRoleStatement_EDIT
+ : 'SET' '<hive>ROLE' 'CURSOR'
+   {
+     parser.suggestKeywords(['ALL', 'NONE']);
+   }
+ ;

+ 741 - 0
desktop/core/src/desktop/js/parse/jison/impala/sql_show.jison

@@ -0,0 +1,741 @@
+// Licensed to Cloudera, Inc. under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  Cloudera, Inc. licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+DataDefinition
+ : ShowStatement
+ ;
+
+DataDefinition_EDIT
+ : ShowStatement_EDIT
+ ;
+
+ShowStatement
+ : ShowColumnStatsStatement
+ | ShowColumnsStatement
+ | ShowCompactionsStatement
+ | ShowConfStatement
+ | ShowCreateTableStatement
+ | ShowCurrentRolesStatement
+ | ShowDatabasesStatement
+ | ShowFilesStatement
+ | ShowFunctionsStatement
+ | ShowGrantStatement
+ | ShowIndexStatement
+ | ShowLocksStatement
+ | ShowPartitionsStatement
+ | ShowRoleStatement
+ | ShowRolesStatement
+ | ShowTableStatement
+ | ShowTablesStatement
+ | ShowTblPropertiesStatement
+ | ShowTransactionsStatement
+ | ShowViewsStatement
+ ;
+
+AnyShow
+ : 'SHOW'
+ | '<hive>SHOW'
+ ;
+
+ShowStatement_EDIT
+ : AnyShow 'CURSOR'
+   {
+     if (parser.isHive()) {
+       parser.suggestKeywords(['COLUMNS', 'COMPACTIONS', 'CONF', 'CREATE TABLE', 'CURRENT ROLES', 'DATABASES', 'FORMATTED', 'FUNCTIONS', 'GRANT', 'INDEX', 'INDEXES', 'LOCKS', 'PARTITIONS', 'PRINCIPALS', 'ROLE GRANT', 'ROLES', 'SCHEMAS', 'TABLE EXTENDED', 'TABLES', 'TBLPROPERTIES', 'TRANSACTIONS', 'VIEWS']);
+     } else if (parser.isImpala()) {
+       parser.suggestKeywords(['AGGREGATE FUNCTIONS', 'ANALYTIC FUNCTIONS', 'COLUMN STATS', 'CREATE TABLE', 'CURRENT ROLES', 'CREATE VIEW', 'DATABASES', 'FILES IN', 'FUNCTIONS', 'GRANT ROLE', 'GRANT USER', 'PARTITIONS', 'RANGE PARTITIONS', 'ROLE GRANT GROUP', 'ROLES', 'SCHEMAS', 'TABLE STATS', 'TABLES']);
+     } else {
+       parser.suggestKeywords(['COLUMNS', 'DATABASES', 'TABLES']);
+     }
+   }
+ | AnyShow 'CURSOR' RegularOrBackTickedSchemaQualifiedName
+   {
+     // ROLES is considered a non-reserved keywords so we can't match it in ShowCurrentRolesStatement_EDIT
+     if (!parser.isImpala() && $3.identifierChain && $3.identifierChain.length === 1 && $3.identifierChain[0].name.toLowerCase() === 'roles') {
+       parser.suggestKeywords(['CURRENT']);
+       parser.yy.locations.pop();
+     } else {
+       parser.addTablePrimary($3);
+       if (parser.isImpala()) {
+         parser.suggestKeywords(['COLUMN STATS', 'CREATE TABLE', 'CREATE VIEW', 'FILES IN', 'PARTITIONS', 'RANGE PARTITIONS', 'TABLE STATS']);
+       }
+     }
+   }
+ | AnyShow 'CURSOR' LIKE SingleQuotedValue
+   {
+     if (parser.isImpala()) {
+       parser.suggestKeywords(['AGGREGATE FUNCTIONS', 'ANALYTIC FUNCTIONS', 'DATABASES', 'FUNCTIONS', 'SCHEMAS', 'TABLES']);
+     } else if (parser.isHive()) {
+       parser.suggestKeywords(['DATABASES', 'SCHEMAS', 'TABLE EXTENDED']);
+     }
+   }
+ | ShowColumnStatsStatement_EDIT
+ | ShowColumnsStatement_EDIT
+ | ShowCreateTableStatement_EDIT
+ | ShowCurrentRolesStatement_EDIT
+ | ShowDatabasesStatement_EDIT
+ | ShowFilesStatement_EDIT
+ | ShowFunctionsStatement_EDIT
+ | ShowGrantStatement_EDIT
+ | ShowIndexStatement_EDIT
+ | ShowLocksStatement_EDIT
+ | ShowPartitionsStatement_EDIT
+ | ShowRoleStatement_EDIT
+ | ShowTableStatement_EDIT
+ | ShowTablesStatement_EDIT
+ | ShowTblPropertiesStatement_EDIT
+ | ShowViewsStatement_EDIT
+ ;
+
+ShowColumnStatsStatement
+ : AnyShow '<impala>COLUMN' '<impala>STATS' RegularOrBackTickedSchemaQualifiedName
+   {
+     parser.addTablePrimary($4);
+   }
+ ;
+
+ShowColumnStatsStatement_EDIT
+ : AnyShow '<impala>COLUMN' 'CURSOR'
+   {
+     parser.suggestKeywords(['STATS']);
+   }
+ | AnyShow '<impala>COLUMN' '<impala>STATS' 'CURSOR'
+   {
+     parser.suggestTables();
+     parser.suggestDatabases({
+       appendDot: true
+     });
+   }
+ | AnyShow '<impala>COLUMN' '<impala>STATS' RegularOrBackTickedSchemaQualifiedName_EDIT
+ ;
+
+ShowColumnsStatement
+ : AnyShow '<hive>COLUMNS' AnyFromOrIn RegularOrBacktickedIdentifier
+ | AnyShow '<hive>COLUMNS' AnyFromOrIn RegularOrBacktickedIdentifier AnyFromOrIn RegularOrBacktickedIdentifier
+ ;
+
+ShowColumnsStatement_EDIT
+ : AnyShow '<hive>COLUMNS' 'CURSOR'
+   {
+     parser.suggestKeywords(['FROM', 'IN']);
+   }
+ | AnyShow '<hive>COLUMNS' 'CURSOR' RegularOrBacktickedIdentifier
+   {
+     parser.suggestKeywords(['FROM', 'IN']);
+   }
+ | AnyShow '<hive>COLUMNS' AnyFromOrIn 'CURSOR'
+   {
+     parser.suggestTables();
+   }
+ | AnyShow '<hive>COLUMNS' AnyFromOrIn 'CURSOR' AnyFromOrIn
+   {
+     parser.suggestTables();
+   }
+ | AnyShow '<hive>COLUMNS' AnyFromOrIn 'CURSOR' AnyFromOrIn RegularOrBacktickedIdentifier
+   {
+     parser.suggestTables();
+   }
+ | AnyShow '<hive>COLUMNS' AnyFromOrIn RegularOrBacktickedIdentifier 'CURSOR'
+   {
+     parser.suggestKeywords(['FROM', 'IN']);
+   }
+ | AnyShow '<hive>COLUMNS' AnyFromOrIn RegularOrBacktickedIdentifier 'CURSOR' RegularOrBacktickedIdentifier
+   {
+     parser.suggestKeywords(['FROM', 'IN']);
+   }
+ | AnyShow '<hive>COLUMNS' AnyFromOrIn RegularOrBacktickedIdentifier AnyFromOrIn 'CURSOR'
+   {
+     parser.suggestDatabases();
+   }
+ ;
+
+ShowCompactionsStatement
+ : AnyShow '<hive>COMPACTIONS'
+ ;
+
+ShowConfStatement
+ : AnyShow '<hive>CONF' ConfigurationName
+ ;
+
+ShowCreateTableStatement
+ : AnyShow HiveOrImpalaCreate AnyTableOrView RegularOrBackTickedSchemaQualifiedName
+   {
+     parser.addTablePrimary($4);
+   }
+ ;
+
+ShowCreateTableStatement_EDIT
+ : AnyShow HiveOrImpalaCreate 'CURSOR'
+   {
+     if (parser.isImpala()) {
+       parser.suggestKeywords(['TABLE', 'VIEW']);
+     } else {
+       parser.suggestKeywords(['TABLE']);
+     }
+   }
+ | AnyShow HiveOrImpalaCreate AnyTableOrView 'CURSOR'
+   {
+     if ($3.isView && parser.isImpala()) {
+       parser.suggestTables({ onlyViews: true });
+     } else {
+       parser.suggestTables();
+     }
+     parser.suggestDatabases({
+       appendDot: true
+     });
+   }
+ | AnyShow HiveOrImpalaCreate AnyTableOrView RegularOrBackTickedSchemaQualifiedName_EDIT
+   {
+     if (parser.yy.result.suggestTables && $3.isView) {
+       parser.yy.result.suggestTables.onlyViews = true;
+     }
+   }
+ | AnyShow HiveOrImpalaCreate 'CURSOR' RegularOrBackTickedSchemaQualifiedName
+   {
+     parser.addTablePrimary($4);
+     if (parser.isImpala()) {
+       parser.suggestKeywords(['TABLE', 'VIEW']);
+     } else {
+       parser.suggestKeywords(['TABLE']);
+     }
+   }
+ ;
+
+AnyTableOrView
+ : AnyTable
+ | 'VIEW'   --> { isView: true }
+ ;
+
+ShowCurrentRolesStatement
+ : AnyShow '<hive>CURRENT' '<hive>ROLES'
+ | AnyShow '<impala>CURRENT' '<impala>ROLES'
+ ;
+
+ShowCurrentRolesStatement_EDIT
+ : AnyShow '<hive>CURRENT' 'CURSOR'
+   {
+     parser.suggestKeywords([ 'ROLES' ]);
+   }
+ | AnyShow '<impala>CURRENT' 'CURSOR'
+   {
+     parser.suggestKeywords([ 'ROLES' ]);
+   }
+ | AnyShow 'CURSOR' '<impala>ROLES'
+   {
+     parser.suggestKeywords([ 'CURRENT' ]);
+   }
+ ;
+
+ShowDatabasesStatement
+ : AnyShow HiveOrImpalaDatabasesOrSchemas 'LIKE' SingleQuotedValue
+ | AnyShow '<impala>DATABASES' SingleQuotedValue
+ ;
+
+ShowDatabasesStatement_EDIT
+ : AnyShow HiveOrImpalaDatabasesOrSchemas 'CURSOR'
+   {
+     parser.suggestKeywords(['LIKE']);
+   }
+ ;
+
+ShowFilesStatement
+ : AnyShow '<impala>FILES' 'IN' RegularOrBackTickedSchemaQualifiedName OptionalPartitionSpec
+   {
+     parser.addTablePrimary($4);
+   }
+ ;
+
+ShowFilesStatement_EDIT
+ : AnyShow '<impala>FILES' 'CURSOR'
+   {
+     parser.suggestKeywords(['IN']);
+   }
+ | AnyShow '<impala>FILES' 'IN' 'CURSOR'
+   {
+     parser.suggestTables();
+     parser.suggestDatabases({
+       appendDot: true
+     });
+   }
+ | AnyShow '<impala>FILES' 'IN' RegularOrBackTickedSchemaQualifiedName_EDIT OptionalPartitionSpec
+ | AnyShow '<impala>FILES' 'IN' RegularOrBackTickedSchemaQualifiedName OptionalPartitionSpec 'CURSOR'
+   {
+     parser.addTablePrimary($4);
+     if (!$5) {
+       parser.suggestKeywords(['PARTITION']);
+     }
+   }
+ | AnyShow '<impala>FILES' 'IN' RegularOrBackTickedSchemaQualifiedName OptionalPartitionSpec_EDIT
+ | AnyShow '<impala>FILES' 'CURSOR' RegularOrBackTickedSchemaQualifiedName OptionalPartitionSpec
+   {
+     parser.addTablePrimary($4);
+     parser.suggestKeywords(['IN']);
+   }
+ ;
+
+ShowFunctionsStatement
+ : AnyShow '<hive>FUNCTIONS'
+ | AnyShow '<hive>FUNCTIONS' DoubleQuotedValue
+ | AnyShow OptionalAggregateOrAnalytic '<impala>FUNCTIONS' OptionalInDatabase
+ | AnyShow OptionalAggregateOrAnalytic '<impala>FUNCTIONS' OptionalInDatabase 'LIKE' QuotedValue
+ ;
+
+ShowFunctionsStatement_EDIT
+ : AnyShow AggregateOrAnalytic 'CURSOR'
+   {
+     parser.suggestKeywords(['FUNCTIONS']);
+   }
+ | AnyShow 'CURSOR' '<impala>FUNCTIONS' OptionalInDatabase
+   {
+     parser.suggestKeywords(['AGGREGATE', 'ANALYTICAL']);
+   }
+ | AnyShow OptionalAggregateOrAnalytic '<impala>FUNCTIONS' OptionalInDatabase 'CURSOR'
+   {
+     if (!$4) {
+       parser.suggestKeywords(['IN', 'LIKE']);
+     } else {
+       parser.suggestKeywords(['LIKE']);
+     }
+   }
+ | AnyShow AggregateOrAnalytic 'CURSOR' OptionalInDatabase 'LIKE' QuotedValue
+   {
+     parser.suggestKeywords(['FUNCTIONS']);
+   }
+ | AnyShow 'CURSOR' '<impala>FUNCTIONS' OptionalInDatabase 'LIKE' QuotedValue
+   {
+     parser.suggestKeywords(['AGGREGATE', 'ANALYTICAL']);
+   }
+ | AnyShow OptionalAggregateOrAnalytic '<impala>FUNCTIONS' OptionalInDatabase 'CURSOR' QuotedValue
+   {
+     if (!$4) {
+       parser.suggestKeywords([{ value: 'IN', weight: 2 }, { value: 'LIKE', weight: 1 }]);
+     } else {
+       parser.suggestKeywords(['LIKE']);
+     }
+   }
+ ;
+
+ShowGrantStatement
+ : AnyShow '<hive>GRANT' OptionalPrincipalName
+ | AnyShow '<hive>GRANT' OptionalPrincipalName 'ON' '<hive>ALL'
+ | AnyShow '<hive>GRANT' OptionalPrincipalName 'ON' SchemaQualifiedTableIdentifier
+ | AnyShow '<hive>GRANT' OptionalPrincipalName 'ON' AnyTable SchemaQualifiedTableIdentifier
+ | AnyShow '<impala>GRANT' RoleOrUser RegularOrBacktickedIdentifier
+ | AnyShow '<impala>GRANT' RoleOrUser RegularOrBacktickedIdentifier 'ON' 'DATABASE' RegularOrBacktickedIdentifier
+   {
+     parser.addDatabaseLocation(@7, [ { name: $7 } ]);
+   }
+ | AnyShow '<impala>GRANT' RoleOrUser RegularOrBacktickedIdentifier 'ON' '<impala>SERVER'
+ | AnyShow '<impala>GRANT' RoleOrUser RegularOrBacktickedIdentifier 'ON' '<impala>TABLE' SchemaQualifiedTableIdentifier
+ | AnyShow '<impala>GRANT' RoleOrUser RegularOrBacktickedIdentifier 'ON' '<impala>URI' RegularOrBacktickedIdentifier
+ ;
+
+ShowGrantStatement_EDIT
+ : AnyShow '<hive>GRANT' OptionalPrincipalName_EDIT
+   {
+     parser.suggestKeywords(['ON']);
+   }
+ | AnyShow '<hive>GRANT' OptionalPrincipalName_EDIT 'ON' '<hive>ALL'
+ | AnyShow '<hive>GRANT' OptionalPrincipalName 'ON' 'CURSOR'
+   {
+     parser.suggestKeywords(['ALL', 'TABLE']);
+     parser.suggestTables();
+   }
+ | AnyShow '<hive>GRANT' OptionalPrincipalName 'ON' SchemaQualifiedTableIdentifier_EDIT
+ | AnyShow  '<hive>GRANT' OptionalPrincipalName 'ON' AnyTable 'CURSOR'
+   {
+     parser.suggestTables();
+   }
+ | AnyShow '<hive>GRANT' OptionalPrincipalName 'ON' 'CURSOR' SchemaQualifiedTableIdentifier
+   {
+     parser.suggestKeywords(['TABLE']);
+   }
+ | AnyShow '<hive>GRANT' OptionalPrincipalName 'ON' 'CURSOR' SchemaQualifiedTableIdentifier_EDIT
+ | AnyShow '<impala>GRANT' 'CURSOR'
+   {
+     parser.suggestKeywords(['ROLE', 'USER']);
+   }
+ | AnyShow '<impala>GRANT' RoleOrUser 'CURSOR'
+ | AnyShow '<impala>GRANT' RoleOrUser RegularOrBacktickedIdentifier 'CURSOR'
+   {
+     parser.suggestKeywords(['ON DATABASE', 'ON SERVER', 'ON TABLE', 'ON URI']);
+   }
+ | AnyShow '<impala>GRANT' RoleOrUser RegularOrBacktickedIdentifier 'ON' 'CURSOR'
+   {
+     parser.suggestKeywords(['DATABASE', 'SERVER', 'TABLE', 'URI']);
+   }
+ | AnyShow '<impala>GRANT' RoleOrUser RegularOrBacktickedIdentifier 'ON' 'DATABASE' 'CURSOR'
+   {
+     parser.suggestDatabases();
+   }
+ | AnyShow '<impala>GRANT' RoleOrUser RegularOrBacktickedIdentifier 'ON' '<impala>TABLE' 'CURSOR'
+   {
+     parser.suggestDatabases({
+       appendDot: true
+     });
+     parser.suggestTables();
+   }
+ | AnyShow '<impala>GRANT' RoleOrUser RegularOrBacktickedIdentifier 'ON' '<impala>TABLE' SchemaQualifiedTableIdentifier_EDIT
+ | AnyShow '<impala>GRANT' RoleOrUser RegularOrBacktickedIdentifier 'ON' '<impala>URI' 'CURSOR'
+ ;
+
+OptionalPrincipalName
+ :
+ | RegularIdentifier
+ ;
+
+OptionalPrincipalName_EDIT
+ : 'CURSOR'
+ | RegularIdentifier 'CURSOR'
+ ;
+
+ShowIndexStatement
+ : AnyShow OptionallyFormattedIndex 'ON' RegularOrBacktickedIdentifier
+ | AnyShow OptionallyFormattedIndex 'ON' RegularOrBacktickedIdentifier AnyFromOrIn RegularOrBacktickedIdentifier
+ ;
+
+ShowIndexStatement_EDIT
+ : AnyShow OptionallyFormattedIndex
+ | AnyShow OptionallyFormattedIndex_EDIT
+ | AnyShow OptionallyFormattedIndex_EDIT 'ON' RegularOrBacktickedIdentifier
+ | AnyShow OptionallyFormattedIndex_EDIT 'ON' RegularOrBacktickedIdentifier AnyFromOrIn RegularOrBacktickedIdentifier
+ | AnyShow OptionallyFormattedIndex 'CURSOR'
+   {
+     parser.suggestKeywords(['ON']);
+   }
+ | AnyShow OptionallyFormattedIndex 'ON' 'CURSOR'
+   {
+     parser.suggestTables();
+   }
+ | AnyShow OptionallyFormattedIndex 'CURSOR' RegularOrBacktickedIdentifier
+   {
+     parser.suggestKeywords(['ON']);
+   }
+ | AnyShow OptionallyFormattedIndex 'ON' RegularOrBacktickedIdentifier 'CURSOR'
+   {
+     parser.suggestKeywords(['FROM', 'IN']);
+   }
+ | AnyShow OptionallyFormattedIndex 'ON' RegularOrBacktickedIdentifier 'CURSOR' RegularOrBacktickedIdentifier
+   {
+     parser.suggestKeywords(['FROM', 'IN']);
+   }
+ | AnyShow OptionallyFormattedIndex 'ON' RegularOrBacktickedIdentifier AnyFromOrIn 'CURSOR'
+   {
+     parser.suggestDatabases();
+   }
+ | AnyShow OptionallyFormattedIndex 'ON' 'CURSOR' AnyFromOrIn RegularOrBacktickedIdentifier
+   {
+     parser.suggestTables({identifierChain: [{name: $6}]});
+   }
+ ;
+
+ShowLocksStatement
+ : AnyShow '<hive>LOCKS' RegularOrBackTickedSchemaQualifiedName
+   {
+     parser.addTablePrimary($3);
+   }
+ | AnyShow '<hive>LOCKS' RegularOrBackTickedSchemaQualifiedName '<hive>EXTENDED'
+   {
+     parser.addTablePrimary($3);
+   }
+ | AnyShow '<hive>LOCKS' RegularOrBackTickedSchemaQualifiedName PartitionSpec
+   {
+     parser.addTablePrimary($3);
+   }
+ | AnyShow '<hive>LOCKS' RegularOrBackTickedSchemaQualifiedName PartitionSpec '<hive>EXTENDED'
+   {
+     parser.addTablePrimary($3);
+   }
+ | AnyShow '<hive>LOCKS' DatabaseOrSchema RegularOrBacktickedIdentifier
+ ;
+
+ShowLocksStatement_EDIT
+ : AnyShow '<hive>LOCKS' 'CURSOR'
+   {
+     parser.suggestTables();
+     parser.suggestDatabases({
+       appendDot: true
+     });
+     parser.suggestKeywords(['DATABASE', 'SCHEMA']);
+   }
+ | AnyShow '<hive>LOCKS' RegularOrBackTickedSchemaQualifiedName_EDIT
+ | AnyShow '<hive>LOCKS' RegularOrBackTickedSchemaQualifiedName 'CURSOR'
+    {
+      parser.addTablePrimary($3);
+      parser.suggestKeywords(['EXTENDED', 'PARTITION']);
+    }
+ | AnyShow '<hive>LOCKS' RegularOrBackTickedSchemaQualifiedName_EDIT '<hive>EXTENDED'
+ | AnyShow '<hive>LOCKS' RegularOrBackTickedSchemaQualifiedName_EDIT PartitionSpec
+ | AnyShow '<hive>LOCKS' RegularOrBackTickedSchemaQualifiedName PartitionSpec 'CURSOR'
+   {
+     parser.addTablePrimary($3);
+     parser.suggestKeywords(['EXTENDED']);
+   }
+ | AnyShow '<hive>LOCKS' RegularOrBackTickedSchemaQualifiedName_EDIT PartitionSpec '<hive>EXTENDED'
+ | AnyShow '<hive>LOCKS' DatabaseOrSchema 'CURSOR'
+   {
+     parser.suggestDatabases();
+   }
+ ;
+
+ShowPartitionsStatement
+ : AnyShow '<hive>PARTITIONS' RegularOrBackTickedSchemaQualifiedName
+   {
+     parser.addTablePrimary($3);
+   }
+ | AnyShow '<hive>PARTITIONS' RegularOrBackTickedSchemaQualifiedName PartitionSpec
+   {
+     parser.addTablePrimary($3);
+   }
+ | AnyShow '<impala>PARTITIONS' RegularOrBackTickedSchemaQualifiedName
+   {
+     parser.addTablePrimary($3);
+   }
+ | AnyShow '<impala>RANGE' '<impala>PARTITIONS' RegularOrBackTickedSchemaQualifiedName
+   {
+     parser.addTablePrimary($3);
+   }
+ ;
+
+ShowPartitionsStatement_EDIT
+ : AnyShow '<hive>PARTITIONS' 'CURSOR'
+   {
+     parser.suggestTables();
+     parser.suggestDatabases({
+       appendDot: true
+     });
+   }
+ | AnyShow '<hive>PARTITIONS' RegularOrBackTickedSchemaQualifiedName_EDIT
+ | AnyShow '<hive>PARTITIONS' RegularOrBackTickedSchemaQualifiedName 'CURSOR'
+   {
+     parser.addTablePrimary($3);
+     parser.suggestKeywords(['PARTITION']);
+   }
+ | AnyShow '<hive>PARTITIONS' RegularOrBackTickedSchemaQualifiedName_EDIT PartitionSpec
+ | AnyShow '<impala>PARTITIONS' 'CURSOR'
+   {
+     parser.suggestTables();
+     parser.suggestDatabases({
+       appendDot: true
+     });
+   }
+ | AnyShow '<impala>PARTITIONS' RegularOrBackTickedSchemaQualifiedName_EDIT
+ | AnyShow '<impala>RANGE' '<impala>PARTITIONS' 'CURSOR'
+   {
+     parser.suggestTables();
+     parser.suggestDatabases({
+       appendDot: true
+     });
+   }
+ | AnyShow '<impala>RANGE' '<impala>PARTITIONS' RegularOrBackTickedSchemaQualifiedName_EDIT
+ ;
+
+ShowRoleStatement
+ : AnyShow '<hive>ROLE' '<hive>GRANT' HiveRoleOrUser RegularIdentifier
+ | AnyShow '<impala>ROLE' '<impala>GRANT' '<impala>GROUP' RegularIdentifier
+ ;
+
+ShowRoleStatement_EDIT
+ : AnyShow '<hive>ROLE' 'CURSOR'
+   {
+     parser.suggestKeywords(['GRANT']);
+   }
+ | AnyShow '<impala>ROLE' 'CURSOR'
+   {
+     parser.suggestKeywords(['GRANT']);
+   }
+ | AnyShow '<hive>ROLE' 'CURSOR' HiveRoleOrUser RegularIdentifier
+   {
+     parser.suggestKeywords(['GRANT']);
+   }
+ | AnyShow '<hive>ROLE' '<hive>GRANT' 'CURSOR'
+   {
+     parser.suggestKeywords(['ROLE', 'USER']);
+   }
+ | AnyShow '<hive>ROLE' '<hive>GRANT' 'CURSOR' RegularIdentifier
+   {
+     parser.suggestKeywords(['ROLE', 'USER']);
+   }
+ | AnyShow '<impala>ROLE' '<impala>GRANT' 'CURSOR'
+   {
+     parser.suggestKeywords(['GROUP']);
+   }
+ | AnyShow '<impala>ROLE' '<impala>GRANT' 'CURSOR' RegularIdentifier
+   {
+     parser.suggestKeywords(['GROUP']);
+   }
+ ;
+
+ShowRolesStatement
+ : AnyShow '<impala>ROLES'
+ | AnyShow '<hive>ROLES'
+ ;
+
+ShowTableStatement
+ : AnyShow '<hive>TABLE' '<hive>EXTENDED' OptionalFromDatabase 'LIKE' SingleQuotedValue
+ | AnyShow '<hive>TABLE' '<hive>EXTENDED' OptionalFromDatabase 'LIKE' SingleQuotedValue PartitionSpec
+ ;
+
+ShowTableStatement_EDIT
+ : AnyShow '<hive>TABLE' 'CURSOR'
+   {
+     parser.suggestKeywords(['EXTENDED']);
+   }
+ | AnyShow '<hive>TABLE' '<hive>EXTENDED' OptionalFromDatabase
+ | AnyShow '<hive>TABLE' '<hive>EXTENDED' OptionalFromDatabase_EDIT
+ | AnyShow '<hive>TABLE' '<hive>EXTENDED' OptionalFromDatabase 'CURSOR'
+    {
+      if ($4) {
+        parser.suggestKeywords(['LIKE']);
+      } else {
+        parser.suggestKeywords(['FROM', 'IN', 'LIKE']);
+      }
+    }
+ | AnyShow '<hive>TABLE' '<hive>EXTENDED' OptionalFromDatabase_EDIT 'LIKE' SingleQuotedValue
+ | AnyShow '<hive>TABLE' 'CURSOR' OptionalFromDatabase 'LIKE' SingleQuotedValue
+    {
+      if (parser.isHive()) {
+        parser.suggestKeywords(['EXTENDED']);
+      }
+    }
+ | AnyShow '<hive>TABLE' '<hive>EXTENDED' OptionalFromDatabase 'CURSOR' SingleQuotedValue
+    {
+      parser.suggestKeywords(['LIKE']);
+    }
+ | AnyShow '<hive>TABLE' '<hive>EXTENDED' OptionalFromDatabase 'LIKE' SingleQuotedValue 'CURSOR'
+    {
+      parser.suggestKeywords(['PARTITION']);
+    }
+ | AnyShow '<hive>TABLE' '<hive>EXTENDED' OptionalFromDatabase_EDIT 'LIKE' SingleQuotedValue PartitionSpec
+ | AnyShow '<hive>TABLE' 'CURSOR' OptionalFromDatabase 'LIKE' SingleQuotedValue PartitionSpec
+   {
+     parser.suggestKeywords(['EXTENDED']);
+   }
+ | AnyShow '<hive>TABLE' '<hive>EXTENDED' OptionalFromDatabase 'CURSOR' SingleQuotedValue PartitionSpec
+   {
+     parser.suggestKeywords(['LIKE']);
+   }
+ | AnyShow '<hive>TABLE' '<hive>EXTENDED' OptionalFromDatabase 'LIKE' SingleQuotedValue 'CURSOR' PartitionSpecList
+   {
+     parser.suggestKeywords(['PARTITION']);
+   }
+ | AnyShow '<impala>TABLE' 'CURSOR'
+   {
+     parser.suggestKeywords(['STATS']);
+   }
+ | AnyShow '<impala>TABLE' '<impala>STATS' 'CURSOR'
+   {
+     parser.suggestTables();
+     parser.suggestDatabases({
+       appendDot: true
+     });
+   }
+ | AnyShow '<impala>TABLE' '<impala>STATS' RegularOrBackTickedSchemaQualifiedName
+    {
+      parser.addTablePrimary($4);
+    }
+ | AnyShow '<impala>TABLE' '<impala>STATS' RegularOrBackTickedSchemaQualifiedName_EDIT
+ ;
+
+ShowTablesStatement
+ : AnyShow HiveOrImpalaTables OptionalInDatabase
+ | AnyShow HiveOrImpalaTables OptionalInDatabase SingleQuotedValue
+ | AnyShow HiveOrImpalaTables OptionalInDatabase 'LIKE' SingleQuotedValue
+ ;
+
+ShowTablesStatement_EDIT
+ : AnyShow HiveOrImpalaTables OptionalInDatabase 'CURSOR'
+   {
+     if (!$3) {
+       parser.suggestKeywords(['IN', 'LIKE']);
+     } else {
+       parser.suggestKeywords(['LIKE']);
+     }
+   }
+ ;
+
+ShowTblPropertiesStatement
+ : AnyShow '<hive>TBLPROPERTIES' RegularOrBackTickedSchemaQualifiedName
+   {
+     parser.addTablePrimary($3);
+   }
+ | AnyShow '<hive>TBLPROPERTIES' RegularOrBackTickedSchemaQualifiedName '(' QuotedValue ')'
+   {
+     parser.addTablePrimary($3);
+   }
+ ;
+
+ShowTblPropertiesStatement_EDIT
+ : AnyShow '<hive>TBLPROPERTIES' RegularOrBackTickedSchemaQualifiedName_EDIT
+ | AnyShow '<hive>TBLPROPERTIES' 'CURSOR'
+   {
+     parser.suggestTables();
+     parser.suggestDatabases({ prependDot: true });
+   }
+ ;
+
+ShowTransactionsStatement
+ : AnyShow '<hive>TRANSACTIONS'
+ ;
+
+ShowViewsStatement
+ : AnyShow '<hive>VIEWS' OptionalInOrFromDatabase OptionalLike
+ ;
+
+ShowViewsStatement_EDIT
+ : AnyShow '<hive>VIEWS' OptionalInOrFromDatabase OptionalLike 'CURSOR'
+   {
+     if (!$4 && !$3) {
+       parser.suggestKeywords([{ value: 'IN', weight: 2 }, { value: 'FROM', weight: 2 }, { value: 'LIKE', weight: 1 }]);
+     } else if (!$4) {
+       parser.suggestKeywords(['LIKE']);
+     }
+   }
+ | AnyShow '<hive>VIEWS' InOrFromDatabase_EDIT OptionalLike
+ | AnyShow '<hive>VIEWS' OptionalInOrFromDatabase Like_EDIT
+ ;
+
+OptionalInOrFromDatabase
+ :
+ | 'IN' RegularOrBacktickedIdentifier
+   {
+     parser.addDatabaseLocation(@2, [ { name: $2 } ]);
+   }
+ | 'FROM' RegularOrBacktickedIdentifier
+   {
+     parser.addDatabaseLocation(@2, [ { name: $2 } ]);
+   }
+ ;
+
+InOrFromDatabase_EDIT
+ : 'IN' 'CURSOR'
+   {
+     parser.suggestDatabases();
+   }
+ | 'FROM' 'CURSOR'
+   {
+     parser.suggestDatabases();
+   }
+ ;
+
+OptionalLike
+ :
+ | 'LIKE' SingleQuotedValue
+ ;
+
+Like_EDIT
+ : 'LIKE' 'CURSOR'
+ ;

+ 138 - 0
desktop/core/src/desktop/js/parse/jison/impala/sql_update.jison

@@ -0,0 +1,138 @@
+// Licensed to Cloudera, Inc. under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  Cloudera, Inc. licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+DataManipulation
+ : UpdateStatement
+ ;
+
+DataManipulation_EDIT
+ : UpdateStatement_EDIT
+ ;
+
+UpdateStatement
+ : 'UPDATE' TargetTable 'SET' SetClauseList OptionalFromJoinedTable OptionalWhereClause
+ ;
+
+UpdateStatement_EDIT
+ : 'UPDATE' TargetTable_EDIT 'SET' SetClauseList OptionalFromJoinedTable OptionalWhereClause
+ | 'UPDATE' TargetTable 'SET' SetClauseList_EDIT OptionalFromJoinedTable OptionalWhereClause
+ | 'UPDATE' TargetTable 'SET' SetClauseList FromJoinedTable_EDIT OptionalWhereClause
+ | 'UPDATE' TargetTable 'SET' SetClauseList OptionalFromJoinedTable WhereClause_EDIT
+ | 'UPDATE' TargetTable 'SET' SetClauseList OptionalFromJoinedTable OptionalWhereClause 'CURSOR'
+   {
+     if (parser.isImpala() && !$6 && !$5) {
+       parser.suggestKeywords([{ value: 'FROM', weight: 2 }, { value: 'WHERE', weight: 1 }]);
+     } else if (parser.isImpala() && !$6 && $5) {
+       var keywords = [{ value: 'FULL JOIN', weight: 2 }, { value: 'FULL OUTER JOIN', weight: 2 }, { value: 'JOIN', weight: 2 }, { value: 'LEFT JOIN', weight: 2 }, { value: 'LEFT OUTER JOIN', weight: 2 }, { value: 'RIGHT JOIN', weight: 2 }, { value: 'RIGHT OUTER JOIN', weight: 2 }, { value: 'INNER JOIN', weight: 2 },  { value: 'LEFT ANTI JOIN', weight: 2 }, { value: 'LEFT SEMI JOIN', weight: 2 }, { value: 'RIGHT ANTI JOIN', weight: 2 }, { value: 'RIGHT SEMI JOIN', weight: 2 }, { value: 'WHERE', weight: 1 }];
+       if ($5.suggestJoinConditions) {
+         parser.suggestJoinConditions($5.suggestJoinConditions);
+       }
+       if ($5.suggestJoins) {
+         parser.suggestJoins($5.suggestJoins);
+       }
+       if ($5.suggestKeywords) {
+         keywords = keywords.concat(parser.createWeightedKeywords($5.suggestKeywords, 3));
+       }
+       parser.suggestKeywords(keywords);
+     } else if (!$6) {
+       parser.suggestKeywords([ 'WHERE' ]);
+     }
+   }
+ | 'UPDATE' TargetTable 'CURSOR'
+   {
+     parser.suggestKeywords([ 'SET' ]);
+   }
+ | 'UPDATE' TargetTable_EDIT
+ | 'UPDATE' TargetTable
+ | 'UPDATE' 'CURSOR'
+   {
+     parser.suggestTables();
+     parser.suggestDatabases({ appendDot: true });
+   }
+ ;
+
+TargetTable
+ : TableName
+ ;
+
+TargetTable_EDIT
+ : TableName_EDIT
+ ;
+
+TableName
+ : LocalOrSchemaQualifiedName
+   {
+     parser.addTablePrimary($1);
+   }
+ ;
+
+TableName_EDIT
+ : LocalOrSchemaQualifiedName_EDIT
+ ;
+
+SetClauseList
+ : SetClause
+ | SetClauseList ',' SetClause
+ ;
+
+SetClauseList_EDIT
+ : SetClause_EDIT
+ | SetClauseList ',' SetClause_EDIT
+ | SetClause_EDIT ',' SetClauseList
+ | SetClauseList ',' SetClause_EDIT ',' SetClauseList
+ ;
+
+SetClause
+ : SetTarget '=' UpdateSource
+ ;
+
+SetClause_EDIT
+ : SetTarget '=' UpdateSource_EDIT
+ | SetTarget 'CURSOR'
+   {
+     parser.suggestKeywords([ '=' ]);
+   }
+ | 'CURSOR'
+   {
+     parser.suggestColumns();
+   }
+ ;
+
+SetTarget
+ : ColumnReference
+ ;
+
+UpdateSource
+ : ValueExpression
+ ;
+
+UpdateSource_EDIT
+ : ValueExpression_EDIT
+ ;
+
+OptionalFromJoinedTable
+ :
+ | 'FROM' TableReference  -> $2
+ ;
+
+FromJoinedTable_EDIT
+ : 'FROM' 'CURSOR'
+   {
+     parser.suggestTables();
+     parser.suggestDatabases({ appendDot: true });
+   }
+ | 'FROM' TableReference_EDIT
+ ;

+ 47 - 0
desktop/core/src/desktop/js/parse/jison/impala/sql_use.jison

@@ -0,0 +1,47 @@
+// Licensed to Cloudera, Inc. under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  Cloudera, Inc. licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+DataDefinition
+ : UseStatement
+ ;
+
+DataDefinition_EDIT
+ : UseStatement_EDIT
+ ;
+
+AnyUse
+ : 'USE'
+ | '<hive>USE'
+ ;
+
+UseStatement
+ : AnyUse RegularIdentifier
+   {
+     if (! parser.yy.cursorFound) {
+       parser.yy.result.useDatabase = $2;
+     }
+   }
+ ;
+
+UseStatement_EDIT
+ : AnyUse 'CURSOR'
+   {
+     parser.suggestDatabases();
+   }
+ ;
+
+
+// ===================================== Fin =====================================

+ 867 - 0
desktop/core/src/desktop/js/parse/jison/impala/sql_valueExpression.jison

@@ -0,0 +1,867 @@
+// Licensed to Cloudera, Inc. under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  Cloudera, Inc. licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+ValueExpression
+ : 'NOT' ValueExpression
+   {
+     // verifyType($2, 'BOOLEAN');
+     $$ = { types: [ 'BOOLEAN' ] };
+   }
+ | '!' ValueExpression
+   {
+     // verifyType($2, 'BOOLEAN');
+     $$ = { types: [ 'BOOLEAN' ] };
+   }
+ | '~' ValueExpression                                                 -> $2
+ | '-' ValueExpression %prec NEGATION
+   {
+     // verifyType($2, 'NUMBER');
+     $$ = $2;
+     $2.types = ['NUMBER'];
+   }
+ | ValueExpression 'IS' OptionalNot 'NULL'                             -> { types: [ 'BOOLEAN' ] }
+ | ValueExpression 'IS' OptionalNot 'TRUE'                             -> { types: [ 'BOOLEAN' ] }
+ | ValueExpression 'IS' OptionalNot 'FALSE'                            -> { types: [ 'BOOLEAN' ] }
+ | ValueExpression 'IS' OptionalNot '<impala>UNKNOWN'                  -> { types: [ 'BOOLEAN' ] }
+ | ValueExpression 'IS' OptionalNot 'DISTINCT' 'FROM' ValueExpression  -> { types: [ 'BOOLEAN' ] }
+ ;
+
+ValueExpression_EDIT
+ : 'NOT' ValueExpression_EDIT                           -> { types: [ 'BOOLEAN' ], suggestFilters: $2.suggestFilters }
+ | 'NOT' 'CURSOR'
+   {
+     parser.suggestFunctions();
+     parser.suggestColumns();
+     parser.suggestKeywords(['EXISTS']);
+     $$ = { types: [ 'BOOLEAN' ] };
+   }
+ | '!' ValueExpression_EDIT                             -> { types: [ 'BOOLEAN' ], suggestFilters: $2.suggestFilters }
+ | '!' AnyCursor
+   {
+     parser.suggestFunctions({ types: [ 'BOOLEAN' ] });
+     parser.suggestColumns({ types: [ 'BOOLEAN' ] });
+     $$ = { types: [ 'BOOLEAN' ] };
+   }
+ | '~' ValueExpression_EDIT                             -> { types: [ 'T' ], suggestFilters: $2.suggestFilters }
+ | '~' 'PARTIAL_CURSOR'
+   {
+     parser.suggestFunctions();
+     parser.suggestColumns();
+     $$ = { types: [ 'T' ] };
+   }
+ | '-' ValueExpression_EDIT %prec NEGATION
+   {
+     if (!$2.typeSet) {
+       parser.applyTypeToSuggestions('NUMBER');
+     }
+     $$ = { types: [ 'NUMBER' ], suggestFilters: $2.suggestFilters };
+   }
+ | '-' 'PARTIAL_CURSOR' %prec NEGATION
+   {
+     parser.suggestFunctions({ types: [ 'NUMBER' ] });
+     parser.suggestColumns({ types: [ 'NUMBER' ] });
+     $$ = { types: [ 'NUMBER' ] };
+   }
+ | ValueExpression 'IS' 'CURSOR'
+   {
+     var keywords = ['FALSE', 'NOT NULL', 'NOT TRUE', 'NOT FALSE', 'NULL', 'TRUE'];
+     if (parser.isImpala()) {
+       keywords = keywords.concat(['DISTINCT FROM', 'NOT DISTINCT FROM', 'NOT UNKNOWN', 'UNKNOWN']);
+     }
+     parser.suggestKeywords(keywords);
+     $$ = { types: [ 'BOOLEAN' ] };
+   }
+ | ValueExpression 'IS' 'NOT' 'CURSOR'
+   {
+     var keywords = ['FALSE', 'NULL', 'TRUE'];
+     if (parser.isImpala()) {
+       keywords = keywords.concat(['DISTINCT FROM', 'UNKNOWN']);
+     }
+     parser.suggestKeywords(keywords);
+     $$ = { types: [ 'BOOLEAN' ] };
+   }
+ | ValueExpression 'IS' OptionalNot 'DISTINCT' 'CURSOR'
+   {
+     if (parser.isImpala()) {
+       parser.suggestKeywords(['FROM']);
+     }
+     $$ = { types: [ 'BOOLEAN' ] };
+   }
+ | ValueExpression 'IS' 'CURSOR' 'NULL'
+   {
+     parser.suggestKeywords(['NOT']);
+     $$ = { types: [ 'BOOLEAN' ] };
+   }
+ | ValueExpression 'IS' 'CURSOR' 'FALSE'
+   {
+     parser.suggestKeywords(['NOT']);
+     $$ = { types: [ 'BOOLEAN' ] };
+   }
+ | ValueExpression 'IS' 'CURSOR' 'TRUE'
+   {
+     parser.suggestKeywords(['NOT']);
+     $$ = { types: [ 'BOOLEAN' ] };
+   }
+ | ValueExpression 'IS' OptionalNot 'DISTINCT' 'FROM' PartialBacktickedOrAnyCursor
+   {
+     parser.valueExpressionSuggest($1, $3 ? 'IS NOT DISTINCT FROM' : 'IS DISTINCT FROM');
+     $$ = { types: [ 'BOOLEAN' ] };
+   }
+ | ValueExpression 'IS' OptionalNot 'DISTINCT' 'FROM' ValueExpression_EDIT
+   {
+     $$ = { types: [ 'BOOLEAN' ], suggestFilters: $6.suggestFilters }
+   }
+ ;
+
+// ------------------  EXISTS and parenthesized ------------------
+ValueExpression
+ : 'EXISTS' TableSubQuery
+   {
+     $$ = { types: [ 'BOOLEAN' ] };
+     // clear correlated flag after completed sub-query (set by lexer)
+     parser.yy.correlatedSubQuery = false;
+   }
+ | '(' ValueExpression ')'                                -> $2
+ ;
+
+ValueExpression_EDIT
+ : 'EXISTS' TableSubQuery_EDIT                               -> { types: [ 'BOOLEAN' ] }
+ | '(' ValueExpression_EDIT RightParenthesisOrError
+   {
+     $$ = $2;
+   }
+ | '(' 'CURSOR' RightParenthesisOrError
+   {
+     parser.valueExpressionSuggest();
+     $$ = { types: ['T'], typeSet: true };
+   }
+ ;
+
+// ------------------  COMPARISON ------------------
+
+ValueExpression
+ : ValueExpression '=' ValueExpression
+   {
+     parser.addColRefToVariableIfExists($1, $3);
+     $$ = { types: [ 'BOOLEAN' ] };
+   }
+ | ValueExpression '<' ValueExpression
+   {
+     parser.addColRefToVariableIfExists($1, $3);
+     $$ = { types: [ 'BOOLEAN' ] };
+   }
+ | ValueExpression '>' ValueExpression
+   {
+     parser.addColRefToVariableIfExists($1, $3);
+     $$ = { types: [ 'BOOLEAN' ] };
+   }
+ | ValueExpression 'COMPARISON_OPERATOR' ValueExpression
+   {
+     parser.addColRefToVariableIfExists($1, $3);
+     $$ = { types: [ 'BOOLEAN' ] };
+   }
+ ;
+
+ValueExpression_EDIT
+ : 'CURSOR' '=' ValueExpression
+   {
+     parser.valueExpressionSuggest($3, $2);
+     parser.applyTypeToSuggestions($3.types);
+     $$ = { types: [ 'BOOLEAN' ], typeSet: true };
+   }
+ | 'CURSOR' '<' ValueExpression
+   {
+     parser.valueExpressionSuggest($3, $2);
+     parser.applyTypeToSuggestions($3.types);
+     $$ = { types: [ 'BOOLEAN' ], typeSet: true  };
+   }
+ | 'CURSOR' '>' ValueExpression
+   {
+     parser.valueExpressionSuggest($3, $2);
+     parser.applyTypeToSuggestions($3.types);
+     $$ = { types: [ 'BOOLEAN' ], typeSet: true  };
+   }
+ | 'CURSOR' 'COMPARISON_OPERATOR' ValueExpression
+   {
+     parser.valueExpressionSuggest($3, $2);
+     parser.applyTypeToSuggestions($3.types);
+     $$ = { types: [ 'BOOLEAN' ], typeSet: true  };
+   }
+ | ValueExpression_EDIT '=' ValueExpression
+   {
+     if (!$1.typeSet) {
+       parser.applyTypeToSuggestions($3.types);
+       parser.addColRefIfExists($3);
+     }
+     $$ = { types: [ 'BOOLEAN' ], suggestFilters: $1.suggestFilters }
+   }
+ | ValueExpression_EDIT '<' ValueExpression
+   {
+     if (!$1.typeSet) {
+       parser.applyTypeToSuggestions($3.types);
+       parser.addColRefIfExists($3);
+     }
+     $$ = { types: [ 'BOOLEAN' ], suggestFilters: $1.suggestFilters }
+   }
+ | ValueExpression_EDIT '>' ValueExpression
+   {
+     if (!$1.typeSet) {
+       parser.applyTypeToSuggestions($3.types);
+       parser.addColRefIfExists($3);
+     }
+     $$ = { types: [ 'BOOLEAN' ], suggestFilters: $1.suggestFilters }
+   }
+ | ValueExpression_EDIT 'COMPARISON_OPERATOR' ValueExpression
+   {
+     if (!$1.typeSet) {
+       parser.applyTypeToSuggestions($3.types);
+       parser.addColRefIfExists($3);
+     }
+     $$ = { types: [ 'BOOLEAN' ], suggestFilters: $1.suggestFilters }
+   }
+ | ValueExpression '=' PartialBacktickedOrAnyCursor
+   {
+     parser.valueExpressionSuggest($1, $2);
+     parser.applyTypeToSuggestions($1.types);
+     $$ = { types: [ 'BOOLEAN' ], typeSet: true  };
+   }
+ | ValueExpression '<' PartialBacktickedOrAnyCursor
+   {
+     parser.valueExpressionSuggest($1, $2);
+     parser.applyTypeToSuggestions($1.types);
+     $$ = { types: [ 'BOOLEAN' ] , typeSet: true, endsWithLessThanOrEqual: true };
+   }
+ | ValueExpression '>' PartialBacktickedOrAnyCursor
+   {
+     parser.valueExpressionSuggest($1, $2);
+     parser.applyTypeToSuggestions($1.types);
+     $$ = { types: [ 'BOOLEAN' ], typeSet: true  };
+   }
+ | ValueExpression 'COMPARISON_OPERATOR' PartialBacktickedOrAnyCursor
+   {
+     parser.valueExpressionSuggest($1, $2);
+     parser.applyTypeToSuggestions($1.types);
+     $$ = { types: [ 'BOOLEAN' ], typeSet: true, endsWithLessThanOrEqual: $2 === '<='  };
+   }
+ | ValueExpression '=' ValueExpression_EDIT
+   {
+     if (!$3.typeSet) {
+       parser.applyTypeToSuggestions($1.types);
+       parser.addColRefIfExists($1);
+     }
+     $$ = { types: [ 'BOOLEAN' ], suggestFilters: $3.suggestFilters }
+   }
+ | ValueExpression '<' ValueExpression_EDIT
+   {
+     if (!$3.typeSet) {
+       parser.applyTypeToSuggestions($1.types);
+       parser.addColRefIfExists($1);
+     }
+     $$ = { types: [ 'BOOLEAN' ], suggestFilters: $3.suggestFilters }
+   }
+ | ValueExpression '>' ValueExpression_EDIT
+   {
+     if (!$3.typeSet) {
+       parser.applyTypeToSuggestions($1.types);
+       parser.addColRefIfExists($1);
+     }
+     $$ = { types: [ 'BOOLEAN' ], suggestFilters: $3.suggestFilters }
+   }
+ | ValueExpression 'COMPARISON_OPERATOR' ValueExpression_EDIT
+   {
+     if (!$3.typeSet) {
+       parser.applyTypeToSuggestions($1.types);
+       parser.addColRefIfExists($1);
+     }
+     $$ = { types: [ 'BOOLEAN' ], suggestFilters: $3.suggestFilters }
+   }
+ ;
+
+
+// ------------------  IN ------------------
+
+ValueExpression
+ : ValueExpression 'NOT' 'IN' '(' TableSubQueryInner ')'   -> { types: [ 'BOOLEAN' ] }
+ | ValueExpression 'NOT' 'IN' '(' ValueExpressionList ')'  -> { types: [ 'BOOLEAN' ] }
+ | ValueExpression 'IN' '(' TableSubQueryInner ')'         -> { types: [ 'BOOLEAN' ] }
+ | ValueExpression 'IN' '(' ValueExpressionList ')'        -> { types: [ 'BOOLEAN' ] }
+ ;
+
+ValueExpression_EDIT
+ : ValueExpression 'NOT' 'IN' ValueExpressionInSecondPart_EDIT
+   {
+     if ($4.inValueEdit) {
+       parser.valueExpressionSuggest($1, $2 + ' ' + $3);
+       parser.applyTypeToSuggestions($1.types);
+     }
+     if ($4.cursorAtStart) {
+       parser.suggestKeywords(['SELECT']);
+     }
+     $$ = { types: [ 'BOOLEAN' ], typeSet: true  };
+   }
+ | ValueExpression 'IN' ValueExpressionInSecondPart_EDIT
+   {
+     if ($3.inValueEdit) {
+       parser.valueExpressionSuggest($1, $2);
+       parser.applyTypeToSuggestions($1.types);
+     }
+     if ($3.cursorAtStart) {
+       parser.suggestKeywords(['SELECT']);
+     }
+     $$ = { types: [ 'BOOLEAN' ], typeSet: true  };
+   }
+ | ValueExpression_EDIT 'NOT' 'IN' '(' ValueExpressionList RightParenthesisOrError  -> { types: [ 'BOOLEAN' ], suggestFilters: $1.suggestFilters }
+ | ValueExpression_EDIT 'NOT' 'IN' '(' TableSubQueryInner RightParenthesisOrError   -> { types: [ 'BOOLEAN' ], suggestFilters: $1.suggestFilters }
+ | ValueExpression_EDIT 'IN' '(' ValueExpressionList RightParenthesisOrError        -> { types: [ 'BOOLEAN' ], suggestFilters: $1.suggestFilters }
+ | ValueExpression_EDIT 'IN' '(' TableSubQueryInner RightParenthesisOrError         -> { types: [ 'BOOLEAN' ], suggestFilters: $1.suggestFilters }
+ ;
+
+ValueExpressionInSecondPart_EDIT
+ : '(' TableSubQueryInner_EDIT RightParenthesisOrError
+ | '(' ValueExpressionList_EDIT RightParenthesisOrError -> { inValueEdit: true }
+ | '(' AnyCursor RightParenthesisOrError                -> { inValueEdit: true, cursorAtStart: true }
+ ;
+
+// ------------------  BETWEEN ------------------
+
+ValueExpression
+ : ValueExpression 'NOT' 'BETWEEN' ValueExpression 'BETWEEN_AND' ValueExpression  -> { types: [ 'BOOLEAN' ] }
+ | ValueExpression 'BETWEEN' ValueExpression 'BETWEEN_AND' ValueExpression        -> { types: [ 'BOOLEAN' ] }
+ ;
+
+ValueExpression_EDIT
+ : ValueExpression_EDIT 'NOT' 'BETWEEN' ValueExpression 'BETWEEN_AND' ValueExpression
+   {
+     if ($4.types[0] === $6.types[0] && !$1.typeSet) {
+       parser.applyTypeToSuggestions($4.types);
+     }
+     $$ = { types: [ 'BOOLEAN' ], suggestFilters: $1.suggestFilters };
+   }
+ | ValueExpression 'NOT' 'BETWEEN' ValueExpression_EDIT 'BETWEEN_AND' ValueExpression
+   {
+     if ($1.types[0] === $6.types[0] && !$4.typeSet) {
+       parser.applyTypeToSuggestions($1.types);
+     }
+     $$ = { types: [ 'BOOLEAN' ], suggestFilters: $4.suggestFilters };
+   }
+ | ValueExpression 'NOT' 'BETWEEN' ValueExpression 'BETWEEN_AND' ValueExpression_EDIT
+   {
+     if ($1.types[0] === $4.types[0] && !$6.typeSet) {
+       parser.applyTypeToSuggestions($1.types);
+     }
+     $$ = { types: [ 'BOOLEAN' ], suggestFilters: $6.suggestFilters };
+   }
+ | ValueExpression 'NOT' 'BETWEEN' ValueExpression 'BETWEEN_AND' 'CURSOR'
+   {
+     parser.valueExpressionSuggest($1, $5);
+     $$ = { types: [ 'BOOLEAN' ], typeSet: true  };
+   }
+ | ValueExpression 'NOT' 'BETWEEN' ValueExpression 'CURSOR'
+   {
+     parser.suggestValueExpressionKeywords($4, ['AND']);
+     $$ = { types: [ 'BOOLEAN' ] };
+   }
+ | ValueExpression 'NOT' 'BETWEEN' 'CURSOR'
+   {
+     parser.valueExpressionSuggest($1, $2 + ' ' + $3);
+     $$ = { types: [ 'BOOLEAN' ], typeSet: true  };
+   }
+ | ValueExpression_EDIT 'BETWEEN' ValueExpression 'BETWEEN_AND' ValueExpression
+   {
+     if ($1.types[0] === $3.types[0] && !$1.typeSet) {
+       parser.applyTypeToSuggestions($1.types)
+     }
+     $$ = { types: [ 'BOOLEAN' ], suggestFilters: $1.suggestFilters };
+   }
+ | ValueExpression 'BETWEEN' ValueExpression_EDIT 'BETWEEN_AND' ValueExpression
+   {
+     if ($1.types[0] === $3.types[0] && !$3.typeSet) {
+       parser.applyTypeToSuggestions($1.types)
+     }
+     $$ = { types: [ 'BOOLEAN' ], suggestFilters: $3.suggestFilters };
+   }
+ | ValueExpression 'BETWEEN' ValueExpression 'BETWEEN_AND' ValueExpression_EDIT
+   {
+     if ($1.types[0] === $3.types[0] && !$5.typeSet) {
+       parser.applyTypeToSuggestions($1.types)
+     }
+     $$ = { types: [ 'BOOLEAN' ], suggestFilters: $5.suggestFilters };
+   }
+ | ValueExpression 'BETWEEN' ValueExpression 'BETWEEN_AND' 'CURSOR'
+   {
+     parser.valueExpressionSuggest($1, $4);
+     parser.applyTypeToSuggestions($1.types);
+     $$ = { types: [ 'BOOLEAN' ], typeSet: true  };
+   }
+ | ValueExpression 'BETWEEN' ValueExpression 'CURSOR'
+   {
+     parser.suggestValueExpressionKeywords($3, ['AND']);
+     $$ = { types: [ 'BOOLEAN' ] };
+   }
+ | ValueExpression 'BETWEEN' 'CURSOR'
+   {
+     parser.valueExpressionSuggest($1, $2);
+     parser.applyTypeToSuggestions($1.types);
+     $$ = { types: [ 'BOOLEAN' ], typeSet: true };
+   }
+ ;
+
+// ------------------  BOOLEAN ------------------
+
+ValueExpression
+ : ValueExpression 'OR' ValueExpression
+   {
+     // verifyType($1, 'BOOLEAN');
+     // verifyType($3, 'BOOLEAN');
+     $$ = { types: [ 'BOOLEAN' ] };
+   }
+ | ValueExpression 'AND' ValueExpression
+   {
+     // verifyType($1, 'BOOLEAN');
+     // verifyType($3, 'BOOLEAN');
+     $$ = { types: [ 'BOOLEAN' ] };
+   }
+ ;
+
+ValueExpression_EDIT
+ : 'CURSOR' 'OR' ValueExpression
+   {
+     parser.valueExpressionSuggest(undefined, $2);
+     $$ = { types: [ 'BOOLEAN' ], typeSet: true, suggestFilters: true };
+   }
+ | ValueExpression_EDIT 'OR' ValueExpression
+   {
+     parser.addColRefIfExists($3);
+     $$ = { types: [ 'BOOLEAN' ], suggestFilters: $1.suggestFilters }
+   }
+ | ValueExpression 'OR' PartialBacktickedOrAnyCursor
+   {
+     parser.valueExpressionSuggest(undefined, $2);
+     $$ = { types: [ 'BOOLEAN' ], typeSet: true, suggestFilters: true };
+   }
+ | ValueExpression 'OR' ValueExpression_EDIT
+   {
+     parser.addColRefIfExists($1);
+     $$ = { types: [ 'BOOLEAN' ], suggestFilters: $3.suggestFilters }
+   }
+ | 'CURSOR' 'AND' ValueExpression
+   {
+     parser.valueExpressionSuggest(undefined, $2);
+     $$ = { types: [ 'BOOLEAN' ], typeSet: true, suggestFilters: true };
+   }
+ | ValueExpression_EDIT 'AND' ValueExpression
+   {
+     parser.addColRefIfExists($3);
+     $$ = { types: [ 'BOOLEAN' ], suggestFilters: $1.suggestFilters }
+   }
+ | ValueExpression 'AND' PartialBacktickedOrAnyCursor
+   {
+     parser.valueExpressionSuggest(undefined, $2);
+     $$ = { types: [ 'BOOLEAN' ], typeSet: true, suggestFilters: true };
+   }
+ | ValueExpression 'AND' ValueExpression_EDIT
+   {
+     parser.addColRefIfExists($1);
+     $$ = { types: [ 'BOOLEAN' ], suggestFilters: $3.suggestFilters }
+   }
+ ;
+
+// ------------------  ARITHMETIC ------------------
+
+ValueExpression
+ : ValueExpression '-' ValueExpression
+   {
+     // verifyType($1, 'NUMBER');
+     // verifyType($3, 'NUMBER');
+     $$ = { types: [ 'NUMBER' ] };
+   }
+ | ValueExpression '*' ValueExpression
+   {
+     // verifyType($1, 'NUMBER');
+     // verifyType($3, 'NUMBER');
+     $$ = { types: [ 'NUMBER' ] };
+   }
+ | ValueExpression 'ARITHMETIC_OPERATOR' ValueExpression
+   {
+     // verifyType($1, 'NUMBER');
+     // verifyType($3, 'NUMBER');
+     $$ = { types: [ 'NUMBER' ] };
+   }
+ ;
+
+ValueExpression_EDIT
+ : 'CURSOR' '*' ValueExpression
+   {
+     parser.valueExpressionSuggest(undefined, $2);
+     parser.applyTypeToSuggestions([ 'NUMBER' ]);
+     $$ = { types: [ 'NUMBER' ], typeSet: true };
+   }
+ | 'CURSOR' 'ARITHMETIC_OPERATOR' ValueExpression
+   {
+     parser.valueExpressionSuggest(undefined, $2);
+     parser.applyTypeToSuggestions([ 'NUMBER' ]);
+     $$ = { types: [ 'NUMBER' ], typeSet: true };
+   }
+ | ValueExpression_EDIT '-' ValueExpression
+   {
+     if (!$1.typeSet) {
+       parser.applyTypeToSuggestions(['NUMBER']);
+       parser.addColRefIfExists($3);
+     }
+     $$ = { types: [ 'NUMBER' ], suggestFilters: $1.suggestFilters }
+   }
+ | ValueExpression_EDIT '*' ValueExpression
+   {
+     if (!$1.typeSet) {
+       parser.applyTypeToSuggestions(['NUMBER']);
+       parser.addColRefIfExists($3);
+     }
+     $$ = { types: [ 'NUMBER' ], suggestFilters: $1.suggestFilters }
+   }
+ | ValueExpression_EDIT 'ARITHMETIC_OPERATOR' ValueExpression
+   {
+     if (!$1.typeSet) {
+       parser.applyTypeToSuggestions(['NUMBER']);
+       parser.addColRefIfExists($3);
+     }
+     $$ = { types: [ 'NUMBER' ], suggestFilters: $1.suggestFilters }
+   }
+ | ValueExpression '-' PartialBacktickedOrAnyCursor
+   {
+     parser.valueExpressionSuggest(undefined, $2);
+     parser.applyTypeToSuggestions(['NUMBER']);
+     $$ = { types: [ 'NUMBER' ], typeSet: true };
+   }
+ | ValueExpression '*' PartialBacktickedOrAnyCursor
+   {
+     parser.valueExpressionSuggest(undefined, $2);
+     parser.applyTypeToSuggestions(['NUMBER']);
+     $$ = { types: [ 'NUMBER' ], typeSet: true };
+   }
+ | ValueExpression 'ARITHMETIC_OPERATOR' PartialBacktickedOrAnyCursor
+   {
+     parser.valueExpressionSuggest(undefined, $2);
+     parser.applyTypeToSuggestions(['NUMBER']);
+     $$ = { types: [ 'NUMBER' ], typeSet: true };
+   }
+ | ValueExpression '-' ValueExpression_EDIT
+   {
+     if (!$3.typeSet) {
+       parser.applyTypeToSuggestions(['NUMBER']);
+       parser.addColRefIfExists($1);
+     }
+     $$ = { types: [ 'NUMBER' ], suggestFilters: $3.suggestFilters };
+   }
+ | ValueExpression '*' ValueExpression_EDIT
+   {
+     if (!$3.typeSet) {
+       parser.applyTypeToSuggestions(['NUMBER']);
+       parser.addColRefIfExists($1);
+     }
+     $$ = { types: [ 'NUMBER' ], suggestFilters: $3.suggestFilters };
+   }
+ | ValueExpression 'ARITHMETIC_OPERATOR' ValueExpression_EDIT
+   {
+     if (!$3.typeSet) {
+       parser.applyTypeToSuggestions(['NUMBER']);
+       parser.addColRefIfExists($1);
+     }
+     $$ = { types: [ 'NUMBER' ], suggestFilters: $3.suggestFilters };
+   }
+ ;
+
+// ------------------  LIKE, RLIKE and REGEXP ------------------
+
+ValueExpression
+ : ValueExpression LikeRightPart          -> { types: [ 'BOOLEAN' ] }
+ | ValueExpression 'NOT' LikeRightPart    -> { types: [ 'BOOLEAN' ] }
+ ;
+
+LikeRightPart
+ : 'LIKE' ValueExpression             -> { suggestKeywords: ['NOT'] }
+ | '<impala>ILIKE' ValueExpression    -> { suggestKeywords: ['NOT'] }
+ | '<impala>IREGEXP' ValueExpression  -> { suggestKeywords: ['NOT'] }
+ | 'RLIKE' ValueExpression            -> { suggestKeywords: ['NOT'] }
+ | 'REGEXP' ValueExpression           -> { suggestKeywords: ['NOT'] }
+ ;
+
+LikeRightPart_EDIT
+ : 'LIKE' ValueExpression_EDIT
+ | '<impala>ILIKE' ValueExpression_EDIT
+ | '<impala>IREGEXP' ValueExpression_EDIT
+ | 'RLIKE' ValueExpression_EDIT
+ | 'REGEXP' ValueExpression_EDIT
+ | 'LIKE' PartialBacktickedOrCursor
+   {
+     parser.suggestFunctions({ types: [ 'STRING' ] });
+     parser.suggestColumns({ types: [ 'STRING' ] });
+     $$ = { types: ['BOOLEAN'] }
+   }
+ | '<impala>ILIKE' PartialBacktickedOrCursor
+   {
+     parser.suggestFunctions({ types: [ 'STRING' ] });
+     parser.suggestColumns({ types: [ 'STRING' ] });
+     $$ = { types: ['BOOLEAN'] }
+   }
+ | '<impala>IREGEXP' PartialBacktickedOrCursor
+   {
+     parser.suggestFunctions({ types: [ 'STRING' ] });
+     parser.suggestColumns({ types: [ 'STRING' ] });
+     $$ = { types: ['BOOLEAN'] }
+   }
+ | 'RLIKE' PartialBacktickedOrCursor
+   {
+     parser.suggestFunctions({ types: [ 'STRING' ] });
+     parser.suggestColumns({ types: [ 'STRING' ] });
+     $$ = { types: ['BOOLEAN'] }
+   }
+ | 'REGEXP' PartialBacktickedOrCursor
+   {
+     parser.suggestFunctions({ types: [ 'STRING' ] });
+     parser.suggestColumns({ types: [ 'STRING' ] });
+     $$ = { types: ['BOOLEAN'] }
+   }
+ ;
+
+ValueExpression_EDIT
+ : ValueExpression_EDIT LikeRightPart               -> { types: [ 'BOOLEAN' ], suggestFilters: $1.suggestFilters }
+ | ValueExpression_EDIT 'NOT' LikeRightPart         -> { types: [ 'BOOLEAN' ], suggestFilters: $1.suggestFilters }
+ | ValueExpression LikeRightPart_EDIT               -> { types: [ 'BOOLEAN' ] }
+ | ValueExpression 'NOT' LikeRightPart_EDIT         -> { types: [ 'BOOLEAN' ] }
+ | 'CURSOR' LikeRightPart
+   {
+     parser.valueExpressionSuggest(undefined, $2);
+     parser.applyTypeToSuggestions([ 'STRING' ]);
+     $$ = { types: [ 'BOOLEAN' ], typeSet: true };
+   }
+ | 'CURSOR' 'NOT' LikeRightPart
+   {
+     parser.valueExpressionSuggest(undefined, $2 + ' ' + $3);
+     parser.applyTypeToSuggestions([ 'STRING' ]);
+     $$ = { types: [ 'BOOLEAN' ], typeSet: true };
+   }
+ ;
+
+// ------------------  CASE, WHEN, THEN ------------------
+
+ValueExpression
+ : 'CASE' CaseRightPart                  -> $2
+ | 'CASE' ValueExpression CaseRightPart  -> $3
+ ;
+
+ValueExpression_EDIT
+ : 'CASE' CaseRightPart_EDIT                         -> $2
+ | 'CASE' 'CURSOR' EndOrError
+   {
+     parser.valueExpressionSuggest();
+     parser.suggestKeywords(['WHEN']);
+     $$ = { types: [ 'T' ], typeSet: true };
+   }
+ | 'CASE' ValueExpression CaseRightPart_EDIT         -> $3
+ | 'CASE' ValueExpression 'CURSOR' EndOrError
+   {
+     parser.suggestValueExpressionKeywords($2, ['WHEN']);
+     $$ = { types: [ 'T' ], typeSet: true };
+   }
+ | 'CASE' ValueExpression_EDIT CaseRightPart
+    {
+      $$ = $3;
+      $$.suggestFilters = $2.suggestFilters;
+    }
+ | 'CASE' ValueExpression_EDIT EndOrError            -> { types: [ 'T' ], suggestFilters: $2.suggestFilters }
+ | 'CASE' 'CURSOR' CaseRightPart                     -> { types: [ 'T' ] }
+ ;
+
+CaseRightPart
+ : CaseWhenThenList 'END'                         -> parser.findCaseType($1)
+ | CaseWhenThenList 'ELSE' ValueExpression 'END'
+   {
+     $1.caseTypes.push($3);
+     $$ = parser.findCaseType($1);
+   }
+ ;
+
+CaseRightPart_EDIT
+ : CaseWhenThenList_EDIT EndOrError                            -> parser.findCaseType($1)
+ | CaseWhenThenList 'ELSE' ValueExpression 'CURSOR'
+   {
+     parser.suggestValueExpressionKeywords($3, ['END']);
+     $1.caseTypes.push($3);
+     $$ = parser.findCaseType($1);
+   }
+ | CaseWhenThenList_EDIT 'ELSE' ValueExpression EndOrError
+   {
+     $1.caseTypes.push($3);
+     $$ = parser.findCaseType($1);
+   }
+ | CaseWhenThenList_EDIT 'ELSE' EndOrError                      -> parser.findCaseType($1)
+ | CaseWhenThenList 'CURSOR' ValueExpression EndOrError
+   {
+     if ($4.toLowerCase() !== 'end') {
+       parser.suggestValueExpressionKeywords($1, [{ value: 'END', weight: 3 }, { value: 'ELSE', weight: 2 }, { value: 'WHEN', weight: 1 }]);
+     } else {
+       parser.suggestValueExpressionKeywords($1, [{ value: 'ELSE', weight: 2 }, { value: 'WHEN', weight: 1 }]);
+     }
+     $$ = parser.findCaseType($1);
+   }
+ | CaseWhenThenList 'CURSOR' EndOrError
+   {
+     if ($3.toLowerCase() !== 'end') {
+       parser.suggestValueExpressionKeywords($1, [{ value: 'END', weight: 3 }, { value: 'ELSE', weight: 2 }, { value: 'WHEN', weight: 1 }]);
+     } else {
+       parser.suggestValueExpressionKeywords($1, [{ value: 'ELSE', weight: 2 }, { value: 'WHEN', weight: 1 }]);
+     }
+     $$ = parser.findCaseType($1);
+   }
+ | CaseWhenThenList 'ELSE' ValueExpression_EDIT EndOrError
+   {
+     $1.caseTypes.push($3);
+     $$ = parser.findCaseType($1);
+     $$.suggestFilters = $3.suggestFilters
+   }
+ | CaseWhenThenList 'ELSE' 'CURSOR' EndOrError
+   {
+     parser.valueExpressionSuggest();
+     $$ = parser.findCaseType($1);
+   }
+ | 'ELSE' 'CURSOR' EndOrError
+   {
+     parser.valueExpressionSuggest();
+     $$ = { types: [ 'T' ], typeSet: true };
+   }
+ | 'CURSOR' 'ELSE' ValueExpression EndOrError
+   {
+     parser.valueExpressionSuggest();
+     parser.suggestKeywords(['WHEN']);
+     $$ = $3;
+   }
+ | 'CURSOR' 'ELSE' EndOrError
+   {
+     parser.valueExpressionSuggest();
+     parser.suggestKeywords(['WHEN']);
+     $$ = { types: [ 'T' ] };
+   }
+ ;
+
+EndOrError
+ : 'END'
+ | error
+ ;
+
+CaseWhenThenList
+ : CaseWhenThenListPartTwo                   -> { caseTypes: [ $1 ], lastType: $1 }
+ | CaseWhenThenList CaseWhenThenListPartTwo
+   {
+     $1.caseTypes.push($2);
+     $$ = { caseTypes: $1.caseTypes, lastType: $2 };
+   }
+ ;
+
+CaseWhenThenList_EDIT
+ : CaseWhenThenListPartTwo_EDIT
+ | CaseWhenThenList CaseWhenThenListPartTwo_EDIT
+ | CaseWhenThenList CaseWhenThenListPartTwo_EDIT CaseWhenThenList
+ | CaseWhenThenList 'CURSOR' CaseWhenThenList
+   {
+     parser.suggestValueExpressionKeywords($1, ['WHEN']);
+   }
+ | CaseWhenThenListPartTwo_EDIT CaseWhenThenList                   -> $2
+ ;
+
+CaseWhenThenListPartTwo
+ : 'WHEN' ValueExpression 'THEN' ValueExpression  -> $4
+ ;
+
+CaseWhenThenListPartTwo_EDIT
+ : 'WHEN' ValueExpression_EDIT                         -> { caseTypes: [{ types: ['T'] }], suggestFilters: $2.suggestFilters }
+ | 'WHEN' ValueExpression_EDIT 'THEN'                  -> { caseTypes: [{ types: ['T'] }], suggestFilters: $2.suggestFilters }
+ | 'WHEN' ValueExpression_EDIT 'THEN' ValueExpression  -> { caseTypes: [$4], suggestFilters: $2.suggestFilters }
+ | 'WHEN' ValueExpression 'THEN' ValueExpression_EDIT  -> { caseTypes: [$4], suggestFilters: $4.suggestFilters }
+ | 'WHEN' 'THEN' ValueExpression_EDIT                  -> { caseTypes: [$3], suggestFilters: $3.suggestFilters }
+ | 'CURSOR' ValueExpression 'THEN'
+   {
+     parser.suggestKeywords(['WHEN']);
+     $$ = { caseTypes: [{ types: ['T'] }] };
+   }
+ | 'CURSOR' ValueExpression 'THEN' ValueExpression
+   {
+     parser.suggestKeywords(['WHEN']);
+     $$ = { caseTypes: [$4] };
+   }
+ | 'CURSOR' 'THEN'
+   {
+     parser.valueExpressionSuggest();
+     parser.suggestKeywords(['WHEN']);
+     $$ = { caseTypes: [{ types: ['T'] }] };
+   }
+ | 'CURSOR' 'THEN' ValueExpression
+    {
+      parser.valueExpressionSuggest();
+      parser.suggestKeywords(['WHEN']);
+      $$ = { caseTypes: [{ types: ['T'] }] };
+    }
+ | 'WHEN' 'CURSOR'
+   {
+     parser.valueExpressionSuggest();
+     $$ = { caseTypes: [{ types: ['T'] }], suggestFilters: true };
+   }
+ | 'WHEN' 'CURSOR' ValueExpression
+   {
+     parser.valueExpressionSuggest();
+     parser.suggestKeywords(['THEN']);
+     $$ = { caseTypes: [{ types: ['T'] }], suggestFilters: true };
+   }
+ | 'WHEN' 'CURSOR' 'THEN'
+   {
+     parser.valueExpressionSuggest();
+     $$ = { caseTypes: [{ types: ['T'] }], suggestFilters: true };
+   }
+ | 'WHEN' 'CURSOR' 'THEN' ValueExpression
+   {
+     parser.valueExpressionSuggest();
+     $$ = { caseTypes: [$4], suggestFilters: true };
+   }
+ | 'WHEN' ValueExpression 'CURSOR'
+   {
+     parser.suggestValueExpressionKeywords($2, ['THEN']);
+     $$ = { caseTypes: [{ types: ['T'] }] };
+   }
+ | 'WHEN' ValueExpression 'CURSOR' ValueExpression
+   {
+     parser.suggestValueExpressionKeywords($2, ['THEN']);
+     $$ = { caseTypes: [{ types: ['T'] }] };
+   }
+ | 'WHEN' ValueExpression 'THEN' 'CURSOR'
+   {
+     parser.valueExpressionSuggest();
+     $$ = { caseTypes: [{ types: ['T'] }] };
+   }
+ | 'WHEN' ValueExpression 'THEN' 'CURSOR' ValueExpression
+   {
+     parser.valueExpressionSuggest();
+     $$ = { caseTypes: [{ types: ['T'] }] };
+   }
+ | 'WHEN' 'THEN' 'CURSOR' ValueExpression
+   {
+     parser.valueExpressionSuggest();
+     $$ = { caseTypes: [{ types: ['T'] }] };
+   }
+ | 'WHEN' 'THEN' 'CURSOR'
+   {
+     parser.valueExpressionSuggest();
+     $$ = { caseTypes: [{ types: ['T'] }] };
+   }
+ ;