Browse Source

HUE-4578 [editor] Add autocompletion of GRANT and REVOKE statements

Johan Ahlen 9 năm trước cách đây
mục cha
commit
054030d

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

@@ -55,6 +55,7 @@
 <hive>'NONE'                               { return '<hive>NONE'; }
 <hive>'OF'                                 { return '<hive>OF'; }
 <hive>'OUT'                                { return '<hive>OUT'; }
+<hive>'REVOKE'                             { return '<hive>REVOKE'; }
 <hive>'ROLLUP'                             { return '<hive>ROLLUP'; }
 <hive>'TABLE'                              { return '<hive>TABLE'; }
 <hive>'USER'                               { return '<hive>USER'; }
@@ -62,6 +63,7 @@
 
 // Non-reserved Keywords
 <hive>'ADD'                                { return '<hive>ADD'; }
+<hive>'ADMIN'                              { return '<hive>ADMIN'; }
 <hive>'AFTER'                              { return '<hive>AFTER'; }
 <hive>'ANALYZE'                            { determineCase(yytext); return '<hive>ANALYZE'; }
 <hive>'ARCHIVE'                            { return '<hive>ARCHIVE'; }
@@ -114,6 +116,7 @@
 <hive>'LINES'                              { return '<hive>LINES'; }
 <hive>'LOAD'                               { determineCase(yytext); return '<hive>LOAD'; }
 <hive>'LOCATION'                           { this.begin('hdfs'); return '<hive>LOCATION'; }
+<hive>'LOCK'                               { return '<hive>LOCK'; }
 <hive>'LOCKS'                              { return '<hive>LOCKS'; }
 <hive>'METADATA'                           { return '<hive>METADATA'; }
 <hive>'MSCK'                               { return '<hive>MSCK'; }
@@ -127,6 +130,7 @@
 <hive>'PARQUET'                            { return '<hive>PARQUET'; }
 <hive>'PARTITIONED'                        { return '<hive>PARTITIONED'; }
 <hive>'PARTITIONS'                         { return '<hive>PARTITIONS'; }
+<hive>'PRIVILEGES'                         { return '<hive>PRIVILEGES'; }
 <hive>'PURGE'                              { return '<hive>PURGE'; }
 <hive>'RCFILE'                             { return '<hive>RCFILE'; }
 <hive>'REBUILD'                            { return '<hive>REBUILD'; }
@@ -145,6 +149,7 @@
 <hive>'SERDEPROPERTIES'                    { return '<hive>SERDEPROPERTIES'; }
 <hive>'SETS'                               { return '<hive>SETS'; }
 <hive>'SHOW'                               { determineCase(yytext); return '<hive>SHOW'; }
+<hive>'SHOW_DATABASE'                      { return '<hive>SHOW_DATABASE'; }
 <hive>'SKEWED'                             { return '<hive>SKEWED'; }
 <hive>'SKEWED LOCATION'                    { return '<hive>SKEWED_LOCATION'; } // Hack to prevent hdfs lexer state
 <hive>'SORT'                               { return '<hive>SORT'; }
@@ -228,10 +233,12 @@
 <impala>'RENAME'                           { return '<impala>RENAME'; }
 <impala>'REPLACE'                          { return '<impala>REPLACE'; }
 <impala>'RETURNS'                          { return '<impala>RETURNS'; }
+<impala>'REVOKE'                           { return '<impala>REVOKE'; }
 <impala>'SEQUENCEFILE'                     { return '<impala>SEQUENCEFILE'; }
 <impala>'SERDEPROPERTIES'                  { return '<impala>SERDEPROPERTIES'; }
 <impala>'SCHEMAS'                          { return '<impala>SCHEMAS'; }
 <impala>'SERIALIZE_FN'                     { return '<impala>SERIALIZE_FN'; }
+<impala>'SERVER'                           { return '<impala>SERVER'; }
 <impala>'STATS'                            { return '<impala>STATS'; }
 <impala>'STORED'                           { return '<impala>STORED'; }
 <impala>'STRAIGHT_JOIN'                    { return '<impala>STRAIGHT_JOIN'; }
@@ -243,6 +250,7 @@
 <impala>'TEXTFILE'                         { return '<impala>TEXTFILE'; }
 <impala>'UNCACHED'                         { return '<impala>UNCACHED'; }
 <impala>'UPDATE_FN'                        { return '<impala>UPDATE_FN'; }
+<impala>'URI'                              { return '<impala>URI'; }
 <impala>'USING'                            { return '<impala>USING'; }
 
 // Non-reserved Keywords
@@ -307,6 +315,7 @@
 'NOT'                                      { return 'NOT'; }
 'NULL'                                     { return 'NULL'; }
 'ON'                                       { return 'ON'; }
+'OPTION'                                   { return 'OPTION'; }
 'OR'                                       { return 'OR'; }
 'ORDER'                                    { return 'ORDER'; }
 'OUTER'                                    { return 'OUTER'; }

+ 490 - 0
desktop/core/src/desktop/static/desktop/js/autocomplete/jison/sql_grant.jison

@@ -0,0 +1,490 @@
+// 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'
+   {
+     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) {
+       suggestKeywords(['ON', 'TO']);
+     } else {
+       suggestKeywords(['TO']);
+     }
+   }
+ | '<hive>GRANT' HivePrivilegeTypeList OptionalOnSpecification 'TO' 'CURSOR'
+   {
+     suggestKeywords(['GROUP', 'ROLE', 'USER']);
+   }
+ | '<hive>GRANT' HivePrivilegeTypeList OptionalOnSpecification 'TO' PrincipalSpecificationList_EDIT
+ | '<hive>GRANT' HivePrivilegeTypeList OptionalOnSpecification 'TO' PrincipalSpecificationList OptionalWithGrantOption 'CURSOR'
+   {
+     if (!$6) {
+       suggestKeywords(['WITH GRANT OPTION']);
+     }
+   }
+ | '<hive>GRANT' HivePrivilegeTypeList OptionalOnSpecification 'TO' PrincipalSpecificationList WithGrantOption_EDIT
+ | '<hive>GRANT' UserOrRoleList 'CURSOR'
+   {
+     suggestKeywords(['TO']);
+   }
+ | '<hive>GRANT' UserOrRoleList 'TO' 'CURSOR'
+   {
+     suggestKeywords(['GROUP', 'ROLE', 'USER']);
+   }
+ | '<hive>GRANT' UserOrRoleList 'TO' PrincipalSpecificationList_EDIT
+ | '<hive>GRANT' UserOrRoleList 'TO' PrincipalSpecificationList OptionalWithAdminOption 'CURSOR'
+   {
+     if (!$5) {
+       suggestKeywords(['WITH ADMIN OPTION']);
+     }
+   }
+ | '<hive>GRANT' UserOrRoleList 'TO' PrincipalSpecificationList WithAdminOption_EDIT
+ | '<hive>GRANT' '<hive>ROLE' UserOrRoleList 'TO' 'CURSOR'
+   {
+     suggestKeywords(['GROUP', 'ROLE', 'USER']);
+   }
+ | '<hive>GRANT' '<hive>ROLE' UserOrRoleList 'TO' PrincipalSpecificationList_EDIT
+ | '<hive>GRANT' '<hive>ROLE' UserOrRoleList 'TO' PrincipalSpecificationList OptionalWithAdminOption 'CURSOR'
+   {
+     if (!$6) {
+       suggestKeywords(['WITH ADMIN OPTION']);
+     }
+   }
+ | '<hive>GRANT' '<hive>ROLE' UserOrRoleList 'TO' PrincipalSpecificationList WithAdminOption_EDIT
+ | '<impala>GRANT' 'CURSOR'
+   {
+     suggestKeywords(['ALL', 'INSERT', 'ROLE', 'SELECT']);
+   }
+ | '<impala>GRANT' '<impala>ROLE' RegularOrBacktickedIdentifier 'CURSOR'
+   {
+     suggestKeywords(['TO GROUP']);
+   }
+ | '<impala>GRANT' '<impala>ROLE' RegularOrBacktickedIdentifier 'TO' 'CURSOR'
+   {
+     suggestKeywords(['GROUP']);
+   }
+ | '<impala>GRANT' ImpalaPrivilegeType_EDIT
+ | '<impala>GRANT' ImpalaPrivilegeType 'CURSOR'
+   {
+     suggestKeywords(['ON DATABASE', 'ON SERVER', 'ON TABLE', 'ON URI']);
+   }
+ | '<impala>GRANT' ImpalaPrivilegeType 'ON' 'CURSOR'
+   {
+     suggestKeywords(['DATABASE', 'SERVER', 'TABLE', 'URI']);
+   }
+ | '<impala>GRANT' ImpalaPrivilegeType 'ON' ImpalaObjectSpecification_EDIT
+ | '<impala>GRANT' ImpalaPrivilegeType 'ON' ImpalaObjectSpecification 'CURSOR'
+   {
+     suggestKeywords(['TO']);
+   }
+ | '<impala>GRANT' ImpalaPrivilegeType 'ON' ImpalaObjectSpecification 'TO' 'CURSOR'
+   {
+     suggestKeywords(['ROLE']);
+   }
+ | '<impala>GRANT' ImpalaPrivilegeType 'ON' ImpalaObjectSpecification 'TO' RegularOrBacktickedIdentifier OptionalWithGrantOption 'CURSOR'
+   {
+     if (!$7) {
+       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) {
+       suggestKeywords(['WITH GRANT OPTION']);
+     }
+   }
+ | '<impala>GRANT' ImpalaPrivilegeType 'ON' ImpalaObjectSpecification 'TO' '<impala>ROLE' RegularOrBacktickedIdentifier WithGrantOption_EDIT
+ ;
+
+OptionalOnSpecification
+ :
+ | 'ON' HiveObjectSpecification
+ ;
+
+OnSpecification_EDIT
+ : 'ON' 'CURSOR'
+   {
+     suggestKeywords(['DATABASE', 'TABLE']);
+     suggestTables();
+     suggestDatabases({ appendDot: true });
+   }
+ | 'ON' HiveObjectSpecification_EDIT
+ ;
+
+HiveObjectSpecification
+ : 'DATABASE' RegularOrBacktickedIdentifier
+ | '<hive>TABLE' SchemaQualifiedTableIdentifier
+   {
+     addTablePrimary($2);
+   }
+ | SchemaQualifiedTableIdentifier
+   {
+     addTablePrimary($1);
+   }
+ ;
+
+HiveObjectSpecification_EDIT
+ : 'DATABASE' 'CURSOR'
+   {
+     suggestDatabases();
+   }
+ | '<hive>TABLE' 'CURSOR'
+   {
+     suggestTables();
+     suggestDatabases({ appendDot: true });
+   }
+ | '<hive>TABLE' SchemaQualifiedTableIdentifier_EDIT
+ | SchemaQualifiedTableIdentifier_EDIT
+ ;
+
+ImpalaObjectSpecification
+ : 'DATABASE' RegularOrBacktickedIdentifier
+ | '<impala>TABLE' SchemaQualifiedTableIdentifier
+   {
+     addTablePrimary($2);
+   }
+ | '<impala>SERVER' RegularOrBacktickedIdentifier
+ | '<impala>URI' RegularOrBacktickedIdentifier
+ ;
+
+ImpalaObjectSpecification_EDIT
+ : 'DATABASE' 'CURSOR'
+   {
+     suggestDatabases();
+   }
+ | '<impala>TABLE' 'CURSOR'
+   {
+     suggestTables();
+     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
+   {
+     suggestKeywords(['ALL', 'ALTER', 'CREATE', 'DELETE', 'DROP', 'INDEX', 'INSERT', 'LOCK', 'SELECT', 'SHOW_DATABASE', 'UPDATE']);
+   }
+ | HivePrivilegeTypeList ',' 'CURSOR'
+   {
+     suggestKeywords(['ALL', 'ALTER', 'CREATE', 'DELETE', 'DROP', 'INDEX', 'INSERT', 'LOCK', 'SELECT', 'SHOW_DATABASE', 'UPDATE']);
+   }
+ | HivePrivilegeTypeList ',' 'CURSOR' ',' HivePrivilegeTypeList
+   {
+     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
+ : '<impala>INSERT'
+ | 'SELECT' OptionalParenthesizedColumnList
+ | 'ALL'
+ ;
+
+ImpalaPrivilegeType_EDIT
+ : 'SELECT' ParenthesizedColumnList_EDIT
+ ;
+
+PrincipalSpecificationList
+ : PrincipalSpecification
+ | PrincipalSpecificationList ',' PrincipalSpecification
+ ;
+
+PrincipalSpecificationList_EDIT
+ : PrincipalSpecificationList ',' 'CURSOR'
+   {
+     suggestKeywords(['GROUP', 'ROLE', 'USER']);
+   }
+ | 'CURSOR' ',' PrincipalSpecificationList
+   {
+     suggestKeywords(['GROUP', 'ROLE', 'USER']);
+   }
+ | PrincipalSpecificationList ',' 'CURSOR' ',' PrincipalSpecificationList
+   {
+     suggestKeywords(['GROUP', 'ROLE', 'USER']);
+   }
+ ;
+
+PrincipalSpecification
+ : '<hive>USER' RegularOrBacktickedIdentifier
+ | 'GROUP' RegularOrBacktickedIdentifier
+ | '<hive>ROLE' RegularOrBacktickedIdentifier
+ ;
+
+UserOrRoleList
+ : RegularOrBacktickedIdentifier
+ | UserOrRoleList ',' RegularOrBacktickedIdentifier
+ ;
+
+OptionalWithGrantOption
+ :
+ | 'WITH' '<hive>GRANT' 'OPTION'
+ | 'WITH' '<impala>GRANT' 'OPTION'
+ ;
+
+WithGrantOption_EDIT
+ : 'WITH' 'CURSOR'
+   {
+     suggestKeywords(['GRANT OPTION']);
+   }
+ | 'WITH' '<hive>GRANT' 'CURSOR'
+   {
+     suggestKeywords(['OPTION']);
+   }
+ | 'WITH' '<impala>GRANT' 'CURSOR'
+   {
+     suggestKeywords(['OPTION']);
+   }
+ ;
+
+OptionalWithAdminOption
+ :
+ | 'WITH' '<hive>ADMIN' 'OPTION'
+ ;
+
+WithAdminOption_EDIT
+ : 'WITH' 'CURSOR'
+   {
+     suggestKeywords(['ADMIN OPTION']);
+   }
+ | 'WITH' '<hive>ADMIN' 'CURSOR'
+   {
+     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'
+   {
+     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) {
+         suggestKeywords(['FROM', 'GRANT OPTION', 'ON', 'PRIVILEGES FROM']);
+       } else {
+         suggestKeywords(['FROM', 'ON']);
+       }
+     } else {
+       suggestKeywords(['FROM']);
+     }
+   }
+ | '<hive>REVOKE' HivePrivilegeTypeList OptionalOnSpecification 'FROM' 'CURSOR'
+   {
+     suggestKeywords(['GROUP', 'ROLE', 'USER']);
+   }
+ | '<hive>REVOKE' HivePrivilegeTypeList OptionalOnSpecification 'FROM' PrincipalSpecificationList_EDIT
+ | '<hive>REVOKE' '<hive>GRANT' 'CURSOR'
+   {
+     suggestKeywords(['OPTION FOR']);
+   }
+ | '<hive>REVOKE' '<hive>GRANT' 'OPTION' 'CURSOR'
+   {
+     suggestKeywords(['FOR']);
+   }
+ | '<hive>REVOKE' '<hive>GRANT' 'OPTION' '<hive>FOR' 'CURSOR'
+   {
+     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) {
+       suggestKeywords(['FROM', 'ON']);
+     } else {
+       suggestKeywords(['FROM']);
+     }
+   }
+ | '<hive>REVOKE' '<hive>GRANT' 'OPTION' '<hive>FOR' HivePrivilegeTypeList OptionalOnSpecification 'FROM' 'CURSOR'
+   {
+     suggestKeywords(['GROUP', 'ROLE', 'USER']);
+   }
+ | '<hive>REVOKE' '<hive>GRANT' 'OPTION' '<hive>FOR' HivePrivilegeTypeList OptionalOnSpecification 'FROM' PrincipalSpecificationList_EDIT
+ | '<hive>REVOKE' UserOrRoleList 'CURSOR'
+   {
+     if ($2.toUpperCase() === 'ADMIN') {
+       suggestKeywords(['FROM', 'OPTION FOR']);
+     } else {
+       suggestKeywords(['FROM']);
+     }
+   }
+ | '<hive>REVOKE' UserOrRoleList 'FROM' 'CURSOR'
+   {
+     suggestKeywords(['GROUP', 'ROLE', 'USER']);
+   }
+ | '<hive>REVOKE' UserOrRoleList 'FROM' PrincipalSpecificationList_EDIT
+ | '<hive>REVOKE' '<hive>ROLE' UserOrRoleList 'CURSOR'
+   {
+     suggestKeywords(['FROM']);
+   }
+ | '<hive>REVOKE' '<hive>ROLE' UserOrRoleList 'FROM' 'CURSOR'
+   {
+     suggestKeywords(['GROUP', 'ROLE', 'USER']);
+   }
+ | '<hive>REVOKE' '<hive>ROLE' UserOrRoleList 'FROM' PrincipalSpecificationList_EDIT
+
+ | '<hive>REVOKE' '<hive>ADMIN' 'OPTION' 'CURSOR'
+   {
+     suggestKeywords(['FOR']);
+   }
+ | '<hive>REVOKE' '<hive>ADMIN' 'OPTION' '<hive>FOR' 'CURSOR'
+   {
+     suggestKeywords(['ROLE']);
+   }
+ | '<hive>REVOKE' '<hive>ADMIN' 'OPTION' '<hive>FOR' UserOrRoleList 'CURSOR'
+   {
+     suggestKeywords(['FROM']);
+   }
+ | '<hive>REVOKE' '<hive>ADMIN' 'OPTION' '<hive>FOR' UserOrRoleList 'FROM' 'CURSOR'
+   {
+     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'
+   {
+     suggestKeywords(['FROM']);
+   }
+ | '<hive>REVOKE' '<hive>ADMIN' 'OPTION' '<hive>FOR' '<hive>ROLE' UserOrRoleList 'FROM' 'CURSOR'
+   {
+     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'
+   {
+     suggestKeywords(['FROM']);
+   }
+ | '<impala>REVOKE' 'CURSOR'
+   {
+     suggestKeywords(['ALL', 'INSERT', 'ROLE', 'SELECT']);
+   }
+ | '<impala>REVOKE' '<impala>ROLE' RegularOrBacktickedIdentifier 'CURSOR'
+   {
+     suggestKeywords(['FROM GROUP']);
+   }
+ | '<impala>REVOKE' '<impala>ROLE' RegularOrBacktickedIdentifier 'FROM' 'CURSOR'
+   {
+     suggestKeywords(['GROUP']);
+   }
+ | '<impala>REVOKE' ImpalaPrivilegeType_EDIT
+ | '<impala>REVOKE' ImpalaPrivilegeType 'CURSOR'
+   {
+     suggestKeywords(['ON DATABASE', 'ON SERVER', 'ON TABLE', 'ON URI']);
+   }
+ | '<impala>REVOKE' ImpalaPrivilegeType 'ON' 'CURSOR'
+   {
+     suggestKeywords(['DATABASE', 'SERVER', 'TABLE', 'URI']);
+   }
+ | '<impala>REVOKE' ImpalaPrivilegeType 'ON' ImpalaObjectSpecification_EDIT
+ | '<impala>REVOKE' ImpalaPrivilegeType 'ON' ImpalaObjectSpecification 'CURSOR'
+   {
+     suggestKeywords(['FROM']);
+   }
+ | '<impala>REVOKE' ImpalaPrivilegeType 'ON' ImpalaObjectSpecification 'FROM' 'CURSOR'
+   {
+     suggestKeywords(['ROLE']);
+   }
+ ;
+
+PrivilegesOrGrantOption
+ : '<hive>PRIVILEGES'
+ | '<hive>GRANT' 'OPTION'
+ ;
+
+PrivilegesOrGrantOption_EDIT
+ : '<hive>GRANT' 'CURSOR'
+   {
+     suggestKeywords(['OPTION']);
+   }
+ ;

+ 11 - 4
desktop/core/src/desktop/static/desktop/js/autocomplete/jison/sql_main.jison

@@ -30,6 +30,7 @@
 
 NonReservedKeyword
  : '<hive>ADD'
+ | '<hive>ADMIN'
  | '<hive>AFTER'
  | '<hive>ANALYZE'
  | '<hive>ARCHIVE'
@@ -86,6 +87,7 @@ NonReservedKeyword
  | '<hive>PARQUET'
  | '<hive>PARTITIONED'
  | '<hive>PARTITIONS'
+ | '<hive>PRIVILEGES'
  | '<hive>PURGE'
  | '<hive>RCFILE'
  | '<hive>REBUILD'
@@ -121,7 +123,7 @@ NonReservedKeyword
  | '<hive>UNIONTYPE'
  | '<hive>USE'
  | '<hive>VIEW'
-// | '<hive>ASC'      // These cause conflicts, we could use a separate lexer state for DESCRIBE, ALTER and SHOW
+// | '<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'
@@ -129,7 +131,9 @@ NonReservedKeyword
 // | '<hive>FUNCTION'
 // | '<hive>INDEX'
 // | '<hive>INDEXES'
+// | '<hive>LOCK'
 // | '<hive>SCHEMA'
+// | '<hive>SHOW_DATABASE'
 // | '<hive>SORT'
  ;
 
@@ -140,6 +144,8 @@ NonReservedKeyword
  | '<impala>GRANT'
  | '<impala>ROLE'
  | '<impala>ROLES'
+ | '<impala>URI'
+ | '<impala>SERVER'
 // | '<impala>BROADCAST'
 // | '<impala>NOSHUFFLE'
 // | '<impala>SHUFFLE'
@@ -147,6 +153,7 @@ NonReservedKeyword
 
 NonReservedKeyword
  : 'ROLE'
+ | 'OPTION'
  ;
 
 RegularIdentifier
@@ -272,9 +279,9 @@ OptionalHiveExplainTypes
 // 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>ALL' | '<hive>ARRAY' | '<hive>AS' | '<hive>AUTHORIZATION' | '<hive>AVRO' | '<hive>BINARY' | '<hive>BUCKET' | '<hive>BUCKETS' | '<hive>CACHE' | '<hive>CLUSTER' | '<hive>CLUSTERED' | '<hive>COLLECTION' | '<hive>COMPUTE' | '<hive>CONF' | '<hive>CROSS' | '<hive>CUBE' | '<hive>CURRENT' | '<hive>DATE' | '<hive>DEFERRED' | '<hive>DELIMITED' | '<hive>DEPENDENCY' | '<hive>DIRECTORY' | '<hive>DISTRIBUTE' | '<hive>DISTRIBUTED' | '<hive>ESCAPED' | '<hive>EXTENDED' | '<hive>EXTERNAL' | '<hive>FIELDS' | '<hive>FILE' | '<hive>FOR' | '<hive>FORMAT' | '<hive>FUNCTION' | '<hive>GRANT' | '<hive>GROUPING' | '<hive>IDXPROPERTIES' | '<hive>LATERAL' | '<hive>LOCAL' | '<hive>MACRO' | '<hive>OVERWRITE' | '<hive>PARTITION' | '<hive>REBUILD' | '<hive>REPAIR' | '<hive>ROLLUP' | '<hive>SETS' | '<hive>STATISTICS' | '<hive>TABLE' | '<hive>USER' | '<hive>ASC' | '<hive>COLUMNS' | '<hive>COMMENT' | '<hive>COMPACTIONS' | '<hive>DATA' | '<hive>DATABASES' | '<hive>DEFINED' | '<hive>DESC' |  '<hive>FORMATTED' | '<hive>FUNCTIONS' | '<hive>INDEX' | '<hive>INDEXES' | '<hive>INPATH' | '<hive>INPUTFORMAT' | '<hive>ITEMS' | '<hive>JAR' | '<hive>KEYS' | '<hive>LINES' | '<hive>LOCATION' | '<hive>LOCKS' | '<hive>MAP' | '<hive>METADATA' | '<hive>NONE' | '<hive>NOSCAN' | '<hive>OF' | '<hive>ORC' | '<hive>OUT' | '<hive>OUTPUTFORMAT' | '<hive>PARQUET' | '<hive>PARTITIONED' | '<hive>PARTITIONS' | '<hive>RCFILE' | '<hive>ROLE' | '<hive>ROLES' | '<hive>SCHEMA' | '<hive>SCHEMAS' | '<hive>SEQUENCEFILE' | '<hive>SERDE' | '<hive>SERDEPROPERTIES' | '<hive>SKEWED' | '<hive>SORTED' | '<hive>STORED' | '<hive>STORED_AS_DIRECTORIES' | '<hive>STRING' | '<hive>STRUCT' | '<hive>TABLES' | '<hive>TABLESAMPLE' | '<hive>TBLPROPERTIES' | '<hive>TEMPORARY' | '<hive>TERMINATED' | '<hive>TEXTFILE' | '<hive>TINYINT' | '<hive>TRANSACTIONS' | '<hive>UNIONTYPE' | '<hive>USING' | '<hive>VIEW' | '<hive>WINDOW' | '<hive>.' | '<hive>[' | '<hive>]'
- | '<impala>AGGREGATE' | '<impala>AVRO' | '<impala>CACHED' | '<impala>CLOSE_FN' | '<impala>COLUMN' | '<impala>COMMENT' | '<impala>DATA' | '<impala>DATABASES' | '<impala>DELIMITED' | '<impala>ESCAPED' | '<impala>EXTERNAL' | '<impala>FIELDS' | '<impala>FINALIZE_FN' | '<impala>FIRST' | '<impala>FORMAT' | '<impala>FORMATTED' | '<impala>FUNCTION' | '<impala>FUNCTIONS' | '<impala>GROUP' | '<impala>INCREMENTAL' | '<impala>INTERVAL' | '<impala>INIT_FN' | '<impala>INPATH' | '<impala>LAST' | '<impala>LIMIT' | '<impala>LINES' | '<impala>LOCATION' | '<impala>MERGE_FN' | '<impala>NULLS' | '<impala>PARTITIONS' | '<impala>PREPARE_FN' | '<impala>REAL' | '<impala>RETURNS' | '<impala>SCHEMAS' | '<impala>SERIALIZE_FN' | '<impala>STATS' | '<impala>STRAIGHT_JOIN' | '<impala>SYMBOL' | '<impala>TABLE' | '<impala>TABLES' | '<impala>USING' | '<impala>ANALYTIC' | '<impala>ANTI' | '<impala>CURRENT' | '<impala>GRANT' | '<impala>NOSHUFFLE' | '<impala>PARQUET' | '<impala>PARTITIONED' | '<impala>RCFILE' | '<impala>ROLE' | '<impala>ROLES' | '<impala>SEQUENCEFILE' | '<impala>SERDEPROPERTIES' | '<impala>SHUFFLE' | '<impala>STORED' | '<impala>TBLPROPERTIES' | '<impala>TERMINATED' | '<impala>TEXTFILE' | '<impala>UPDATE_FN' | '<impala>BROADCAST' | '<impala>...' | '<impala>.' | '<impala>[' | '<impala>]'
- | 'ALL' | 'AS' | 'ASC' | 'BETWEEN' | 'BIGINT' | 'BOOLEAN' | 'BY' | 'CASE' | 'CHAR' | 'CURRENT' | 'DATABASE' | 'DECIMAL' | 'DISTINCT' | 'DOUBLE' | 'DESC' | 'ELSE' | 'END' | 'EXISTS' | 'FALSE' | 'FLOAT' | 'FOLLOWING' | 'FROM' | 'FULL' | 'GROUP' | 'HAVING' | 'IF' | 'IN' | 'INNER' | 'INSERT' | 'INT' | 'INTO' | 'IS' | 'JOIN' | 'LEFT' | 'LIKE' | 'LIMIT' | 'NOT' | 'NULL' | 'ON' | 'ORDER' | 'OUTER' | 'OVER' | 'PARTITION' | 'PRECEDING' | 'RANGE' | 'REGEXP' | 'RIGHT' | 'RLIKE' | 'ROW' | 'ROWS' | 'SCHEMA' | 'SEMI' | 'SET' | 'SMALLINT' | 'STRING' | 'TABLE' | 'THEN' | 'TIMESTAMP' | 'TINYINT' | 'TRUE' | 'UNION' | 'VALUES' | 'VARCHAR' | 'WHEN' | 'WHERE' | 'WITH' | 'ROLE'
+ : '<hive>ADMIN' | '<hive>ALL' | '<hive>ARRAY' | '<hive>AS' | '<hive>AUTHORIZATION' | '<hive>AVRO' | '<hive>BINARY' | '<hive>BUCKET' | '<hive>BUCKETS' | '<hive>CACHE' | '<hive>CLUSTER' | '<hive>CLUSTERED' | '<hive>COLLECTION' | '<hive>COMPUTE' | '<hive>CONF' | '<hive>CROSS' | '<hive>CUBE' | '<hive>CURRENT' | '<hive>DATE' | '<hive>DEFERRED' | '<hive>DELIMITED' | '<hive>DEPENDENCY' | '<hive>DIRECTORY' | '<hive>DISTRIBUTE' | '<hive>DISTRIBUTED' | '<hive>ESCAPED' | '<hive>EXTENDED' | '<hive>EXTERNAL' | '<hive>FIELDS' | '<hive>FILE' | '<hive>FOR' | '<hive>FORMAT' | '<hive>FUNCTION' | '<hive>GRANT' | '<hive>GROUPING' | '<hive>IDXPROPERTIES' | '<hive>LATERAL' | '<hive>LOCAL' | '<hive>LOCK' | '<hive>MACRO' | '<hive>OVERWRITE' | '<hive>PARTITION' | '<hive>PRIVILEGES' | '<hive>REBUILD' | '<hive>REPAIR' | '<hive>ROLLUP' | '<hive>SETS' | '<hive>STATISTICS' | '<hive>SHOW_DATABASE' | '<hive>TABLE' | '<hive>USER' | '<hive>ASC' | '<hive>COLUMNS' | '<hive>COMMENT' | '<hive>COMPACTIONS' | '<hive>DATA' | '<hive>DATABASES' | '<hive>DEFINED' | '<hive>DESC' |  '<hive>FORMATTED' | '<hive>FUNCTIONS' | '<hive>INDEX' | '<hive>INDEXES' | '<hive>INPATH' | '<hive>INPUTFORMAT' | '<hive>ITEMS' | '<hive>JAR' | '<hive>KEYS' | '<hive>LINES' | '<hive>LOCATION' | '<hive>LOCKS' | '<hive>MAP' | '<hive>METADATA' | '<hive>NONE' | '<hive>NOSCAN' | '<hive>OF' | '<hive>ORC' | '<hive>OUT' | '<hive>OUTPUTFORMAT' | '<hive>PARQUET' | '<hive>PARTITIONED' | '<hive>PARTITIONS' | '<hive>RCFILE' | '<hive>ROLE' | '<hive>ROLES' | '<hive>SCHEMA' | '<hive>SCHEMAS' | '<hive>SEQUENCEFILE' | '<hive>SERDE' | '<hive>SERDEPROPERTIES' | '<hive>SKEWED' | '<hive>SORTED' | '<hive>STORED' | '<hive>STORED_AS_DIRECTORIES' | '<hive>STRING' | '<hive>STRUCT' | '<hive>TABLES' | '<hive>TABLESAMPLE' | '<hive>TBLPROPERTIES' | '<hive>TEMPORARY' | '<hive>TERMINATED' | '<hive>TEXTFILE' | '<hive>TINYINT' | '<hive>TRANSACTIONS' | '<hive>UNIONTYPE' | '<hive>USING' | '<hive>VIEW' | '<hive>WINDOW' | '<hive>.' | '<hive>[' | '<hive>]'
+ | '<impala>AGGREGATE' | '<impala>AVRO' | '<impala>CACHED' | '<impala>CLOSE_FN' | '<impala>COLUMN' | '<impala>COMMENT' | '<impala>DATA' | '<impala>DATABASES' | '<impala>DELIMITED' | '<impala>ESCAPED' | '<impala>EXTERNAL' | '<impala>FIELDS' | '<impala>FINALIZE_FN' | '<impala>FIRST' | '<impala>FORMAT' | '<impala>FORMATTED' | '<impala>FUNCTION' | '<impala>FUNCTIONS' | '<impala>GROUP' | '<impala>INCREMENTAL' | '<impala>INTERVAL' | '<impala>INIT_FN' | '<impala>INPATH' | '<impala>LAST' | '<impala>LIMIT' | '<impala>LINES' | '<impala>LOCATION' | '<impala>MERGE_FN' | '<impala>NULLS' | '<impala>PARTITIONS' | '<impala>PREPARE_FN' | '<impala>REAL' | '<impala>RETURNS' | '<impala>SCHEMAS' | '<impala>SERIALIZE_FN' | '<impala>SERVER' | '<impala>STATS' | '<impala>STRAIGHT_JOIN' | '<impala>SYMBOL' | '<impala>TABLE' | '<impala>TABLES' | '<impala>URI' | '<impala>USING' | '<impala>ANALYTIC' | '<impala>ANTI' | '<impala>CURRENT' | '<impala>GRANT' | '<impala>NOSHUFFLE' | '<impala>PARQUET' | '<impala>PARTITIONED' | '<impala>RCFILE' | '<impala>ROLE' | '<impala>ROLES' | '<impala>SEQUENCEFILE' | '<impala>SERDEPROPERTIES' | '<impala>SHUFFLE' | '<impala>STORED' | '<impala>TBLPROPERTIES' | '<impala>TERMINATED' | '<impala>TEXTFILE' | '<impala>UPDATE_FN' | '<impala>BROADCAST' | '<impala>...' | '<impala>.' | '<impala>[' | '<impala>]'
+ | 'ALL' | 'AS' | 'ASC' | 'BETWEEN' | 'BIGINT' | 'BOOLEAN' | 'BY' | 'CASE' | 'CHAR' | 'CURRENT' | 'DATABASE' | 'DECIMAL' | 'DISTINCT' | 'DOUBLE' | 'DESC' | 'ELSE' | 'END' | 'EXISTS' | 'FALSE' | 'FLOAT' | 'FOLLOWING' | 'FROM' | 'FULL' | 'GROUP' | 'HAVING' | 'IF' | 'IN' | 'INNER' | 'INSERT' | 'INT' | 'INTO' | 'IS' | 'JOIN' | 'LEFT' | 'LIKE' | 'LIMIT' | 'NOT' | 'NULL' | 'ON' | 'OPTION' | 'ORDER' | 'OUTER' | 'OVER' | 'PARTITION' | 'PRECEDING' | 'RANGE' | 'REGEXP' | 'RIGHT' | 'RLIKE' | 'ROW' | 'ROWS' | 'SCHEMA' | 'SEMI' | 'SET' | 'SMALLINT' | 'STRING' | 'TABLE' | 'THEN' | 'TIMESTAMP' | 'TINYINT' | 'TRUE' | 'UNION' | 'VALUES' | 'VARCHAR' | 'WHEN' | 'WHERE' | 'WITH' | 'ROLE'
  | 'AVG' | 'CAST' | 'COUNT' | 'MAX' | 'MIN' | 'STDDEV_POP' | 'STDDEV_SAMP' | 'SUM' | 'VARIANCE' | 'VAR_POP' | 'VAR_SAMP'
  | '<hive>COLLECT_SET' | '<hive>COLLECT_LIST' | '<hive>CORR' | '<hive>COVAR_POP' | '<hive>COVAR_SAMP' | '<hive>HISTOGRAM_NUMERIC' | '<hive>NTILE' | '<hive>PERCENTILE' | '<hive>PERCENTILE_APPROX'
  | '<impala>APPX_MEDIAN' | '<impala>EXTRACT' | '<impala>GROUP_CONCAT' | '<impala>STDDEV' | '<impala>VARIANCE_POP' | '<impala>VARIANCE_SAMP'

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
desktop/core/src/desktop/static/desktop/js/autocomplete/sql.js


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

@@ -922,7 +922,7 @@ var getKeywordsForOptionalsLR = function (optionals, keywords, override) {
 };
 
 var suggestDdlAndDmlKeywords = function (extraKeywords) {
-  var keywords = ['ALTER', 'CREATE', 'DESCRIBE', 'DROP', 'INSERT', 'REVOKE', 'SELECT', 'SET', 'SHOW', 'TRUNCATE', 'UPDATE', 'USE', 'WITH'];
+  var keywords = ['ALTER', 'CREATE', 'DESCRIBE', 'DROP', 'GRANT', 'INSERT', 'REVOKE', 'SELECT', 'SET', 'SHOW', 'TRUNCATE', 'UPDATE', 'USE', 'WITH'];
 
   if (extraKeywords) {
     keywords = keywords.concat(extraKeywords);

+ 1 - 1
desktop/core/src/desktop/static/desktop/js/sqlAutocompleter2.js

@@ -1103,7 +1103,7 @@ var SqlAutocompleter2 = (function () {
   };
 
   var extraHiveReservedKeywords = {
-    ASC: true, CLUSTER: true, DESC: true, DISTRIBUTE: true, FORMATTED: true, FUNCTION: true, INDEX: true, INDEXES: true, LIMIT: true, SCHEMA: true, SORT: true
+    ASC: true, CLUSTER: true, DESC: true, DISTRIBUTE: true, FORMATTED: true, FUNCTION: true, INDEX: true, INDEXES: true, LIMIT: true, LOCK: true, SCHEMA: true, SORT: true
   };
 
   var impalaReservedKeywords = {

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

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

+ 1176 - 0
desktop/core/src/desktop/static/desktop/spec/autocomplete/sqlSpecGrant.js

@@ -0,0 +1,1176 @@
+// 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.
+
+(function () {
+  describe('sql.js GRANT statements', function() {
+
+    beforeAll(function () {
+      sql.yy.parseError = function (msg) {
+        throw Error(msg);
+      };
+      jasmine.addMatchers(SqlTestUtils.testDefinitionMatcher);
+    });
+
+    var assertAutoComplete = SqlTestUtils.assertAutocomplete;
+
+    describe('GRANT', function () {
+
+      it('should suggest keywords for "|"', function() {
+        assertAutoComplete({
+          beforeCursor: '',
+          afterCursor: '',
+          noErrors: true,
+          containsKeywords: ['GRANT'],
+          expectedResult: {
+            lowerCase: false
+          }
+        });
+      });
+
+      describe('Hive specific', function () {
+
+        it('should suggest keywords for "GRANT |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'GRANT ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['ALL', 'ALTER', 'CREATE', 'DELETE', 'DROP', 'INDEX', 'INSERT', 'LOCK', 'ROLE', 'SELECT', 'UPDATE']
+            }
+          });
+        });
+
+        it('should suggest keywords for "GRANT ALL, |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'GRANT ALL, ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['ALL', 'ALTER', 'CREATE', 'DELETE', 'DROP', 'INDEX', 'INSERT', 'LOCK', 'SELECT', 'SHOW_DATABASE', 'UPDATE']
+            }
+          });
+        });
+
+        it('should suggest keywords for "GRANT CREATE, DELETE |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'GRANT CREATE, DELETE ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['ON', 'TO']
+            }
+          });
+        });
+
+        it('should suggest keywords for "GRANT ALTER ON |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'GRANT ALTER ON ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['DATABASE', 'TABLE'],
+              suggestTables: {},
+              suggestDatabases: { appendDot: true }
+            }
+          });
+        });
+
+        it('should suggest keywords for "GRANT ALTER ON DATABASE |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'GRANT ALTER ON DATABASE ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestDatabases: {}
+            }
+          });
+        });
+
+        it('should suggest keywords for "GRANT ALTER ON DATABASE bla |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'GRANT ALTER ON DATABASE bla ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['TO']
+            }
+          });
+        });
+
+        it('should suggest keywords for "GRANT ALTER ON TABLE |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'GRANT ALTER ON TABLE ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestTables: {},
+              suggestDatabases: { appendDot: true }
+            }
+          });
+        });
+
+        it('should suggest keywords for "GRANT ALTER ON TABLE bla |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'GRANT ALTER ON TABLE bla ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            hasLocations: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['TO']
+            }
+          });
+        });
+
+        it('should suggest keywords for "GRANT INDEX ON TABLE bla TO |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'GRANT INDEX ON TABLE bla TO ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            hasLocations: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['GROUP', 'ROLE', 'USER']
+            }
+          });
+        });
+
+        it('should suggest keywords for "GRANT INDEX ON TABLE bla TO USER bla, |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'GRANT INDEX ON TABLE bla TO USER bla, ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            hasLocations: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['GROUP', 'ROLE', 'USER']
+            }
+          });
+        });
+
+        it('should suggest keywords for "GRANT INDEX ON TABLE bla TO USER bla, ROLE boo |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'GRANT INDEX ON TABLE bla TO USER bla, ROLE boo ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            hasLocations: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['WITH GRANT OPTION']
+            }
+          });
+        });
+
+        it('should suggest keywords for "GRANT INDEX ON TABLE bla TO USER bla, ROLE boo WITH |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'GRANT INDEX ON TABLE bla TO USER bla, ROLE boo WITH ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            hasLocations: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['GRANT OPTION']
+            }
+          });
+        });
+
+        it('should suggest keywords for "GRANT SHOW_DATABASE ON DATABASE boo TO USER bla, ROLE boo WITH GRANT |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'GRANT SHOW_DATABASE ON DATABASE boo TO USER bla, ROLE boo WITH GRANT ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['OPTION']
+            }
+          });
+        });
+
+        it('should suggest keywords for "GRANT bla, ble TO |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'GRANT bla, ble TO ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['GROUP', 'ROLE', 'USER']
+            }
+          });
+        });
+
+        it('should suggest keywords for "GRANT bla, ble TO USER baa, |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'GRANT bla, ble TO USER baa, ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['GROUP', 'ROLE', 'USER']
+            }
+          });
+        });
+
+        it('should suggest keywords for "GRANT bla, ble TO USER baa, ROLE boo |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'GRANT bla, ble TO USER baa, ROLE boo  ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['WITH ADMIN OPTION']
+            }
+          });
+        });
+
+        it('should suggest keywords for "GRANT ble TO ROLE baa WITH |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'GRANT ble TO ROLE baa WITH ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['ADMIN OPTION']
+            }
+          });
+        });
+
+        it('should suggest keywords for "GRANT ble TO ROLE baa WITH ADMIN |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'GRANT ble TO ROLE baa WITH ADMIN ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['OPTION']
+            }
+          });
+        });
+
+        it('should suggest keywords for "GRANT ROLE bla, ble TO |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'GRANT ROLE bla, ble TO ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['GROUP', 'ROLE', 'USER']
+            }
+          });
+        });
+
+        it('should suggest keywords for "GRANT ROLE bla, ble TO USER baa, |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'GRANT ROLE bla, ble TO USER baa, ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['GROUP', 'ROLE', 'USER']
+            }
+          });
+        });
+
+        it('should suggest keywords for "GRANT ROLE bla, ble TO USER baa, ROLE boo |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'GRANT ROLE bla, ble TO USER baa, ROLE boo  ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['WITH ADMIN OPTION']
+            }
+          });
+        });
+
+        it('should suggest keywords for "GRANT ROLE ble TO ROLE baa WITH |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'GRANT ROLE ble TO ROLE baa WITH ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['ADMIN OPTION']
+            }
+          });
+        });
+
+        it('should suggest keywords for "GRANT ROLE ble TO ROLE baa WITH ADMIN |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'GRANT ROLE ble TO ROLE baa WITH ADMIN ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['OPTION']
+            }
+          });
+        });
+
+        it('should handle "GRANT ROLE foo TO GROUP bla;|"', function() {
+          assertAutoComplete({
+            beforeCursor: 'GRANT ROLE foo TO GROUP bla;',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            containsKeywords: ['SELECT'],
+            expectedResult: {
+              lowerCase: false
+            }
+          });
+        });
+
+        it('should handle "GRANT ROLE foo, bar TO USER bla, ROLE boo WITH ADMIN OPTION;|"', function() {
+          assertAutoComplete({
+            beforeCursor: 'GRANT ROLE foo, bar TO USER bla, ROLE boo WITH ADMIN OPTION;',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            containsKeywords: ['SELECT'],
+            expectedResult: {
+              lowerCase: false
+            }
+          });
+        });
+
+        it('should handle "GRANT SELECT TO ROLE baa;|"', function() {
+          assertAutoComplete({
+            beforeCursor: 'GRANT SELECT TO ROLE baa;',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            containsKeywords: ['SELECT'],
+            expectedResult: {
+              lowerCase: false
+            }
+          });
+        });
+
+        it('should handle "GRANT ALTER (col1, col2), LOCK, ALL (col3, col4) ON TABLE tbl1 TO USER baa, ROLE boo WITH GRANT OPTION;|"', function() {
+          assertAutoComplete({
+            beforeCursor: 'GRANT ALTER (col1, col2), LOCK, ALL (col3, col4) ON TABLE tbl1 TO USER baa, ROLE boo WITH GRANT OPTION;',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            containsKeywords: ['SELECT'],
+            hasLocations: true,
+            expectedResult: {
+              lowerCase: false
+            }
+          });
+        });
+      });
+
+      describe('Impala specific', function () {
+        it('should suggest keywords for "GRANT |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'GRANT ',
+            afterCursor: '',
+            noErrors: true,
+            dialect: 'impala',
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['ALL', 'INSERT', 'ROLE', 'SELECT']
+            }
+          });
+        });
+
+        it('should suggest keywords for "GRANT ROLE baa |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'GRANT ROLE baa ',
+            afterCursor: '',
+            noErrors: true,
+            dialect: 'impala',
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['TO GROUP']
+            }
+          });
+        });
+
+        it('should suggest keywords for "GRANT ROLE baa TO |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'GRANT ROLE baa TO ',
+            afterCursor: '',
+            noErrors: true,
+            dialect: 'impala',
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['GROUP']
+            }
+          });
+        });
+
+        it('should suggest keywords for "GRANT SELECT |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'GRANT SELECT ',
+            afterCursor: '',
+            noErrors: true,
+            dialect: 'impala',
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['ON DATABASE', 'ON SERVER', 'ON TABLE', 'ON URI']
+            }
+          });
+        });
+
+        it('should suggest keywords for "GRANT INSERT ON |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'GRANT INSERT ON ',
+            afterCursor: '',
+            noErrors: true,
+            dialect: 'impala',
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['DATABASE', 'SERVER', 'TABLE', 'URI']
+            }
+          });
+        });
+
+        it('should suggest tables for "GRANT INSERT ON TABLE |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'GRANT INSERT ON TABLE ',
+            afterCursor: '',
+            noErrors: true,
+            dialect: 'impala',
+            expectedResult: {
+              lowerCase: false,
+              suggestTables: {},
+              suggestDatabases: { appendDot: true }
+            }
+          });
+        });
+
+        it('should suggest databases for "GRANT INSERT ON DATABASE |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'GRANT INSERT ON DATABASE ',
+            afterCursor: '',
+            noErrors: true,
+            dialect: 'impala',
+            expectedResult: {
+              lowerCase: false,
+              suggestDatabases: { }
+            }
+          });
+        });
+
+        it('should suggest keywords for "GRANT ALL ON TABLE tbl |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'GRANT ALL ON TABLE tbl ',
+            afterCursor: '',
+            noErrors: true,
+            dialect: 'impala',
+            hasLocations: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['TO']
+            }
+          });
+        });
+
+        it('should suggest keywords for "GRANT ALL ON TABLE tbl TO |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'GRANT ALL ON TABLE tbl TO ',
+            afterCursor: '',
+            noErrors: true,
+            dialect: 'impala',
+            hasLocations: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['ROLE']
+            }
+          });
+        });
+
+        it('should suggest keywords for "GRANT ALL ON TABLE tbl TO bla |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'GRANT ALL ON TABLE tbl TO bla ',
+            afterCursor: '',
+            noErrors: true,
+            dialect: 'impala',
+            hasLocations: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['WITH GRANT OPTION']
+            }
+          });
+        });
+
+        it('should suggest keywords for "GRANT ALL ON TABLE tbl TO bla WITH |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'GRANT ALL ON TABLE tbl TO bla WITH ',
+            afterCursor: '',
+            noErrors: true,
+            dialect: 'impala',
+            hasLocations: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['GRANT OPTION']
+            }
+          });
+        });
+
+        it('should suggest keywords for "GRANT ALL ON TABLE tbl TO bla WITH GRANT |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'GRANT ALL ON TABLE tbl TO bla WITH GRANT ',
+            afterCursor: '',
+            noErrors: true,
+            dialect: 'impala',
+            hasLocations: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['OPTION']
+            }
+          });
+        });
+
+        it('should handle "GRANT ROLE baa TO GROUP ble;|"', function() {
+          assertAutoComplete({
+            beforeCursor: 'GRANT ROLE baa TO GROUP ble;',
+            afterCursor: '',
+            dialect: 'impala',
+            noErrors: true,
+            containsKeywords: ['SELECT'],
+            expectedResult: {
+              lowerCase: false
+            }
+          });
+        });
+
+        it('should handle "GRANT SELECT(id) ON TABLE tbl TO ROLE bla WITH GRANT OPTION;|"', function() {
+          assertAutoComplete({
+            beforeCursor: 'GRANT SELECT(id) ON TABLE tbl TO ROLE bla WITH GRANT OPTION;',
+            afterCursor: '',
+            dialect: 'impala',
+            noErrors: true,
+            containsKeywords: ['SELECT'],
+            hasLocations: true,
+            expectedResult: {
+              lowerCase: false
+            }
+          });
+        });
+
+        it('should handle "GRANT ALL ON DATABASE db1 TO bla;|"', function() {
+          assertAutoComplete({
+            beforeCursor: 'GRANT ALL ON DATABASE db1 TO bla;',
+            afterCursor: '',
+            dialect: 'impala',
+            noErrors: true,
+            containsKeywords: ['SELECT'],
+            //hasLocations: true, // TODO: should have database location
+            expectedResult: {
+              lowerCase: false
+            }
+          });
+        });
+      });
+    });
+
+    describe('REVOKE', function () {
+      it('should suggest keywords for "|"', function() {
+        assertAutoComplete({
+          beforeCursor: '',
+          afterCursor: '',
+          noErrors: true,
+          containsKeywords: ['REVOKE'],
+          expectedResult: {
+            lowerCase: false
+          }
+        });
+      });
+
+      describe('Hive specific', function () {
+        it('should suggest keywords for "REVOKE |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'REVOKE ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              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']
+            }
+          });
+        });
+
+        it('should suggest keywords for "REVOKE ADMIN |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'REVOKE ADMIN ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['FROM', 'OPTION FOR']
+            }
+          });
+        });
+
+        it('should suggest keywords for "REVOKE ADMIN OPTION |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'REVOKE ADMIN OPTION ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['FOR']
+            }
+          });
+        });
+
+        it('should suggest keywords for "REVOKE ADMIN OPTION FOR |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'REVOKE ADMIN OPTION FOR ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['ROLE']
+            }
+          });
+        });
+
+        it('should suggest keywords for "REVOKE ADMIN OPTION FOR ROLE bla |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'REVOKE ADMIN OPTION FOR ROLE bla ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['FROM']
+            }
+          });
+        });
+
+        it('should suggest keywords for "REVOKE ADMIN OPTION FOR ROLE bla FROM |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'REVOKE ADMIN OPTION FOR ROLE bla FROM ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['GROUP', 'ROLE', 'USER']
+            }
+          });
+        });
+
+        it('should suggest keywords for "REVOKE ADMIN OPTION FOR ROLE bla, ble FROM GROUP baa, |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'REVOKE ADMIN OPTION FOR ROLE bla, ble FROM GROUP baa, ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['GROUP', 'ROLE', 'USER']
+            }
+          });
+        });
+
+        it('should suggest keywords for "REVOKE ALL |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'REVOKE ALL ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['FROM', 'GRANT OPTION', 'ON', 'PRIVILEGES FROM']
+            }
+          });
+        });
+
+        it('should suggest keywords for "REVOKE ALL PRIVILEGES |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'REVOKE ALL PRIVILEGES ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['FROM']
+            }
+          });
+        });
+
+        it('should suggest keywords for "REVOKE ALL GRANT |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'REVOKE ALL GRANT ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['OPTION']
+            }
+          });
+        });
+
+        it('should suggest keywords for "REVOKE GRANT |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'REVOKE GRANT ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['OPTION FOR']
+            }
+          });
+        });
+
+        it('should suggest keywords for "REVOKE GRANT OPTION |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'REVOKE GRANT OPTION ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['FOR']
+            }
+          });
+        });
+
+        it('should suggest keywords for "REVOKE GRANT OPTION FOR |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'REVOKE GRANT OPTION FOR ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['ALL', 'ALTER', 'CREATE', 'DELETE', 'DROP', 'INDEX', 'INSERT', 'LOCK', 'SELECT', 'SHOW_DATABASE', 'UPDATE']
+            }
+          });
+        });
+
+        it('should suggest keywords for "REVOKE GRANT OPTION FOR CREATE(col1), |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'REVOKE GRANT OPTION FOR CREATE(col1), ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['ALL', 'ALTER', 'CREATE', 'DELETE', 'DROP', 'INDEX', 'INSERT', 'LOCK', 'SELECT', 'SHOW_DATABASE', 'UPDATE']
+            }
+          });
+        });
+
+        it('should suggest keywords for "REVOKE GRANT OPTION FOR CREATE(col1), SELECT |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'REVOKE GRANT OPTION FOR CREATE(col1), SELECT ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['FROM', 'ON']
+            }
+          });
+        });
+
+        it('should suggest keywords for "REVOKE GRANT OPTION FOR CREATE(col1), SELECT ON |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'REVOKE GRANT OPTION FOR CREATE(col1), SELECT ON ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['DATABASE', 'TABLE'],
+              suggestTables: {},
+              suggestDatabases: { appendDot: true }
+            }
+          });
+        });
+
+        it('should suggest tables for "REVOKE GRANT OPTION FOR CREATE(col1), SELECT ON TABLE |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'REVOKE GRANT OPTION FOR CREATE(col1), SELECT ON TABLE ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestTables: {},
+              suggestDatabases: { appendDot: true }
+            }
+          });
+        });
+
+        it('should suggest tables for "REVOKE CREATE(col1), SELECT ON DATABASE |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'REVOKE CREATE(col1), SELECT ON DATABASE ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestDatabases: { }
+            }
+          });
+        });
+
+        it('should suggest keywords for "REVOKE GRANT OPTION FOR CREATE(col1), SELECT ON TABLE tbl1 |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'REVOKE GRANT OPTION FOR CREATE(col1), SELECT ON TABLE tbl1 ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            hasLocations: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['FROM']
+            }
+          });
+        });
+
+        it('should suggest tables for "REVOKE CREATE(col1), SELECT ON DATABASE db1 |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'REVOKE CREATE(col1), SELECT ON DATABASE db1 ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['FROM']
+            }
+          });
+        });
+
+        it('should suggest keywords for "REVOKE GRANT OPTION FOR CREATE(col1), SELECT ON TABLE tbl1 FROM |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'REVOKE GRANT OPTION FOR CREATE(col1), SELECT ON TABLE tbl1 FROM ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            hasLocations: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['GROUP', 'ROLE', 'USER']
+            }
+          });
+        });
+
+        it('should suggest keywords for "REVOKE GRANT OPTION FOR CREATE(col1), SELECT ON TABLE tbl1 FROM USER baa, |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'REVOKE GRANT OPTION FOR CREATE(col1), SELECT ON TABLE tbl1 FROM USER baa, ',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            hasLocations: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['GROUP', 'ROLE', 'USER']
+            }
+          });
+        });
+
+        it('should handle "REVOKE ROLE baa FROM GROUP bla;|"', function() {
+          assertAutoComplete({
+            beforeCursor: 'REVOKE ROLE baa FROM GROUP bla;',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            containsKeywords: ['SELECT'],
+            expectedResult: {
+              lowerCase: false
+            }
+          });
+        });
+
+        it('should handle "REVOKE ADMIN OPTION FOR ROLE baa, boo FROM ROLE bla, USER ble;|"', function() {
+          assertAutoComplete({
+            beforeCursor: 'REVOKE ADMIN OPTION FOR ROLE baa, boo FROM ROLE bla, USER ble;',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            containsKeywords: ['SELECT'],
+            expectedResult: {
+              lowerCase: false
+            }
+          });
+        });
+
+        it('should handle "REVOKE GRANT OPTION FOR ALTER (col1, col2), LOCK, ALL (col3, col4) ON TABLE tbl1 FROM USER baa, ROLE boo;|"', function() {
+          assertAutoComplete({
+            beforeCursor: 'REVOKE GRANT OPTION FOR ALTER (col1, col2), LOCK, ALL (col3, col4) ON TABLE tbl1 FROM USER baa, ROLE boo;',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            containsKeywords: ['SELECT'],
+            hasLocations: true,
+            expectedResult: {
+              lowerCase: false
+            }
+          });
+        });
+
+        it('should handle "REVOKE ALL FROM GROUP ble;|"', function() {
+          assertAutoComplete({
+            beforeCursor: 'REVOKE ALL FROM GROUP ble;',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            containsKeywords: ['SELECT'],
+            expectedResult: {
+              lowerCase: false
+            }
+          });
+        });
+
+        it('should handle "REVOKE ALL PRIVILEGES FROM boo, baa;|"', function() {
+          assertAutoComplete({
+            beforeCursor: 'REVOKE ALL PRIVILEGES FROM boo, baa;',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            containsKeywords: ['SELECT'],
+            expectedResult: {
+              lowerCase: false
+            }
+          });
+        });
+
+        it('should handle "REVOKE ALL GRANT OPTION FROM boo;|"', function() {
+          assertAutoComplete({
+            beforeCursor: 'REVOKE ALL GRANT OPTION FROM boo;',
+            afterCursor: '',
+            dialect: 'hive',
+            noErrors: true,
+            containsKeywords: ['SELECT'],
+            expectedResult: {
+              lowerCase: false
+            }
+          });
+        });
+      });
+
+      describe('Impala specific', function () {
+        it('should suggest keywords for "REVOKE |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'REVOKE ',
+            afterCursor: '',
+            dialect: 'impala',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['ALL', 'INSERT', 'ROLE', 'SELECT']
+            }
+          });
+        });
+
+        it('should suggest keywords for "REVOKE ALL |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'REVOKE ALL ',
+            afterCursor: '',
+            dialect: 'impala',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['ON DATABASE', 'ON SERVER', 'ON TABLE', 'ON URI']
+            }
+          });
+        });
+
+        it('should suggest keywords for "REVOKE ALL ON |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'REVOKE ALL ON ',
+            afterCursor: '',
+            dialect: 'impala',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['DATABASE', 'SERVER', 'TABLE', 'URI']
+            }
+          });
+        });
+
+        it('should suggest databases for "REVOKE ALL ON DATABASE |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'REVOKE ALL ON DATABASE ',
+            afterCursor: '',
+            dialect: 'impala',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestDatabases: {}
+            }
+          });
+        });
+
+        it('should suggest tables for "REVOKE INSERT ON TABLE |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'REVOKE INSERT ON TABLE ',
+            afterCursor: '',
+            dialect: 'impala',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestTables: {},
+              suggestDatabases: { appendDot: true }
+            }
+          });
+        });
+
+        it('should suggest keywords for "REVOKE INSERT ON TABLE tbl1 |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'REVOKE INSERT ON TABLE tbl1 ',
+            afterCursor: '',
+            dialect: 'impala',
+            noErrors: true,
+            hasLocations: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['FROM']
+            }
+          });
+        });
+
+        it('should suggest keywords for "REVOKE SELECT ON DATABASE db1 FROM |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'REVOKE INSERT ON TABLE tbl1 FROM ',
+            afterCursor: '',
+            dialect: 'impala',
+            noErrors: true,
+            hasLocations: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['ROLE']
+            }
+          });
+        });
+
+        it('should suggest keywords for "REVOKE SELECT ON DATABASE db1 FROM |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'REVOKE INSERT ON TABLE tbl1 FROM ',
+            afterCursor: '',
+            dialect: 'impala',
+            noErrors: true,
+            hasLocations: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['ROLE']
+            }
+          });
+        });
+
+        it('should suggest keywords for "REVOKE ROLE bla |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'REVOKE ROLE bla ',
+            afterCursor: '',
+            dialect: 'impala',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['FROM GROUP']
+            }
+          });
+        });
+
+        it('should suggest keywords for "REVOKE ROLE bla FROM |"', function() {
+          assertAutoComplete({
+            beforeCursor: 'REVOKE ROLE bla FROM ',
+            afterCursor: '',
+            dialect: 'impala',
+            noErrors: true,
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['GROUP']
+            }
+          });
+        });
+
+        it('should handle "REVOKE ROLE bla FROM GROUP ble;|"', function() {
+          assertAutoComplete({
+            beforeCursor: 'REVOKE ROLE bla FROM GROUP ble;',
+            afterCursor: '',
+            dialect: 'impala',
+            noErrors: true,
+            containsKeywords: ['SELECT'],
+            expectedResult: {
+              lowerCase: false
+            }
+          });
+        });
+
+        it('should handle "REVOKE SELECT(id) ON SERVER ble FROM ROLE bla;|"', function() {
+          assertAutoComplete({
+            beforeCursor: 'REVOKE SELECT ON SERVER ble FROM ROLE bla;',
+            afterCursor: '',
+            dialect: 'impala',
+            noErrors: true,
+            containsKeywords: ['SELECT'],
+            hasLocations: false,
+            expectedResult: {
+              lowerCase: false
+            }
+          });
+        });
+
+        it('should handle "REVOKE INSERT ON TABLE ble FROM bla;|"', function() {
+          assertAutoComplete({
+            beforeCursor: 'REVOKE INSERT ON TABLE ble FROM bla;',
+            afterCursor: '',
+            dialect: 'impala',
+            noErrors: true,
+            containsKeywords: ['SELECT'],
+            hasLocations: true,
+            expectedResult: {
+              lowerCase: false
+            }
+          });
+        });
+      });
+    });
+  });
+})();

+ 1 - 0
desktop/core/src/desktop/templates/jasmineRunner.html

@@ -61,6 +61,7 @@
   <script type="text/javascript" src="../static/desktop/spec/autocomplete/sqlSpecDescribe.js"></script>
   <script type="text/javascript" src="../static/desktop/spec/autocomplete/sqlSpecDrop.js"></script>
   <script type="text/javascript" src="../static/desktop/spec/autocomplete/sqlSpecError.js"></script>
+  <script type="text/javascript" src="../static/desktop/spec/autocomplete/sqlSpecGrant.js"></script>
   <script type="text/javascript" src="../static/desktop/spec/autocomplete/sqlSpecInsert.js"></script>
   <script type="text/javascript" src="../static/desktop/spec/autocomplete/sqlSpecLoad.js"></script>
   <script type="text/javascript" src="../static/desktop/spec/autocomplete/sqlSpecLocations.js"></script>

+ 1 - 1
tools/jison/hue-jison.sh

@@ -31,7 +31,7 @@ echo "%%" > sql_end.jison
 # For quick version of select with create only and no support for value expressions (i.e. a = b or a IN (1, 2, 3))
 # cat sql_main.jison sql_create.jison sql_end.jison ../sql_support.js > sql.jison
 
-cat sql_main.jison sql_valueExpression.jison sql_error.jison sql_alter.jison sql_analyze.jison sql_create.jison sql_drop.jison sql_insert.jison sql_load.jison sql_set.jison sql_show.jison sql_update.jison sql_use.jison sql_end.jison ../sql_support.js > sql.jison
+cat sql_main.jison sql_valueExpression.jison sql_error.jison sql_alter.jison sql_analyze.jison sql_create.jison sql_drop.jison sql_grant.jison sql_insert.jison sql_load.jison sql_set.jison sql_show.jison sql_update.jison sql_use.jison sql_end.jison ../sql_support.js > sql.jison
 
 jison sql.jison sql.jisonlex
 cat license.txt sql.js > ../sql.js

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác