This is an automated email from the ASF dual-hosted git repository.
shuwenwei pushed a commit to branch flink-iotdb-table-connector
in repository https://gitbox.apache.org/repos/asf/iotdb-extras.git
The following commit(s) were added to refs/heads/flink-iotdb-table-connector by
this push:
new b9c61c1 refactor: unify option keys under iotdb. prefix
b9c61c1 is described below
commit b9c61c1ae4d5586b084f0335c1c46d99ec2ccc43
Author: shuwenwei <[email protected]>
AuthorDate: Wed Sep 23 15:54:36 2026 +0800
refactor: unify option keys under iotdb. prefix
Consolidate literal/aggregate pushdown helpers into IoTDBUtils and update
option keys in code, tests and messages.
---
.../iotdb/relational/flink/cfg/IoTDBOptions.java | 40 +--
.../source/cdc/client/IoTDBSubscriptionClient.java | 2 +-
.../flink/source/lookup/IoTDBLookupReader.java | 3 +-
.../source/lookup/IoTDBRuntimeLiteralUtils.java | 108 -------
.../scan/pushdown/IoTDBAggregatePushDownUtils.java | 192 ------------
.../scan/pushdown/IoTDBExpressionVisitor.java | 2 +-
.../source/scan/pushdown/IoTDBLiteralUtils.java | 115 -------
.../iotdb/relational/flink/utils/IoTDBUtils.java | 330 ++++++++++++++++++++-
.../relational/flink/catalog/IoTDBCatalog.java | 6 +-
.../relational/flink/sink/IoTDBSinkWriter.java | 4 +-
.../table/IoTDBRelationalDynamicTableSource.java | 11 +-
.../flink/IoTDBRelationalLocalQueryManual.java | 16 +-
.../IoTDBRelationalSourcePushDownPlannerTest.java | 14 +-
13 files changed, 371 insertions(+), 472 deletions(-)
diff --git
a/connectors/flink-iotdb-table-connector/flink-iotdb-table-connector-base/src/main/java/org/apache/iotdb/relational/flink/cfg/IoTDBOptions.java
b/connectors/flink-iotdb-table-connector/flink-iotdb-table-connector-base/src/main/java/org/apache/iotdb/relational/flink/cfg/IoTDBOptions.java
index 7ab12c6..1463679 100644
---
a/connectors/flink-iotdb-table-connector/flink-iotdb-table-connector-base/src/main/java/org/apache/iotdb/relational/flink/cfg/IoTDBOptions.java
+++
b/connectors/flink-iotdb-table-connector/flink-iotdb-table-connector-base/src/main/java/org/apache/iotdb/relational/flink/cfg/IoTDBOptions.java
@@ -39,58 +39,60 @@ public class IoTDBOptions implements Serializable {
public static final String IDENTIFIER = "iotdb-relational";
public static final ConfigOption<String> NODE_URLS =
- ConfigOptions.key("nodeUrls").stringType().noDefaultValue();
+ ConfigOptions.key("iotdb.node-urls").stringType().noDefaultValue();
public static final ConfigOption<String> USER =
- ConfigOptions.key("user").stringType().defaultValue("root");
+ ConfigOptions.key("iotdb.user").stringType().defaultValue("root");
public static final ConfigOption<String> PASSWORD =
- ConfigOptions.key("password").stringType().defaultValue("root");
+ ConfigOptions.key("iotdb.password").stringType().defaultValue("root");
public static final ConfigOption<String> DATABASE =
- ConfigOptions.key("database").stringType().noDefaultValue();
+ ConfigOptions.key("iotdb.database").stringType().noDefaultValue();
public static final ConfigOption<String> TABLE =
- ConfigOptions.key("table").stringType().noDefaultValue();
+ ConfigOptions.key("iotdb.table").stringType().noDefaultValue();
public static final ConfigOption<String> DEFAULT_DATABASE =
-
ConfigOptions.key("default-database").stringType().defaultValue("public");
+
ConfigOptions.key("iotdb.default-database").stringType().defaultValue("public");
public static final ConfigOption<String> TIME_COLUMN =
- ConfigOptions.key("time-column").stringType().noDefaultValue();
+ ConfigOptions.key("iotdb.time-column").stringType().noDefaultValue();
public static final ConfigOption<String> TAG_COLUMNS =
- ConfigOptions.key("tag-columns").stringType().defaultValue("");
+ ConfigOptions.key("iotdb.tag-columns").stringType().defaultValue("");
public static final ConfigOption<String> ATTRIBUTE_COLUMNS =
- ConfigOptions.key("attribute-columns").stringType().defaultValue("");
+
ConfigOptions.key("iotdb.attribute-columns").stringType().defaultValue("");
public static final ConfigOption<Boolean> LOOKUP_ASYNC =
- ConfigOptions.key("lookup.async").booleanType().defaultValue(false);
+
ConfigOptions.key("iotdb.lookup.async").booleanType().defaultValue(false);
public static final ConfigOption<Integer> LOOKUP_THREAD_SIZE =
- ConfigOptions.key("lookup.thread-size").intType().defaultValue(5);
+ ConfigOptions.key("iotdb.lookup.thread-size").intType().defaultValue(5);
public static final ConfigOption<ScanMode> SCAN_MODE =
-
ConfigOptions.key("scan.mode").enumType(ScanMode.class).defaultValue(ScanMode.SNAPSHOT);
+ ConfigOptions.key("iotdb.scan.mode")
+ .enumType(ScanMode.class)
+ .defaultValue(ScanMode.SNAPSHOT);
public static final ConfigOption<String> CDC_TOPIC =
- ConfigOptions.key("cdc.topic").stringType().noDefaultValue();
+ ConfigOptions.key("iotdb.cdc.topic").stringType().noDefaultValue();
public static final ConfigOption<String> CDC_CONSUMER_GROUP =
- ConfigOptions.key("cdc.consumer-group").stringType().noDefaultValue();
+
ConfigOptions.key("iotdb.cdc.consumer-group").stringType().noDefaultValue();
public static final ConfigOption<String> CDC_MODE =
- ConfigOptions.key("cdc.mode").stringType().defaultValue("live");
+ ConfigOptions.key("iotdb.cdc.mode").stringType().defaultValue("live");
public static final ConfigOption<String> CDC_START_TIME =
- ConfigOptions.key("cdc.start-time").stringType().noDefaultValue();
+ ConfigOptions.key("iotdb.cdc.start-time").stringType().noDefaultValue();
public static final ConfigOption<Long> CDC_POLL_TIMEOUT_MS =
- ConfigOptions.key("cdc.poll-timeout-ms").longType().defaultValue(1000L);
+
ConfigOptions.key("iotdb.cdc.poll-timeout-ms").longType().defaultValue(1000L);
public static final ConfigOption<Boolean> CDC_AUTO_COMMIT =
- ConfigOptions.key("cdc.auto-commit").booleanType().defaultValue(true);
+
ConfigOptions.key("iotdb.cdc.auto-commit").booleanType().defaultValue(true);
private static final String CDC_TOPIC_PREFIX = "flink_iotdb_table_";
@@ -183,7 +185,7 @@ public class IoTDBOptions implements Serializable {
}
/**
- * @return the configured IoTDB time-column name, or {@code null} when
unspecified.
+ * @return the configured IoTDB {@code iotdb.time-column} name, or {@code
null} when unspecified.
*/
public String getTimeColumn() {
return timeColumn;
diff --git
a/connectors/flink-iotdb-table-connector/flink-iotdb-table-connector-base/src/main/java/org/apache/iotdb/relational/flink/source/cdc/client/IoTDBSubscriptionClient.java
b/connectors/flink-iotdb-table-connector/flink-iotdb-table-connector-base/src/main/java/org/apache/iotdb/relational/flink/source/cdc/client/IoTDBSubscriptionClient.java
index 8df5242..e76b8ed 100644
---
a/connectors/flink-iotdb-table-connector/flink-iotdb-table-connector-base/src/main/java/org/apache/iotdb/relational/flink/source/cdc/client/IoTDBSubscriptionClient.java
+++
b/connectors/flink-iotdb-table-connector/flink-iotdb-table-connector-base/src/main/java/org/apache/iotdb/relational/flink/source/cdc/client/IoTDBSubscriptionClient.java
@@ -38,7 +38,7 @@ public final class IoTDBSubscriptionClient {
public static void createTopicIfNotExists(IoTDBOptions options) throws
Exception {
List<String> nodeUrls = options.getNodeUrls();
if (nodeUrls == null || nodeUrls.isEmpty()) {
- throw new IllegalArgumentException("IoTDB nodeUrls must not be empty for
CDC.");
+ throw new IllegalArgumentException("IoTDB 'iotdb.node-urls' must not be
empty for CDC.");
}
String[] hostPort = splitNodeUrl(nodeUrls.get(0));
diff --git
a/connectors/flink-iotdb-table-connector/flink-iotdb-table-connector-base/src/main/java/org/apache/iotdb/relational/flink/source/lookup/IoTDBLookupReader.java
b/connectors/flink-iotdb-table-connector/flink-iotdb-table-connector-base/src/main/java/org/apache/iotdb/relational/flink/source/lookup/IoTDBLookupReader.java
index eb973c4..c92e6c6 100644
---
a/connectors/flink-iotdb-table-connector/flink-iotdb-table-connector-base/src/main/java/org/apache/iotdb/relational/flink/source/lookup/IoTDBLookupReader.java
+++
b/connectors/flink-iotdb-table-connector/flink-iotdb-table-connector-base/src/main/java/org/apache/iotdb/relational/flink/source/lookup/IoTDBLookupReader.java
@@ -117,8 +117,7 @@ public class IoTDBLookupReader implements AutoCloseable {
List<String> predicates = new ArrayList<>(keyIndices.length);
for (int position = 0; position < keyIndices.length; position++) {
int fieldIndex = keyIndices[position];
- String literal =
- IoTDBRuntimeLiteralUtils.render(keyRow, position,
fieldTypes.get(fieldIndex));
+ String literal = IoTDBUtils.renderLiteral(keyRow, position,
fieldTypes.get(fieldIndex));
if (literal == null) {
return null;
}
diff --git
a/connectors/flink-iotdb-table-connector/flink-iotdb-table-connector-base/src/main/java/org/apache/iotdb/relational/flink/source/lookup/IoTDBRuntimeLiteralUtils.java
b/connectors/flink-iotdb-table-connector/flink-iotdb-table-connector-base/src/main/java/org/apache/iotdb/relational/flink/source/lookup/IoTDBRuntimeLiteralUtils.java
deleted file mode 100644
index 9993c91..0000000
---
a/connectors/flink-iotdb-table-connector/flink-iotdb-table-connector-base/src/main/java/org/apache/iotdb/relational/flink/source/lookup/IoTDBRuntimeLiteralUtils.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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.flink.source.lookup;
-
-import org.apache.flink.table.data.RowData;
-import org.apache.flink.table.data.TimestampData;
-import org.apache.flink.table.types.DataType;
-import org.apache.flink.table.types.logical.LogicalTypeRoot;
-import org.apache.flink.table.types.logical.TimestampType;
-
-import java.time.LocalDate;
-
-/**
- * Renders a runtime {@link RowData} field as an IoTDB SQL literal, used to
build lookup queries.
- *
- * <p>Returns {@code null} when the value is {@code null} or cannot be
represented in IoTDB SQL.
- */
-public final class IoTDBRuntimeLiteralUtils {
-
- private IoTDBRuntimeLiteralUtils() {}
-
- public static String render(RowData row, int position, DataType dataType) {
- if (row == null || row.isNullAt(position) || dataType == null) {
- return null;
- }
-
- LogicalTypeRoot typeRoot = dataType.getLogicalType().getTypeRoot();
- switch (typeRoot) {
- case BOOLEAN:
- return Boolean.toString(row.getBoolean(position));
- case TINYINT:
- return Byte.toString(row.getByte(position));
- case SMALLINT:
- return Short.toString(row.getShort(position));
- case INTEGER:
- return Integer.toString(row.getInt(position));
- case BIGINT:
- return Long.toString(row.getLong(position));
- case FLOAT:
- float floatValue = row.getFloat(position);
- return isFinite(floatValue) ? Float.toString(floatValue) : null;
- case DOUBLE:
- double doubleValue = row.getDouble(position);
- return isFinite(doubleValue) ? Double.toString(doubleValue) : null;
- case CHAR:
- case VARCHAR:
- return quoteString(row.getString(position).toString());
- case BINARY:
- case VARBINARY:
- byte[] bytes = row.getBinary(position);
- return bytes == null ? null : formatBinary(bytes);
- case DATE:
- return "CAST('" + LocalDate.ofEpochDay(row.getInt(position)) + "' AS
DATE)";
- case TIMESTAMP_WITHOUT_TIME_ZONE:
- return "CAST('"
- + getTimestamp(row, position, dataType).toLocalDateTime()
- + "' AS TIMESTAMP)";
- case TIMESTAMP_WITH_LOCAL_TIME_ZONE:
- return "CAST('" + getTimestamp(row, position, dataType).toInstant() +
"' AS TIMESTAMP)";
- default:
- return null;
- }
- }
-
- private static TimestampData getTimestamp(RowData row, int position,
DataType dataType) {
- int precision = ((TimestampType) dataType.getLogicalType()).getPrecision();
- return row.getTimestamp(position, precision);
- }
-
- private static boolean isFinite(float value) {
- return !Float.isNaN(value) && !Float.isInfinite(value);
- }
-
- private static boolean isFinite(double value) {
- return !Double.isNaN(value) && !Double.isInfinite(value);
- }
-
- private static String quoteString(String value) {
- return "'" + value.replace("'", "''") + "'";
- }
-
- private static String formatBinary(byte[] value) {
- StringBuilder builder = new StringBuilder(value.length * 2 + 3);
- builder.append("X'");
- for (byte b : value) {
- builder.append(String.format("%02X", b));
- }
- builder.append("'");
- return builder.toString();
- }
-}
diff --git
a/connectors/flink-iotdb-table-connector/flink-iotdb-table-connector-base/src/main/java/org/apache/iotdb/relational/flink/source/scan/pushdown/IoTDBAggregatePushDownUtils.java
b/connectors/flink-iotdb-table-connector/flink-iotdb-table-connector-base/src/main/java/org/apache/iotdb/relational/flink/source/scan/pushdown/IoTDBAggregatePushDownUtils.java
deleted file mode 100644
index 3e74d95..0000000
---
a/connectors/flink-iotdb-table-connector/flink-iotdb-table-connector-base/src/main/java/org/apache/iotdb/relational/flink/source/scan/pushdown/IoTDBAggregatePushDownUtils.java
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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.flink.source.scan.pushdown;
-
-import org.apache.iotdb.relational.flink.utils.IoTDBUtils;
-
-import org.apache.flink.table.expressions.AggregateExpression;
-import org.apache.flink.table.expressions.FieldReferenceExpression;
-import org.apache.flink.table.types.DataType;
-import org.apache.tsfile.enums.TSDataType;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Translates Flink aggregate pushdown information into a serializable {@link
AggregateSpec}.
- *
- * <p>The pushdown is all-or-nothing: any unsupported aggregate, argument or
grouping makes this
- * return {@code null} so the whole aggregation stays in Flink.
- *
- * <p>Each aggregate is classified and translated in a single pass from its
function class name;
- * grouping columns and aggregate arguments are rendered through {@link
IoTDBExpressionVisitor}.
- */
-public final class IoTDBAggregatePushDownUtils {
-
- private IoTDBAggregatePushDownUtils() {}
-
- public static AggregateSpec translate(
- List<int[]> groupingSets,
- List<AggregateExpression> aggregateExpressions,
- DataType sourceRowDataType,
- DataType producedDataType) {
- if (groupingSets == null
- || groupingSets.size() != 1
- || aggregateExpressions == null
- || aggregateExpressions.isEmpty()) {
- return null;
- }
-
- final List<String> sourceFieldNames;
- final List<DataType> producedFieldTypes;
- try {
- sourceFieldNames = DataType.getFieldNames(sourceRowDataType);
- producedFieldTypes = DataType.getFieldDataTypes(producedDataType);
- } catch (RuntimeException e) {
- return null;
- }
-
- int[] grouping = groupingSets.get(0);
- if (grouping == null) {
- return null;
- }
-
- List<String> groupByExpressions = new ArrayList<>(grouping.length);
- List<String> selectExpressions = new ArrayList<>(grouping.length +
aggregateExpressions.size());
- for (int index : grouping) {
- if (index < 0 || index >= sourceFieldNames.size()) {
- return null;
- }
- String column = IoTDBUtils.quoteIdentifier(sourceFieldNames.get(index));
- groupByExpressions.add(column);
- selectExpressions.add(column);
- }
-
- IoTDBExpressionVisitor visitor = new IoTDBExpressionVisitor();
- for (int i = 0; i < aggregateExpressions.size(); i++) {
- int producedIndex = grouping.length + i;
- if (producedIndex >= producedFieldTypes.size()) {
- return null;
- }
- String sql =
- translateAggregate(
- aggregateExpressions.get(i),
producedFieldTypes.get(producedIndex), visitor);
- if (sql == null) {
- return null;
- }
- selectExpressions.add(sql);
- }
-
- return new AggregateSpec(selectExpressions, groupByExpressions);
- }
-
- private static String translateAggregate(
- AggregateExpression aggregate, DataType producedType,
IoTDBExpressionVisitor visitor) {
- if (!isSupportedAggregate(aggregate)) {
- return null;
- }
-
- Class<?> functionClass = aggregate.getFunctionDefinition().getClass();
- String simpleName = functionClass == null ? null :
functionClass.getSimpleName();
- TSDataType outType = toTsDataType(producedType);
- if (simpleName == null || outType == null) {
- return null;
- }
-
- List<FieldReferenceExpression> args = aggregate.getArgs();
- int argCount = args == null ? 0 : args.size();
-
- String expression;
- if (simpleName.endsWith("Count1AggFunction")) {
- if (argCount != 0 || !isCountType(outType)) {
- return null;
- }
- expression = "COUNT(*)";
- } else if (simpleName.endsWith("CountAggFunction")) {
- if (argCount != 1 || !isCountType(outType)) {
- return null;
- }
- String argSql = args.get(0).accept(visitor);
- if (argSql == null || toTsDataType(args.get(0).getOutputDataType()) ==
null) {
- return null;
- }
- expression = "COUNT(" + argSql + ")";
- } else if (simpleName.endsWith("Sum0AggFunction") ||
simpleName.endsWith("SumAggFunction")) {
- if (argCount != 1 || !isNumeric(outType)) {
- return null;
- }
- String argSql = args.get(0).accept(visitor);
- TSDataType argType = argSql == null ? null :
toTsDataType(args.get(0).getOutputDataType());
- if (argType == null || !isNumeric(argType)) {
- return null;
- }
- expression = "SUM(" + argSql + ")";
- } else if (simpleName.endsWith("MaxAggFunction") ||
simpleName.endsWith("MinAggFunction")) {
- if (argCount != 1) {
- return null;
- }
- String argSql = args.get(0).accept(visitor);
- if (argSql == null || toTsDataType(args.get(0).getOutputDataType()) ==
null) {
- return null;
- }
- String functionName = simpleName.endsWith("MaxAggFunction") ? "MAX" :
"MIN";
- expression = functionName + "(" + argSql + ")";
- } else {
- return null;
- }
-
- return "CAST(" + expression + " AS " + outType.name() + ")";
- }
-
- private static boolean isSupportedAggregate(AggregateExpression aggregate) {
- return aggregate != null
- && !aggregate.isDistinct()
- && !aggregate.isApproximate()
- && !aggregate.isIgnoreNulls()
- && !aggregate.getFilterExpression().isPresent();
- }
-
- private static boolean isNumeric(TSDataType dataType) {
- switch (dataType) {
- case INT32:
- case INT64:
- case FLOAT:
- case DOUBLE:
- return true;
- default:
- return false;
- }
- }
-
- private static boolean isCountType(TSDataType dataType) {
- return dataType == TSDataType.INT32 || dataType == TSDataType.INT64;
- }
-
- private static TSDataType toTsDataType(DataType dataType) {
- if (dataType == null) {
- return null;
- }
- try {
- return IoTDBUtils.toIoTDBDataType(dataType);
- } catch (RuntimeException e) {
- return null;
- }
- }
-}
diff --git
a/connectors/flink-iotdb-table-connector/flink-iotdb-table-connector-base/src/main/java/org/apache/iotdb/relational/flink/source/scan/pushdown/IoTDBExpressionVisitor.java
b/connectors/flink-iotdb-table-connector/flink-iotdb-table-connector-base/src/main/java/org/apache/iotdb/relational/flink/source/scan/pushdown/IoTDBExpressionVisitor.java
index e40e3cf..4884e39 100644
---
a/connectors/flink-iotdb-table-connector/flink-iotdb-table-connector-base/src/main/java/org/apache/iotdb/relational/flink/source/scan/pushdown/IoTDBExpressionVisitor.java
+++
b/connectors/flink-iotdb-table-connector/flink-iotdb-table-connector-base/src/main/java/org/apache/iotdb/relational/flink/source/scan/pushdown/IoTDBExpressionVisitor.java
@@ -114,7 +114,7 @@ public class IoTDBExpressionVisitor implements
ExpressionVisitor<String> {
@Override
public String visit(ValueLiteralExpression valueLiteral) {
- return IoTDBLiteralUtils.render(valueLiteral);
+ return IoTDBUtils.renderLiteral(valueLiteral);
}
@Override
diff --git
a/connectors/flink-iotdb-table-connector/flink-iotdb-table-connector-base/src/main/java/org/apache/iotdb/relational/flink/source/scan/pushdown/IoTDBLiteralUtils.java
b/connectors/flink-iotdb-table-connector/flink-iotdb-table-connector-base/src/main/java/org/apache/iotdb/relational/flink/source/scan/pushdown/IoTDBLiteralUtils.java
deleted file mode 100644
index d8e7968..0000000
---
a/connectors/flink-iotdb-table-connector/flink-iotdb-table-connector-base/src/main/java/org/apache/iotdb/relational/flink/source/scan/pushdown/IoTDBLiteralUtils.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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.flink.source.scan.pushdown;
-
-import org.apache.flink.table.expressions.ValueLiteralExpression;
-import org.apache.flink.table.types.logical.LogicalTypeRoot;
-
-import java.time.Instant;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.util.Optional;
-
-/** Renders Flink literal expressions as IoTDB SQL literals. */
-public final class IoTDBLiteralUtils {
-
- private IoTDBLiteralUtils() {}
-
- /**
- * Renders a literal for pushdown. Returns {@code null} if the literal type
or value cannot be
- * represented in IoTDB SQL.
- */
- public static String render(ValueLiteralExpression literal) {
- if (literal == null || literal.isNull()) {
- return null;
- }
-
- try {
- LogicalTypeRoot typeRoot =
literal.getOutputDataType().getLogicalType().getTypeRoot();
- switch (typeRoot) {
- case BOOLEAN:
- return
literal.getValueAs(Boolean.class).map(String::valueOf).orElse(null);
- case TINYINT:
- return value(literal.getValueAs(Byte.class));
- case SMALLINT:
- return value(literal.getValueAs(Short.class));
- case INTEGER:
- return value(literal.getValueAs(Integer.class));
- case BIGINT:
- return value(literal.getValueAs(Long.class));
- case FLOAT:
- return literal
- .getValueAs(Float.class)
- .filter(value -> !value.isNaN() && !value.isInfinite())
- .map(String::valueOf)
- .orElse(null);
- case DOUBLE:
- return literal
- .getValueAs(Double.class)
- .filter(value -> !value.isNaN() && !value.isInfinite())
- .map(String::valueOf)
- .orElse(null);
- case CHAR:
- case VARCHAR:
- return
literal.getValueAs(String.class).map(IoTDBLiteralUtils::quoteString).orElse(null);
- case BINARY:
- case VARBINARY:
- return
literal.getValueAs(byte[].class).map(IoTDBLiteralUtils::formatBinary).orElse(null);
- case DATE:
- return literal
- .getValueAs(LocalDate.class)
- .map(value -> "CAST('" + value + "' AS DATE)")
- .orElse(null);
- case TIMESTAMP_WITHOUT_TIME_ZONE:
- return literal
- .getValueAs(LocalDateTime.class)
- .map(value -> "CAST('" + value + "' AS TIMESTAMP)")
- .orElse(null);
- case TIMESTAMP_WITH_LOCAL_TIME_ZONE:
- return literal
- .getValueAs(Instant.class)
- .map(value -> "CAST('" + value + "' AS TIMESTAMP)")
- .orElse(null);
- default:
- return null;
- }
- } catch (RuntimeException e) {
- return null;
- }
- }
-
- private static String value(Optional<?> value) {
- return value.map(Object::toString).orElse(null);
- }
-
- private static String quoteString(String value) {
- return "'" + value.replace("'", "''") + "'";
- }
-
- private static String formatBinary(byte[] value) {
- StringBuilder builder = new StringBuilder(value.length * 2 + 3);
- builder.append("X'");
- for (byte b : value) {
- builder.append(String.format("%02X", b));
- }
- builder.append("'");
- return builder.toString();
- }
-}
diff --git
a/connectors/flink-iotdb-table-connector/flink-iotdb-table-connector-base/src/main/java/org/apache/iotdb/relational/flink/utils/IoTDBUtils.java
b/connectors/flink-iotdb-table-connector/flink-iotdb-table-connector-base/src/main/java/org/apache/iotdb/relational/flink/utils/IoTDBUtils.java
index f3c9237..183b1ee 100644
---
a/connectors/flink-iotdb-table-connector/flink-iotdb-table-connector-base/src/main/java/org/apache/iotdb/relational/flink/utils/IoTDBUtils.java
+++
b/connectors/flink-iotdb-table-connector/flink-iotdb-table-connector-base/src/main/java/org/apache/iotdb/relational/flink/utils/IoTDBUtils.java
@@ -19,12 +19,25 @@
package org.apache.iotdb.relational.flink.utils;
+import org.apache.iotdb.relational.flink.source.scan.pushdown.AggregateSpec;
+import
org.apache.iotdb.relational.flink.source.scan.pushdown.IoTDBExpressionVisitor;
+
import org.apache.flink.table.api.DataTypes;
import org.apache.flink.table.catalog.exceptions.CatalogException;
+import org.apache.flink.table.data.RowData;
+import org.apache.flink.table.data.TimestampData;
+import org.apache.flink.table.expressions.AggregateExpression;
+import org.apache.flink.table.expressions.FieldReferenceExpression;
+import org.apache.flink.table.expressions.ValueLiteralExpression;
import org.apache.flink.table.types.DataType;
+import org.apache.flink.table.types.logical.LogicalTypeRoot;
+import org.apache.flink.table.types.logical.TimestampType;
import org.apache.tsfile.enums.ColumnCategory;
import org.apache.tsfile.enums.TSDataType;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
@@ -32,13 +45,16 @@ import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
+import java.util.Optional;
import java.util.Set;
/**
* Shared utilities for the IoTDB relational (table model) Flink connector.
*
- * <p>This class centralizes identifier quoting, Flink/IoTDB data type
conversion and the column
- * name/category resolution used by both the Flink catalog (DDL) and the sink
serializer.
+ * <p>This class centralizes identifier quoting, Flink/IoTDB data type
conversion, the column
+ * name/category resolution used by both the Flink catalog (DDL) and the sink
serializer, the
+ * rendering of Flink planner/runtime values as IoTDB SQL literals, and the
aggregate pushdown
+ * translation.
*/
public final class IoTDBUtils {
@@ -140,8 +156,8 @@ public final class IoTDBUtils {
}
/**
- * Validates the {@code time-column}, {@code tag-columns} and {@code
attribute-columns} options
- * against an existing table schema.
+ * Validates the {@code iotdb.time-column}, {@code iotdb.tag-columns} and
{@code
+ * iotdb.attribute-columns} options against an existing table schema.
*
* @param timeColumn normalized TIME column name
* @param tagColumns normalized TAG column names
@@ -154,7 +170,8 @@ public final class IoTDBUtils {
Collection<String> attributeColumns,
Map<String, TSDataType> dataTypesByColumn) {
if (timeColumn == null || timeColumn.isEmpty()) {
- throw new CatalogException("Table option 'time-column' must specify the
IoTDB TIME column.");
+ throw new CatalogException(
+ "Table option 'iotdb.time-column' must specify the IoTDB TIME
column.");
}
if (tagColumns.contains(timeColumn) ||
attributeColumns.contains(timeColumn)) {
throw new CatalogException("The TIME column cannot also be a TAG or
ATTRIBUTE column.");
@@ -165,12 +182,12 @@ public final class IoTDBUtils {
throw new CatalogException(
"TAG and ATTRIBUTE columns must not overlap: " +
overlappingColumns.iterator().next());
}
- validateColumnExists(timeColumn, "time-column", dataTypesByColumn);
+ validateColumnExists(timeColumn, "iotdb.time-column", dataTypesByColumn);
for (String columnName : tagColumns) {
- validateColumnExists(columnName, "tag-columns", dataTypesByColumn);
+ validateColumnExists(columnName, "iotdb.tag-columns", dataTypesByColumn);
}
for (String columnName : attributeColumns) {
- validateColumnExists(columnName, "attribute-columns", dataTypesByColumn);
+ validateColumnExists(columnName, "iotdb.attribute-columns",
dataTypesByColumn);
}
if (dataTypesByColumn.get(timeColumn) != TSDataType.TIMESTAMP) {
throw new CatalogException("The IoTDB TIME column must use the TIMESTAMP
data type.");
@@ -278,6 +295,303 @@ public final class IoTDBUtils {
return sql.toString();
}
+ /**
+ * Renders a Flink planner literal as an IoTDB SQL literal. Returns {@code
null} if the literal
+ * type or value cannot be represented in IoTDB SQL.
+ */
+ public static String renderLiteral(ValueLiteralExpression literal) {
+ if (literal == null || literal.isNull()) {
+ return null;
+ }
+
+ try {
+ LogicalTypeRoot typeRoot =
literal.getOutputDataType().getLogicalType().getTypeRoot();
+ switch (typeRoot) {
+ case BOOLEAN:
+ return
literal.getValueAs(Boolean.class).map(String::valueOf).orElse(null);
+ case TINYINT:
+ return value(literal.getValueAs(Byte.class));
+ case SMALLINT:
+ return value(literal.getValueAs(Short.class));
+ case INTEGER:
+ return value(literal.getValueAs(Integer.class));
+ case BIGINT:
+ return value(literal.getValueAs(Long.class));
+ case FLOAT:
+ return literal
+ .getValueAs(Float.class)
+ .filter(value -> !value.isNaN() && !value.isInfinite())
+ .map(String::valueOf)
+ .orElse(null);
+ case DOUBLE:
+ return literal
+ .getValueAs(Double.class)
+ .filter(value -> !value.isNaN() && !value.isInfinite())
+ .map(String::valueOf)
+ .orElse(null);
+ case CHAR:
+ case VARCHAR:
+ return
literal.getValueAs(String.class).map(IoTDBUtils::quoteString).orElse(null);
+ case BINARY:
+ case VARBINARY:
+ return
literal.getValueAs(byte[].class).map(IoTDBUtils::formatBinary).orElse(null);
+ case DATE:
+ return literal
+ .getValueAs(LocalDate.class)
+ .map(value -> "CAST('" + value + "' AS DATE)")
+ .orElse(null);
+ case TIMESTAMP_WITHOUT_TIME_ZONE:
+ return literal
+ .getValueAs(LocalDateTime.class)
+ .map(value -> "CAST('" + value + "' AS TIMESTAMP)")
+ .orElse(null);
+ case TIMESTAMP_WITH_LOCAL_TIME_ZONE:
+ return literal
+ .getValueAs(Instant.class)
+ .map(value -> "CAST('" + value + "' AS TIMESTAMP)")
+ .orElse(null);
+ default:
+ return null;
+ }
+ } catch (RuntimeException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Renders a runtime {@link RowData} field as an IoTDB SQL literal. Returns
{@code null} when the
+ * value is {@code null} or cannot be represented in IoTDB SQL.
+ */
+ public static String renderLiteral(RowData row, int position, DataType
dataType) {
+ if (row == null || row.isNullAt(position) || dataType == null) {
+ return null;
+ }
+
+ LogicalTypeRoot typeRoot = dataType.getLogicalType().getTypeRoot();
+ switch (typeRoot) {
+ case BOOLEAN:
+ return Boolean.toString(row.getBoolean(position));
+ case TINYINT:
+ return Byte.toString(row.getByte(position));
+ case SMALLINT:
+ return Short.toString(row.getShort(position));
+ case INTEGER:
+ return Integer.toString(row.getInt(position));
+ case BIGINT:
+ return Long.toString(row.getLong(position));
+ case FLOAT:
+ float floatValue = row.getFloat(position);
+ return isFinite(floatValue) ? Float.toString(floatValue) : null;
+ case DOUBLE:
+ double doubleValue = row.getDouble(position);
+ return isFinite(doubleValue) ? Double.toString(doubleValue) : null;
+ case CHAR:
+ case VARCHAR:
+ return quoteString(row.getString(position).toString());
+ case BINARY:
+ case VARBINARY:
+ byte[] bytes = row.getBinary(position);
+ return bytes == null ? null : formatBinary(bytes);
+ case DATE:
+ return "CAST('" + LocalDate.ofEpochDay(row.getInt(position)) + "' AS
DATE)";
+ case TIMESTAMP_WITHOUT_TIME_ZONE:
+ return "CAST('"
+ + getTimestamp(row, position, dataType).toLocalDateTime()
+ + "' AS TIMESTAMP)";
+ case TIMESTAMP_WITH_LOCAL_TIME_ZONE:
+ return "CAST('" + getTimestamp(row, position, dataType).toInstant() +
"' AS TIMESTAMP)";
+ default:
+ return null;
+ }
+ }
+
+ /**
+ * Translates Flink aggregate pushdown information into a serializable
{@link AggregateSpec}.
+ *
+ * <p>The pushdown is all-or-nothing: any unsupported aggregate, argument or
grouping makes this
+ * return {@code null} so the whole aggregation stays in Flink. Each
aggregate is classified and
+ * translated in a single pass from its function class name; grouping
columns and aggregate
+ * arguments are rendered through {@link IoTDBExpressionVisitor}.
+ */
+ public static AggregateSpec translateAggregate(
+ List<int[]> groupingSets,
+ List<AggregateExpression> aggregateExpressions,
+ DataType sourceRowDataType,
+ DataType producedDataType) {
+ if (groupingSets == null
+ || groupingSets.size() != 1
+ || aggregateExpressions == null
+ || aggregateExpressions.isEmpty()) {
+ return null;
+ }
+
+ final List<String> sourceFieldNames;
+ final List<DataType> producedFieldTypes;
+ try {
+ sourceFieldNames = DataType.getFieldNames(sourceRowDataType);
+ producedFieldTypes = DataType.getFieldDataTypes(producedDataType);
+ } catch (RuntimeException e) {
+ return null;
+ }
+
+ int[] grouping = groupingSets.get(0);
+ if (grouping == null) {
+ return null;
+ }
+
+ List<String> groupByExpressions = new ArrayList<>(grouping.length);
+ List<String> selectExpressions = new ArrayList<>(grouping.length +
aggregateExpressions.size());
+ for (int index : grouping) {
+ if (index < 0 || index >= sourceFieldNames.size()) {
+ return null;
+ }
+ String column = quoteIdentifier(sourceFieldNames.get(index));
+ groupByExpressions.add(column);
+ selectExpressions.add(column);
+ }
+
+ IoTDBExpressionVisitor visitor = new IoTDBExpressionVisitor();
+ for (int i = 0; i < aggregateExpressions.size(); i++) {
+ int producedIndex = grouping.length + i;
+ if (producedIndex >= producedFieldTypes.size()) {
+ return null;
+ }
+ String sql =
+ translateAggregateFunction(
+ aggregateExpressions.get(i),
producedFieldTypes.get(producedIndex), visitor);
+ if (sql == null) {
+ return null;
+ }
+ selectExpressions.add(sql);
+ }
+
+ return new AggregateSpec(selectExpressions, groupByExpressions);
+ }
+
+ private static String translateAggregateFunction(
+ AggregateExpression aggregate, DataType producedType,
IoTDBExpressionVisitor visitor) {
+ if (!isSupportedAggregate(aggregate)) {
+ return null;
+ }
+
+ Class<?> functionClass = aggregate.getFunctionDefinition().getClass();
+ String simpleName = functionClass == null ? null :
functionClass.getSimpleName();
+ TSDataType outType = toTsDataType(producedType);
+ if (simpleName == null || outType == null) {
+ return null;
+ }
+
+ List<FieldReferenceExpression> args = aggregate.getArgs();
+ int argCount = args == null ? 0 : args.size();
+
+ String expression;
+ if (simpleName.endsWith("Count1AggFunction")) {
+ if (argCount != 0 || !isCountType(outType)) {
+ return null;
+ }
+ expression = "COUNT(*)";
+ } else if (simpleName.endsWith("CountAggFunction")) {
+ if (argCount != 1 || !isCountType(outType)) {
+ return null;
+ }
+ String argSql = args.get(0).accept(visitor);
+ if (argSql == null || toTsDataType(args.get(0).getOutputDataType()) ==
null) {
+ return null;
+ }
+ expression = "COUNT(" + argSql + ")";
+ } else if (simpleName.endsWith("Sum0AggFunction") ||
simpleName.endsWith("SumAggFunction")) {
+ if (argCount != 1 || !isNumeric(outType)) {
+ return null;
+ }
+ String argSql = args.get(0).accept(visitor);
+ TSDataType argType = argSql == null ? null :
toTsDataType(args.get(0).getOutputDataType());
+ if (argType == null || !isNumeric(argType)) {
+ return null;
+ }
+ expression = "SUM(" + argSql + ")";
+ } else if (simpleName.endsWith("MaxAggFunction") ||
simpleName.endsWith("MinAggFunction")) {
+ if (argCount != 1) {
+ return null;
+ }
+ String argSql = args.get(0).accept(visitor);
+ if (argSql == null || toTsDataType(args.get(0).getOutputDataType()) ==
null) {
+ return null;
+ }
+ String functionName = simpleName.endsWith("MaxAggFunction") ? "MAX" :
"MIN";
+ expression = functionName + "(" + argSql + ")";
+ } else {
+ return null;
+ }
+
+ return "CAST(" + expression + " AS " + outType.name() + ")";
+ }
+
+ private static boolean isSupportedAggregate(AggregateExpression aggregate) {
+ return aggregate != null
+ && !aggregate.isDistinct()
+ && !aggregate.isApproximate()
+ && !aggregate.isIgnoreNulls()
+ && !aggregate.getFilterExpression().isPresent();
+ }
+
+ private static boolean isNumeric(TSDataType dataType) {
+ switch (dataType) {
+ case INT32:
+ case INT64:
+ case FLOAT:
+ case DOUBLE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ private static boolean isCountType(TSDataType dataType) {
+ return dataType == TSDataType.INT32 || dataType == TSDataType.INT64;
+ }
+
+ private static TSDataType toTsDataType(DataType dataType) {
+ if (dataType == null) {
+ return null;
+ }
+ try {
+ return toIoTDBDataType(dataType);
+ } catch (RuntimeException e) {
+ return null;
+ }
+ }
+
+ private static TimestampData getTimestamp(RowData row, int position,
DataType dataType) {
+ int precision = ((TimestampType) dataType.getLogicalType()).getPrecision();
+ return row.getTimestamp(position, precision);
+ }
+
+ private static boolean isFinite(float value) {
+ return !Float.isNaN(value) && !Float.isInfinite(value);
+ }
+
+ private static boolean isFinite(double value) {
+ return !Double.isNaN(value) && !Double.isInfinite(value);
+ }
+
+ private static String value(Optional<?> value) {
+ return value.map(Object::toString).orElse(null);
+ }
+
+ private static String quoteString(String value) {
+ return "'" + value.replace("'", "''") + "'";
+ }
+
+ private static String formatBinary(byte[] value) {
+ StringBuilder builder = new StringBuilder(value.length * 2 + 3);
+ builder.append("X'");
+ for (byte b : value) {
+ builder.append(String.format("%02X", b));
+ }
+ builder.append("'");
+ return builder.toString();
+ }
+
private static void validateColumnExists(
String columnName, String optionName, Map<String, TSDataType>
dataTypesByColumn) {
if (!dataTypesByColumn.containsKey(columnName)) {
diff --git
a/connectors/flink-iotdb-table-connector/flink-iotdb-table-connector-flink1/src/main/java/org/apache/iotdb/relational/flink/catalog/IoTDBCatalog.java
b/connectors/flink-iotdb-table-connector/flink-iotdb-table-connector-flink1/src/main/java/org/apache/iotdb/relational/flink/catalog/IoTDBCatalog.java
index 3e3d6c0..25f4ebd 100644
---
a/connectors/flink-iotdb-table-connector/flink-iotdb-table-connector-flink1/src/main/java/org/apache/iotdb/relational/flink/catalog/IoTDBCatalog.java
+++
b/connectors/flink-iotdb-table-connector/flink-iotdb-table-connector-flink1/src/main/java/org/apache/iotdb/relational/flink/catalog/IoTDBCatalog.java
@@ -342,10 +342,10 @@ public class IoTDBCatalog extends AbstractCatalog {
Map<String, String> tableOptions = table.getOptions();
String timeColumn = getRequiredTimeColumn(tableOptions);
Set<String> tagColumns =
- parseColumnNames(tableOptions.get(IoTDBOptions.TAG_COLUMNS.key()),
"tag-columns");
+ parseColumnNames(tableOptions.get(IoTDBOptions.TAG_COLUMNS.key()),
"iotdb.tag-columns");
Set<String> attributeColumns =
parseColumnNames(
- tableOptions.get(IoTDBOptions.ATTRIBUTE_COLUMNS.key()),
"attribute-columns");
+ tableOptions.get(IoTDBOptions.ATTRIBUTE_COLUMNS.key()),
"iotdb.attribute-columns");
List<String> columnNames = new ArrayList<>();
List<TSDataType> dataTypes = new ArrayList<>();
@@ -383,7 +383,7 @@ public class IoTDBCatalog extends AbstractCatalog {
String timeColumn = tableOptions.get(IoTDBOptions.TIME_COLUMN.key());
if (timeColumn == null || timeColumn.trim().isEmpty()) {
throw new CatalogException(
- "Table option 'time-column' must specify the IoTDB TIME column for
CREATE TABLE.");
+ "Table option 'iotdb.time-column' must specify the IoTDB TIME column
for CREATE TABLE.");
}
return IoTDBUtils.normalizeColumnName(timeColumn);
}
diff --git
a/connectors/flink-iotdb-table-connector/flink-iotdb-table-connector-flink1/src/main/java/org/apache/iotdb/relational/flink/sink/IoTDBSinkWriter.java
b/connectors/flink-iotdb-table-connector/flink-iotdb-table-connector-flink1/src/main/java/org/apache/iotdb/relational/flink/sink/IoTDBSinkWriter.java
index c41d3dc..0422e34 100644
---
a/connectors/flink-iotdb-table-connector/flink-iotdb-table-connector-flink1/src/main/java/org/apache/iotdb/relational/flink/sink/IoTDBSinkWriter.java
+++
b/connectors/flink-iotdb-table-connector/flink-iotdb-table-connector-flink1/src/main/java/org/apache/iotdb/relational/flink/sink/IoTDBSinkWriter.java
@@ -159,13 +159,13 @@ public class IoTDBSinkWriter<IN> implements
SinkWriter<IN> {
private void initializeTablet() throws IOException {
String tableName = options.getTable();
if (tableName == null || tableName.trim().isEmpty()) {
- throw new IOException("Table option 'table' must specify the IoTDB table
name.");
+ throw new IOException("Table option 'iotdb.table' must specify the IoTDB
table name.");
}
String rawTimeColumn = options.getTimeColumn();
if (rawTimeColumn == null || rawTimeColumn.trim().isEmpty()) {
throw new IOException(
- "Table option 'time-column' is required to write into an IoTDB table
model table.");
+ "Table option 'iotdb.time-column' is required to write into an IoTDB
table model table.");
}
try {
diff --git
a/connectors/flink-iotdb-table-connector/flink-iotdb-table-connector-flink1/src/main/java/org/apache/iotdb/relational/flink/table/IoTDBRelationalDynamicTableSource.java
b/connectors/flink-iotdb-table-connector/flink-iotdb-table-connector-flink1/src/main/java/org/apache/iotdb/relational/flink/table/IoTDBRelationalDynamicTableSource.java
index 64bbd76..966651f 100644
---
a/connectors/flink-iotdb-table-connector/flink-iotdb-table-connector-flink1/src/main/java/org/apache/iotdb/relational/flink/table/IoTDBRelationalDynamicTableSource.java
+++
b/connectors/flink-iotdb-table-connector/flink-iotdb-table-connector-flink1/src/main/java/org/apache/iotdb/relational/flink/table/IoTDBRelationalDynamicTableSource.java
@@ -26,7 +26,6 @@ import
org.apache.iotdb.relational.flink.source.lookup.IoTDBAsyncLookupFunction;
import org.apache.iotdb.relational.flink.source.lookup.IoTDBLookupFunction;
import org.apache.iotdb.relational.flink.source.scan.IoTDBSource;
import org.apache.iotdb.relational.flink.source.scan.pushdown.AggregateSpec;
-import
org.apache.iotdb.relational.flink.source.scan.pushdown.IoTDBAggregatePushDownUtils;
import
org.apache.iotdb.relational.flink.source.scan.pushdown.IoTDBExpressionVisitor;
import org.apache.iotdb.relational.flink.utils.IoTDBUtils;
@@ -63,10 +62,10 @@ import java.util.List;
* <p>It supports three read paths:
*
* <ul>
- * <li>bounded scan reads ({@code scan.mode=snapshot}, the default) with
filter, projection, limit
- * and aggregate pushdown;
- * <li>lookup reads, either synchronous or asynchronous ({@code
lookup.async});
- * <li>unbounded CDC reads backed by the IoTDB subscription API ({@code
scan.mode=cdc}).
+ * <li>bounded scan reads ({@code iotdb.scan.mode=snapshot}, the default)
with filter, projection,
+ * limit and aggregate pushdown;
+ * <li>lookup reads, either synchronous or asynchronous ({@code
iotdb.lookup.async});
+ * <li>unbounded CDC reads backed by the IoTDB subscription API ({@code
iotdb.scan.mode=cdc}).
* </ul>
*
* <p>All rows are emitted as inserts, so the changelog mode is insert-only.
@@ -196,7 +195,7 @@ public class IoTDBRelationalDynamicTableSource
// Grouping and argument indices refer to the scan's current row type,
which is the row type
// after any projection that has already been pushed into this source.
AggregateSpec spec =
- IoTDBAggregatePushDownUtils.translate(
+ IoTDBUtils.translateAggregate(
groupingSets, aggregateExpressions, physicalRowDataType,
producedDataType);
if (spec == null) {
return false;
diff --git
a/connectors/flink-iotdb-table-connector/flink-iotdb-table-connector-flink1/src/test/java/org/apache/iotdb/relational/flink/IoTDBRelationalLocalQueryManual.java
b/connectors/flink-iotdb-table-connector/flink-iotdb-table-connector-flink1/src/test/java/org/apache/iotdb/relational/flink/IoTDBRelationalLocalQueryManual.java
index 68c6712..6bff06a 100644
---
a/connectors/flink-iotdb-table-connector/flink-iotdb-table-connector-flink1/src/test/java/org/apache/iotdb/relational/flink/IoTDBRelationalLocalQueryManual.java
+++
b/connectors/flink-iotdb-table-connector/flink-iotdb-table-connector-flink1/src/test/java/org/apache/iotdb/relational/flink/IoTDBRelationalLocalQueryManual.java
@@ -140,25 +140,25 @@ public class IoTDBRelationalLocalQueryManual {
.append(" `temperature` DOUBLE\n")
.append(") WITH (\n")
.append(" 'connector' = 'iotdb-relational',\n")
- .append(" 'nodeUrls' = '")
+ .append(" 'iotdb.node-urls' = '")
.append(nodeUrls)
.append("',\n")
- .append(" 'user' = '")
+ .append(" 'iotdb.user' = '")
.append(user)
.append("',\n")
- .append(" 'password' = '")
+ .append(" 'iotdb.password' = '")
.append(password)
.append("',\n")
- .append(" 'database' = '")
+ .append(" 'iotdb.database' = '")
.append(database)
.append("',\n")
- .append(" 'table' = '")
+ .append(" 'iotdb.table' = '")
.append(table)
.append("',\n")
- .append(" 'time-column' = 'time',\n")
- .append(" 'tag-columns' = 'device_id'");
+ .append(" 'iotdb.time-column' = 'time',\n")
+ .append(" 'iotdb.tag-columns' = 'device_id'");
if (async != null) {
- ddl.append(",\n 'lookup.async' = '").append(async).append("'");
+ ddl.append(",\n 'iotdb.lookup.async' = '").append(async).append("'");
}
ddl.append("\n)");
return ddl.toString();
diff --git
a/connectors/flink-iotdb-table-connector/flink-iotdb-table-connector-flink1/src/test/java/org/apache/iotdb/relational/flink/table/IoTDBRelationalSourcePushDownPlannerTest.java
b/connectors/flink-iotdb-table-connector/flink-iotdb-table-connector-flink1/src/test/java/org/apache/iotdb/relational/flink/table/IoTDBRelationalSourcePushDownPlannerTest.java
index 497a85f..559efea 100644
---
a/connectors/flink-iotdb-table-connector/flink-iotdb-table-connector-flink1/src/test/java/org/apache/iotdb/relational/flink/table/IoTDBRelationalSourcePushDownPlannerTest.java
+++
b/connectors/flink-iotdb-table-connector/flink-iotdb-table-connector-flink1/src/test/java/org/apache/iotdb/relational/flink/table/IoTDBRelationalSourcePushDownPlannerTest.java
@@ -50,13 +50,13 @@ public class IoTDBRelationalSourcePushDownPlannerTest {
+ " `humidity` DOUBLE\n"
+ ") WITH (\n"
+ " 'connector' = 'iotdb-relational',\n"
- + " 'nodeUrls' = '127.0.0.1:6667',\n"
- + " 'user' = 'root',\n"
- + " 'password' = 'root',\n"
- + " 'database' = 'test',\n"
- + " 'table' = 'sensor',\n"
- + " 'time-column' = 'time',\n"
- + " 'tag-columns' = 'device_id'\n"
+ + " 'iotdb.node-urls' = '127.0.0.1:6667',\n"
+ + " 'iotdb.user' = 'root',\n"
+ + " 'iotdb.password' = 'root',\n"
+ + " 'iotdb.database' = 'test',\n"
+ + " 'iotdb.table' = 'sensor',\n"
+ + " 'iotdb.time-column' = 'time',\n"
+ + " 'iotdb.tag-columns' = 'device_id'\n"
+ ")";
@Test