This is an automated email from the ASF dual-hosted git repository.

jackietien pushed a commit to branch ty/TableModelGrammar
in repository https://gitbox.apache.org/repos/asf/iotdb.git

commit ae8e5fa6bbfd6dfbe32c7e0532fb6e4deaea6d04
Author: JackieTien97 <[email protected]>
AuthorDate: Tue Apr 9 18:19:06 2024 +0800

    add returnType impl
---
 .../plan/relational/analyzer/AnalyzerTest.java     |  49 ++---
 .../plan/relational/analyzer/TestMatadata.java     | 206 ++++++++++++++++++++-
 2 files changed, 227 insertions(+), 28 deletions(-)

diff --git 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/AnalyzerTest.java
 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/AnalyzerTest.java
index d2018ff4256..95436deea9e 100644
--- 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/AnalyzerTest.java
+++ 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/AnalyzerTest.java
@@ -22,16 +22,12 @@ package 
org.apache.iotdb.db.queryengine.plan.relational.analyzer;
 import org.apache.iotdb.db.queryengine.common.MPPQueryContext;
 import org.apache.iotdb.db.queryengine.common.QueryId;
 import org.apache.iotdb.db.queryengine.common.SessionInfo;
-import org.apache.iotdb.db.queryengine.plan.relational.function.BoundSignature;
-import org.apache.iotdb.db.queryengine.plan.relational.function.FunctionId;
-import org.apache.iotdb.db.queryengine.plan.relational.function.FunctionKind;
 import org.apache.iotdb.db.queryengine.plan.relational.function.OperatorType;
 import org.apache.iotdb.db.queryengine.plan.relational.metadata.ColumnHandle;
 import org.apache.iotdb.db.queryengine.plan.relational.metadata.ColumnSchema;
 import org.apache.iotdb.db.queryengine.plan.relational.metadata.Metadata;
 import 
org.apache.iotdb.db.queryengine.plan.relational.metadata.OperatorNotFoundException;
 import 
org.apache.iotdb.db.queryengine.plan.relational.metadata.QualifiedObjectName;
-import 
org.apache.iotdb.db.queryengine.plan.relational.metadata.ResolvedFunction;
 import org.apache.iotdb.db.queryengine.plan.relational.metadata.TableHandle;
 import org.apache.iotdb.db.queryengine.plan.relational.metadata.TableSchema;
 import org.apache.iotdb.db.queryengine.plan.relational.security.AccessControl;
@@ -51,6 +47,7 @@ import java.util.Optional;
 
 import static 
org.apache.iotdb.db.queryengine.execution.warnings.WarningCollector.NOOP;
 import static org.apache.iotdb.tsfile.read.common.type.BooleanType.BOOLEAN;
+import static org.apache.iotdb.tsfile.read.common.type.DoubleType.DOUBLE;
 import static org.apache.iotdb.tsfile.read.common.type.IntType.INT32;
 import static org.apache.iotdb.tsfile.read.common.type.LongType.INT64;
 import static org.junit.Assert.assertNotNull;
@@ -96,25 +93,35 @@ public class AnalyzerTest {
     Mockito.when(metadata.getTableSchema(Mockito.any(), 
eq(tableHandle))).thenReturn(tableSchema);
     Mockito.when(metadata.getColumnHandles(Mockito.any(), 
eq(tableHandle))).thenReturn(map);
 
-    ResolvedFunction lLessThanI =
-        new ResolvedFunction(
-            new BoundSignature("l<i", BOOLEAN, Arrays.asList(INT64, INT32)),
-            new FunctionId("l<i"),
-            FunctionKind.SCALAR,
-            true);
-
-    ResolvedFunction iAddi =
-        new ResolvedFunction(
-            new BoundSignature("l+i", INT64, Arrays.asList(INT32, INT32)),
-            new FunctionId("l+i"),
-            FunctionKind.SCALAR,
-            true);
+    //    ResolvedFunction lLessThanI =
+    //        new ResolvedFunction(
+    //            new BoundSignature("l<i", BOOLEAN, Arrays.asList(INT64, 
INT32)),
+    //            new FunctionId("l<i"),
+    //            FunctionKind.SCALAR,
+    //            true);
+    //
+    //    ResolvedFunction iAddi =
+    //        new ResolvedFunction(
+    //            new BoundSignature("l+i", INT64, Arrays.asList(INT32, 
INT32)),
+    //            new FunctionId("l+i"),
+    //            FunctionKind.SCALAR,
+    //            true);
+    //
+    //    Mockito.when(
+    //            metadata.resolveOperator(eq(OperatorType.LESS_THAN), 
eq(Arrays.asList(INT64,
+    // INT32))))
+    //        .thenReturn(lLessThanI);
+    //    Mockito.when(metadata.resolveOperator(eq(OperatorType.ADD), 
eq(Arrays.asList(INT32,
+    // INT32))))
+    //        .thenReturn(iAddi);
 
     Mockito.when(
-            metadata.resolveOperator(eq(OperatorType.LESS_THAN), 
eq(Arrays.asList(INT64, INT32))))
-        .thenReturn(lLessThanI);
-    Mockito.when(metadata.resolveOperator(eq(OperatorType.ADD), 
eq(Arrays.asList(INT32, INT32))))
-        .thenReturn(iAddi);
+            metadata.getOperatorReturnType(
+                eq(OperatorType.LESS_THAN), eq(Arrays.asList(INT64, INT32))))
+        .thenReturn(BOOLEAN);
+    Mockito.when(
+            metadata.getOperatorReturnType(eq(OperatorType.ADD), 
eq(Arrays.asList(INT32, INT32))))
+        .thenReturn(DOUBLE);
 
     Analysis actualAnalysis = analyzeSQL(sql, metadata);
     assertNotNull(actualAnalysis);
diff --git 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/TestMatadata.java
 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/TestMatadata.java
index 486f18c761b..993ed00ebda 100644
--- 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/TestMatadata.java
+++ 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/TestMatadata.java
@@ -1,5 +1,8 @@
 package org.apache.iotdb.db.queryengine.plan.relational.analyzer;
 
+import org.apache.iotdb.commons.udf.builtin.BuiltinAggregationFunction;
+import org.apache.iotdb.commons.udf.builtin.BuiltinScalarFunction;
+import org.apache.iotdb.db.exception.sql.SemanticException;
 import org.apache.iotdb.db.queryengine.common.SessionInfo;
 import org.apache.iotdb.db.queryengine.plan.relational.function.OperatorType;
 import org.apache.iotdb.db.queryengine.plan.relational.metadata.ColumnHandle;
@@ -13,8 +16,11 @@ import 
org.apache.iotdb.db.queryengine.plan.relational.metadata.TableHandle;
 import org.apache.iotdb.db.queryengine.plan.relational.metadata.TableMetadata;
 import org.apache.iotdb.db.queryengine.plan.relational.metadata.TableSchema;
 import org.apache.iotdb.db.queryengine.plan.relational.security.AccessControl;
+import 
org.apache.iotdb.db.queryengine.plan.relational.type.InternalTypeManager;
+import org.apache.iotdb.db.queryengine.plan.relational.type.TypeManager;
 import 
org.apache.iotdb.db.queryengine.plan.relational.type.TypeNotFoundException;
 import org.apache.iotdb.db.queryengine.plan.relational.type.TypeSignature;
+import org.apache.iotdb.db.utils.constant.SqlConstant;
 import org.apache.iotdb.tsfile.read.common.type.BinaryType;
 import org.apache.iotdb.tsfile.read.common.type.DoubleType;
 import org.apache.iotdb.tsfile.read.common.type.Type;
@@ -24,15 +30,22 @@ import org.mockito.Mockito;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Optional;
 
+import static org.apache.iotdb.tsfile.read.common.type.BinaryType.TEXT;
+import static org.apache.iotdb.tsfile.read.common.type.BooleanType.BOOLEAN;
+import static org.apache.iotdb.tsfile.read.common.type.DoubleType.DOUBLE;
+import static org.apache.iotdb.tsfile.read.common.type.FloatType.FLOAT;
 import static org.apache.iotdb.tsfile.read.common.type.IntType.INT32;
 import static org.apache.iotdb.tsfile.read.common.type.LongType.INT64;
 
 public class TestMatadata implements Metadata {
 
-  public static final String DB1 = "db1";
+  private final TypeManager typeManager = new InternalTypeManager();
+
+  public static final String DB1 = "testdb";
   public static final String TABLE1 = "table1";
   public static final String TIME = "time";
   private static final String TAG1 = "tag1";
@@ -85,7 +98,7 @@ public class TestMatadata implements Metadata {
 
   @Override
   public Optional<TableHandle> getTableHandle(SessionInfo session, 
QualifiedObjectName name) {
-    return Optional.empty();
+    return Optional.of(new TableHandle());
   }
 
   @Override
@@ -113,27 +126,206 @@ public class TestMatadata implements Metadata {
   @Override
   public Type getOperatorReturnType(OperatorType operatorType, List<? extends 
Type> argumentTypes)
       throws OperatorNotFoundException {
-    return null;
+
+    switch (operatorType) {
+      case ADD:
+      case SUBTRACT:
+      case MULTIPLY:
+      case DIVIDE:
+      case MODULUS:
+        if (!isTwoNumericType(argumentTypes)) {
+          throw new OperatorNotFoundException(
+              operatorType,
+              argumentTypes,
+              new IllegalArgumentException("Should have two numeric 
operands."));
+        }
+        return DOUBLE;
+      case NEGATION:
+        if (!isOneNumericType(argumentTypes)) {
+          throw new OperatorNotFoundException(
+              operatorType,
+              argumentTypes,
+              new IllegalArgumentException("Should have one numeric 
operands."));
+        }
+        return DOUBLE;
+      case EQUAL:
+      case LESS_THAN:
+      case LESS_THAN_OR_EQUAL:
+        if (!isTwoTypeComparable(argumentTypes)) {
+          throw new OperatorNotFoundException(
+              operatorType,
+              argumentTypes,
+              new IllegalArgumentException("Should have two comparable 
operands."));
+        }
+        return BOOLEAN;
+      default:
+        throw new OperatorNotFoundException(
+            operatorType, argumentTypes, new UnsupportedOperationException());
+    }
   }
 
   @Override
   public Type getFunctionReturnType(String functionName, List<? extends Type> 
argumentTypes) {
-    return null;
+
+    // builtin scalar function
+    if 
(BuiltinScalarFunction.DIFF.getFunctionName().equalsIgnoreCase(functionName)
+        || 
BuiltinScalarFunction.ROUND.getFunctionName().equalsIgnoreCase(functionName)) {
+      if (!isOneNumericType(argumentTypes)) {
+        throw new SemanticException(
+            "Scalar function"
+                + functionName.toLowerCase(Locale.ENGLISH)
+                + " only supports numeric data types [INT32, INT64, FLOAT, 
DOUBLE]");
+      }
+      return DOUBLE;
+    } else if 
(BuiltinScalarFunction.REPLACE.getFunctionName().equalsIgnoreCase(functionName)
+        || 
BuiltinScalarFunction.SUBSTRING.getFunctionName().equalsIgnoreCase(functionName))
 {
+      if (!isOneTextType(argumentTypes)) {
+        throw new SemanticException(
+            "Scalar function"
+                + functionName.toLowerCase(Locale.ENGLISH)
+                + " only supports text data type.");
+      }
+      return TEXT;
+    }
+
+    // builtin aggregation function
+    // check argument type
+    switch (functionName.toLowerCase()) {
+      case SqlConstant.AVG:
+      case SqlConstant.SUM:
+      case SqlConstant.EXTREME:
+      case SqlConstant.MIN_VALUE:
+      case SqlConstant.MAX_VALUE:
+      case SqlConstant.STDDEV:
+      case SqlConstant.STDDEV_POP:
+      case SqlConstant.STDDEV_SAMP:
+      case SqlConstant.VARIANCE:
+      case SqlConstant.VAR_POP:
+      case SqlConstant.VAR_SAMP:
+        if (!isOneNumericType(argumentTypes)) {
+          throw new SemanticException(
+              String.format(
+                  "Aggregate functions [%s] only support numeric data types 
[INT32, INT64, FLOAT, DOUBLE]",
+                  functionName));
+        }
+        break;
+      case SqlConstant.MIN_TIME:
+      case SqlConstant.MAX_TIME:
+      case SqlConstant.FIRST_VALUE:
+      case SqlConstant.LAST_VALUE:
+      case SqlConstant.TIME_DURATION:
+      case SqlConstant.MODE:
+        if (argumentTypes.size() != 1) {
+          throw new SemanticException(
+              String.format(
+                  "Aggregate functions [%s] should only have one argument", 
functionName));
+        }
+        break;
+      case SqlConstant.MAX_BY:
+      case SqlConstant.MIN_BY:
+        if (argumentTypes.size() != 2) {
+          throw new SemanticException(
+              String.format(
+                  "Aggregate functions [%s] should only have two arguments", 
functionName));
+        } else if (!argumentTypes.get(1).isOrderable()) {
+          throw new SemanticException(
+              String.format(
+                  "Second argument of Aggregate functions [%s] should be 
orderable", functionName));
+        }
+
+        break;
+      case SqlConstant.COUNT:
+        break;
+      default:
+        // ignore
+    }
+
+    // get return type
+    switch (functionName.toLowerCase()) {
+      case SqlConstant.MIN_TIME:
+      case SqlConstant.MAX_TIME:
+      case SqlConstant.COUNT:
+      case SqlConstant.TIME_DURATION:
+        return INT64;
+      case SqlConstant.MIN_VALUE:
+      case SqlConstant.LAST_VALUE:
+      case SqlConstant.FIRST_VALUE:
+      case SqlConstant.MAX_VALUE:
+      case SqlConstant.EXTREME:
+      case SqlConstant.MODE:
+      case SqlConstant.MAX_BY:
+      case SqlConstant.MIN_BY:
+        return argumentTypes.get(0);
+      case SqlConstant.AVG:
+      case SqlConstant.SUM:
+      case SqlConstant.STDDEV:
+      case SqlConstant.STDDEV_POP:
+      case SqlConstant.STDDEV_SAMP:
+      case SqlConstant.VARIANCE:
+      case SqlConstant.VAR_POP:
+      case SqlConstant.VAR_SAMP:
+        return DOUBLE;
+      default:
+        // ignore
+    }
+
+    // TODO scalar UDF function
+
+    // TODO UDAF
+
+    throw new SemanticException("Unknown function: " + functionName);
   }
 
   @Override
   public boolean isAggregationFunction(
       SessionInfo session, String functionName, AccessControl accessControl) {
-    return false;
+    return BuiltinAggregationFunction.getNativeFunctionNames()
+        .contains(functionName.toLowerCase(Locale.ENGLISH));
   }
 
   @Override
   public Type getType(TypeSignature signature) throws TypeNotFoundException {
-    return null;
+    return typeManager.getType(signature);
   }
 
   @Override
   public boolean canCoerce(Type from, Type to) {
-    return false;
+    return true;
+  }
+
+  public static boolean isTwoNumericType(List<? extends Type> argumentTypes) {
+    return argumentTypes.size() == 2
+        && isNumericType(argumentTypes.get(0))
+        && isNumericType(argumentTypes.get(1));
+  }
+
+  public static boolean isOneNumericType(List<? extends Type> argumentTypes) {
+    return argumentTypes.size() == 1 && isNumericType(argumentTypes.get(0));
+  }
+
+  public static boolean isOneBooleanType(List<? extends Type> argumentTypes) {
+    return argumentTypes.size() == 1 && BOOLEAN.equals(argumentTypes.get(0));
+  }
+
+  public static boolean isOneTextType(List<? extends Type> argumentTypes) {
+    return argumentTypes.size() == 1 && TEXT.equals(argumentTypes.get(0));
+  }
+
+  public static boolean isNumericType(Type type) {
+    return DOUBLE.equals(type) || FLOAT.equals(type) || INT32.equals(type) || 
INT64.equals(type);
+  }
+
+  public static boolean isTwoTypeComparable(List<? extends Type> 
argumentTypes) {
+    if (argumentTypes.size() != 2) {
+      return false;
+    }
+    Type left = argumentTypes.get(0);
+    Type right = argumentTypes.get(1);
+    if (left.equals(right)) {
+      return true;
+    }
+
+    // Boolean type and Binary Type can not be compared with other types
+    return isNumericType(left) && isNumericType(right);
   }
 }

Reply via email to