Преглед изворни кода

HUE-4194 [editor] Autocomplete CREATE DATABASE

This also enables HDFS autocompletion.
Johan Ahlen пре 9 година
родитељ
комит
e65e10245d

+ 142 - 18
desktop/core/src/desktop/static/desktop/js/autocomplete/sql.jison

@@ -33,11 +33,14 @@
 'BY'                                { return 'BY'; }
 'CHAR'                              { return 'CHAR'; }
 'CREATE'                            { return 'CREATE'; }
+'DATABASE'                          { return 'DATABASE'; }
 'DECIMAL'                           { return 'DECIMAL'; }
 'DOUBLE'                            { return 'DOUBLE'; }
+'EXISTS'                            { return 'EXISTS'; }
 'FLOAT'                             { return 'FLOAT'; }
 'FROM'                              { return 'FROM'; }
 'GROUP'                             { return 'GROUP'; }
+'IF'                                { return 'IF'; }
 'INT'                               { return 'INT'; }
 'INTO'                              { return 'INTO'; }
 'IS'                                { return 'IS'; }
@@ -46,6 +49,7 @@
 'ON'                                { return 'ON'; }
 'OR'                                { return 'OR'; }
 'ORDER'                             { return 'ORDER'; }
+'SCHEMA'                            { return 'SCHEMA'; }
 'SELECT'                            { determineCase(yytext); return 'SELECT'; }
 'SET'                               { return 'SET'; }
 'SMALLINT'                          { return 'SMALLINT'; }
@@ -61,6 +65,7 @@
 
 <hive>'AS'                          { return '<hive>AS'; }
 <hive>'BINARY'                      { return '<hive>BINARY'; }
+<hive>'COMMENT'                     { return '<hive>COMMENT'; }
 <hive>'DATA'                        { return '<hive>DATA'; }
 <hive>'DATE'                        { return '<hive>DATE'; }
 <hive>'EXTERNAL'                    { return '<hive>EXTERNAL'; }
@@ -74,6 +79,7 @@
 
 <hive>[.]                           { return '<hive>.'; }
 
+<impala>'COMMENT'                   { return '<impala>COMMENT'; }
 <impala>'DATA'                      { return '<impala>DATA'; }
 <impala>'EXTERNAL'                  { return '<impala>EXTERNAL'; }
 <impala>'INPATH'                    { this.begin('hdfs'); return '<impala>INPATH'; }
@@ -182,7 +188,7 @@ SqlStatements
 SqlStatement
  : UseStatement
  | DataManipulation
- | TableDefinition
+ | DataDefinition
  | QueryExpression
  | 'REGULAR_IDENTIFIER' 'PARTIAL_CURSOR' 'REGULAR_IDENTIFIER'
  | 'REGULAR_IDENTIFIER' 'PARTIAL_CURSOR'
@@ -325,41 +331,154 @@ ValueExpression
  : BooleanValueExpression
  ;
 
+DataDefinition
+ : TableDefinition
+ | DatabaseDefinition
+ | 'CREATE' PartialIdentifierOrCursor
+   {
+     if (parser.yy.dialect === 'hive' || parser.yy.dialect === 'impala') {
+       suggestKeywords(['DATABASE', 'EXTERNAL', 'SCHEMA', 'TABLE']);
+     } else {
+       suggestKeywords(['DATABASE', 'SCHEMA', 'TABLE']);
+     }
+   }
+ ;
+
+DatabaseOrSchema
+ : 'DATABASE'
+ | 'SCHEMA'
+ ;
+
+OptionalIfNotExists
+ :
+ | 'IF' PartialIdentifierOrCursor
+   {
+     suggestKeywords(['NOT EXISTS']);
+   }
+ | 'IF' 'NOT' PartialIdentifierOrCursor
+   {
+     suggestKeywords(['EXISTS']);
+   }
+ | 'IF' 'NOT' 'EXISTS'
+ | 'CURSOR'
+   {
+     suggestKeywords(['IF NOT EXISTS']);
+   }
+ ;
+
+Comment
+ : HiveOrImpalaComment SINGLE_QUOTE
+ | HiveOrImpalaComment SINGLE_QUOTE VALUE
+ | HiveOrImpalaComment SINGLE_QUOTE VALUE SINGLE_QUOTE
+ ;
+
+HivePropertyAssignmentList
+ : HivePropertyAssignment
+ | HivePropertyAssignmentList ',' HivePropertyAssignment
+ ;
+
+HivePropertyAssignment
+ : 'REGULAR_IDENTIFIER' '=' 'REGULAR_IDENTIFIER'
+ | SINGLE_QUOTE VALUE SINGLE_QUOTE '=' SINGLE_QUOTE VALUE SINGLE_QUOTE
+ ;
+
+HiveDbProperties
+ : '<hive>WITH' 'DBPROPERTIES' '(' HivePropertyAssignmentList ')'
+ | '<hive>WITH' 'DBPROPERTIES'
+ | '<hive>WITH' 'CURSOR'
+   {
+     suggestKeywords(['DBPROPERTIES']);
+   }
+ ;
+
+DatabaseDefinitionOptionals
+ : DatabaseDefinitionOptional
+ | DatabaseDefinitionOptional DatabaseDefinitionOptional
+ | DatabaseDefinitionOptional DatabaseDefinitionOptional DatabaseDefinitionOptional
+ ;
+
+DatabaseDefinitionOptional
+ : Comment
+   {
+     parser.yy.afterComment = true;
+   }
+ | HdfsLocation
+   {
+     parser.yy.afterHdfsLocation = true;
+   }
+ | HiveDbProperties
+   {
+     parser.yy.afterHiveDbProperties = true;
+   }
+ ;
+
+CleanUpDatabaseConditions
+ : /* empty */
+   {
+     delete parser.yy.afterComment;
+     delete parser.yy.afterHdfsLocation;
+     delete parser.yy.afterHiveDbProperties;
+   }
+ ;
+
+DatabaseDefinition
+ : 'CREATE' DatabaseOrSchema OptionalIfNotExists
+ | 'CREATE' DatabaseOrSchema OptionalIfNotExists 'REGULAR_IDENTIFIER'
+ | 'CREATE' DatabaseOrSchema OptionalIfNotExists 'REGULAR_IDENTIFIER' 'CURSOR'
+   {
+     if (parser.yy.dialect === 'hive') {
+       suggestKeywords(['COMMENT', 'LOCATION', 'WITH DBPROPERTIES']);
+     } else if (parser.yy.dialect === 'impala') {
+       suggestKeywords(['COMMENT', 'LOCATION']);
+     }
+   }
+ | 'CREATE' DatabaseOrSchema OptionalIfNotExists 'REGULAR_IDENTIFIER' CleanUpDatabaseConditions DatabaseDefinitionOptionals error
+   // For the HDFS open single quote completion
+ | 'CREATE' DatabaseOrSchema OptionalIfNotExists 'REGULAR_IDENTIFIER' CleanUpDatabaseConditions DatabaseDefinitionOptionals 'CURSOR'
+   {
+     var keywords = [];
+     if (! parser.yy.afterComment) {
+       keywords.push('COMMENT');
+     }
+     if (! parser.yy.afterHdfsLocation) {
+       keywords.push('LOCATION');
+     }
+     if (! parser.yy.afterHiveDbProperties && parser.yy.dialect === 'hive') {
+       keywords.push('WITH DBPROPERTIES');
+     }
+     if (keywords.length > 0) {
+       suggestKeywords(keywords);
+     }
+   }
+ ;
+
 TableDefinition
- : 'CREATE' TableScope 'TABLE' 'REGULAR_IDENTIFIER' TableElementList TableLocation
+ : 'CREATE' TableScope 'TABLE' 'REGULAR_IDENTIFIER' TableElementList HdfsLocation
  | 'CREATE' PartialIdentifierOrCursor 'TABLE' 'REGULAR_IDENTIFIER' TableElementList
     {
       if (parser.yy.dialect === 'hive' || parser.yy.dialect === 'impala') {
-        suggestKeywords(['EXTERNAL'])
+        suggestKeywords(['EXTERNAL']);
       }
     }
  | 'CREATE' PartialIdentifierOrCursor 'TABLE' 'REGULAR_IDENTIFIER'
     {
       if (parser.yy.dialect === 'hive' || parser.yy.dialect === 'impala') {
-        suggestKeywords(['EXTERNAL'])
+        suggestKeywords(['EXTERNAL']);
       }
     }
  | 'CREATE' PartialIdentifierOrCursor 'TABLE'
     {
       if (parser.yy.dialect === 'hive' || parser.yy.dialect === 'impala') {
-        suggestKeywords(['EXTERNAL'])
+        suggestKeywords(['EXTERNAL']);
       }
     }
  | 'CREATE' TableScope 'TABLE' 'REGULAR_IDENTIFIER' TableElementList PartialIdentifierOrCursor
    {
      if (parser.yy.dialect === 'hive' || parser.yy.dialect === 'impala') {
-       suggestKeywords(['LOCATION'])
+       suggestKeywords(['LOCATION']);
      }
    }
  | 'CREATE' 'TABLE' 'REGULAR_IDENTIFIER' TableElementList
- | 'CREATE' PartialIdentifierOrCursor
-    {
-      if (parser.yy.dialect === 'hive' || parser.yy.dialect === 'impala') {
-        suggestKeywords(['EXTERNAL', 'TABLE'])
-      } else {
-        suggestKeywords(['TABLE'])
-      }
-    }
  ;
 
 TableScope
@@ -405,7 +524,7 @@ ColumnDefinitionError
    }
  ;
 
-TableLocation
+HdfsLocation
  : HiveOrImpalaLocation HdfsPath
  ;
 
@@ -414,6 +533,11 @@ HiveOrImpalaLocation
  | '<impala>LOCATION'
  ;
 
+HiveOrImpalaComment
+ : '<hive>COMMENT'
+ | '<impala>COMMENT'
+ ;
+
 HdfsPath
  : 'HDFS_START_QUOTE' 'HDFS_PATH' 'HDFS_END_QUOTE'
  | 'HDFS_START_QUOTE' 'HDFS_PATH' 'PARTIAL_CURSOR' 'HDFS_PATH' 'HDFS_END_QUOTE'
@@ -430,11 +554,11 @@ HdfsPath
     }
  | 'HDFS_START_QUOTE' 'PARTIAL_CURSOR' 'HDFS_END_QUOTE'
    {
-     suggestHdfs({ path: '/' });
+     suggestHdfs({ path: '' });
    }
  | 'HDFS_START_QUOTE' 'PARTIAL_CURSOR'
     {
-      suggestHdfs({ path: '/' });
+      suggestHdfs({ path: '' });
     }
  ;
 
@@ -645,7 +769,7 @@ ColumnReference
 BasicIdentifierChain
  : InitIdentifierChain IdentifierChain
    {
-     $$ = parser.yy.identifierChain
+     $$ = parser.yy.identifierChain;
      delete parser.yy.identifierChain;
    }
  ;

Разлика између датотеке није приказан због своје велике величине
+ 1 - 1
desktop/core/src/desktop/static/desktop/js/autocomplete/sql.js


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

@@ -57,11 +57,39 @@
       completions.push({ value: '*', meta: 'keyword' });
     }
 
-    if (parseResult.suggestTables || parseResult.suggestColumns || parseResult.suggestValues) {
+    if (parseResult.suggestHdfs || parseResult.suggestTables || parseResult.suggestColumns || parseResult.suggestValues) {
       var database = parseResult.useDatabase || self.snippet.database();
 
       var deferrals = [];
 
+      if (parseResult.suggestHdfs) {
+        var parts = parseResult.suggestHdfs.path.split('/');
+        // Drop the first " or '
+        parts.shift();
+        // Last one is either partial name or empty
+        parts.pop();
+
+        var hdfsDeferred = $.Deferred();
+        deferrals.push(hdfsDeferred);
+
+        self.snippet.getApiHelper().fetchHdfsPath({
+          pathParts: parts,
+          successCallback: function (data) {
+            if (!data.error) {
+              data.files.forEach(function (file) {
+                if (file.name !== '..' && file.name !== '.') {
+                  completions.push({ value: parseResult.suggestHdfs.path === '' ? '/' + file.name : file.name, meta: file.type });
+                }
+              });
+            }
+            hdfsDeferred.resolve();
+          },
+          silenceErrors: true,
+          errorCallback: hdfsDeferred.resolve,
+          editor: editor
+        });
+      }
+
       if (parseResult.suggestTables) {
         var prefix = parseResult.suggestTables.prependQuestionMark ? '? ' : '';
         if (parseResult.suggestTables.prependFrom) {

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

@@ -91,7 +91,51 @@ define([
           afterCursor: '',
           expectedResult: {
             lowerCase: false,
-            suggestKeywords: ['TABLE']
+            suggestKeywords: ['DATABASE', 'SCHEMA', 'TABLE']
+          }
+        });
+      });
+
+      it('should suggest keywords after CREATE DATABASE ', function () {
+        assertAutoComplete({
+          beforeCursor: 'CREATE DATABASE ',
+          afterCursor: '',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['IF NOT EXISTS']
+          }
+        });
+      });
+
+      it('should suggest keywords after CREATE DATABASE IF ', function () {
+        assertAutoComplete({
+          beforeCursor: 'CREATE DATABASE IF ',
+          afterCursor: '',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['NOT EXISTS']
+          }
+        });
+      });
+
+      it('should suggest keywords after CREATE SCHEMA ', function () {
+        assertAutoComplete({
+          beforeCursor: 'CREATE SCHEMA ',
+          afterCursor: '',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['IF NOT EXISTS']
+          }
+        });
+      });
+
+      it('should suggest keywords after CREATE DATABASE and before Identifier', function () {
+        assertAutoComplete({
+          beforeCursor: 'CREATE DATABASE ',
+          afterCursor: ' bla;',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['IF NOT EXISTS']
           }
         });
       });
@@ -270,6 +314,18 @@ define([
             }
           });
         });
+
+        it('should suggest keywords after CREATE DATABASE foo ', function () {
+          assertAutoComplete({
+            beforeCursor: 'CREATE DATABASE foo ',
+            afterCursor: '',
+            dialect: 'impala',
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['COMMENT', 'LOCATION']
+            }
+          });
+        });
       });
 
       describe('Hive specific', function () {
@@ -294,7 +350,7 @@ define([
             dialect: 'hive',
             expectedResult: {
               lowerCase: false,
-              suggestKeywords: ['EXTERNAL', 'TABLE']
+              suggestKeywords: ['DATABASE', 'EXTERNAL', 'SCHEMA', 'TABLE']
             }
           });
         });
@@ -323,6 +379,42 @@ define([
           });
         });
 
+        it('should suggest keywords after CREATE DATABASE foo ', function () {
+          assertAutoComplete({
+            beforeCursor: 'CREATE DATABASE foo ',
+            afterCursor: '',
+            dialect: 'hive',
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['COMMENT', 'LOCATION', 'WITH DBPROPERTIES']
+            }
+          });
+        });
+
+        it('should suggest keywords after CREATE DATABASE foo COMMENT ', function () {
+          assertAutoComplete({
+            beforeCursor: 'CREATE DATABASE foo COMMENT \'bla\' ',
+            afterCursor: '',
+            dialect: 'hive',
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['LOCATION', 'WITH DBPROPERTIES']
+            }
+          });
+        });
+
+        it('should suggest keywords after CREATE DATABASE foo COMMENT and LOCATION', function () {
+          assertAutoComplete({
+            beforeCursor: 'CREATE DATABASE foo COMMENT \'bla\' LOCATION \'/bla\' ',
+            afterCursor: '',
+            dialect: 'hive',
+            expectedResult: {
+              lowerCase: false,
+              suggestKeywords: ['WITH DBPROPERTIES']
+            }
+          });
+        });
+
         it('should suggest keywords after SELECT SelectList FROM TablePrimary ', function () {
           assertAutoComplete({
             beforeCursor: 'SELECT bar FROM foo ',
@@ -901,6 +993,30 @@ define([
     });
 
     describe('HDFS autocompletion', function () {
+      it('should autocomplete hdfs paths in database location references without initial /', function () {
+        assertAutoComplete({
+          beforeCursor: 'CREATE DATABASE foo LOCATION \'',
+          afterCursor: '\'',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestHdfs : { path: '' }
+          }
+        });
+      });
+
+      it('should autocomplete hdfs paths in database location references after comment without initial /', function () {
+        assertAutoComplete({
+          beforeCursor: 'CREATE DATABASE foo COMMENT \'blabla\' LOCATION \'',
+          afterCursor: '\'',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestHdfs : { path: '' }
+          }
+        });
+      });
+
       it('should autocomplete hdfs paths in location references without initial /', function () {
         assertAutoComplete({
           beforeCursor: 'CREATE EXTERNAL TABLE foo (id int) LOCATION \'',
@@ -908,7 +1024,7 @@ define([
           dialect: 'hive',
           expectedResult: {
             lowerCase: false,
-            suggestHdfs : { path: '/' }
+            suggestHdfs : { path: '' }
           }
         });
       });
@@ -956,7 +1072,7 @@ define([
           dialect: 'impala',
           expectedResult: {
             lowerCase: false,
-            suggestHdfs: { path: '/'}
+            suggestHdfs: { path: ''}
           }
         });
       });

Неке датотеке нису приказане због велике количине промена