Browse Source

HUE-4161 [editor] Autocomplete tables and columns in update statements

Johan Ahlen 9 years ago
parent
commit
7e24660

File diff suppressed because it is too large
+ 0 - 0
desktop/core/src/desktop/static/desktop/js/ace/ace.js


File diff suppressed because it is too large
+ 0 - 0
desktop/core/src/desktop/static/desktop/js/ace/mode-hive.js


+ 116 - 25
desktop/core/src/desktop/static/desktop/js/autocomplete/sql.jison

@@ -47,11 +47,13 @@
 'OR'                                { return 'OR'; }
 'ORDER'                             { return 'ORDER'; }
 'SELECT'                            { determineCase(yytext); return 'SELECT'; }
+'SET'                               { return 'SET'; }
 'SMALLINT'                          { return 'SMALLINT'; }
 'STRING'                            { return 'STRING'; }
 'TABLE'                             { return 'TABLE'; }
 'TIMESTAMP'                         { return 'TIMESTAMP'; }
 'TINYINT'                           { return 'TINYINT'; }
+'UPDATE'                            { determineCase(yytext); return 'UPDATE'; }
 'USE'                               { determineCase(yytext); return 'USE'; }
 'VARCHAR'                           { return 'VARCHAR'; }
 'VIEW'                              { return 'VIEW'; }
@@ -115,7 +117,7 @@ AnyCursor
  | 'PARTIAL_CURSOR'
  ;
 
-NoOrPartialToken
+NoOrPartialRegularIdentifier
  : 'REGULAR_IDENTIFIER' 'PARTIAL_CURSOR'
  | 'CURSOR'
  ;
@@ -135,7 +137,7 @@ InitResults
 
      parser.parseError = function (message, error) {
        if (typeof parser.yy.result.suggestColumns !== 'undefined') {
-         linkTablesPrimaries();
+         linkTablePrimaries();
        }
        prioritizeSuggestions();
        parser.yy.result.error = error;
@@ -196,21 +198,26 @@ UseStatement
  ;
 
 DataManipulation
+ : LoadStatement
+ | UpdateStatement
+ ;
+
+LoadStatement
  : HiveOrImpalaLoad HiveOrImpalaData HiveOrImpalaInpath HdfsPath 'INTO' 'TABLE' 'REGULAR_IDENTIFIER'
- | HiveOrImpalaLoad HiveOrImpalaData HiveOrImpalaInpath HdfsPath 'INTO' NoOrPartialToken
+ | HiveOrImpalaLoad HiveOrImpalaData HiveOrImpalaInpath HdfsPath 'INTO' NoOrPartialRegularIdentifier
    {
      suggestKeywords([ 'TABLE' ]);
    }
- | HiveOrImpalaLoad HiveOrImpalaData HiveOrImpalaInpath HdfsPath NoOrPartialToken
+ | HiveOrImpalaLoad HiveOrImpalaData HiveOrImpalaInpath HdfsPath NoOrPartialRegularIdentifier
    {
      suggestKeywords([ 'INTO' ]);
    }
  | HiveOrImpalaLoad HiveOrImpalaData HiveOrImpalaInpath HdfsPath
- | HiveOrImpalaLoad HiveOrImpalaData NoOrPartialToken
+ | HiveOrImpalaLoad HiveOrImpalaData NoOrPartialRegularIdentifier
    {
      suggestKeywords([ 'INPATH' ]);
    }
- | HiveOrImpalaLoad NoOrPartialToken
+ | HiveOrImpalaLoad NoOrPartialRegularIdentifier
    {
      suggestKeywords([ 'DATA' ]);
    }
@@ -231,34 +238,119 @@ HiveOrImpalaInpath
  | '<impala>INPATH'
  ;
 
+UpdateStatement
+ : 'UPDATE' TargetTable 'SET' SetClauseList WhereClause
+   {
+     linkTablePrimaries();
+   }
+ | 'UPDATE' TargetTable 'SET' SetClauseList 'CURSOR'
+   {
+     suggestKeywords([ 'WHERE' ]);
+   }
+ | 'UPDATE' TargetTable 'SET' SetClauseList
+   {
+     linkTablePrimaries();
+   }
+ | 'UPDATE' TargetTable 'CURSOR'
+   {
+     suggestKeywords([ 'SET' ]);
+   }
+ | 'UPDATE' TargetTable
+ | 'UPDATE' NoOrPartialRegularIdentifier
+   {
+     suggestTables();
+     suggestDatabases({ appendDot: true });
+   }
+ ;
+
+TargetTable
+ : TableName
+ ;
+
+TableName
+ : LocalOrSchemaQualifiedName
+ ;
+
+LocalOrSchemaQualifiedName
+ : 'REGULAR_IDENTIFIER' AnyDot 'PARTIAL_CURSOR'
+   {
+     suggestTables({ database: $1 });
+   }
+ | 'REGULAR_IDENTIFIER' AnyDot 'REGULAR_IDENTIFIER' 'PARTIAL_CURSOR'
+   {
+     suggestTables({ database: $1 });
+   }
+ | 'REGULAR_IDENTIFIER' AnyDot 'REGULAR_IDENTIFIER'
+   {
+     addTablePrimary({ identifierChain: [{ name: $1 }, { name: $3 }] });
+   }
+ | 'REGULAR_IDENTIFIER'
+   {
+     addTablePrimary({ identifierChain: [{ name: $1 }] });
+   }
+ | 'REGULAR_IDENTIFIER' AnyDot
+   {
+     addTablePrimary({ identifierChain: [{ name: $1 }] });
+   }
+ ;
+
+SetClauseList
+ : SetClause
+ | SetClauseList ',' SetClause
+ ;
+
+SetClause
+ : SetTarget '=' UpdateSource
+ | SetTarget 'CURSOR'
+   {
+     suggestKeywords([ '=' ]);
+   }
+ | NoOrPartialRegularIdentifier
+   {
+     suggestColumns();
+   }
+ ;
+
+SetTarget
+ : 'REGULAR_IDENTIFIER'
+ ;
+
+UpdateSource
+ : ValueExpression
+ ;
+
+ValueExpression
+ : BooleanValueExpression
+ ;
+
 TableDefinition
  : 'CREATE' TableScope 'TABLE' 'REGULAR_IDENTIFIER' TableElementList TableLocation
- | 'CREATE' NoOrPartialToken 'TABLE' 'REGULAR_IDENTIFIER' TableElementList
+ | 'CREATE' NoOrPartialRegularIdentifier 'TABLE' 'REGULAR_IDENTIFIER' TableElementList
     {
       if (parser.yy.dialect === 'hive' || parser.yy.dialect === 'impala') {
         suggestKeywords(['EXTERNAL'])
       }
     }
- | 'CREATE' NoOrPartialToken 'TABLE' 'REGULAR_IDENTIFIER'
+ | 'CREATE' NoOrPartialRegularIdentifier 'TABLE' 'REGULAR_IDENTIFIER'
     {
       if (parser.yy.dialect === 'hive' || parser.yy.dialect === 'impala') {
         suggestKeywords(['EXTERNAL'])
       }
     }
- | 'CREATE' NoOrPartialToken 'TABLE'
+ | 'CREATE' NoOrPartialRegularIdentifier 'TABLE'
     {
       if (parser.yy.dialect === 'hive' || parser.yy.dialect === 'impala') {
         suggestKeywords(['EXTERNAL'])
       }
     }
- | 'CREATE' TableScope 'TABLE' 'REGULAR_IDENTIFIER' TableElementList NoOrPartialToken
+ | 'CREATE' TableScope 'TABLE' 'REGULAR_IDENTIFIER' TableElementList NoOrPartialRegularIdentifier
    {
      if (parser.yy.dialect === 'hive' || parser.yy.dialect === 'impala') {
        suggestKeywords(['LOCATION'])
      }
    }
  | 'CREATE' 'TABLE' 'REGULAR_IDENTIFIER' TableElementList
- | 'CREATE' NoOrPartialToken
+ | 'CREATE' NoOrPartialRegularIdentifier
     {
       if (parser.yy.dialect === 'hive' || parser.yy.dialect === 'impala') {
         suggestKeywords(['EXTERNAL', 'TABLE'])
@@ -288,7 +380,7 @@ TableElement
 
 ColumnDefinition
  : 'REGULAR_IDENTIFIER' PrimitiveType
- | 'REGULAR_IDENTIFIER' NoOrPartialToken
+ | 'REGULAR_IDENTIFIER' NoOrPartialRegularIdentifier
    {
      if (parser.yy.dialect == 'hive') {
        suggestKeywords(['BIGINT', 'BINARY', 'BOOLEAN', 'CHAR', 'DATE', 'DECIMAL', 'DOUBLE', 'FLOAT', 'INT', 'SMALLINT', 'TIMESTAMP', 'STRING', 'TINYINT', 'VARCHAR']);
@@ -296,7 +388,7 @@ ColumnDefinition
        suggestKeywords(['BIGINT', 'BOOLEAN', 'CHAR', 'DECIMAL', 'DOUBLE', 'FLOAT', 'INT', 'SMALLINT', 'TIMESTAMP', 'STRING', 'TINYINT', 'VARCHAR']);
      }
    }
- | 'REGULAR_IDENTIFIER' NoOrPartialToken ColumnDefinitionError error
+ | 'REGULAR_IDENTIFIER' NoOrPartialRegularIdentifier ColumnDefinitionError error
    // error here is because it expects closing ')'
  ;
 
@@ -371,7 +463,7 @@ PrimitiveType
 QueryExpression
  : 'SELECT' CleanUpSelectConditions SelectList TableExpression
    {
-     linkTablesPrimaries();
+     linkTablePrimaries();
    }
  | 'SELECT' CleanUpSelectConditions SelectList
  ;
@@ -393,7 +485,7 @@ CleanUpSelectConditions
 
 FromClause
  : 'FROM' TableReferenceList
- | 'FROM' NoOrPartialToken
+ | 'FROM' NoOrPartialRegularIdentifier
    {
      suggestTables();
      suggestDatabases({ appendDot: true });
@@ -584,7 +676,7 @@ Identifier
 
 GroupByClause
  : 'GROUP' 'BY' ColumnList
- | 'GROUP' NoOrPartialToken
+ | 'GROUP' NoOrPartialRegularIdentifier
    {
      suggestKeywords(['BY']);
    }
@@ -592,7 +684,7 @@ GroupByClause
 
 OrderByClause
  : 'ORDER' 'BY' ColumnList
- | 'ORDER' NoOrPartialToken
+ | 'ORDER' NoOrPartialRegularIdentifier
    {
      suggestKeywords(['BY']);
    }
@@ -600,7 +692,7 @@ OrderByClause
 
 LimitClause
  : 'LIMIT' 'UNSIGNED_INTEGER'
- | 'LIMIT' NoOrPartialToken
+ | 'LIMIT' NoOrPartialRegularIdentifier
    {
      suggestNumbers([1, 5, 10]);
    }
@@ -608,12 +700,12 @@ LimitClause
 
 SelectList
  : ColumnList
- | ColumnList NoOrPartialToken
+ | ColumnList NoOrPartialRegularIdentifier
    {
       suggestTables({ prependFrom: true });
       suggestDatabases({ prependFrom: true, appendDot: true });
     }
- | '*' NoOrPartialToken
+ | '*' NoOrPartialRegularIdentifier
    {
      suggestTables({ prependFrom: true });
      suggestDatabases({ prependFrom: true, appendDot: true });
@@ -792,15 +884,15 @@ LateralView
     {
       $$ = { udtf: $3, columnAliases: $4 }
     }
- | '<hive>LATERAL' 'VIEW' userDefinedTableGeneratingFunction NoOrPartialToken
+ | '<hive>LATERAL' 'VIEW' userDefinedTableGeneratingFunction NoOrPartialRegularIdentifier
    {
      suggestKeywords(['AS']);
    }
- | '<hive>LATERAL' 'VIEW' NoOrPartialToken
+ | '<hive>LATERAL' 'VIEW' NoOrPartialRegularIdentifier
    {
      suggestKeywords(['explode', 'posexplode']);
    }
- | '<hive>LATERAL' NoOrPartialToken
+ | '<hive>LATERAL' NoOrPartialRegularIdentifier
    {
      suggestKeywords(['VIEW']);
    }
@@ -941,7 +1033,6 @@ parser.expandLateralViews = function (tablePrimaries, identifierChain) {
 var linkSuggestion = function (suggestion, isColumnSuggestion) {
   var identifierChain = suggestion.identifierChain;
   var tablePrimaries = parser.yy.latestTablePrimaries;
-
   // Impala can have references to maps or array, i.e. FROM table t, t.map m
   // We need to replace those in the identifierChain
   if (parser.yy.dialect === 'impala') {
@@ -1025,7 +1116,7 @@ var suggestTablePrimariesAsIdentifiers = function () {
   });
 }
 
-var linkTablesPrimaries = function () {
+var linkTablePrimaries = function () {
    if (!parser.yy.cursorFound) {
      return;
    }

File diff suppressed because it is too large
+ 1 - 1
desktop/core/src/desktop/static/desktop/js/autocomplete/sql.js


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

@@ -175,6 +175,39 @@ define([
         });
       });
 
+      it('should suggest keywords after UPDATE TableReference ', function () {
+        assertAutoComplete({
+          beforeCursor: 'UPDATE bar  ',
+          afterCursor: '',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['SET']
+          }
+        });
+      });
+
+      it('should suggest keywords after UPDATE TableReference SET SetClauseList ', function () {
+        assertAutoComplete({
+          beforeCursor: 'UPDATE bar SET id=1, foo=2 ',
+          afterCursor: '',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['WHERE']
+          }
+        });
+      });
+
+      it('should suggest keywords after UPDATE TableReference SET identifier ', function () {
+        assertAutoComplete({
+          beforeCursor: 'UPDATE bar SET id ',
+          afterCursor: '',
+          expectedResult: {
+            lowerCase: false,
+            suggestKeywords: ['=']
+          }
+        });
+      });
+
       describe('Impala specific', function () {
         it('should suggest keywords for empty statement', function() {
           assertAutoComplete({
@@ -634,6 +667,133 @@ define([
       });
     });
 
+    describe('update statements', function () {
+      it('should suggest tables after UPDATE', function() {
+        assertAutoComplete({
+          beforeCursor: 'UPDATE ',
+          afterCursor: '',
+          expectedResult: {
+            lowerCase: false,
+            suggestTables: {},
+            suggestDatabases: {
+              appendDot: true
+            }
+          }
+        });
+      });
+
+      it('should suggest tables after UPDATE with partial table or schema ref', function() {
+        assertAutoComplete({
+          beforeCursor: 'UPDATE bla',
+          afterCursor: '',
+          expectedResult: {
+            lowerCase: false,
+            suggestTables: {},
+            suggestDatabases: {
+              appendDot: true
+            }
+          }
+        });
+      });
+
+      it('should suggest tables after UPDATE with database', function() {
+        assertAutoComplete({
+          beforeCursor: 'UPDATE bar.',
+          afterCursor: '',
+          expectedResult: {
+            lowerCase: false,
+            suggestTables: {
+              database: 'bar'
+            }
+          }
+        });
+      });
+
+      it('should suggest tables after UPDATE with database and partial table', function() {
+        assertAutoComplete({
+          beforeCursor: 'UPDATE bar.foo',
+          afterCursor: '',
+          expectedResult: {
+            lowerCase: false,
+            suggestTables: {
+              database: 'bar'
+            }
+          }
+        });
+      });
+
+      it('should suggest columns after SET', function() {
+        assertAutoComplete({
+          beforeCursor: 'UPDATE bar.foo SET ',
+          afterCursor: '',
+          expectedResult: {
+            lowerCase: false,
+            suggestColumns: {
+              database: 'bar',
+              table: 'foo'
+            }
+          }
+        });
+      });
+
+      it('should suggest columns after SET id = 1, bar = \'foo\', ', function() {
+        assertAutoComplete({
+          beforeCursor: 'UPDATE bar.foo SET id = 1, bar = \'foo\', ',
+          afterCursor: '',
+          expectedResult: {
+            lowerCase: false,
+            suggestColumns: {
+              database: 'bar',
+              table: 'foo'
+            }
+          }
+        });
+      });
+
+      it('should suggest columns after SET bar = \'foo\' WHERE ', function() {
+        assertAutoComplete({
+          beforeCursor: 'UPDATE bar.foo SET bar = \'foo\' WHERE ',
+          afterCursor: '',
+          expectedResult: {
+            lowerCase: false,
+            suggestColumns: {
+              database: 'bar',
+              table: 'foo'
+            }
+          }
+        });
+      });
+
+      it('should suggest values after SET bar = \'foo\' WHERE id = ', function() {
+        assertAutoComplete({
+          beforeCursor: 'UPDATE bar.foo SET bar = \'foo\' WHERE id = ',
+          afterCursor: '',
+          expectedResult: {
+            lowerCase: false,
+            suggestValues: {
+              database: 'bar',
+              table: 'foo',
+              identifierChain: [{ name: 'id' }]
+            }
+          }
+        });
+      });
+
+      it('should suggest columns after SET bar = \'foo\' WHERE id = 1 AND ', function() {
+        assertAutoComplete({
+          beforeCursor: 'UPDATE bar.foo SET bar = \'foo\' WHERE id = 1 AND ',
+          afterCursor: '',
+          expectedResult: {
+            lowerCase: false,
+            suggestColumns: {
+              database: 'bar',
+              table: 'foo'
+            }
+          }
+        });
+      });
+    });
+
     describe('HDFS autocompletion', function () {
       it('should autocomplete hdfs paths in location references without initial /', function () {
         assertAutoComplete({
@@ -1193,7 +1353,7 @@ define([
               suggestStar: true, // TODO: Check if really true
               suggestIdentifiers: [{ name: 'explodedMap.', type: 'alias' }, { name: 'testMapKey', type: 'alias' }, { name: 'testMapValue', type: 'alias' }],
               suggestColumns: {
-                table: 'testTable',
+                table: 'testTable'
               }
             }
           });

+ 1 - 1
tools/ace-editor/lib/ace/mode/hive_highlight_rules.js

@@ -25,7 +25,7 @@ define(function (require, exports, module) {
     // regexps are ordered -> the first match is used
 
     var keywords = (
-        "ADD|AFTER|ALL|ALTER|ANALYZE|AND|ARCHIVE|AS|ASC|BETWEEN|BUCKET|BUCKETS|BY|CASCADE|CHANGE|CLI|CLUSTER|CLUSTERED|COALESCE|COLLECTION|COLUMN|COLUMNS|COMMENT|COMPUTE|CREATE|CROSS|DATA|DATABASE|DATABASES|DBPROPERTIES|DEFERRED|DELIMITED|DEPENDENCY|DESC|DESCRIBE|DIRECTORY|DISABLE|DISTINCT|DISTRIBUTE|DOT|DROP|ENABLE|ESCAPED|EXISTS|EXPLAIN|EXPORT|EXTENDED|EXTERNAL|FIELDS|FILEFORMAT|FIRST|FORMAT|FORMATTED|FROM|FULL|FUNCTION|FUNCTIONS|GRANT|GROUP|HAVING|IDXPROPERTIES|IF|IGNORE|IMPORT|IN|INDEX|INDEXES|INPATH|INSERT|INTO|IS|ITEMS|JOIN|KEYS|LATERAL|LEFT|LIKE|LIMIT|LINES|LOAD|LOCAL|LOCATION|LOCKS|MAP|MAPJOIN|MSCK|NOT|OF|OFFLINE|ON|OPTION|ORDER|OUT|OUTER|OVERWRITE|PARTITION|PARTITIONED|PARTITIONS|PERCENT|PRIVILEGES|PROTECTION|REBUILD|RECORDREADER|RECOVER|REDUCE|REGEXP|RENAME|REPAIR|REPLACE|RESTRICT|REVOKE|RIGHT|RLIKE|ROLE|ROW|SCHEMA|SCHEMAS|SELECT|SEMI|SEPARATED|SERDE|SERDEPROPERTIES|SET|SHOW|SKEWED|SORT|SORTED|STATISTICS|STORED|SUM|TABLE|TABLES|TABLESAMPLE|TBLPROPERTIES|TEMPORARY|TERMINATED|TO|TOUCH|TRANSFORM|TRUNCATE|UNARCHIVE|UNION|US|USE|USER|USING|VIEW|WHERE|WITH"
+        "ADD|AFTER|ALL|ALTER|ANALYZE|AND|ARCHIVE|AS|ASC|BETWEEN|BUCKET|BUCKETS|BY|CASCADE|CHANGE|CLI|CLUSTER|CLUSTERED|COALESCE|COLLECTION|COLUMN|COLUMNS|COMMENT|COMPUTE|CREATE|CROSS|DATA|DATABASE|DATABASES|DBPROPERTIES|DEFERRED|DELIMITED|DEPENDENCY|DESC|DESCRIBE|DIRECTORY|DISABLE|DISTINCT|DISTRIBUTE|DOT|DROP|ENABLE|ESCAPED|EXISTS|EXPLAIN|EXPORT|EXTENDED|EXTERNAL|FIELDS|FILEFORMAT|FIRST|FORMAT|FORMATTED|FROM|FULL|FUNCTION|FUNCTIONS|GRANT|GROUP|HAVING|IDXPROPERTIES|IF|IGNORE|IMPORT|IN|INDEX|INDEXES|INPATH|INSERT|INTO|IS|ITEMS|JOIN|KEYS|LATERAL|LEFT|LIKE|LIMIT|LINES|LOAD|LOCAL|LOCATION|LOCKS|MAP|MAPJOIN|MSCK|NOT|OF|OFFLINE|ON|OPTION|ORDER|OUT|OUTER|OVERWRITE|PARTITION|PARTITIONED|PARTITIONS|PERCENT|PRIVILEGES|PROTECTION|REBUILD|RECORDREADER|RECOVER|REDUCE|REGEXP|RENAME|REPAIR|REPLACE|RESTRICT|REVOKE|RIGHT|RLIKE|ROLE|ROW|SCHEMA|SCHEMAS|SELECT|SEMI|SEPARATED|SERDE|SERDEPROPERTIES|SET|SHOW|SKEWED|SORT|SORTED|STATISTICS|STORED|SUM|TABLE|TABLES|TABLESAMPLE|TBLPROPERTIES|TEMPORARY|TERMINATED|TO|TOUCH|TRANSFORM|TRUNCATE|UNARCHIVE|UNION|UPDATE|US|USE|USER|USING|VIEW|WHERE|WITH"
     );
 
     var builtinConstants = (

Some files were not shown because too many files changed in this diff