Răsfoiți Sursa

HUE-4320 [editor] New autocompleter should make suggestions based on types in functions

It now makes the right type completions based on return types and arguments for UDFs. For CAST it'll figure out the correct return type but not for other functions like T = x(INT, T) where it will suggest anything (T).

Arrays, maps and structs are always suggested as you could do cos(structCol.structCol.number), for this type of UDF arguments, like in explode(), it will only suggest functions or columns that are structs, arrays and maps.

For the known functions it will only make completions for argument lengths that are valid i.e. sin(|) but not sin(1,2,3,|). If the function is unknown it will make completions like before.
Johan Ahlen 9 ani în urmă
părinte
comite
46266f1

+ 169 - 42
desktop/core/src/desktop/static/desktop/js/autocomplete/sql.jison

@@ -97,6 +97,7 @@
 <impala>'NULLS'                     { return '<impala>NULLS'; }
 <impala>'OVER'                      { return '<impala>OVER'; }
 <impala>'PARTITIONS'                { return '<impala>PARTITIONS'; }
+<impala>'REAL'                      { return '<impala>REAL'; }
 <impala>'RIGHT'                     { return '<impala>RIGHT'; }
 <impala>'ROLE'                      { return '<impala>ROLE'; }
 <impala>'ROLES'                     { return '<impala>ROLES'; }
@@ -206,7 +207,6 @@
 <impala>'STDDEV('                   { return '<impala>STDDEV('; }
 <impala>'VARIANCE_POP('             { return '<impala>VARIANCE_POP('; }
 <impala>'VARIANCE_SAMP('            { return '<impala>VARIANCE_SAMP('; }
-
 [A-Za-z][A-Za-z0-9_]*\(             { return 'UDF('; }
 
 [0-9]+                              { return 'UNSIGNED_INTEGER'; }
@@ -785,6 +785,7 @@ PrimitiveType
  | 'BOOLEAN'
  | 'FLOAT'
  | 'DOUBLE'
+ | '<impala>REAL'
  | 'STRING'
  | 'DECIMAL'
  | 'CHAR'
@@ -1567,6 +1568,7 @@ ValueExpression
    {
      // verifyType($2, 'NUMBER');
      $$ = $2;
+     $2.types = ['NUMBER'];
    }
  | 'EXISTS' TableSubquery
    {
@@ -2020,8 +2022,16 @@ ValueExpression_EDIT
  ;
 
 ValueExpression_EDIT
- : ValueExpression '=' ValueExpression_EDIT                    -> { types: [ 'BOOLEAN' ] }
- | ValueExpression 'COMPARISON_OPERATOR' ValueExpression_EDIT  -> { types: [ 'BOOLEAN' ] }
+ : ValueExpression '=' ValueExpression_EDIT
+   {
+     applyTypeToSuggestions($1.types);
+     $$ = { types: [ 'BOOLEAN' ] }
+   }
+ | ValueExpression 'COMPARISON_OPERATOR' ValueExpression_EDIT
+   {
+     applyTypeToSuggestions($1.types);
+     $$ = { types: [ 'BOOLEAN' ] }
+   }
  | ValueExpression '-' ValueExpression_EDIT
    {
      applyTypeToSuggestions(['NUMBER']);
@@ -2042,11 +2052,13 @@ ValueExpression_EDIT
  | ValueExpression '=' RightPart_EDIT
    {
      valueExpressionSuggest($1);
+     applyTypeToSuggestions($1.types);
      $$ = { types: [ 'BOOLEAN' ] };
    }
  | ValueExpression 'COMPARISON_OPERATOR' RightPart_EDIT
    {
      valueExpressionSuggest($1);
+     applyTypeToSuggestions($1.types);
      $$ = { types: [ 'BOOLEAN' ] };
    }
  | ValueExpression '-' RightPart_EDIT
@@ -2080,31 +2092,55 @@ ValueExpression_EDIT
  ;
 
 ValueExpression_EDIT
- : ValueExpression_EDIT '=' ValueExpression                    -> { types: [ 'BOOLEAN' ] }
- | ValueExpression_EDIT 'COMPARISON_OPERATOR' ValueExpression  -> { types: [ 'BOOLEAN' ] }
- | ValueExpression_EDIT '-' ValueExpression                    -> { types: [ 'NUMBER' ] }
- | ValueExpression_EDIT '*' ValueExpression                    -> { types: [ 'NUMBER' ] }
- | ValueExpression_EDIT 'ARITHMETIC_OPERATOR' ValueExpression  -> { types: [ 'NUMBER' ] }
- | ValueExpression_EDIT 'OR' ValueExpression                   -> { types: [ 'BOOLEAN' ] }
- | ValueExpression_EDIT 'AND' ValueExpression                  -> { types: [ 'BOOLEAN' ] }
+ : ValueExpression_EDIT '=' ValueExpression
+   {
+     applyTypeToSuggestions($3.types);
+     $$ = { types: [ 'BOOLEAN' ] }
+   }
+ | ValueExpression_EDIT 'COMPARISON_OPERATOR' ValueExpression
+   {
+     applyTypeToSuggestions($3.types);
+     $$ = { types: [ 'BOOLEAN' ] }
+   }
+ | ValueExpression_EDIT '-' ValueExpression
+   {
+     applyTypeToSuggestions(['NUMBER']);
+     $$ = { types: [ 'NUMBER' ] }
+   }
+ | ValueExpression_EDIT '*' ValueExpression
+   {
+     applyTypeToSuggestions(['NUMBER']);
+     $$ = { types: [ 'NUMBER' ] }
+   }
+ | ValueExpression_EDIT 'ARITHMETIC_OPERATOR' ValueExpression
+   {
+     applyTypeToSuggestions(['NUMBER']);
+     $$ = { types: [ 'NUMBER' ] }
+   }
+ | ValueExpression_EDIT 'OR' ValueExpression   -> { types: [ 'BOOLEAN' ] }
+ | ValueExpression_EDIT 'AND' ValueExpression  -> { types: [ 'BOOLEAN' ] }
  | 'CURSOR' '=' ValueExpression
    {
      valueExpressionSuggest($3);
+     applyTypeToSuggestions($3.types);
      $$ = { types: [ 'BOOLEAN' ] };
    }
  | 'CURSOR' 'COMPARISON_OPERATOR' ValueExpression
    {
      valueExpressionSuggest($3);
+     applyTypeToSuggestions($3.types);
      $$ = { types: [ 'BOOLEAN' ] };
    }
  | 'CURSOR' '*' ValueExpression
    {
      valueExpressionSuggest($3);
+     applyTypeToSuggestions([ 'NUMBER' ]);
      $$ = { types: [ 'NUMBER' ] };
    }
  | 'CURSOR' 'ARITHMETIC_OPERATOR' ValueExpression
    {
      valueExpressionSuggest($3);
+     applyTypeToSuggestions([ 'NUMBER' ]);
      $$ = { types: [ 'NUMBER' ] };
    }
  | 'CURSOR' 'OR' ValueExpression
@@ -2120,40 +2156,65 @@ ValueExpression_EDIT
  ;
 
 ValueExpressionList
- : ValueExpression                          -> $1
- | ValueExpressionList ',' ValueExpression  -> $3
+ : ValueExpression
+   {
+     $1.position = 1;
+   }
+ | ValueExpressionList ',' ValueExpression
+   {
+     $3.position = $1.position + 1;
+     $$ = $3;
+   }
  ;
 
 ValueExpressionList_EDIT
  : ValueExpression_EDIT
+   {
+     $1.position = 1;
+   }
  | ValueExpressionList ',' ValueExpression_EDIT
+   {
+     $1.position += 1;
+   }
  | ValueExpression_EDIT ',' ValueExpressionList
+   {
+     $1.position = 1;
+   }
  | ValueExpressionList ',' ValueExpression_EDIT ',' ValueExpressionList
+   {
+     // $3.position = $1.position + 1;
+     // $$ = $3
+     $1.position += 1;
+   }
  | ValueExpressionList ',' AnyCursor
    {
      valueExpressionSuggest();
+     $1.position += 1;
    }
  | ValueExpressionList ',' AnyCursor ',' ValueExpressionList
    {
      valueExpressionSuggest();
+     $1.position += 1;
    }
  | AnyCursor ',' ValueExpressionList
    {
      valueExpressionSuggest();
-     $$ = { cursorAtStart : true };
+     $$ = { cursorAtStart : true, position: 1 };
    }
  | AnyCursor ','
    {
      valueExpressionSuggest();
-     $$ = { cursorAtStart : true };
+     $$ = { cursorAtStart : true, position: 1 };
    }
  | ',' AnyCursor
    {
      valueExpressionSuggest();
+     $$ = { position: 2 };
    }
  | ',' AnyCursor ',' ValueExpressionList
    {
      valueExpressionSuggest();
+     $$ = { position: 2 };
    }
  ;
 
@@ -2824,24 +2885,32 @@ UserDefinedFunction_EDIT
  ;
 
 ArbitraryFunction
- : 'UDF(' ')'
- | 'UDF(' ValueExpressionList ')'  -> { function: $1.substring(0, $1.length - 1), expression: $2 }
+ : 'UDF(' ')'                      -> { types: findReturnTypes($1) }
+ | 'UDF(' ValueExpressionList ')'  -> { function: $1.substring(0, $1.length - 1), expression: $2, types: findReturnTypes($1) }
  ;
 
 ArbitraryFunction_EDIT
  : 'UDF(' AnyCursor RightParenthesisOrError
    {
      valueExpressionSuggest();
+     applyArgumentTypesToSuggestions($1, 1);
+     $$ = { types: findReturnTypes($1) };
    }
  | 'UDF(' ValueExpressionList 'CURSOR' RightParenthesisOrError
    {
      suggestValueExpressionKeywords($2);
+     $$ = { types: findReturnTypes($1) };
    }
  | 'UDF(' ValueExpressionList 'CURSOR' ',' ValueExpressionList RightParenthesisOrError
    {
      suggestValueExpressionKeywords($2);
+     $$ = { types: findReturnTypes($1) };
    }
  | 'UDF(' ValueExpressionList_EDIT RightParenthesisOrError
+   {
+     applyArgumentTypesToSuggestions($1, $2.position);
+     $$ = { types: findReturnTypes($1) };
+   }
  ;
 
 AggregateFunction
@@ -2857,48 +2926,55 @@ AggregateFunction_EDIT
  ;
 
 CastFunction
- : 'CAST(' ValueExpression AnyAs PrimitiveType ')'
- | 'CAST(' ')'
+ : 'CAST(' ValueExpression AnyAs PrimitiveType ')'  -> { types: [ $4.toUpperCase() ] }
+ | 'CAST(' ')'                                      -> { types: [ 'T' ] }
  ;
 
 CastFunction_EDIT
  : 'CAST(' AnyCursor AnyAs PrimitiveType RightParenthesisOrError
    {
      valueExpressionSuggest();
+     $$ = { types: [ $4.toUpperCase() ] };
    }
  | 'CAST(' AnyCursor AnyAs RightParenthesisOrError
    {
      valueExpressionSuggest();
+     $$ = { types: [ 'T' ] };
    }
  | 'CAST(' AnyCursor RightParenthesisOrError
    {
      valueExpressionSuggest();
+     $$ = { types: [ 'T' ] };
    }
- | 'CAST(' ValueExpression_EDIT AnyAs PrimitiveType RightParenthesisOrError
- | 'CAST(' ValueExpression_EDIT AnyAs RightParenthesisOrError
- | 'CAST(' ValueExpression_EDIT RightParenthesisOrError
+ | 'CAST(' ValueExpression_EDIT AnyAs PrimitiveType RightParenthesisOrError  -> { types: [ $4.toUpperCase() ] }
+ | 'CAST(' ValueExpression_EDIT AnyAs RightParenthesisOrError                -> { types: [ 'T' ] }
+ | 'CAST(' ValueExpression_EDIT RightParenthesisOrError                      -> { types: [ 'T' ] }
  | 'CAST(' ValueExpression 'CURSOR' PrimitiveType RightParenthesisOrError
    {
      suggestValueExpressionKeywords($2, ['AS']);
+     $$ =  { types: [ $4.toUpperCase() ] };
    }
  | 'CAST(' ValueExpression 'CURSOR' RightParenthesisOrError
    {
      suggestValueExpressionKeywords($2, ['AS']);
+     $$ = { types: [ 'T' ] };
    }
  | 'CAST(' ValueExpression AnyAs 'CURSOR' RightParenthesisOrError
    {
      suggestTypeKeywords();
+     $$ = { types: [ 'T' ] };
    }
  | 'CAST(' AnyAs 'CURSOR' RightParenthesisOrError
-    {
-      suggestTypeKeywords();
-    }
+   {
+     suggestTypeKeywords();
+     $$ = { types: [ 'T' ] };
+   }
  ;
 
 CountFunction
- : 'COUNT(' '*' ')'
- | 'COUNT(' ')'
- | 'COUNT(' OptionalAllOrDistinct ValueExpressionList ')'
+ : 'COUNT(' '*' ')'                                        -> { types: findReturnTypes($1) }
+ | 'COUNT(' ')'                                            -> { types: findReturnTypes($1) }
+ | 'COUNT(' OptionalAllOrDistinct ValueExpressionList ')'  -> { types: findReturnTypes($1) }
  ;
 
 CountFunction_EDIT
@@ -2912,10 +2988,12 @@ CountFunction_EDIT
          suggestKeywords(['*', 'DISTINCT']);
        }
      }
+     $$ = { types: findReturnTypes($1) };
    }
  | 'COUNT(' OptionalAllOrDistinct ValueExpressionList 'CURSOR' RightParenthesisOrError
    {
      suggestValueExpressionKeywords($3);
+     $$ = { types: findReturnTypes($1) };
    }
  | 'COUNT(' OptionalAllOrDistinct ValueExpressionList_EDIT RightParenthesisOrError
    {
@@ -2926,12 +3004,13 @@ CountFunction_EDIT
          suggestKeywords(['DISTINCT']);
        }
      }
+     $$ = { types: findReturnTypes($1) };
    }
  ;
 
 OtherAggregateFunction
- : OtherAggregateFunction_Type OptionalAllOrDistinct ')'
- | OtherAggregateFunction_Type OptionalAllOrDistinct ValueExpressionList ')'
+ : OtherAggregateFunction_Type OptionalAllOrDistinct ')'                      -> { types: findReturnTypes($1) }
+ | OtherAggregateFunction_Type OptionalAllOrDistinct ValueExpressionList ')'  -> { types: findReturnTypes($1) }
  ;
 
 OtherAggregateFunction_EDIT
@@ -2948,10 +3027,12 @@ OtherAggregateFunction_EDIT
          suggestKeywords(['DISTINCT']);
        }
      }
+     $$ = { types: findReturnTypes($1) };
    }
  | OtherAggregateFunction_Type OptionalAllOrDistinct ValueExpressionList 'CURSOR' RightParenthesisOrError
    {
      suggestValueExpressionKeywords($3);
+     $$ = { types: findReturnTypes($1) };
    }
  | OtherAggregateFunction_Type OptionalAllOrDistinct ValueExpressionList_EDIT RightParenthesisOrError
    {
@@ -2964,6 +3045,7 @@ OtherAggregateFunction_EDIT
          suggestKeywords(['DISTINCT']);
        }
      }
+     $$ = { types: findReturnTypes($1) };
    }
  ;
 
@@ -3001,35 +3083,42 @@ ExtractFunction_EDIT
  : '<impala>EXTRACT(' AnyCursor FromOrComma ValueExpression RightParenthesisOrError
    {
      valueExpressionSuggest();
+     $$ = { types: findReturnTypes($1) };
    }
  | '<impala>EXTRACT(' AnyCursor FromOrComma RightParenthesisOrError
    {
      valueExpressionSuggest();
+     $$ = { types: findReturnTypes($1) };
    }
  | '<impala>EXTRACT(' AnyCursor RightParenthesisOrError
    {
      valueExpressionSuggest();
+     $$ = { types: findReturnTypes($1) };
    }
- | '<impala>EXTRACT(' ValueExpression_EDIT FromOrComma ValueExpression RightParenthesisOrError
- | '<impala>EXTRACT(' ValueExpression_EDIT FromOrComma RightParenthesisOrError
- | '<impala>EXTRACT(' ValueExpression_EDIT RightParenthesisOrError
+ | '<impala>EXTRACT(' ValueExpression_EDIT FromOrComma ValueExpression RightParenthesisOrError  -> { types: findReturnTypes($1) }
+ | '<impala>EXTRACT(' ValueExpression_EDIT FromOrComma RightParenthesisOrError                  -> { types: findReturnTypes($1) }
+ | '<impala>EXTRACT(' ValueExpression_EDIT RightParenthesisOrError                              -> { types: findReturnTypes($1) }
  | '<impala>EXTRACT(' ValueExpression FromOrComma AnyCursor RightParenthesisOrError
    {
      valueExpressionSuggest();
+     $$ = { types: findReturnTypes($1) };
    }
  | '<impala>EXTRACT(' FromOrComma AnyCursor RightParenthesisOrError
    {
      valueExpressionSuggest();
+     $$ = { types: findReturnTypes($1) };
    }
- | '<impala>EXTRACT(' ValueExpression FromOrComma ValueExpression_EDIT RightParenthesisOrError
- | '<impala>EXTRACT(' FromOrComma ValueExpression_EDIT RightParenthesisOrError
+ | '<impala>EXTRACT(' ValueExpression FromOrComma ValueExpression_EDIT RightParenthesisOrError  -> { types: findReturnTypes($1) }
+ | '<impala>EXTRACT(' FromOrComma ValueExpression_EDIT RightParenthesisOrError                  -> { types: findReturnTypes($1) }
  | '<impala>EXTRACT(' ValueExpression 'CURSOR' ValueExpression RightParenthesisOrError
    {
      suggestValueExpressionKeywords($2, [',', 'FROM']);
+     $$ = { types: findReturnTypes($1) };
    }
  | '<impala>EXTRACT(' ValueExpression 'CURSOR' RightParenthesisOrError
    {
      suggestValueExpressionKeywords($2, [',', 'FROM']);
+     $$ = { types: findReturnTypes($1) };
    }
  ;
 
@@ -3039,8 +3128,8 @@ FromOrComma
  ;
 
 SumFunction
- : 'SUM(' OptionalAllOrDistinct ValueExpression ')'
- | 'SUM(' ')'
+ : 'SUM(' OptionalAllOrDistinct ValueExpression ')'  -> { types: findReturnTypes($1) }
+ | 'SUM(' ')'                                        -> { types: findReturnTypes($1) }
  ;
 
 SumFunction_EDIT
@@ -3054,21 +3143,32 @@ SumFunction_EDIT
          suggestKeywords(['DISTINCT']);
        }
      }
+     $$ = { types: findReturnTypes($1) };
    }
  | 'SUM(' OptionalAllOrDistinct ValueExpression 'CURSOR' RightParenthesisOrError
    {
      suggestValueExpressionKeywords($3);
+     $$ = { types: findReturnTypes($1) };
    }
- | 'SUM(' OptionalAllOrDistinct ValueExpression_EDIT RightParenthesisOrError
+ | 'SUM(' OptionalAllOrDistinct ValueExpression_EDIT RightParenthesisOrError  -> { types: findReturnTypes($1) }
  ;
 
-WithinGroupSpecification
- : 'WITHIN' 'GROUP' '(' 'ORDER' 'BY' SortSpecificationList ')'
- ;
+// TODO: WITHIN
+//WithinGroupSpecification
+// : 'WITHIN' 'GROUP' '(' 'ORDER' 'BY' SortSpecificationList ')'
+// ;
 
 LateralView
  : '<hive>LATERAL' 'VIEW' UserDefinedFunction RegularIdentifier LateralViewColumnAliases  -> [{ udtf: $3, tableAlias: $4, columnAliases: $5 }]
  | '<hive>LATERAL' 'VIEW' UserDefinedFunction LateralViewColumnAliases                    -> [{ udtf: $3, columnAliases: $4 }]
+ | LateralView_ERROR
+ ;
+
+LateralView_ERROR
+ : '<hive>LATERAL' 'VIEW' UserDefinedFunction RegularIdentifier error                     -> []
+ | '<hive>LATERAL' 'VIEW' UserDefinedFunction error                                       -> []
+ | '<hive>LATERAL' 'VIEW' error                                                           -> []
+ | '<hive>LATERAL' error                                                                  -> []
  ;
 
 LateralView_EDIT
@@ -3772,6 +3872,8 @@ var getValueExpressionKeywords = function (valueExpression, extras) {
 var suggestTypeKeywords = function () {
   if (isHive()) {
     suggestKeywords(['BIGINT', 'BINARY', 'BOOLEAN', 'CHAR', 'DATE', 'DECIMAL', 'DOUBLE', 'FLOAT', 'INT', 'SMALLINT', 'TIMESTAMP', 'STRING', 'TINYINT', 'VARCHAR']);
+  } else if (isImpala()) {
+    suggestKeywords(['BIGINT', 'BOOLEAN', 'CHAR', 'DECIMAL', 'DOUBLE', 'FLOAT', 'INT', 'REAL', 'SMALLINT', 'TIMESTAMP', 'STRING', 'TINYINT', 'VARCHAR']);
   } else {
     suggestKeywords(['BIGINT', 'BOOLEAN', 'CHAR', 'DECIMAL', 'DOUBLE', 'FLOAT', 'INT', 'SMALLINT', 'TIMESTAMP', 'STRING', 'TINYINT', 'VARCHAR']);
   }
@@ -3789,6 +3891,9 @@ var valueExpressionSuggest = function (oppositeValueExpression) {
 }
 
 var applyTypeToSuggestions = function (types) {
+  if (types[0] === 'BOOLEAN') {
+    return;
+  }
   if (parser.yy.result.suggestFunctions) {
     parser.yy.result.suggestFunctions.types = types;
   }
@@ -3810,6 +3915,24 @@ var findCaseType = function (whenThenList) {
   return { types: [ 'T' ] };
 }
 
+findReturnTypes = function (funcToken) {
+  var funcName = funcToken.substring(0, funcToken.length - 1).toLowerCase();
+  return parser.yy.sqlFunctions.getReturnTypes(parser.yy.activeDialect, funcName);
+}
+
+var applyArgumentTypesToSuggestions = function (funcToken, position) {
+  var funcName = funcToken.substring(0, funcToken.length - 1).toLowerCase();
+  var foundArguments = parser.yy.sqlFunctions.getArgumentTypes(parser.yy.activeDialect, funcName, position);
+  if (foundArguments.length == 0 && parser.yy.result.suggestColumns) {
+    delete parser.yy.result.suggestColumns;
+    delete parser.yy.result.suggestValues;
+    delete parser.yy.result.suggestFunctions;
+    delete parser.yy.result.suggestIdentifiers;
+  } else {
+    applyTypeToSuggestions(foundArguments);
+  }
+}
+
 var prioritizeSuggestions = function () {
   parser.yy.result.lowerCase = parser.yy.lowerCase || false;
   if (typeof parser.yy.result.suggestIdentifiers !== 'undefined' &&  parser.yy.result.suggestIdentifiers.length > 0) {
@@ -3834,7 +3957,6 @@ var prioritizeSuggestions = function () {
   }
 }
 
-
 /**
  * Impala supports referencing maps and arrays in the the table reference list i.e.
  *
@@ -4142,10 +4264,11 @@ var lexerModified = false;
 /**
  * Main parser function
  */
-parser.parseSql = function(beforeCursor, afterCursor, dialect) {
+parser.parseSql = function(beforeCursor, afterCursor, dialect, sqlFunctions, debug) {
   if (dialect === 'generic') {
     dialect = undefined;
   }
+  parser.yy.sqlFunctions = sqlFunctions;
   parser.yy.activeDialect = dialect;
   parser.yy.result = {};
   parser.yy.lowerCase = false;
@@ -4183,6 +4306,10 @@ parser.parseSql = function(beforeCursor, afterCursor, dialect) {
     if (typeof parser.yy.result === 'undefined') {
       throw err;
     }
+    if (debug) {
+      console.log(err);
+      console.error(err.stack);
+    }
     if (parser.yy.result.error && !parser.yy.result.error.recoverable) {
       console.log(parser.yy.result.error);
     }

Fișier diff suprimat deoarece este prea mare
+ 0 - 0
desktop/core/src/desktop/static/desktop/js/autocomplete/sql.js


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

@@ -39,7 +39,7 @@
 
   SqlAutocompleter2.prototype.autocomplete = function (beforeCursor, afterCursor, callback, editor) {
     var self = this;
-    var parseResult = sqlParser.parseSql(beforeCursor, afterCursor, self.snippet.type());
+    var parseResult = sqlParser.parseSql(beforeCursor, afterCursor, self.snippet.type(), sqlFunctions);
 
     var completions = [];
 

+ 157 - 119
desktop/core/src/desktop/static/desktop/js/sqlFunctions.js

@@ -34,13 +34,13 @@
         returnTypes: ['DOUBLE'],
         arguments: [[{type: 'DECIMAL'}, {type: 'DOUBLE'}]],
         signature: 'acos(DECIMAL|DOUBLE a)',
-        description: 'Returns the arccosine of a if -1&lt;=a&lt;=1 or NULL otherwise.'
+        description: 'Returns the arccosine of a if -1<=a<=1 or NULL otherwise.'
       },
       asin: {
         returnTypes: ['DOUBLE'],
         arguments: [[{type: 'DECIMAL'}, {type: 'DOUBLE'}]],
         signature: 'asin(DECIMAL|DOUBLE a)',
-        description: 'Returns the arc sin of a if -1&lt;=a&lt;=1 or NULL otherwise.'
+        description: 'Returns the arc sin of a if -1<=a<=1 or NULL otherwise.'
       },
       atan: {
         returnTypes: ['DOUBLE'],
@@ -121,7 +121,7 @@
         returnTypes: ['T'],
         arguments: [[{type: 'T', multiple: true}]],
         signature: 'greatest(T a1, T a2, ...)',
-        description: 'Returns the greatest value of the list of values. Fixed to return NULL when one or more arguments are NULL, and strict type restriction relaxed, consistent with "&gt;" operator.'
+        description: 'Returns the greatest value of the list of values. Fixed to return NULL when one or more arguments are NULL, and strict type restriction relaxed, consistent with ">" operator.'
       },
       hex: {
         returnTypes: ['STRING'],
@@ -133,7 +133,7 @@
         returnTypes: ['T'],
         arguments: [[{type: 'T', multiple: true}]],
         signature: 'least(T a1, T a2, ...)',
-        description: 'Returns the least value of the list of values. Fixed to return NULL when one or more arguments are NULL, and strict type restriction relaxed, consistent with "&lt;" operator.'
+        description: 'Returns the least value of the list of values. Fixed to return NULL when one or more arguments are NULL, and strict type restriction relaxed, consistent with "<" operator.'
       },
       ln: {
         returnTypes: ['DOUBLE'],
@@ -162,7 +162,7 @@
       negative: {
         returnTypes: ['T'],
         arguments: [[{type: 'DOUBLE'}, {type: 'INT'}]],
-        signature: 'negative(T&lt;DOUBLE|INT&gt; a)',
+        signature: 'negative(T<DOUBLE|INT> a)',
         description: 'Returns -a.'
       },
       pi: {
@@ -171,13 +171,13 @@
       pmod: {
         returnTypes: ['T'],
         arguments: [[{type: 'DOUBLE'}, {type: 'INT'}], [{type: 'T'}]],
-        signature: 'pmod(T&lt;DOUBLE|INT&gt; a, T b)',
+        signature: 'pmod(T<DOUBLE|INT> a, T b)',
         description: 'Returns the positive value of a mod b'
       },
       positive: {
         returnTypes: ['T'],
         arguments: [[{type: 'DOUBLE'}, {type: 'INT'}]],
-        signature: 'positive(T&lt;DOUBLE|INT&gt; a)',
+        signature: 'positive(T<DOUBLE|INT> a)',
         description: 'Returns a.'
       },
       pow: {
@@ -213,25 +213,25 @@
       shiftleft: {
         returnTypes: ['T'],
         arguments: [[{type: 'BIGINT'}, {type: 'INT'}, {type: 'SMALLINT'}, {type: 'TINYINT'}], [{type: 'INT'}]],
-        signature: 'shiftleft(T&lt;BIGINT|INT|SMALLINT|TINYINT&gt; a, INT b)',
+        signature: 'shiftleft(T<BIGINT|INT|SMALLINT|TINYINT> a, INT b)',
         description: 'Bitwise left shift. Shifts a b positions to the left. Returns int for tinyint, smallint and int a. Returns bigint for bigint a.'
       },
       shiftright: {
         returnTypes: ['T'],
         arguments: [[{type: 'BIGINT'}, {type: 'INT'}, {type: 'SMALLINT'}, {type: 'TINYINT'}], [{type: 'INT'}]],
-        signature: 'shiftright(T&lt;BIGINT|INT|SMALLINT|TINYINT&gt; a, INT b)',
+        signature: 'shiftright(T<BIGINT|INT|SMALLINT|TINYINT> a, INT b)',
         description: 'Bitwise right shift. Shifts a b positions to the right. Returns int for tinyint, smallint and int a. Returns bigint for bigint a.'
       },
       shiftrightunsigned: {
         returnTypes: ['T'],
         arguments: [[{type: 'BIGINT'}, {type: 'INT'}, {type: 'SMALLINT'}, {type: 'TINYINT'}], [{type: 'INT'}]],
-        signature: 'shiftrightunsigned(T&lt;BIGINT|INT|SMALLINT|TINYINT&gt; a, INT b)',
+        signature: 'shiftrightunsigned(T<BIGINT|INT|SMALLINT|TINYINT> a, INT b)',
         description: 'Bitwise unsigned right shift. Shifts a b positions to the right. Returns int for tinyint, smallint and int a. Returns bigint for bigint a.'
       },
       sign: {
         returnTypes: ['T'],
         arguments: [[{type: 'DOUBLE'}, {type: 'INT'}]],
-        signature: 'sign(T&lt;DOUBLE|INT&gt; a)',
+        signature: 'sign(T<DOUBLE|INT> a)',
         description: 'Returns the sign of a as \'1.0\' (if a is positive) or \'-1.0\' (if a is negative), \'0.0\' otherwise. The decimal version returns INT instead of DOUBLE.'
       },
       sin: {
@@ -293,19 +293,19 @@
       ceil: {
         returnTypes: ['T'],
         arguments: [[{type: 'DOUBLE'}, {type: 'DECIMAL'}]],
-        signature: 'ceil(T&lt;DOUBLE|DECIMAL&gt; a)',
+        signature: 'ceil(T<DOUBLE|DECIMAL> a)',
         description: 'Returns the smallest integer that is greater than or equal to the argument.'
       },
       ceiling: {
         returnTypes: ['T'],
         arguments: [[{type: 'DOUBLE'}, {type: 'DECIMAL'}]],
-        signature: 'ceiling(T&lt;DOUBLE|DECIMAL&gt; a)',
+        signature: 'ceiling(T<DOUBLE|DECIMAL> a)',
         description: 'Returns the smallest integer that is greater than or equal to the argument.'
       },
       conv: {
         returnTypes: ['T'],
         arguments: [[{type: 'BIGINT'}, {type: 'STRING'}], [{type: 'INT'}], [{type: 'INT'}]],
-        signature: 'conv(T&lt;BIGINT|STRING&gt; a, INT from_base, INT to_base)',
+        signature: 'conv(T<BIGINT|STRING> a, INT from_base, INT to_base)',
         description: 'Returns a string representation of an integer value in a particular base. The input value can be a string, for example to convert a hexadecimal number such as fce2 to decimal. To use the return value as a number (for example, when converting to base 10), use CAST() to convert to the appropriate type.'
       },
       cos: {
@@ -338,7 +338,7 @@
       fmod: {
         returnTypes: ['T'],
         arguments: [[{type: 'DOUBLE'}, {type: 'FLOAT'}], [{type: 'DOUBLE'}, {type: 'FLOAT'}]],
-        signature: 'fmod(T&lt;DOUBLE|FLOAT&gt; a, T&lt;DOUBLE|FLOAT&gt; b)',
+        signature: 'fmod(T<DOUBLE|FLOAT> a, T<DOUBLE|FLOAT> b)',
         description: 'Returns the modulus of a number.'
       },
       fnv_hash: {
@@ -356,7 +356,7 @@
       hex: {
         returnTypes: ['STRING'],
         arguments: [[{type: 'BIGINT'}, {type: 'STRING'}]],
-        signature: 'hex(T&lt;BIGINT|STRING&gt; a)',
+        signature: 'hex(T<BIGINT|STRING> a)',
         description: 'Returns the hexadecimal representation of an integer value, or of the characters in a string.'
       },
       is_inf: {
@@ -461,7 +461,7 @@
       pmod: {
         returnTypes: ['T'],
         arguments: [[{type: 'DOUBLE'}, {type: 'INT'}], [{type: 'T'}]],
-        signature: 'pmod(T&lt;DOUBLE|INT&gt; a, T b)',
+        signature: 'pmod(T<DOUBLE|INT> a, T b)',
         description: 'Returns the positive modulus of a number.'
       },
       positive: {
@@ -508,8 +508,7 @@
       },
       round: {
         returnTypes: ['T'],
-        arguments: [[{type: 'DOUBLE'}], [{type: 'INT', optional: true}]],
-        altArguments: [[{type: 'DECIMAL'}], [{type: 'INT'}]],
+        arguments: [[{type: 'DECIMAL'}, {type: 'DOUBLE'}], [{type: 'INT', optional: true}]],
         signature: 'round(DOUBLE a [, INT d]), round(DECIMAL val, INT d)',
         description: 'Rounds a floating-point value. By default (with a single argument), rounds to the nearest integer. Values ending in .5 are rounded up for positive numbers, down for negative numbers (that is, away from zero). The optional second argument specifies how many digits to leave after the decimal point; values greater than zero produce a floating-point return value rounded to the requested number of digits to the right of the decimal point.'
       },
@@ -584,24 +583,11 @@
         signature: 'struct(val1, val2, ...)',
         description: 'Creates a struct with the given field values. Struct field names will be col1, col2, ....'
       }
-    }
+    },
+    impala: {}
   };
 
   var AGGREGATE_FUNCTIONS = {
-    shared: {
-      var_pop: {
-        returnTypes: ['DOUBLE'],
-        arguments: [[{type: 'T'}]],
-        signature: 'var_pop(col)',
-        description: 'Returns the variance of a numeric column in the group.'
-      },
-      var_samp: {
-        returnTypes: ['DOUBLE'],
-        arguments: [[{type: 'T'}]],
-        signature: 'var_samp(col)',
-        description: 'Returns the unbiased sample variance of a numeric column in the group.'
-      }
-    },
     generic: {
       count: {
         returnTypes: ['BIGINT'],
@@ -690,21 +676,21 @@
         description: 'Returns the sample covariance of a pair of a numeric columns in the group.'
       },
       collect_set: {
-        returnTypes: ['array'],
+        returnTypes: ['ARRAY'],
         arguments: [[{type: 'T'}]],
         signature: 'collect_set(col)',
         description: 'Returns a set of objects with duplicate elements eliminated.'
       },
       collect_list: {
-        returnTypes: ['array'],
+        returnTypes: ['ARRAY'],
         arguments: [[{type: 'T'}]],
         signature: 'collect_list(col)',
         description: 'Returns a list of objects with duplicates. (As of Hive 0.13.0.)'
       },
       histogram_numeric: {
-        returnTypes: ['array<struct {\'x\', \'y\'}>'],
+        returnTypes: ['ARRAY'],
         arguments: [[{type: 'T'}], [{type: 'INT'}]],
-        signature: 'histogram_numeric(col, b)',
+        signature: 'array<struct {\'x\', \'y\'}> histogram_numeric(col, b)',
         description: 'Computes a histogram of a numeric column in the group using b non-uniformly spaced bins. The output is an array of size b of double-valued (x,y) coordinates that represent the bin centers and heights'
       },
       ntile: {
@@ -714,15 +700,15 @@
         description: 'Divides an ordered partition into x groups called buckets and assigns a bucket number to each row in the partition. This allows easy calculation of tertiles, quartiles, deciles, percentiles and other common summary statistics. (As of Hive 0.11.0.)'
       },
       percentile: {
-        returnTypes: ['DOUBLE', 'array<DOUBLE>'],
-        arguments: [[{type: 'BIGINT'}], [{type: 'DOUBLE'}, {type: 'array'}]],
-        signature: 'percentile(BIGINT col, p), percentile(BIGINT col, array(p1 [, p2]...))',
+        returnTypes: ['DOUBLE', 'ARRAY'],
+        arguments: [[{type: 'BIGINT'}], [{type: 'ARRAY'}, {type: 'DOUBLE'}]],
+        signature: 'percentile(BIGINT col, p), array<DOUBLE> percentile(BIGINT col, array(p1 [, p2]...))',
         description: 'Returns the exact pth percentile (or percentiles p1, p2, ..) of a column in the group (does not work with floating point types). p must be between 0 and 1. NOTE: A true percentile can only be computed for integer values. Use PERCENTILE_APPROX if your input is non-integral.'
       },
       percentile_approx: {
-        returnTypes: ['DOUBLE', 'array<DOUBLE>'],
-        arguments: [[{type: 'DOUBLE'}], [{type: 'DOUBLE'}, {type: 'array'}], [{type: 'BIGINT', optional: true}]],
-        signature: 'percentile_approx(DOUBLE col, p, [, B]), percentile_approx(DOUBLE col, array(p1 [, p2]...), [, B])',
+        returnTypes: ['DOUBLE', 'ARRAY'],
+        arguments: [[{type: 'DOUBLE'}], [{type: 'DOUBLE'}, {type: 'ARRAY'}], [{type: 'BIGINT', optional: true}]],
+        signature: 'percentile_approx(DOUBLE col, p, [, B]), array<DOUBLE> percentile_approx(DOUBLE col, array(p1 [, p2]...), [, B])',
         description: 'Returns an approximate pth percentile (or percentiles p1, p2, ..) of a numeric column (including floating point types) in the group. The B parameter controls approximation accuracy at the cost of memory. Higher values yield better approximations, and the default is 10,000. When the number of distinct values in col is smaller than B, this gives an exact percentile value.'
       },
       variance: {
@@ -730,6 +716,18 @@
         arguments: [[{type: 'T'}]],
         signature: 'variance(col)',
         description: 'Returns the variance of a numeric column in the group.'
+      },
+      var_pop: {
+        returnTypes: ['DOUBLE'],
+        arguments: [[{type: 'T'}]],
+        signature: 'var_pop(col)',
+        description: 'Returns the variance of a numeric column in the group.'
+      },
+      var_samp: {
+        returnTypes: ['DOUBLE'],
+        arguments: [[{type: 'T'}]],
+        signature: 'var_samp(col)',
+        description: 'Returns the unbiased sample variance of a numeric column in the group.'
       }
     },
     impala: {
@@ -816,6 +814,18 @@
         arguments: [[{type: 'T'}]],
         signature: 'variance_samp([DISTINCT | ALL] col)',
         description: 'An aggregate function that returns the sample variance of a set of numbers. This is a mathematical property that signifies how far the values spread apart from the mean. The return value can be zero (if the input is a single value, or a set of identical values), or a positive number otherwise.'
+      },
+      var_pop: {
+        returnTypes: ['DOUBLE'],
+        arguments: [[{type: 'T'}]],
+        signature: 'var_pop(col)',
+        description: 'Returns the variance of a numeric column in the group.'
+      },
+      var_samp: {
+        returnTypes: ['DOUBLE'],
+        arguments: [[{type: 'T'}]],
+        signature: 'var_samp(col)',
+        description: 'Returns the unbiased sample variance of a numeric column in the group.'
       }
     }
   };
@@ -824,35 +834,36 @@
     hive: {
       array_contains: {
         returnTypes: ['BOOLEAN'],
-        arguments: [[{type: 'array'}], [{type: 'T'}]],
-        signature: 'array_contains(Array&lt;T&gt; a, val)',
+        arguments: [[{type: 'ARRAY'}], [{type: 'T'}]],
+        signature: 'array_contains(Array<T> a, val)',
         description: 'Returns TRUE if the array contains value.'
       },
       map_keys: {
-        returnTypes: ['array<K.V>'],
-        arguments: [[{type: 'map'}]],
-        signature: 'map_keys(Map&lt;K.V&gt; a)',
+        returnTypes: ['ARRAY'],
+        arguments: [[{type: 'MAP'}]],
+        signature: 'array<K.V> map_keys(Map<K.V> a)',
         description: 'Returns an unordered array containing the keys of the input map.'
       },
       map_values: {
-        returnTypes: ['array<K.V>'],
-        arguments: [[{type: 'map'}]],
-        signature: 'map_values(Map&lt;K.V&gt; a)',
+        returnTypes: ['ARRAY'],
+        arguments: [[{type: 'MAP'}]],
+        signature: 'array<K.V> map_values(Map<K.V> a)',
         description: 'Returns an unordered array containing the values of the input map.'
       },
       size: {
         returnTypes: ['INT'],
-        arguments: [[{type: 'map'}, {type: 'array'}]],
-        signature: 'size(Map&lt;K.V&gt;|Array&lt;T&gt; a)',
+        arguments: [[{type: 'ARRAY'}, {type: 'MAP'}]],
+        signature: 'size(Map<K.V>|Array<T> a)',
         description: 'Returns the number of elements in the map or array type.'
       },
       sort_array: {
-        returnTypes: ['array<T>'],
-        arguments: [[{type: 'array'}]],
-        signature: 'sort_array(Array&lt;T&gt; a)',
+        returnTypes: ['ARRAY'],
+        arguments: [[{type: 'ARRAY'}]],
+        signature: 'sort_array(Array<T> a)',
         description: 'Sorts the input array in ascending order according to the natural ordering of the array elements and returns it.'
       }
-    }
+    },
+    impala: {}
   };
 
   var TYPE_CONVERSION_FUNCTIONS = {
@@ -914,7 +925,7 @@
       },
       date_format: {
         returnTypes: ['STRING'],
-        arguments: [[{type: 'DATE'}, {type: 'TIMESTAMP'}, {type: 'STRING'}], [{type: 'STRING'}]],
+        arguments: [[{type: 'DATE'}, {type: 'STRING'}, {type: 'TIMESTAMP'}], [{type: 'STRING'}]],
         signature: 'date_format(DATE|TIMESTAMP|STRING ts, STRING fmt)',
         description: 'Converts a date/timestamp/string to a value of string in the format specified by the date format fmt (as of Hive 1.2.0). Supported formats are Java SimpleDateFormat formats – https://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html. The second argument fmt should be constant. Example: date_format(\'2015-04-08\', \'y\') = \'2015\'.'
       },
@@ -974,7 +985,7 @@
       },
       months_between: {
         returnTypes: ['DOUBLE'],
-        arguments: [[{type: 'DATE'}, {type: 'TIMESTAMP'}, {type: 'STRING'}], [{type: 'DATE'}, {type: 'TIMESTAMP'}, {type: 'STRING'}]],
+        arguments: [[{type: 'DATE'}, {type: 'STRING'}, {type: 'TIMESTAMP'}], [{type: 'DATE'}, {type: 'STRING'}, {type: 'TIMESTAMP'}]],
         signature: 'months_between(DATE|TIMESTAMP|STRING date1, DATE|TIMESTAMP|STRING date2)',
         description: 'Returns number of months between dates date1 and date2 (as of Hive 1.2.0). If date1 is later than date2, then the result is positive. If date1 is earlier than date2, then the result is negative. If date1 and date2 are either the same days of the month or both last days of months, then the result is always an integer. Otherwise the UDF calculates the fractional portion of the result based on a 31-day month and considers the difference in time components date1 and date2. date1 and date2 type can be date, timestamp or string in the format \'yyyy-MM-dd\' or \'yyyy-MM-dd HH:mm:ss\'. The result is rounded to 8 decimal places. Example: months_between(\'1997-02-28 10:30:00\', \'1996-10-30\') = 3.94959677'
       },
@@ -986,7 +997,7 @@
       },
       quarter: {
         returnTypes: ['INT'],
-        arguments: [[{type: 'DATE'}, {type: 'TIMESTAMP'}, {type: 'STRING'}]],
+        arguments: [[{type: 'DATE'}, {type: 'STRING'}, {type: 'TIMESTAMP'}]],
         signature: 'quarter(DATE|TIMESTAMP|STRING a)	',
         description: 'Returns the quarter of the year for a date, timestamp, or string in the range 1 to 4. Example: quarter(\'2015-04-08\') = 2.'
       },
@@ -1434,14 +1445,14 @@
       concat_ws: {
         returnTypes: ['STRING'],
         arguments: [[{type: 'STRING'}], [{type: 'STRING'}], [{type: 'STRING', multiple: true}]],
-        altArguments: [[{type: 'STRING'}], [{type: 'array'}]],
-        signature: 'concat_ws(STRING sep, STRING a, STRING b...), concat_ws(STRING sep, Array&lt;STRING&gt;)',
+        altArguments: [[{type: 'STRING'}], [{type: 'ARRAY'}]],
+        signature: 'concat_ws(STRING sep, STRING a, STRING b...), concat_ws(STRING sep, Array<STRING>)',
         description: 'Like concat(), but with custom separator SEP.'
       },
       context_ngrams: {
-        returnTypes: ['array<struct<STRING,DOUBLE>>'],
-        arguments: [[{type: 'array'}], [{type: 'array'}], [{type: 'INT'}], [{type: 'INT'}]],
-        signature: 'context_ngrams(Array&lt;Array&lt;STRING&gt;&gt;, Array&lt;STRING&gt;, INT k, INT pf)',
+        returnTypes: ['ARRAY'],
+        arguments: [[{type: 'ARRAY'}], [{type: 'ARRAY'}], [{type: 'INT'}], [{type: 'INT'}]],
+        signature: 'array<struct<STRING,DOUBLE>> context_ngrams(Array<Array<STRING>>, Array<STRING>, INT k, INT pf)',
         description: 'Returns the top-k contextual N-grams from a set of tokenized sentences, given a string of "context".'
       },
       decode: {
@@ -1535,9 +1546,9 @@
         description: 'Returns the string resulting from trimming spaces from the beginning(left hand side) of A. For example, ltrim(\' foobar \') results in \'foobar \'.'
       },
       ngrams: {
-        returnTypes: ['array<struct<STRING, DOUBLE>>'],
-        arguments: [[{type: 'array'}], [{type: 'INT'}], [{type: 'INT'}], [{type: 'INT'}]],
-        signature: 'ngrams(Array&lt;Array&lt;STRING&gt;&gt; a, INT n, INT k, INT pf)',
+        returnTypes: ['ARRAY'],
+        arguments: [[{type: 'ARRAY'}], [{type: 'INT'}], [{type: 'INT'}], [{type: 'INT'}]],
+        signature: 'array<struct<STRING, DOUBLE>> ngrams(Array<Array<STRING>> a, INT n, INT k, INT pf)',
         description: 'Returns the top-k N-grams from a set of tokenized sentences, such as those returned by the sentences() UDAF.'
       },
       parse_url: {
@@ -1589,9 +1600,9 @@
         description: 'Returns the string resulting from trimming spaces from the end(right hand side) of A. For example, rtrim(\' foobar \') results in \' foobar\'.'
       },
       sentences: {
-        returnTypes: ['array<array<STRING>>'],
+        returnTypes: ['ARRAY'],
         arguments: [[{type: 'STRING'}], [{type: 'STRING'}], [{type: 'STRING'}]],
-        signature: 'sentences(STRING str, STRING lang, STRING locale)',
+        signature: 'array<array<STRING>> sentences(STRING str, STRING lang, STRING locale)',
         description: 'Tokenizes a string of natural language text into words and sentences, where each sentence is broken at the appropriate sentence boundary and returned as an array of words. The \'lang\' and \'locale\' are optional arguments. For example, sentences(\'Hello there! How are you?\') returns ( ("Hello", "there"), ("How", "are", "you") ).'
       },
       soundex: {
@@ -1607,15 +1618,15 @@
         description: 'Returns a string of n spaces.'
       },
       split: {
-        returnTypes: ['array<STRING>'],
+        returnTypes: ['ARRAY'],
         arguments: [[{type: 'STRING'}], [{type: 'STRING'}]],
-        signature: 'split(STRING str, STRING pat)',
+        signature: 'array<STRING> split(STRING str, STRING pat)',
         description: 'Splits str around pat (pat is a regular expression).'
       },
       str_to_map: {
-        returnTypes: ['map<STRING,STRING>'],
+        returnTypes: ['MAP'],
         arguments: [[{type: 'STRING'}], [{type: 'STRING', optional: true}], [{type: 'STRING', optional: true}]],
-        signature: 'str_to_map(STRING [, STRING delimiter1, STRING delimiter2])',
+        signature: 'map<STRING,STRING> str_to_map(STRING [, STRING delimiter1, STRING delimiter2])',
         description: 'Splits text into key-value pairs using two delimiters. Delimiter1 separates text into K-V pairs, and Delimiter2 splits each K-V pair. Default delimiters are \',\' for delimiter1 and \'=\' for delimiter2.'
       },
       substr: {
@@ -1861,13 +1872,13 @@
     hive: {
       explode: {
         returnTypes: ['table'],
-        arguments: [[{type: 'array'}, {type: 'map'}]],
+        arguments: [[{type: 'ARRAY'}, {type: 'MAP'}]],
         signature: 'explode(Array|Array<T>|Map a)',
         description: ''
       },
       inline: {
         returnTypes: ['table'],
-        arguments: [[{type: 'array'}]],
+        arguments: [[{type: 'ARRAY'}]],
         signature: 'inline(Array<Struct [, Struct]> a)',
         description: 'Explodes an array of structs into a table. (As of Hive 0.10.)'
       },
@@ -1885,7 +1896,7 @@
       },
       posexplode: {
         returnTypes: ['table'],
-        arguments: [[{type: 'array'}]],
+        arguments: [[{type: 'ARRAY'}]],
         signature: 'posexplode(ARRAY) ',
         description: 'posexplode() is similar to explode but instead of just returning the elements of the array it returns the element as well as its position  in the original array.'
       },
@@ -1895,7 +1906,8 @@
         signature: 'stack(INT n, v1, v2, ..., vk)',
         description: 'Breaks up v1, v2, ..., vk into n rows. Each row will have k/n columns. n must be constant.'
       }
-    }
+    },
+    impala: {}
   };
 
   var MISC_FUNCTIONS = {
@@ -1979,9 +1991,9 @@
         description: 'Calculates the SHA-2 family of hash functions (SHA-224, SHA-256, SHA-384, and SHA-512) (as of Hive 1.3.0). The first argument is the string or binary to be hashed. The second argument indicates the desired bit length of the result, which must have a value of 224, 256, 384, 512, or 0 (which is equivalent to 256). SHA-224 is supported starting from Java 8. If either argument is NULL or the hash length is not one of the permitted values, the return value is NULL. Example: sha2(\'ABC\', 256) = \'b5d4045c3f466fa91fe2cc6abe79232a1a57cdf104f7a26e716e0a1e2789df78\'.'
       },
       xpath: {
-        returnTypes: ['array<STRING>'],
+        returnTypes: ['ARRAY'],
         arguments: [[{type: 'STRING'}], [{type: 'STRING'}]],
-        signature: 'xpath(STRING xml, STRING xpath)',
+        signature: 'array<STRING> xpath(STRING xml, STRING xpath)',
         description: 'The xpath family of UDFs are wrappers around the Java XPath library javax.xml.xpath provided by the JDK. The library is based on the XPath 1.0 specification.'
       },
       xpath_boolean: {
@@ -2161,35 +2173,12 @@
   var createDocHtml = function (funcDesc) {
     var html = '<div style="max-width: 600px; white-space: normal; overflow-y: auto; height: 100%; padding: 8px;"><p><span style="white-space: pre; font-family: monospace;">' + funcDesc.signature + '</span></p>';
     if (funcDesc.description) {
-      html += '<p>' + funcDesc.description + '</p>';
+      html += '<p>' + funcDesc.description.replace(/[<]/g, "&lt;").replace(/[>]/g, "&gt;") + '</p>';
     }
     html += '<div>';
     return html;
   };
 
-  var addFunctions = function (functionIndex, dialect, completions) {
-    if (typeof functionIndex.shared !== 'undefined') {
-      functionIndex.shared.forEach(function (func) {
-        completions.push({
-          value: func.name,
-          meta: func.returnType,
-          type: 'function',
-          docHTML: createDocHtml(func)
-        })
-      })
-    }
-    if (typeof functionIndex[dialect] !== 'undefined') {
-      functionIndex[dialect].forEach(function (func) {
-        completions.push({
-          value: func.name,
-          meta: func.returnType,
-          type: 'function',
-          docHTML: createDocHtml(func)
-        })
-      })
-    }
-  };
-
   /**
    * Matches types based on implicit conversion i.e. if you expect a BIGINT then INT is ok but not BOOLEAN etc.
    *
@@ -2202,6 +2191,9 @@
     if (dialect !== 'hive') {
       dialect = 'impala';
     }
+    if (actualTypes.indexOf('ARRAY') !== -1 || actualTypes.indexOf('MAP') !== -1 || actualTypes.indexOf('STRUCT') !== -1) {
+      return true;
+    }
     for (var i = 0; i < expectedTypes.length; i++) {
       for (var j = 0; j < actualTypes.length; j++) {
         if (typeImplicitConversion[dialect][expectedTypes[i]] && typeImplicitConversion[dialect][expectedTypes[i]][actualTypes[j]]) {
@@ -2212,7 +2204,7 @@
     return false;
   };
 
-  var addFunctionsTwo = function (functionIndex, dialect, returnTypes, result) {
+  var addFunctions = function (functionIndex, dialect, returnTypes, result) {
     var indexForDialect = functionIndex[dialect || 'generic'];
     if (indexForDialect) {
       Object.keys(indexForDialect).forEach(function (funcName) {
@@ -2234,16 +2226,17 @@
 
   var suggestFunctions = function (dialect, returnTypes, includeAggregate, completions) {
     var functionsToSuggest = {};
-    addFunctionsTwo(COLLECTION_FUNCTIONS, dialect, returnTypes, functionsToSuggest);
-    addFunctionsTwo(CONDITIONAL_FUNCTIONS, dialect, returnTypes, functionsToSuggest);
-    addFunctionsTwo(DATE_FUNCTIONS, dialect, returnTypes, functionsToSuggest);
-    addFunctionsTwo(MATHEMATICAL_FUNCTIONS, dialect, returnTypes, functionsToSuggest);
-    addFunctionsTwo(TYPE_CONVERSION_FUNCTIONS, dialect, returnTypes, functionsToSuggest);
-    addFunctionsTwo(STRING_FUNCTIONS, dialect, returnTypes, functionsToSuggest);
-    addFunctionsTwo(MISC_FUNCTIONS, dialect, returnTypes, functionsToSuggest);
-    addFunctionsTwo(TABLE_GENERATING_FUNCTIONS, dialect, returnTypes, functionsToSuggest);
+    addFunctions(COLLECTION_FUNCTIONS, dialect, returnTypes, functionsToSuggest);
+    addFunctions(CONDITIONAL_FUNCTIONS, dialect, returnTypes, functionsToSuggest);
+    addFunctions(COMPLEX_TYPE_CONSTRUCTS, dialect, returnTypes, functionsToSuggest);
+    addFunctions(DATE_FUNCTIONS, dialect, returnTypes, functionsToSuggest);
+    addFunctions(MATHEMATICAL_FUNCTIONS, dialect, returnTypes, functionsToSuggest);
+    addFunctions(TYPE_CONVERSION_FUNCTIONS, dialect, returnTypes, functionsToSuggest);
+    addFunctions(STRING_FUNCTIONS, dialect, returnTypes, functionsToSuggest);
+    addFunctions(MISC_FUNCTIONS, dialect, returnTypes, functionsToSuggest);
+    addFunctions(TABLE_GENERATING_FUNCTIONS, dialect, returnTypes, functionsToSuggest);
     if (includeAggregate) {
-      addFunctionsTwo(AGGREGATE_FUNCTIONS, dialect, returnTypes, functionsToSuggest);
+      addFunctions(AGGREGATE_FUNCTIONS, dialect, returnTypes, functionsToSuggest);
     }
     Object.keys(functionsToSuggest).forEach(function (name) {
       completions.push({
@@ -2255,15 +2248,60 @@
     });
   };
 
-  var getTypes = function (dialect, functionName, argumentPosition) {
+  var findFunction = function (dialect, functionName) {
+    return COLLECTION_FUNCTIONS[dialect][functionName] ||
+        CONDITIONAL_FUNCTIONS[dialect][functionName] ||
+        COMPLEX_TYPE_CONSTRUCTS[dialect][functionName] ||
+        DATE_FUNCTIONS[dialect][functionName] ||
+        MATHEMATICAL_FUNCTIONS[dialect][functionName] ||
+        TYPE_CONVERSION_FUNCTIONS[dialect][functionName] ||
+        STRING_FUNCTIONS[dialect][functionName] ||
+        MISC_FUNCTIONS[dialect][functionName] ||
+        TABLE_GENERATING_FUNCTIONS[dialect][functionName] ||
+        AGGREGATE_FUNCTIONS[dialect][functionName];
+  };
+
+  var getArgumentTypes = function (dialect, functionName, argumentPosition) {
+    if (dialect !== 'hive' && dialect !== 'impala') {
+      return ['T'];
+    }
+    var foundFunction = findFunction(dialect, functionName);
+    if (!foundFunction) {
+      return ['T'];
+    }
+    var arguments = foundFunction.arguments;
+    if (argumentPosition > arguments.length) {
+      var multiples = arguments[arguments.length - 1].filter(function (type) {
+        return type.multiple;
+      });
+      if (multiples.length > 0) {
+        return multiples.map(function (argument) {
+          return argument.type;
+        }).sort();
+      }
+      return [];
+    }
+    return arguments[argumentPosition - 1].map(function (argument) {
+      return argument.type;
+    }).sort();
+  };
 
+  var getReturnTypes = function (dialect, functionName) {
+    if (dialect !== 'hive' && dialect !== 'impala') {
+      return ['T'];
+    }
+    var foundFunction = findFunction(dialect, functionName);
+    if (!foundFunction) {
+      return ['T'];
+    }
+    return foundFunction.returnTypes;
   };
 
   return {
     suggestFunctions: suggestFunctions,
-    
-    getTypes: getTypes,
-
+    getArgumentTypes: getArgumentTypes,
+    getReturnTypes: getReturnTypes,
     matchesType: matchesType
   };
+
 }));

+ 415 - 37
desktop/core/src/desktop/static/desktop/spec/autocomplete/sqlSpecSelect.js

@@ -676,14 +676,14 @@ define([
         });
       });
 
-      it('should suggest columns and values for "SELECT COUNT(foo, bl = |, bla) FROM bar;"', function() {
+      it('should suggest columns and values for "SELECT COUNT(foo, bl = |,bla) FROM bar;"', function() {
         assertAutoComplete({
           beforeCursor: 'SELECT COUNT(foo, bl = ',
           afterCursor: ',bla) FROM bar;',
           expectedResult: {
             lowerCase: false,
-            suggestFunctions: {},
-            suggestColumns: { table: 'bar' },
+            suggestFunctions: { types: ['T'] },
+            suggestColumns: { types: ['T'], table: 'bar' },
             suggestValues: { identifierChain: [ {name: 'bl' }], table: 'bar' }
           }
         });
@@ -1138,8 +1138,9 @@ define([
           afterCursor: ' WHEN c THEN d END FROM testTable',
           expectedResult: {
             lowerCase: false,
-            suggestFunctions: {},
+            suggestFunctions: { types: ['T'] },
             suggestColumns: {
+              types: ['T'],
               table: 'testTable'
             },
             suggestValues: { identifierChain: [{ name: 'a' }], table: 'testTable' }
@@ -1153,8 +1154,9 @@ define([
           afterCursor: ' WHEN c THEN d ELSE e END FROM testTable',
           expectedResult: {
             lowerCase: false,
-            suggestFunctions: {},
+            suggestFunctions: { types: ['T'] },
             suggestColumns: {
+              types: ['T'],
               table: 'testTable'
             },
             suggestValues: { identifierChain: [{ name: 'a' }], table: 'testTable' }
@@ -1179,8 +1181,9 @@ define([
           afterCursor: ' ELSE FROM testTable',
           expectedResult: {
             lowerCase: false,
-            suggestFunctions: {},
+            suggestFunctions: { types: ['T'] },
             suggestColumns: {
+              types: ['T'],
               table: 'testTable'
             },
             suggestValues: { identifierChain: [{ name: 'd' }], table: 'testTable' }
@@ -1446,8 +1449,9 @@ define([
           afterCursor: ' = a FROM testTable',
           expectedResult: {
             lowerCase: false,
-            suggestFunctions: {},
+            suggestFunctions: { types: ['T'] },
             suggestColumns: {
+              types: ['T'],
               table: 'testTable'
             },
             suggestValues: { identifierChain :[{ name :'a'}], table: 'testTable' }
@@ -1517,8 +1521,9 @@ define([
           afterCursor: ' FROM testTable',
           expectedResult: {
             lowerCase: false,
-            suggestFunctions: {},
+            suggestFunctions: { types: ['T'] },
             suggestColumns: {
+              types: ['T'],
               table: 'testTable'
             },
             suggestValues: { identifierChain: [{ name: 'a' }], table: 'testTable' }
@@ -1853,6 +1858,37 @@ define([
           });
         });
 
+
+        it('should suggest tables for "SELECT * FROM | LATERAL VIEW explode("', function () {
+          assertAutoComplete({
+            beforeCursor: 'SELECT * FROM ',
+            afterCursor: ' LATERAL VIEW explode(',
+            dialect: 'hive',
+            expectedResult: {
+              lowerCase: false,
+              suggestTables: {},
+              suggestDatabases: { appendDot: true }
+            }
+          });
+        });
+
+        it('should suggest columns for "SELECT | FROM testTable LATERAL VIEW explode("', function () {
+          assertAutoComplete({
+            beforeCursor: 'SELECT ',
+            afterCursor: ' FROM testTable LATERAL VIEW explode(',
+            dialect: 'hive',
+            expectedResult: {
+              lowerCase: false,
+              suggestFunctions: {},
+              suggestAggregateFunctions: true,
+              suggestColumns: {
+                table: 'testTable'
+              },
+              suggestKeywords: ['*','ALL','DISTINCT']
+            }
+          });
+        });
+
         it('should suggest columns for "SELECT * FROM testTable LATERAL VIEW explode(|"', function () {
           assertAutoComplete({
             beforeCursor: 'SELECT * FROM testTable LATERAL VIEW explode(',
@@ -1860,8 +1896,9 @@ define([
             dialect: 'hive',
             expectedResult: {
               lowerCase: false,
-              suggestFunctions: {},
+              suggestFunctions: { types: ['ARRAY', 'MAP' ] },
               suggestColumns: {
+                types: ['ARRAY', 'MAP' ],
                 table: 'testTable'
               }
             }
@@ -1876,6 +1913,7 @@ define([
             expectedResult: {
               lowerCase: false,
               suggestColumns: {
+                types: ['ARRAY', 'MAP' ],
                 table: 'testTable',
                 identifierChain: [ { name: 'a' }, { name: 'b' }]
               }
@@ -1890,8 +1928,9 @@ define([
             dialect: 'hive',
             expectedResult: {
               lowerCase: false,
-              suggestFunctions: {},
+              suggestFunctions: { types: ['ARRAY' ] },
               suggestColumns: {
+                types: ['ARRAY' ],
                 table: 'testTable'
               }
             }
@@ -2281,7 +2320,7 @@ define([
           dialect: 'impala',
           expectedResult: {
             lowerCase: false,
-            suggestFunctions: {},
+            suggestFunctions: { types: ['T'] },
             suggestValues: {
               table: 'testTable',
               identifierChain: [{ name: 'testMap' }, { name: 'key' }]
@@ -2298,7 +2337,7 @@ define([
           dialect: 'impala',
           expectedResult: {
             lowerCase: false,
-            suggestFunctions: {},
+            suggestFunctions: { types: ['T'] },
             suggestValues: {
               table: 'testTable',
               identifierChain: [{ name: 'testMap' }, { name: 'field' }]
@@ -2367,7 +2406,19 @@ define([
           afterCursor: '',
           expectedResult: {
             lowerCase: false,
-            suggestColumns: { table: 'tbl2' }
+            suggestColumns: { types: ['T'], table: 'tbl2' }
+          }
+        });
+      });
+
+      it('should suggest columns for "SELECT * FROM tbl1, tbl2 atbl2, tbl3 WHERE cos(1) = atbl2.bla.|"', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT * FROM tbl1, tbl2 atbl2, tbl3 WHERE cos(1) = atbl2.bla.',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestColumns: { identifierChain: [{ name: 'bla' }], types: ['DOUBLE'], table: 'tbl2' }
           }
         });
       });
@@ -2378,12 +2429,12 @@ define([
           afterCursor: '',
           expectedResult: {
             lowerCase: false,
-            suggestFunctions: {},
+            suggestFunctions: { types: ['T'] },
             suggestValues: {
               table: 'testTable',
               identifierChain: [{ name: 'id' }]
             },
-            suggestColumns: { table: 'testTable' }
+            suggestColumns: { types: ['T'], table: 'testTable' }
           }
         });
       });
@@ -2430,12 +2481,339 @@ define([
           afterCursor: '',
           expectedResult: {
             lowerCase: false,
-            suggestFunctions: {},
+            suggestFunctions: { types: ['NUMBER'] },
             suggestValues: {
               table: 'testTable',
               identifierChain: [{ name: 'id' }]
             },
-            suggestColumns: { table: 'testTable' }
+            suggestColumns: { types: ['NUMBER'], table: 'testTable' }
+          }
+        });
+      });
+
+      it('should suggest values for "SELECT * FROM testTable WHERE \'foo\' = |"', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT * FROM testTable WHERE \'foo\' = ',
+          afterCursor: '',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestFunctions: { types: ['STRING'] },
+            suggestColumns: { types: ['STRING'], table: 'testTable' }
+          }
+        });
+      });
+
+      it('should suggest typed values for "SELECT * FROM testTable WHERE \'foo\' = |"', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT * FROM testTable WHERE \'foo\' = ',
+          afterCursor: '',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestFunctions: { types: ['STRING'] },
+            suggestColumns: { types: ['STRING'], table: 'testTable' }
+          }
+        });
+      });
+
+      it('should suggest keywords for "SELECT cast(\'1\' AS |"', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT cast(\'1\' AS ',
+          afterCursor: '',
+          dialect: 'hive',
+          containsKeywords: ['BIGINT', 'DATE'],
+          doesNotContainKeywords: ['REAL'],
+          expectedResult: {
+            lowerCase: false
+          }
+        });
+      });
+
+      it('should suggest keywords for "SELECT cast(\'1\' AS |"', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT cast(\'1\' AS ',
+          afterCursor: '',
+          dialect: 'impala',
+          containsKeywords: ['BIGINT', 'REAL'],
+          doesNotContainKeywords: ['DATE'],
+          expectedResult: {
+            lowerCase: false
+          }
+        });
+      });
+
+      it('should suggest columns for "SELECT cos(| FROM testTable"', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT cos(',
+          afterCursor: ' FROM testTable',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestFunctions: { types: ['DECIMAL', 'DOUBLE'] },
+            suggestColumns: { types: ['DECIMAL', 'DOUBLE'], table: 'testTable' }
+          }
+        });
+      });
+
+      it('should suggest typed columns for "SELECT cos(| FROM testTable"', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT cos(',
+          afterCursor: ' FROM testTable',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestFunctions: { types: ['DOUBLE'] },
+            suggestColumns: { types: ['DOUBLE'], table: 'testTable' }
+          }
+        });
+      });
+
+      it('should suggest columns for "SELECT ceiling(| FROM testTable"', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT ceiling(',
+          afterCursor: ' FROM testTable',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestFunctions: { types: ['DOUBLE'] },
+            suggestColumns: { types: ['DOUBLE'], table: 'testTable' }
+          }
+        });
+      });
+
+      it('should suggest typed columns for "SELECT ceiling(| FROM testTable"', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT ceiling(',
+          afterCursor: ' FROM testTable',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestFunctions: { types: ['DECIMAL', 'DOUBLE'] },
+            suggestColumns: { types: ['DECIMAL', 'DOUBLE'], table: 'testTable' }
+          }
+        });
+      });
+
+      it('should not suggest columns for "SELECT cos(1, | FROM testTable"', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT cos(1, ',
+          afterCursor: ' FROM testTable',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false
+          }
+        });
+      });
+
+      it('should not suggest columns for "SELECT cos(1, | FROM testTable"', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT cos(1, ',
+          afterCursor: ' FROM testTable',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false
+          }
+        });
+      });
+
+      it('should suggest columns for "SELECT greatest(1, 2, a, 4, | FROM testTable"', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT greatest(1, 2, a, 4, ',
+          afterCursor: ' FROM testTable',
+          expectedResult: {
+            lowerCase: false,
+            suggestFunctions: { types: ['T'] },
+            suggestColumns: { types: ['T'], table: 'testTable' }
+          }
+        });
+      });
+
+      it('should suggest columns for "SELECT greatest(1, |, a, 4) FROM testTable"', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT greatest(1, ',
+          afterCursor: ', a, 4) FROM testTable',
+          expectedResult: {
+            lowerCase: false,
+            suggestFunctions: { types: ['T'] },
+            suggestColumns: { types: ['T'], table: 'testTable' }
+          }
+        });
+      });
+
+      it('should suggest columns for "SELECT log(a, |) FROM testTable"', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT log(a, ',
+          afterCursor: ') FROM testTable',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestFunctions: { types: ['DECIMAL', 'DOUBLE'] },
+            suggestColumns: { types: ['DECIMAL', 'DOUBLE'], table: 'testTable' }
+          }
+        });
+      });
+
+      it('should suggest columns for "SELECT log(a, |) FROM testTable"', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT log(a, ',
+          afterCursor: ') FROM testTable',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestFunctions: { types: ['DOUBLE'] },
+            suggestColumns: { types: ['DOUBLE'], table: 'testTable' }
+          }
+        });
+      });
+
+      it('should not suggest columns for "SELECT log(a, b, | FROM testTable"', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT log(a, b, ',
+          afterCursor: ' FROM testTable',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false
+          }
+        });
+      });
+
+      it('should not suggest columns for "SELECT log(a, b, | FROM testTable"', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT log(a, b, ',
+          afterCursor: ' FROM testTable',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false
+          }
+        });
+      });
+
+      it('should suggest typed columns for "SELECT substr(\'foo\', |) FROM testTable"', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT substr(\'foo\', ',
+          afterCursor: ') FROM testTable',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestFunctions: { types: [ 'INT' ] },
+            suggestColumns: { types: [ 'INT' ], table: 'testTable' }
+          }
+        });
+      });
+
+      it('should suggest typed columns for "SELECT substr(|, 1, 2) FROM testTable"', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT substr(',
+          afterCursor: ', 1, 2) FROM testTable',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestFunctions: { types: [ 'STRING' ] },
+            suggestColumns: { types: [ 'STRING' ], table: 'testTable' }
+          }
+        });
+      });
+
+      xit('should suggest typed columns for "SELECT substr(,,| FROM testTable"', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT substr(,,',
+          afterCursor: ' FROM testTable',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestFunctions: { types: [ 'INT' ] },
+            suggestColumns: { types: [ 'INT' ], table: 'testTable' }
+          }
+        });
+      });
+
+      it('should suggest columns for "SELECT cast(a AS BIGINT) = | FROM testTable"', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT cast(a AS BIGINT) = ',
+          afterCursor: ' FROM testTable',
+          dialect: 'hive',
+          expectedResult: {
+            lowerCase: false,
+            suggestFunctions: { types: [ 'BIGINT' ] },
+            suggestColumns: { types: [ 'BIGINT' ], table: 'testTable' }
+          }
+        });
+      });
+
+      it('should suggest typed columns for "SELECT cast(a AS BIGINT) = | FROM testTable"', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT cast(a AS BIGINT) = ',
+          afterCursor: ' FROM testTable',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestFunctions: { types: [ 'BIGINT' ] },
+            suggestColumns: { types: [ 'BIGINT' ], table: 'testTable' }
+          }
+        });
+      });
+
+      it('should suggest typed columns for "SELECT cast(a AS BIGINT) = | FROM testTable"', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT cast(a AS BIGINT) = ',
+          afterCursor: ' FROM testTable',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestFunctions: { types: [ 'BIGINT' ] },
+            suggestColumns: { types: [ 'BIGINT' ], table: 'testTable' }
+          }
+        });
+      });
+
+      it('should suggest typed columns for "SELECT years_add(a , 10) = | FROM testTable"', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT years_add(a , 10) = ',
+          afterCursor: ' FROM testTable',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestFunctions: { types: [ 'TIMESTAMP' ] },
+            suggestColumns: { types: [ 'TIMESTAMP' ], table: 'testTable' }
+          }
+        });
+      });
+
+      it('should suggest typed columns for "SELECT | > cast(years_add(a , 10) AS INT) FROM testTable"', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT ',
+          afterCursor: ' > cast(years_add(a , 10) AS INT) FROM testTable',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestFunctions: { types: [ 'INT' ] },
+            suggestColumns: { types: [ 'INT' ], table: 'testTable' }
+          }
+        });
+      });
+
+      it('should suggest typed columns for "SELECT partial.parital| > cast(years_add(a , 10) AS INT) FROM testTable"', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT partial.partial',
+          afterCursor: ' > cast(years_add(a , 10) AS INT) FROM testTable',
+          dialect: 'impala',
+          expectedResult: {
+            lowerCase: false,
+            suggestColumns: { identifierChain: [{ name: 'partial' }], types: [ 'INT' ], table: 'testTable' }
+          }
+        });
+      });
+
+      it('should suggest columns for "SELECT | > id FROM testTable"', function() {
+        assertAutoComplete({
+          beforeCursor: 'SELECT ',
+          afterCursor: ' > id FROM testTable',
+          expectedResult: {
+            lowerCase: false,
+            suggestFunctions: { types: ['T'] },
+            suggestColumns: { types: ['T'], table: 'testTable' },
+            suggestValues: { identifierChain: [{ name: 'id' }], table: 'testTable' }
           }
         });
       });
@@ -2446,12 +2824,12 @@ define([
           afterCursor: ' = id',
           expectedResult: {
             lowerCase: false,
-            suggestFunctions: {},
+            suggestFunctions: { types: ['T'] },
             suggestValues: {
               table: 'testTable',
               identifierChain: [{ name: 'id' }]
             },
-            suggestColumns: { table: 'testTable' }
+            suggestColumns: { types: ['T'], table: 'testTable' }
           }
         });
       });
@@ -2462,12 +2840,12 @@ define([
           afterCursor: '',
           expectedResult: {
             lowerCase: false,
-            suggestFunctions: {},
+            suggestFunctions: { types: ['T'] },
             suggestValues: {
               table: 'testTable',
               identifierChain: [{ name: 'd' }]
             },
-            suggestColumns: { table: 'testTable' }
+            suggestColumns: { types: ['T'], table: 'testTable' }
           }
         });
       });
@@ -2478,12 +2856,12 @@ define([
           afterCursor: '',
           expectedResult: {
             lowerCase: false,
-            suggestFunctions: {},
+            suggestFunctions: { types: ['T'] },
             suggestValues: {
               table: 'testTable',
               identifierChain: [{ name: 'd' }]
             },
-            suggestColumns: { table: 'testTable' }
+            suggestColumns: { types: ['T'], table: 'testTable' }
           }
         });
       });
@@ -2494,12 +2872,12 @@ define([
           afterCursor: '',
           expectedResult: {
             lowerCase: false,
-            suggestFunctions: {},
+            suggestFunctions: { types: ['T'] },
             suggestValues: {
               table: 'testTable',
               identifierChain: [{ name: 'd' }]
             },
-            suggestColumns: { table: 'testTable' }
+            suggestColumns: { types: ['T'], table: 'testTable' }
           }
         });
       });
@@ -2510,12 +2888,12 @@ define([
           afterCursor: '',
           expectedResult: {
             lowerCase: false,
-            suggestFunctions: {},
+            suggestFunctions: { types: ['T'] },
             suggestValues: {
               table: 'testTable',
               identifierChain: [{ name: 'd' }]
             },
-            suggestColumns: { table: 'testTable' }
+            suggestColumns: { types: ['T'], table: 'testTable' }
           }
         });
       });
@@ -2526,12 +2904,12 @@ define([
           afterCursor: '',
           expectedResult: {
             lowerCase: false,
-            suggestFunctions: {},
+            suggestFunctions: { types: ['T'] },
             suggestValues: {
               table: 'testTable',
               identifierChain: [{ name: 'd' }]
             },
-            suggestColumns: { table: 'testTable' }
+            suggestColumns: { types: ['T'], table: 'testTable' }
           }
         });
       });
@@ -2542,12 +2920,12 @@ define([
           afterCursor: '',
           expectedResult: {
             lowerCase: false,
-            suggestFunctions: {},
+            suggestFunctions: { types: ['T']},
             suggestValues: {
               table: 'testTable',
               identifierChain: [{ name: 'd' }]
             },
-            suggestColumns: { table: 'testTable' }
+            suggestColumns: { types: ['T'], table: 'testTable' }
           }
         });
       });
@@ -2558,12 +2936,12 @@ define([
           afterCursor: '',
           expectedResult: {
             lowerCase: false,
-            suggestFunctions: {},
+            suggestFunctions: { types: ['T'] },
             suggestValues: {
               table: 'testTable',
               identifierChain: [{ name: 'd' }]
             },
-            suggestColumns: { table: 'testTable' }
+            suggestColumns: { types: ['T'], table: 'testTable' }
           }
         });
       });
@@ -2574,12 +2952,12 @@ define([
           afterCursor: '',
           expectedResult: {
             lowerCase: false,
-            suggestFunctions: {},
+            suggestFunctions: { types: ['T'] },
             suggestValues: {
               table: 'testTable',
               identifierChain: [{ name: 'd' }]
             },
-            suggestColumns: { table: 'testTable' }
+            suggestColumns: { types: ['T'], table: 'testTable' }
           }
         });
       });
@@ -2989,8 +3367,8 @@ define([
           afterCursor: ' = \'bar\' AND ',
           expectedResult: {
             lowerCase: false,
-            suggestFunctions: {},
-            suggestColumns: { table: 'testTable' }
+            suggestFunctions: { types: ['STRING'] },
+            suggestColumns: { types: ['STRING'], table: 'testTable' }
           }
         });
       });

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

@@ -178,13 +178,13 @@ define([
         afterCursor: '',
         expectedResult: {
           lowerCase: false,
-          suggestFunctions: {},
+          suggestFunctions: { types: ['T'] },
           suggestValues: {
             database: 'bar',
             table: 'foo',
             identifierChain: [{ name: 'id' }]
           },
-          suggestColumns : { database: 'bar', table: 'foo' }
+          suggestColumns : { types: ['T'] , database: 'bar', table: 'foo' }
         }
       });
     });

+ 8 - 8
desktop/core/src/desktop/static/desktop/spec/autocompleterTestUtils.js

@@ -14,8 +14,9 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 define([
-  'desktop/js/autocomplete/sql'
-], function(sql) {
+  'desktop/js/autocomplete/sql',
+  'desktop/js/sqlFunctions'
+], function(sql, sqlFunctions) {
   return {
     autocompleteMatcher : {
       toEqualAutocompleteValues : function() {
@@ -100,14 +101,13 @@ define([
       }
     },
     assertAutocomplete: function(testDefinition) {
+      var debug = false;
       if (typeof testDefinition.dialect === 'undefined') {
-        expect(sql.parseSql(testDefinition.beforeCursor, testDefinition.afterCursor, testDefinition.dialect)).toEqualDefinition(testDefinition);
-        testDefinition.dialect = 'hive';
-        expect(sql.parseSql(testDefinition.beforeCursor, testDefinition.afterCursor, testDefinition.dialect)).toEqualDefinition(testDefinition);
-        testDefinition.dialect = 'impala';
-        expect(sql.parseSql(testDefinition.beforeCursor, testDefinition.afterCursor, 'impala')).toEqualDefinition(testDefinition);
+        expect(sql.parseSql(testDefinition.beforeCursor, testDefinition.afterCursor, testDefinition.dialect, sqlFunctions, debug)).toEqualDefinition(testDefinition);
+        expect(sql.parseSql(testDefinition.beforeCursor, testDefinition.afterCursor, 'hive', sqlFunctions, debug)).toEqualDefinition(testDefinition);
+        expect(sql.parseSql(testDefinition.beforeCursor, testDefinition.afterCursor, 'impala', sqlFunctions, debug)).toEqualDefinition(testDefinition);
       } else {
-        expect(sql.parseSql(testDefinition.beforeCursor, testDefinition.afterCursor, testDefinition.dialect)).toEqualDefinition(testDefinition);
+        expect(sql.parseSql(testDefinition.beforeCursor, testDefinition.afterCursor, testDefinition.dialect, sqlFunctions, debug)).toEqualDefinition(testDefinition);
       }
     }
   }

+ 52 - 1
desktop/core/src/desktop/static/desktop/spec/sqlFunctionsSpec.js

@@ -114,6 +114,57 @@ define([
       expect(sqlFunctions.matchesType('hive', ['T'], ['BIGINT'])).toBeTruthy();
       expect(sqlFunctions.matchesType('hive', ['BOOLEAN'], ['BIGINT'])).toBeFalsy();
       expect(sqlFunctions.matchesType('hive', ['STRING'], ['BIGINT'])).toBeTruthy();
-    })
+    });
+
+    it('should give the expected argument types at a specific position', function () {
+      expect(sqlFunctions.getArgumentTypes('hive', 'cos', 1)).toEqual([{ type:'DECIMAL' }, { type:'DOUBLE' }]);
+      expect(sqlFunctions.getArgumentTypes('hive', 'cos', 2)).toEqual([]);
+      expect(sqlFunctions.getArgumentTypes('impala', 'cos', 1)).toEqual([{ type:'DOUBLE' }]);
+      expect(sqlFunctions.getArgumentTypes('impala', 'cos', 2)).toEqual([]);
+
+      expect(sqlFunctions.getArgumentTypes('hive', 'greatest', 1)).toEqual([{ type:'T', multiple: true }]);
+      expect(sqlFunctions.getArgumentTypes('hive', 'greatest', 200)).toEqual([{ type:'T', multiple: true }]);
+      expect(sqlFunctions.getArgumentTypes('impala', 'greatest', 1)).toEqual([{ type:'T', multiple: true }]);
+      expect(sqlFunctions.getArgumentTypes('impala', 'greatest', 200)).toEqual([{ type:'T', multiple: true }]);
+
+      expect(sqlFunctions.getArgumentTypes('hive', 'strleft', 1)).toEqual([{ type:'T' }]);
+      expect(sqlFunctions.getArgumentTypes('hive', 'strleft', 2)).toEqual([{ type:'T' }]);
+      expect(sqlFunctions.getArgumentTypes('hive', 'strleft', 3)).toEqual([{ type:'T' }]);
+      expect(sqlFunctions.getArgumentTypes('hive', 'strleft', 200)).toEqual([{ type:'T' }]);
+      expect(sqlFunctions.getArgumentTypes('impala', 'strleft', 1)).toEqual([{ type:'STRING' }]);
+      expect(sqlFunctions.getArgumentTypes('impala', 'strleft', 2)).toEqual([{ type:'INT' }]);
+      expect(sqlFunctions.getArgumentTypes('impala', 'strleft', 3)).toEqual([]);
+      expect(sqlFunctions.getArgumentTypes('impala', 'strleft', 200)).toEqual([]);
+
+      expect(sqlFunctions.getArgumentTypes('hive', 'substring_index', 1)).toEqual([{ type:'STRING' }]);
+      expect(sqlFunctions.getArgumentTypes('hive', 'substring_index', 2)).toEqual([{ type:'STRING' }]);
+      expect(sqlFunctions.getArgumentTypes('hive', 'substring_index', 3)).toEqual([{ type:'INT' }]);
+      expect(sqlFunctions.getArgumentTypes('hive', 'substring_index', 200)).toEqual([]);
+      expect(sqlFunctions.getArgumentTypes('impala', 'substring_index', 1)).toEqual([{ type:'T' }]);
+      expect(sqlFunctions.getArgumentTypes('impala', 'substring_index', 2)).toEqual([{ type:'T' }]);
+      expect(sqlFunctions.getArgumentTypes('impala', 'substring_index', 3)).toEqual([{ type:'T' }]);
+      expect(sqlFunctions.getArgumentTypes('impala', 'substring_index', 200)).toEqual([{ type:'T' }]);
+
+      expect(sqlFunctions.getArgumentTypes('hive', 'weeks_add', 1)).toEqual([{ type:'T' }]);
+      expect(sqlFunctions.getArgumentTypes('hive', 'weeks_add', 2)).toEqual([{ type:'T' }]);
+      expect(sqlFunctions.getArgumentTypes('hive', 'weeks_add', 3)).toEqual([{ type:'T' }]);
+      expect(sqlFunctions.getArgumentTypes('hive', 'weeks_add', 200)).toEqual([{ type:'T' }]);
+      expect(sqlFunctions.getArgumentTypes('impala', 'weeks_add', 1)).toEqual([{ type:'TIMESTAMP' }]);
+      expect(sqlFunctions.getArgumentTypes('impala', 'weeks_add', 2)).toEqual([{ type:'BIGINT'}, { type:'INT' }]);
+      expect(sqlFunctions.getArgumentTypes('impala', 'weeks_add', 3)).toEqual([]);
+      expect(sqlFunctions.getArgumentTypes('impala', 'weeks_add', 200)).toEqual([]);
+
+      expect(sqlFunctions.getArgumentTypes('hive', 'reflect', 1)).toEqual([{ type:'STRING' }]);
+      expect(sqlFunctions.getArgumentTypes('hive', 'reflect', 2)).toEqual([{ type:'STRING' }]);
+      expect(sqlFunctions.getArgumentTypes('hive', 'reflect', 3)).toEqual([{ type:'T', multiple: true, optional: true }]);
+      expect(sqlFunctions.getArgumentTypes('hive', 'reflect', 200)).toEqual([{ type:'T', multiple: true, optional: true }]);
+      expect(sqlFunctions.getArgumentTypes('impala', 'reflect', 1)).toEqual([{ type:'T' }]);
+      expect(sqlFunctions.getArgumentTypes('impala', 'reflect', 200)).toEqual([{ type:'T' }]);
+
+      expect(sqlFunctions.getArgumentTypes('hive', 'blabla', 2)).toEqual([{ type:'T' }]);
+      expect(sqlFunctions.getArgumentTypes('hive', 'blabla', 200)).toEqual([{ type:'T' }]);
+      expect(sqlFunctions.getArgumentTypes('impala', 'blabla', 2)).toEqual([{ type:'T' }]);
+      expect(sqlFunctions.getArgumentTypes('impala', 'blabla', 200)).toEqual([{ type:'T' }]);
+    });
   });
 });

Unele fișiere nu au fost afișate deoarece prea multe fișiere au fost modificate în acest diff