Skip to content

Commit

Permalink
feat: 添加Greatest 和 Least 的 IT,并支持 Boolean 类型
Browse files Browse the repository at this point in the history
  • Loading branch information
FearfulTomcat27 committed Jan 22, 2025
1 parent e695ff7 commit d20f00c
Show file tree
Hide file tree
Showing 6 changed files with 253 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,12 @@ public class IoTDBFormatFunctionTableIT {
// normal cases
"CREATE DATABASE " + DATABASE_NAME,
"USE " + DATABASE_NAME,
"CREATE TABLE number_table(device_id STRING ID, s1 INT32 MEASUREMENT, s2 INT64 MEASUREMENT, s3 FLOAT MEASUREMENT, s4 DOUBLE MEASUREMENT)",
"CREATE TABLE string_table(device_id STRING ID, s1 STRING MEASUREMENT, s2 TEXT MEASUREMENT)",
"CREATE TABLE boolean_table(device_id STRING ID, s1 BOOLEAN MEASUREMENT)",
"CREATE TABLE timestamp_table(device_id STRING ID, s1 TIMESTAMP MEASUREMENT)",
"CREATE TABLE date_table(device_id STRING ID, s1 DATE MEASUREMENT)",
"CREATE TABLE null_table(device_id STRING ID, s1 INT32 MEASUREMENT)",
"CREATE TABLE number_table(device_id STRING TAG, s1 INT32 FIELD, s2 INT64 FIELD, s3 FLOAT FIELD, s4 DOUBLE FIELD)",
"CREATE TABLE string_table(device_id STRING TAG, s1 STRING FIELD, s2 TEXT FIELD)",
"CREATE TABLE boolean_table(device_id STRING TAG, s1 BOOLEAN FIELD)",
"CREATE TABLE timestamp_table(device_id STRING TAG, s1 TIMESTAMP FIELD)",
"CREATE TABLE date_table(device_id STRING TAG, s1 DATE FIELD)",
"CREATE TABLE null_table(device_id STRING TAG, s1 INT32 FIELD)",
// data for number series
"INSERT INTO number_table(time, device_id, s1, s2, s3, s4) VALUES (10, 'd1', 1000000, 1000000, 3.1415926, 3.1415926)",
"INSERT INTO number_table(time, device_id, s1, s2, s3, s4) VALUES (20, 'd1', 1, 1, 1234567.25, 1234567.25)",
Expand Down Expand Up @@ -205,9 +205,5 @@ public void testAnomalies() {
"SELECT FORMAT('%s') FROM string_table",
"701: Scalar function format must have at least two arguments, and first argument must be char type.",
DATABASE_NAME);

tableAssertTestFail(
"SELECT FORMAT('%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS.%1$tL',s1) FROM date_table",
"701:", DATABASE_NAME);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.iotdb.relational.it.query.old.query;

import org.apache.iotdb.it.env.EnvFactory;
import org.apache.iotdb.it.framework.IoTDBTestRunner;
import org.apache.iotdb.itbase.category.TableClusterIT;
import org.apache.iotdb.itbase.category.TableLocalStandaloneIT;
import org.apache.iotdb.itbase.env.BaseEnv;

import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith;

import java.sql.Connection;
import java.sql.Statement;

import static org.apache.iotdb.db.it.utils.TestUtils.tableAssertTestFail;
import static org.apache.iotdb.db.it.utils.TestUtils.tableResultSetEqualTest;

@RunWith(IoTDBTestRunner.class)
@Category({TableLocalStandaloneIT.class, TableClusterIT.class})
public class IoTDBGreatestLeastTableIT {

private static final String DATABASE_NAME = "db";

private static final String[] SQLs =
new String[] {
"CREATE DATABASE " + DATABASE_NAME,
"USE " + DATABASE_NAME,
"CREATE TABLE boolean_table(device_id STRING TAG, bool1 BOOLEAN FIELD, bool2 BOOLEAN FIELD)",
"CREATE TABLE number_table(device_id STRING TAG, int1 INT32 FIELD, int2 INT32 FIELD, long1 INT64 FIELD, long2 INT64 FIELD, float1 FLOAT FIELD, float2 FLOAT FIELD, double1 DOUBLE FIELD, double2 DOUBLE FIELD)",
"CREATE TABLE string_table(device_id STRING TAG, string1 STRING FIELD, string2 STRING FIELD, text1 TEXT FIELD, text2 TEXT FIELD)",
"CREATE TABLE mix_type_table(device_id STRING TAG, s1 INT32 FIELD, s2 INT64 FIELD, s3 FLOAT FIELD, s4 DOUBLE FIELD, s5 BOOLEAN FIELD, s6 STRING FIELD, s7 TEXT FIELD)",
"CREATE TABLE null_table(device_id STRING TAG, s1 INT32 FIELD, s2 INT32 FIELD)",
"CREATE TABLE any_null_table(device_id STRING TAG, s1 INT32 FIELD, s2 INT32 FIELD)",
// normal case
"INSERT INTO number_table(time, device_id, int1, int2, long1, long2, float1, float2, double1, double2) VALUES (10, 'd1', 1000000, 2000000, 1000000, 2000000, 10.1, 20.2, 10.1, 20.2)",
"INSERT INTO string_table(time, device_id, string1, string2, text1, text2) VALUES(10, 'd1', 'aaa', 'bbb', 'aaa', 'bbb')",
"INSERT INTO boolean_table(time, device_id, bool1, bool2) VALUES(10, 'd1', true, false)",
"INSERT INTO mix_type_table(time, device_id, s1, s2, s3, s4, s5, s6, s7) VALUES(10, 'd1', 1, 1, 1.0, 1.0, true, 'a', 'a')",
"INSERT INTO null_table(time, device_id) VALUES(10, 'd1')",
"INSERT INTO any_null_table(time, device_id, s1) VALUES(10, 'd1', 1)"
};

@BeforeClass
public static void setUp() throws Exception {
EnvFactory.getEnv().initClusterEnvironment();
insertData();
}

protected static void insertData() {
try (Connection connection = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
Statement statement = connection.createStatement()) {

for (String sql : SQLs) {
statement.execute(sql);
}
} catch (Exception e) {
e.printStackTrace();
}
}

@AfterClass
public static void tearDown() throws Exception {
EnvFactory.getEnv().cleanClusterEnvironment();
}

@Test
public void testNumberTypeGreatestFunction() {

tableResultSetEqualTest(
"SELECT GREATEST(int1, int2) FROM number_table",
new String[] {"_col0"},
new String[] {"2000000,"},
DATABASE_NAME);

tableResultSetEqualTest(
"SELECT GREATEST(long1, long2) FROM number_table",
new String[] {"_col0"},
new String[] {"2000000,"},
DATABASE_NAME);

tableResultSetEqualTest(
"SELECT GREATEST(float1, float2) FROM number_table",
new String[] {"_col0"},
new String[] {"20.2,"},
DATABASE_NAME);

tableResultSetEqualTest(
"SELECT GREATEST(double1, double2) FROM number_table",
new String[] {"_col0"},
new String[] {"20.2,"},
DATABASE_NAME);
}

@Test
public void testNumberTypeLeastFunction() {
tableResultSetEqualTest(
"SELECT LEAST(int1, int2) FROM number_table",
new String[] {"_col0"},
new String[] {"1000000,"},
DATABASE_NAME);

tableResultSetEqualTest(
"SELECT LEAST(long1, long2) FROM number_table",
new String[] {"_col0"},
new String[] {"1000000,"},
DATABASE_NAME);

tableResultSetEqualTest(
"SELECT LEAST(float1, float2) FROM number_table",
new String[] {"_col0"},
new String[] {"10.1,"},
DATABASE_NAME);

tableResultSetEqualTest(
"SELECT LEAST(double1, double2) FROM number_table",
new String[] {"_col0"},
new String[] {"10.1,"},
DATABASE_NAME);
}

@Test
public void testStringTypeGreatestFunction() {
tableResultSetEqualTest(
"SELECT GREATEST(string1, string2) FROM string_table",
new String[] {"_col0"},
new String[] {"bbb,"},
DATABASE_NAME);

tableResultSetEqualTest(
"SELECT GREATEST(text1, text2) FROM string_table",
new String[] {"_col0"},
new String[] {"bbb,"},
DATABASE_NAME);
}

@Test
public void testStringTypeLeastFunction() {
tableResultSetEqualTest(
"SELECT LEAST(string1, string2) FROM string_table",
new String[] {"_col0"},
new String[] {"aaa,"},
DATABASE_NAME);

tableResultSetEqualTest(
"SELECT LEAST(text1, text2) FROM string_table",
new String[] {"_col0"},
new String[] {"aaa,"},
DATABASE_NAME);
}

@Test
public void testBooleanTypeGreatestFunction() {
tableResultSetEqualTest(
"SELECT GREATEST(bool1, bool2) FROM boolean_table",
new String[] {"_col0"},
new String[] {"true,"},
DATABASE_NAME);
}

@Test
public void testBooleanTypeLeastFunction() {
tableResultSetEqualTest(
"SELECT LEAST(bool1, bool2) FROM boolean_table",
new String[] {"_col0"},
new String[] {"false,"},
DATABASE_NAME);
}

@Test
public void testAllNullValue() {
tableResultSetEqualTest(
"SELECT GREATEST(s1, s2) FROM null_table",
new String[] {"_col0"},
new String[] {"null,"},
DATABASE_NAME);

tableResultSetEqualTest(
"SELECT LEAST(s1, s2) FROM null_table",
new String[] {"_col0"},
new String[] {"null,"},
DATABASE_NAME);
}

@Test
public void testAnyNullValue() {
tableResultSetEqualTest(
"SELECT GREATEST(s1, s2) FROM any_null_table",
new String[] {"_col0"},
new String[] {"1,"},
DATABASE_NAME);

tableResultSetEqualTest(
"SELECT LEAST(s1, s2) FROM any_null_table",
new String[] {"_col0"},
new String[] {"1,"},
DATABASE_NAME);
}

@Test
public void testAnomalies() {
// do not support different type
for (int i = 1; i <= 7; i++) {
for (int j = i + 1; j <= 7; j++) {
tableAssertTestFail(
String.format("SELECT LEAST(s%d, s%d) FROM mix_type_table", i, j),
"701: Scalar function least must have at least two arguments, and all type must be the same.",
DATABASE_NAME);

tableAssertTestFail(
String.format("SELECT GREATEST(s%d, s%d) FROM mix_type_table", i, j),
"701: Scalar function greatest must have at least two arguments, and all type must be the same.",
DATABASE_NAME);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -888,7 +888,6 @@ public static boolean isTwoTypeComparable(List<? extends Type> argumentTypes) {
}

// Boolean type and Binary Type can not be compared with other types
// Unknown type can compare with other types
return (isNumericType(left) && isNumericType(right))
|| (isCharType(left) && isCharType(right))
|| (isUnknownType(left) && (isNumericType(right) || isCharType(right)))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,6 @@

package org.apache.iotdb.db.queryengine.transformation.dag.column.multi;

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.utils.TypeUtil;
import org.apache.iotdb.db.queryengine.transformation.dag.column.ColumnTransformer;

import org.apache.tsfile.block.column.Column;
Expand All @@ -26,8 +23,6 @@
import org.apache.tsfile.utils.Binary;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public abstract class AbstractGreatestLeastColumnTransformer extends MultiColumnTransformer {
Expand Down Expand Up @@ -66,6 +61,9 @@ protected void doTransform(
protected void transform(ColumnBuilder builder, List<Column> childrenColumns, int i) {
TypeEnum type = columnTransformerList.get(0).getType().getTypeEnum();
switch (type) {
case BOOLEAN:
transformBoolean(builder, getValues(childrenColumns, i, Column::getBoolean));
break;
case INT32:
case DATE:
transformInt(builder, getValues(childrenColumns, i, Column::getInt));
Expand Down Expand Up @@ -105,6 +103,8 @@ private interface ValueExtractor<T> {
T extract(Column column, int index);
}

protected abstract void transformBoolean(ColumnBuilder builder, List<Boolean> values);

protected abstract void transformInt(ColumnBuilder builder, List<Integer> values);

protected abstract void transformLong(ColumnBuilder builder, List<Long> values);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,18 @@
import org.apache.tsfile.utils.Binary;
import org.apache.tsfile.utils.BytesUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class GreatestColumnTransformer extends AbstractGreatestLeastColumnTransformer {
public GreatestColumnTransformer(Type returnType, List<ColumnTransformer> columnTransformerList) {
super(returnType, columnTransformerList);
}

@Override
protected void transformBoolean(ColumnBuilder builder, List<Boolean> values) {
returnType.writeBoolean(builder, values.stream().max(Boolean::compareTo).orElse(false));
}

@Override
protected void transformInt(ColumnBuilder builder, List<Integer> values) {
returnType.writeInt(builder, values.stream().max(Integer::compareTo).orElse(0));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,17 @@
import org.apache.tsfile.utils.Binary;
import org.apache.tsfile.utils.BytesUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class LeastColumnTransformer extends AbstractGreatestLeastColumnTransformer {
public LeastColumnTransformer(Type returnType, List<ColumnTransformer> columnTransformerList) {
super(returnType, columnTransformerList);
}

// values 都不为空,已在前面进行校验
@Override
protected void transformBoolean(ColumnBuilder builder, List<Boolean> values) {
returnType.writeBoolean(builder, values.stream().min(Boolean::compareTo).orElse(false));
}

@Override
protected void transformInt(ColumnBuilder builder, List<Integer> values) {
Expand Down

0 comments on commit d20f00c

Please sign in to comment.