This is an automated email from the ASF dual-hosted git repository.
haonan pushed a commit to branch rc/1.2.0
in repository https://gitbox.apache.org/repos/asf/iotdb.git
The following commit(s) were added to refs/heads/rc/1.2.0 by this push:
new a05fbfd3d7a [To rel/1.2] Support multiple creation of views & Fix
illegal view creation (#10061)
a05fbfd3d7a is described below
commit a05fbfd3d7a9463442da580c764bfa943fad7931
Author: 橘子 <[email protected]>
AuthorDate: Wed Jun 7 19:22:28 2023 +0800
[To rel/1.2] Support multiple creation of views & Fix illegal view creation
(#10061)
---
.../view/IoTDBCreateAndShowViewIT.java | 162 +++++++++++++++++++--
.../metadata/view/UnsupportedViewException.java} | 24 ++-
.../view/ViewContainsAggregationException.java} | 13 +-
.../iotdb/db/metadata/view/ViewPathType.java | 8 +-
.../apache/iotdb/db/metadata/view/ViewPaths.java | 26 ++++
.../iotdb/db/mpp/plan/analyze/AnalyzeVisitor.java | 60 ++++++--
.../iotdb/db/mpp/plan/analyze/SelectIntoUtils.java | 7 +
.../iotdb/db/mpp/plan/parser/ASTVisitor.java | 63 +++++++-
.../metadata/view/AlterLogicalViewStatement.java | 11 ++
.../metadata/view/CreateLogicalViewStatement.java | 51 ++++++-
10 files changed, 375 insertions(+), 50 deletions(-)
diff --git
a/integration-test/src/test/java/org/apache/iotdb/db/it/view/IoTDBCreateAndShowViewIT.java
b/integration-test/src/test/java/org/apache/iotdb/db/it/schema/view/IoTDBCreateAndShowViewIT.java
similarity index 61%
rename from
integration-test/src/test/java/org/apache/iotdb/db/it/view/IoTDBCreateAndShowViewIT.java
rename to
integration-test/src/test/java/org/apache/iotdb/db/it/schema/view/IoTDBCreateAndShowViewIT.java
index fb04ad91a08..5ab968aaf8f 100644
---
a/integration-test/src/test/java/org/apache/iotdb/db/it/view/IoTDBCreateAndShowViewIT.java
+++
b/integration-test/src/test/java/org/apache/iotdb/db/it/schema/view/IoTDBCreateAndShowViewIT.java
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.iotdb.db.it.view;
+package org.apache.iotdb.db.it.schema.view;
import org.apache.iotdb.db.mpp.common.header.ColumnHeaderConstant;
import org.apache.iotdb.it.env.EnvFactory;
@@ -25,6 +25,7 @@ import org.apache.iotdb.itbase.category.ClusterIT;
import org.apache.iotdb.itbase.category.LocalStandaloneIT;
import org.junit.AfterClass;
+import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.experimental.categories.Category;
@@ -32,6 +33,7 @@ import org.junit.runner.RunWith;
import java.sql.Connection;
import java.sql.ResultSet;
+import java.sql.SQLException;
import java.sql.Statement;
import java.util.Arrays;
import java.util.HashSet;
@@ -46,7 +48,7 @@ import static org.junit.Assert.fail;
@Category({LocalStandaloneIT.class, ClusterIT.class})
public class IoTDBCreateAndShowViewIT {
- private static String[] sqls =
+ private static final String[] SQLs =
new String[] {
"CREATE DATABASE root.db;",
"CREATE DATABASE root.myview;",
@@ -60,8 +62,23 @@ public class IoTDBCreateAndShowViewIT {
"CREATE VIEW root.myview.d02(s01, s02) AS SELECT s01, s02 FROM
root.db.d02;",
"CREATE VIEW root.cal_view.avg AS SELECT (s01+s02)/2 FROM
root.db.d01;",
"CREATE VIEW root.cal_view(multiple, divide) AS SELECT s01*s02,
s01/s02 FROM root.db.d02;",
- "CREATE VIEW root.cal_view(agg_max1, agg_max2) AS SELECT
MAX_VALUE(s01) FROM root.db.d01, root.db.d02 ;",
"CREATE VIEW root.cal_view.cast_view AS SELECT CAST(s01 as TEXT) FROM
root.db.d01;",
+ "CREATE VIEW root.multi_view.all_in_one(${2}_${3}) AS SELECT * FROM
root.db.**;",
+ "CREATE VIEW root.copy_view.${2}(${3}) AS SELECT * FROM root.db.**;"
+ };
+
+ private static final String[] unsupportedSQLs =
+ new String[] {
+ "CREATE VIEW root.myview.nested_view AS root.myview.d01.s01;",
+ "CREATE VIEW root.agg_view(agg_avg1, agg_avg2) AS SELECT AVG(s01)+1
FROM root.db.d01, root.db.d02;",
+ "CREATE VIEW root.agg_view(agg_max1, agg_max2) AS SELECT
MAX_VALUE(s01) FROM root.db.d01, root.db.d02;",
+ "CREATE VIEW root.myview.illegal_view AS root.myview.d01.s01 + 1;",
+ "CREATE VIEW root.multi_view($illegal_name) AS root.db.d01.s01;",
+ "CREATE VIEW root.multi_view.multi_nodes(${3}.${2}) AS SELECT * FROM
root.db.**;",
+ "CREATE VIEW root.copy_view.$illegal_char(${3}) AS SELECT * FROM
root.db.**;",
+ "CREATE VIEW root.copy_view.mismatched_count(${3}) AS SELECT * FROM
root.db.**;",
+ "CREATE VIEW root.repeated_view(a, a) AS SELECT s01, s02 FROM
root.db.d01;",
+ "CREATE VIEW root.repeated_view.abc, root.repeated_view.abc AS SELECT
s01, s02 FROM root.db.d01;",
};
@BeforeClass
@@ -78,7 +95,7 @@ public class IoTDBCreateAndShowViewIT {
// region Test show timesereis
@Test
- public void showOriginTimeseries() {
+ public void testShowOriginTimeseries() {
Set<String> retSet =
new HashSet<>(
@@ -127,7 +144,7 @@ public class IoTDBCreateAndShowViewIT {
}
@Test
- public void showAliasViewsWithShowTimeseries() {
+ public void testShowAliasViewsWithShowTimeseries() {
Set<String> retSet =
new HashSet<>(
@@ -176,7 +193,7 @@ public class IoTDBCreateAndShowViewIT {
}
@Test
- public void showViewsWithCalculationWithShowTimeseries() {
+ public void testShowViewsWithCalculationWithShowTimeseries() {
Set<String> retSet =
new HashSet<>(
@@ -184,14 +201,110 @@ public class IoTDBCreateAndShowViewIT {
"root.cal_view.avg,null,root.cal_view,DOUBLE,null,null,null,null,logical;",
"root.cal_view.multiple,null,root.cal_view,DOUBLE,null,null,null,null,logical;",
"root.cal_view.divide,null,root.cal_view,DOUBLE,null,null,null,null,logical;",
-
"root.cal_view.agg_max1,null,root.cal_view,INT32,null,null,null,null,logical;",
-
"root.cal_view.agg_max2,null,root.cal_view,INT32,null,null,null,null,logical;",
"root.cal_view.cast_view,null,root.cal_view,TEXT,null,null,null,null,logical;"));
try (Connection connection = EnvFactory.getEnv().getConnection();
Statement statement = connection.createStatement()) {
- ResultSet resultSet = statement.executeQuery("SHOW TiMESERIES
root.cal_view.*;");
+ ResultSet resultSet = statement.executeQuery("SHOW TiMESERIES
root.cal_view.**;");
+ int count = 0;
+ while (resultSet.next()) {
+ String ans =
+ resultSet.getString(ColumnHeaderConstant.TIMESERIES)
+ + ","
+ + resultSet.getString(ColumnHeaderConstant.ALIAS)
+ + ","
+ + resultSet.getString(ColumnHeaderConstant.DATABASE)
+ + ","
+ + resultSet.getString(ColumnHeaderConstant.DATATYPE)
+ + ","
+ + resultSet.getString(ColumnHeaderConstant.ENCODING)
+ + ","
+ + resultSet.getString(ColumnHeaderConstant.COMPRESSION)
+ + ","
+ + resultSet.getString(ColumnHeaderConstant.TAGS)
+ + ","
+ + resultSet.getString(ColumnHeaderConstant.ATTRIBUTES)
+ + ","
+ + resultSet.getString(ColumnHeaderConstant.VIEW_TYPE)
+ + ";";
+
+ System.out.println("actual result:" + ans);
+ assertTrue(retSet.contains(ans));
+ count++;
+ }
+ assertEquals(retSet.size(), count);
+ resultSet.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail(e.getMessage());
+ }
+ }
+
+ @Test
+ public void testShowViewsWithMultiCreationWithShowTimeseriesPart01() {
+
+ Set<String> retSet =
+ new HashSet<>(
+ Arrays.asList(
+
"root.multi_view.all_in_one.d01_s01,null,root.multi_view,INT32,null,null,null,null,logical;",
+
"root.multi_view.all_in_one.d01_s02,null,root.multi_view,INT32,null,null,null,null,logical;",
+
"root.multi_view.all_in_one.d02_s01,null,root.multi_view,INT32,null,null,null,null,logical;",
+
"root.multi_view.all_in_one.d02_s02,null,root.multi_view,INT32,null,null,null,null,logical;"));
+
+ try (Connection connection = EnvFactory.getEnv().getConnection();
+ Statement statement = connection.createStatement()) {
+
+ ResultSet resultSet = statement.executeQuery("SHOW TiMESERIES
root.multi_view.**;");
+ int count = 0;
+ while (resultSet.next()) {
+ String ans =
+ resultSet.getString(ColumnHeaderConstant.TIMESERIES)
+ + ","
+ + resultSet.getString(ColumnHeaderConstant.ALIAS)
+ + ","
+ + resultSet.getString(ColumnHeaderConstant.DATABASE)
+ + ","
+ + resultSet.getString(ColumnHeaderConstant.DATATYPE)
+ + ","
+ + resultSet.getString(ColumnHeaderConstant.ENCODING)
+ + ","
+ + resultSet.getString(ColumnHeaderConstant.COMPRESSION)
+ + ","
+ + resultSet.getString(ColumnHeaderConstant.TAGS)
+ + ","
+ + resultSet.getString(ColumnHeaderConstant.ATTRIBUTES)
+ + ","
+ + resultSet.getString(ColumnHeaderConstant.VIEW_TYPE)
+ + ";";
+
+ System.out.println("actual result:" + ans);
+ assertTrue(retSet.contains(ans));
+ count++;
+ }
+ assertEquals(retSet.size(), count);
+ resultSet.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail(e.getMessage());
+ }
+ }
+
+ @Test
+ public void testShowViewsWithMultiCreationWithShowTimeseriesPart02() {
+
+ Set<String> retSet =
+ new HashSet<>(
+ Arrays.asList(
+
"root.copy_view.d01.s01,null,root.copy_view,INT32,null,null,null,null,logical;",
+
"root.copy_view.d01.s02,null,root.copy_view,INT32,null,null,null,null,logical;",
+
"root.copy_view.d02.s01,null,root.copy_view,INT32,null,null,null,null,logical;",
+
"root.copy_view.d02.s02,null,root.copy_view,INT32,null,null,null,null,logical;"));
+
+ try (Connection connection = EnvFactory.getEnv().getConnection();
+ Statement statement = connection.createStatement()) {
+
+ ResultSet resultSet = statement.executeQuery("SHOW TiMESERIES
root.copy_view.**;");
int count = 0;
while (resultSet.next()) {
String ans =
@@ -229,7 +342,7 @@ public class IoTDBCreateAndShowViewIT {
// region Test Show View
@Test
- public void showAllViewsWithShowView() {
+ public void testShowAllViewsWithShowView() {
Set<String> retSet =
new HashSet<>(
@@ -241,9 +354,15 @@ public class IoTDBCreateAndShowViewIT {
"root.cal_view.avg,root.cal_view,DOUBLE,null,null,logical,(root.db.d01.s01 +
root.db.d01.s02) / 2;",
"root.cal_view.multiple,root.cal_view,DOUBLE,null,null,logical,root.db.d02.s01
* root.db.d02.s02;",
"root.cal_view.divide,root.cal_view,DOUBLE,null,null,logical,root.db.d02.s01 /
root.db.d02.s02;",
-
"root.cal_view.agg_max1,root.cal_view,INT32,null,null,logical,max_value(root.db.d01.s01);",
-
"root.cal_view.agg_max2,root.cal_view,INT32,null,null,logical,max_value(root.db.d02.s01);",
-
"root.cal_view.cast_view,root.cal_view,TEXT,null,null,logical,cast(type=TEXT)(root.db.d01.s01);"));
+
"root.cal_view.cast_view,root.cal_view,TEXT,null,null,logical,cast(type=TEXT)(root.db.d01.s01);",
+
"root.multi_view.all_in_one.d01_s01,root.multi_view,INT32,null,null,logical,root.db.d01.s01;",
+
"root.multi_view.all_in_one.d01_s02,root.multi_view,INT32,null,null,logical,root.db.d01.s02;",
+
"root.multi_view.all_in_one.d02_s01,root.multi_view,INT32,null,null,logical,root.db.d02.s01;",
+
"root.multi_view.all_in_one.d02_s02,root.multi_view,INT32,null,null,logical,root.db.d02.s02;",
+
"root.copy_view.d01.s01,root.copy_view,INT32,null,null,logical,root.db.d01.s01;",
+
"root.copy_view.d01.s02,root.copy_view,INT32,null,null,logical,root.db.d01.s02;",
+
"root.copy_view.d02.s01,root.copy_view,INT32,null,null,logical,root.db.d02.s01;",
+
"root.copy_view.d02.s02,root.copy_view,INT32,null,null,logical,root.db.d02.s02;"));
try (Connection connection = EnvFactory.getEnv().getConnection();
Statement statement = connection.createStatement()) {
@@ -280,11 +399,26 @@ public class IoTDBCreateAndShowViewIT {
}
// endregion
+ // region unsupported SQLs
+ @Test
+ public void testUnsupportedSQLs() {
+ for (String unsupportedSQL : unsupportedSQLs) {
+ try (Connection connection = EnvFactory.getEnv().getConnection();
+ Statement statement = connection.createStatement()) {
+ statement.execute(String.format(unsupportedSQL));
+ Assert.fail(String.format("SQL [%s] should fail but no exception
thrown.", unsupportedSQL));
+ } catch (SQLException ignored) {
+ }
+ }
+ }
+
+ // endregion
+
private static void createSchema() {
try (Connection connection = EnvFactory.getEnv().getConnection();
Statement statement = connection.createStatement()) {
- for (String sql : sqls) {
+ for (String sql : SQLs) {
statement.execute(sql);
}
} catch (Exception e) {
diff --git
a/server/src/main/java/org/apache/iotdb/db/metadata/view/ViewPathType.java
b/server/src/main/java/org/apache/iotdb/db/exception/metadata/view/UnsupportedViewException.java
similarity index 52%
copy from
server/src/main/java/org/apache/iotdb/db/metadata/view/ViewPathType.java
copy to
server/src/main/java/org/apache/iotdb/db/exception/metadata/view/UnsupportedViewException.java
index 668adbb07d4..b4428af09b3 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/view/ViewPathType.java
+++
b/server/src/main/java/org/apache/iotdb/db/exception/metadata/view/UnsupportedViewException.java
@@ -16,11 +16,25 @@
* specific language governing permissions and limitations
* under the License.
*/
+package org.apache.iotdb.db.exception.metadata.view;
-package org.apache.iotdb.db.metadata.view;
+import org.apache.iotdb.commons.exception.MetadataException;
+import org.apache.iotdb.rpc.TSStatusCode;
-public enum ViewPathType {
- FULL_PATH_LIST,
- PATHS_GROUP,
- QUERY_STATEMENT
+public class UnsupportedViewException extends MetadataException {
+
+ private static final String VIEW_IS_UNSUPPORTED = "View unsupported,
because: %s";
+
+ public UnsupportedViewException(String message) {
+ super(
+ String.format(VIEW_IS_UNSUPPORTED, message),
+ TSStatusCode.UNSUPPORTED_OPERATION.getStatusCode());
+ }
+
+ public UnsupportedViewException(String message, boolean isUserException) {
+ super(
+ String.format(VIEW_IS_UNSUPPORTED, message),
+ TSStatusCode.UNSUPPORTED_OPERATION.getStatusCode(),
+ isUserException);
+ }
}
diff --git
a/server/src/main/java/org/apache/iotdb/db/metadata/view/ViewPathType.java
b/server/src/main/java/org/apache/iotdb/db/exception/metadata/view/ViewContainsAggregationException.java
similarity index 64%
copy from
server/src/main/java/org/apache/iotdb/db/metadata/view/ViewPathType.java
copy to
server/src/main/java/org/apache/iotdb/db/exception/metadata/view/ViewContainsAggregationException.java
index 668adbb07d4..50cf8a8839b 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/view/ViewPathType.java
+++
b/server/src/main/java/org/apache/iotdb/db/exception/metadata/view/ViewContainsAggregationException.java
@@ -16,11 +16,14 @@
* specific language governing permissions and limitations
* under the License.
*/
+package org.apache.iotdb.db.exception.metadata.view;
-package org.apache.iotdb.db.metadata.view;
+public class ViewContainsAggregationException extends UnsupportedViewException
{
-public enum ViewPathType {
- FULL_PATH_LIST,
- PATHS_GROUP,
- QUERY_STATEMENT
+ private static final String VIEW_CONTAINS_AGGREGATION_FUNCTION =
+ "This view contains aggregation function(s) named [%s]";
+
+ public ViewContainsAggregationException(String namesOfAggregationFunctions) {
+ super(String.format(VIEW_CONTAINS_AGGREGATION_FUNCTION,
namesOfAggregationFunctions), true);
+ }
}
diff --git
a/server/src/main/java/org/apache/iotdb/db/metadata/view/ViewPathType.java
b/server/src/main/java/org/apache/iotdb/db/metadata/view/ViewPathType.java
index 668adbb07d4..e34f6f87bfe 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/view/ViewPathType.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/view/ViewPathType.java
@@ -20,7 +20,13 @@
package org.apache.iotdb.db.metadata.view;
public enum ViewPathType {
+ /** Example: root.db.d01.s01, root.db.d02.s01, root.db.d02.s02 */
FULL_PATH_LIST,
+ /** Example: root.db(d01.s01, d02.s02, status) */
PATHS_GROUP,
- QUERY_STATEMENT
+ /** Example: SELECT s01, s02 FROM root.db.*; */
+ QUERY_STATEMENT,
+
+ /** Example: root.db.view(${2}_temperature) */
+ BATCH_GENERATION,
}
diff --git
a/server/src/main/java/org/apache/iotdb/db/metadata/view/ViewPaths.java
b/server/src/main/java/org/apache/iotdb/db/metadata/view/ViewPaths.java
index a0d86d1496b..3a969841166 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/view/ViewPaths.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/view/ViewPaths.java
@@ -20,8 +20,12 @@
package org.apache.iotdb.db.metadata.view;
import org.apache.iotdb.commons.path.PartialPath;
+import org.apache.iotdb.db.exception.metadata.view.UnsupportedViewException;
+import
org.apache.iotdb.db.exception.metadata.view.ViewContainsAggregationException;
import org.apache.iotdb.db.mpp.plan.expression.Expression;
import org.apache.iotdb.db.mpp.plan.expression.leaf.TimeSeriesOperand;
+import
org.apache.iotdb.db.mpp.plan.expression.visitor.CollectAggregationExpressionsVisitor;
+import org.apache.iotdb.tsfile.utils.Pair;
import java.util.ArrayList;
import java.util.List;
@@ -87,9 +91,31 @@ public class ViewPaths {
}
} else if (this.viewPathType == ViewPathType.QUERY_STATEMENT) {
// no nothing. expressions should be set by setExpressionsList
+ } else if (this.viewPathType == ViewPathType.BATCH_GENERATION) {
+ // source paths has no intoItem. target paths should not be converted to
expression.
}
}
+ /**
+ * Check all expression in this list, ensure that the views created using
them are legal. Check
+ * follows above rules: 1. A legal view can NOT contain aggregation
functions.
+ *
+ * @return If all check passed, return true; else return false with failure
message.
+ */
+ public static Pair<Boolean, UnsupportedViewException> checkExpressionList(
+ List<Expression> expressionsList) {
+ CollectAggregationExpressionsVisitor collectAggExpVisitor =
+ new CollectAggregationExpressionsVisitor();
+
+ for (Expression expression : expressionsList) {
+ List<Expression> aggList = collectAggExpVisitor.process(expression,
null);
+ if (aggList.size() > 0) {
+ return new Pair<>(false, new
ViewContainsAggregationException(aggList.get(0).toString()));
+ }
+ }
+ return new Pair<>(true, null);
+ }
+
public void setExpressionsList(List<Expression> expressionsList) {
this.expressionsList = expressionsList;
}
diff --git
a/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/AnalyzeVisitor.java
b/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/AnalyzeVisitor.java
index a96bd165a59..b20d445e3ba 100644
---
a/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/AnalyzeVisitor.java
+++
b/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/AnalyzeVisitor.java
@@ -46,6 +46,7 @@ import
org.apache.iotdb.db.engine.storagegroup.TsFileResourceStatus;
import org.apache.iotdb.db.exception.LoadFileException;
import org.apache.iotdb.db.exception.VerifyMetadataException;
import
org.apache.iotdb.db.exception.metadata.template.TemplateImcompatibeException;
+import org.apache.iotdb.db.exception.metadata.view.UnsupportedViewException;
import org.apache.iotdb.db.exception.sql.MeasurementNotExistException;
import org.apache.iotdb.db.exception.sql.SemanticException;
import org.apache.iotdb.db.exception.sql.StatementAnalyzeException;
@@ -3170,6 +3171,8 @@ public class AnalyzeVisitor extends
StatementVisitor<Analysis, MPPQueryContext>
analysis.setWhereExpression(whereExpression);
}
+ // region view
+
/**
* Compute how many paths exist, get the schema tree and the number of
existed paths.
*
@@ -3304,13 +3307,30 @@ public class AnalyzeVisitor extends
StatementVisitor<Analysis, MPPQueryContext>
"The path " + checkResult.right + " is illegal."));
return;
}
- if (createLogicalViewStatement.getSourceExpressionList().size()
- != createLogicalViewStatement.getTargetPathList().size()) {
+ // make sure there are no redundant paths in targets. Please note that
redundant paths in source
+ // are legal!
+ List<PartialPath> targetPathList =
createLogicalViewStatement.getTargetPathList();
+ Set<String> targetStringSet = new HashSet<>();
+ for (PartialPath path : targetPathList) {
+ boolean repeatPathNotExist = targetStringSet.add(path.toString());
+ if (!repeatPathNotExist) {
+ analysis.setFinishQueryAfterAnalyze(true);
+ analysis.setFailStatus(
+ RpcUtils.getStatus(
+ TSStatusCode.ILLEGAL_PATH.getStatusCode(),
+ String.format("Path [%s] is redundant in target paths.",
path)));
+ return;
+ }
+ }
+ if (createLogicalViewStatement.getSourceExpressionList().size() !=
targetPathList.size()) {
analysis.setFinishQueryAfterAnalyze(true);
analysis.setFailStatus(
RpcUtils.getStatus(
TSStatusCode.UNSUPPORTED_OPERATION.getStatusCode(),
- "The number of target and source paths are miss matched! Please
check your SQL."));
+ String.format(
+ "The number of target paths (%d) and sources (%d) are miss
matched! Please check your SQL.",
+ createLogicalViewStatement.getTargetPathList().size(),
+
createLogicalViewStatement.getSourceExpressionList().size())));
return;
}
// make sure all paths are NOt under any template
@@ -3344,22 +3364,31 @@ public class AnalyzeVisitor extends
StatementVisitor<Analysis, MPPQueryContext>
if (queryAnalysisPair.right.isFinishQueryAfterAnalyze()) {
return analysis;
} else if (queryAnalysisPair.left != null) {
-
createLogicalViewStatement.setSourceExpressions(queryAnalysisPair.left);
+ try {
+
createLogicalViewStatement.setSourceExpressions(queryAnalysisPair.left);
+ } catch (UnsupportedViewException e) {
+ analysis.setFinishQueryAfterAnalyze(true);
+ analysis.setFailStatus(RpcUtils.getStatus(e.getErrorCode(),
e.getMessage()));
+ return analysis;
+ }
}
}
+ }
- // check target paths; check source expressions.
- checkPathsInCreateLogicalView(analysis, createLogicalViewStatement);
- if (analysis.isFinishQueryAfterAnalyze()) {
- return analysis;
- }
+ // use source and into item to generate target views
+ createLogicalViewStatement.parseIntoItemIfNecessary();
- // make sure there is no view in source
- List<Expression> sourceExpressionList =
createLogicalViewStatement.getSourceExpressionList();
- checkViewsInSource(analysis, sourceExpressionList, context);
- if (analysis.isFinishQueryAfterAnalyze()) {
- return analysis;
- }
+ // check target paths; check source expressions.
+ checkPathsInCreateLogicalView(analysis, createLogicalViewStatement);
+ if (analysis.isFinishQueryAfterAnalyze()) {
+ return analysis;
+ }
+
+ // make sure there is no view in source
+ List<Expression> sourceExpressionList =
createLogicalViewStatement.getSourceExpressionList();
+ checkViewsInSource(analysis, sourceExpressionList, context);
+ if (analysis.isFinishQueryAfterAnalyze()) {
+ return analysis;
}
// set schema partition info, this info will be used to split logical plan
node.
@@ -3388,4 +3417,5 @@ public class AnalyzeVisitor extends
StatementVisitor<Analysis, MPPQueryContext>
analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowLogicalViewHeader());
return analysis;
}
+ // endregion view
}
diff --git
a/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/SelectIntoUtils.java
b/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/SelectIntoUtils.java
index 46b076bc8f3..ede0384dfcb 100644
---
a/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/SelectIntoUtils.java
+++
b/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/SelectIntoUtils.java
@@ -26,6 +26,7 @@ import org.apache.iotdb.db.mpp.common.schematree.ISchemaTree;
import org.apache.iotdb.db.mpp.plan.expression.Expression;
import org.apache.iotdb.db.mpp.plan.expression.leaf.TimeSeriesOperand;
import org.apache.iotdb.db.utils.TypeInferenceUtils;
+import org.apache.iotdb.tsfile.common.constant.TsFileConstant;
import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
import org.apache.iotdb.tsfile.utils.Pair;
@@ -99,6 +100,12 @@ public class SelectIntoUtils {
resNode = matcher.replaceFirst(sourceNodes[index]);
matcher = LEVELED_PATH_TEMPLATE_PATTERN.matcher(resNode);
}
+ if (!TsFileConstant.NODE_NAME_PATTERN.matcher(resNode).matches()) {
+ throw new SemanticException(
+ String.format(
+ "Parsed node name %s is illegal, unquoted node name can only
consist of digits, characters and underscore, or start or end with wildcard",
+ resNode));
+ }
return resNode;
}
diff --git
a/server/src/main/java/org/apache/iotdb/db/mpp/plan/parser/ASTVisitor.java
b/server/src/main/java/org/apache/iotdb/db/mpp/plan/parser/ASTVisitor.java
index 57bf1fcee8e..12d7f31d7c4 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/parser/ASTVisitor.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/parser/ASTVisitor.java
@@ -1006,7 +1006,8 @@ public class ASTVisitor extends
IoTDBSqlParserBaseVisitor<Statement> {
parseViewTargetPaths(
ctx.viewTargetPaths(),
createLogicalViewStatement::setTargetFullPaths,
- createLogicalViewStatement::setTargetPathsGroup);
+ createLogicalViewStatement::setTargetPathsGroup,
+ createLogicalViewStatement::setTargetIntoItem);
// parse source
parseViewSourcePaths(
ctx.viewSourcePaths(),
@@ -1069,7 +1070,11 @@ public class ASTVisitor extends
IoTDBSqlParserBaseVisitor<Statement> {
parseViewTargetPaths(
ctx.viewTargetPaths(),
alterLogicalViewStatement::setTargetFullPaths,
- alterLogicalViewStatement::setTargetPathsGroup);
+ alterLogicalViewStatement::setTargetPathsGroup,
+ alterLogicalViewStatement::setTargetIntoItem);
+ if (alterLogicalViewStatement.getIntoItem() != null) {
+ throw new SemanticException("Can not use char '$' or into item in alter
view statement.");
+ }
// parse source
parseViewSourcePaths(
ctx.viewSourcePaths(),
@@ -1080,7 +1085,27 @@ public class ASTVisitor extends
IoTDBSqlParserBaseVisitor<Statement> {
return alterLogicalViewStatement;
}
- // parse suffix paths in logical view
+ // parse suffix paths in logical view with into item
+ private PartialPath
parseViewPrefixPathWithInto(IoTDBSqlParser.PrefixPathContext ctx) {
+ List<IoTDBSqlParser.NodeNameContext> nodeNames = ctx.nodeName();
+ String[] path = new String[nodeNames.size() + 1];
+ path[0] = ctx.ROOT().getText();
+ for (int i = 0; i < nodeNames.size(); i++) {
+ path[i + 1] = parseNodeStringInIntoPath(nodeNames.get(i).getText());
+ }
+ return new PartialPath(path);
+ }
+
+ private PartialPath
parseViewSuffixPatWithInto(IoTDBSqlParser.ViewSuffixPathsContext ctx) {
+ List<IoTDBSqlParser.NodeNameWithoutWildcardContext> nodeNamesWithoutStar =
+ ctx.nodeNameWithoutWildcard();
+ String[] nodeList = new String[nodeNamesWithoutStar.size()];
+ for (int i = 0; i < nodeNamesWithoutStar.size(); i++) {
+ nodeList[i] =
parseNodeStringInIntoPath(nodeNamesWithoutStar.get(i).getText());
+ }
+ return new PartialPath(nodeList);
+ }
+
private PartialPath
parseViewSuffixPath(IoTDBSqlParser.ViewSuffixPathsContext ctx) {
List<IoTDBSqlParser.NodeNameWithoutWildcardContext> nodeNamesWithoutStar =
ctx.nodeNameWithoutWildcard();
@@ -1095,7 +1120,8 @@ public class ASTVisitor extends
IoTDBSqlParserBaseVisitor<Statement> {
private void parseViewTargetPaths(
IoTDBSqlParser.ViewTargetPathsContext ctx,
Consumer<List<PartialPath>> setTargetFullPaths,
- BiConsumer<PartialPath, List<PartialPath>> setTargetPathsGroup) {
+ BiConsumer<PartialPath, List<PartialPath>> setTargetPathsGroup,
+ Consumer<IntoItem> setTargetIntoItem) {
// full paths
if (ctx.fullPath() != null && ctx.fullPath().size() > 0) {
List<IoTDBSqlParser.FullPathContext> fullPathContextList =
ctx.fullPath();
@@ -1110,13 +1136,34 @@ public class ASTVisitor extends
IoTDBSqlParserBaseVisitor<Statement> {
&& ctx.viewSuffixPaths() != null
&& ctx.viewSuffixPaths().size() > 0) {
IoTDBSqlParser.PrefixPathContext prefixPathContext = ctx.prefixPath();
- PartialPath prefixPath = parsePrefixPath(prefixPathContext);
List<IoTDBSqlParser.ViewSuffixPathsContext> suffixPathContextList =
ctx.viewSuffixPaths();
List<PartialPath> suffixPathList = new ArrayList<>();
- for (IoTDBSqlParser.ViewSuffixPathsContext suffixPathContext :
suffixPathContextList) {
- suffixPathList.add(parseViewSuffixPath(suffixPathContext));
+ PartialPath prefixPath = null;
+ boolean isMultipleCreating = false;
+ try {
+ prefixPath = parsePrefixPath(prefixPathContext);
+ for (IoTDBSqlParser.ViewSuffixPathsContext suffixPathContext :
suffixPathContextList) {
+ suffixPathList.add(parseViewSuffixPath(suffixPathContext));
+ }
+ } catch (SemanticException e) {
+ // there is '$', '{', '}' in this statement
+ isMultipleCreating = true;
+ suffixPathList.clear();
+ }
+ if (!isMultipleCreating) {
+ setTargetPathsGroup.accept(prefixPath, suffixPathList);
+ } else {
+ prefixPath = parseViewPrefixPathWithInto(prefixPathContext);
+ for (IoTDBSqlParser.ViewSuffixPathsContext suffixPathContext :
suffixPathContextList) {
+ suffixPathList.add(parseViewSuffixPatWithInto(suffixPathContext));
+ }
+ List<String> intoMeasurementList = new ArrayList<>();
+ for (PartialPath path : suffixPathList) {
+ intoMeasurementList.add(path.toString());
+ }
+ IntoItem intoItem = new IntoItem(prefixPath, intoMeasurementList,
false);
+ setTargetIntoItem.accept(intoItem);
}
- setTargetPathsGroup.accept(prefixPath, suffixPathList);
}
}
diff --git
a/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/metadata/view/AlterLogicalViewStatement.java
b/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/metadata/view/AlterLogicalViewStatement.java
index 899d4f0b3be..fc7507e2b45 100644
---
a/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/metadata/view/AlterLogicalViewStatement.java
+++
b/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/metadata/view/AlterLogicalViewStatement.java
@@ -27,6 +27,7 @@ import
org.apache.iotdb.db.mpp.plan.statement.IConfigStatement;
import org.apache.iotdb.db.mpp.plan.statement.Statement;
import org.apache.iotdb.db.mpp.plan.statement.StatementType;
import org.apache.iotdb.db.mpp.plan.statement.StatementVisitor;
+import org.apache.iotdb.db.mpp.plan.statement.component.IntoItem;
import org.apache.iotdb.db.mpp.plan.statement.crud.QueryStatement;
import java.util.List;
@@ -39,6 +40,7 @@ public class AlterLogicalViewStatement extends Statement
implements IConfigState
// the paths of sources
private ViewPaths sourcePaths;
private QueryStatement queryStatement;
+ private IntoItem intoItem;
public AlterLogicalViewStatement() {
super();
@@ -101,6 +103,15 @@ public class AlterLogicalViewStatement extends Statement
implements IConfigState
this.targetPaths.setSuffixOfPathsGroup(suffixPaths);
this.targetPaths.generateFullPathsFromPathsGroup();
}
+
+ public void setTargetIntoItem(IntoItem intoItem) {
+ this.targetPaths.setViewPathType(ViewPathType.BATCH_GENERATION);
+ this.intoItem = intoItem;
+ }
+
+ public IntoItem getIntoItem() {
+ return this.intoItem;
+ }
// endregion
@Override
diff --git
a/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/metadata/view/CreateLogicalViewStatement.java
b/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/metadata/view/CreateLogicalViewStatement.java
index e70c5772345..9ecd71fce8d 100644
---
a/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/metadata/view/CreateLogicalViewStatement.java
+++
b/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/metadata/view/CreateLogicalViewStatement.java
@@ -21,15 +21,22 @@ package
org.apache.iotdb.db.mpp.plan.statement.metadata.view;
import org.apache.iotdb.commons.path.PartialPath;
import org.apache.iotdb.commons.schema.view.viewExpression.ViewExpression;
+import org.apache.iotdb.db.exception.metadata.view.UnsupportedViewException;
import org.apache.iotdb.db.metadata.view.ViewPathType;
import org.apache.iotdb.db.metadata.view.ViewPaths;
+import org.apache.iotdb.db.mpp.plan.analyze.SelectIntoUtils;
import org.apache.iotdb.db.mpp.plan.expression.Expression;
+import org.apache.iotdb.db.mpp.plan.expression.leaf.TimeSeriesOperand;
import org.apache.iotdb.db.mpp.plan.statement.Statement;
import org.apache.iotdb.db.mpp.plan.statement.StatementType;
import org.apache.iotdb.db.mpp.plan.statement.StatementVisitor;
+import org.apache.iotdb.db.mpp.plan.statement.component.IntoComponent;
+import org.apache.iotdb.db.mpp.plan.statement.component.IntoItem;
import org.apache.iotdb.db.mpp.plan.statement.crud.QueryStatement;
import org.apache.iotdb.tsfile.utils.Pair;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
/** CREATE LOGICAL VIEW statement. */
@@ -37,6 +44,7 @@ public class CreateLogicalViewStatement extends Statement {
// the paths of this view
private ViewPaths targetPaths;
+ private IntoItem batchGenerationItem;
// the paths of sources
private ViewPaths sourcePaths;
@@ -113,8 +121,16 @@ public class CreateLogicalViewStatement extends Statement {
*
* @param expressionList
*/
- public void setSourceExpressions(List<Expression> expressionList) {
- this.sourcePaths.setExpressionsList(expressionList);
+ public void setSourceExpressions(List<Expression> expressionList)
+ throws UnsupportedViewException {
+ // check expressions, make sure no aggregation function expression
+ Pair<Boolean, UnsupportedViewException> checkResult =
+ ViewPaths.checkExpressionList(expressionList);
+ if (checkResult.left) {
+ this.sourcePaths.setExpressionsList(expressionList);
+ } else {
+ throw checkResult.right;
+ }
}
// set target paths
@@ -138,6 +154,37 @@ public class CreateLogicalViewStatement extends Statement {
this.viewExpression = viewExpression;
}
+ public void setTargetIntoItem(IntoItem intoItem) {
+ this.targetPaths.setViewPathType(ViewPathType.BATCH_GENERATION);
+ this.batchGenerationItem = intoItem;
+ }
+
+ public void parseIntoItemIfNecessary() {
+ if (this.batchGenerationItem != null) {
+ List<Expression> sourceExpressionList = this.getSourceExpressionList();
+ IntoComponent intoComponent =
+ new
IntoComponent(Collections.singletonList(this.batchGenerationItem));
+ intoComponent.validate(sourceExpressionList);
+ IntoComponent.IntoPathIterator intoPathIterator =
intoComponent.getIntoPathIterator();
+ List<PartialPath> targetPathsList = new ArrayList<>();
+ for (Expression sourceColumn : sourceExpressionList) {
+ PartialPath deviceTemplate = intoPathIterator.getDeviceTemplate();
+ String measurementTemplate = intoPathIterator.getMeasurementTemplate();
+
+ if (sourceColumn instanceof TimeSeriesOperand) {
+ PartialPath sourcePath = ((TimeSeriesOperand)
sourceColumn).getPath();
+ targetPathsList.add(
+ SelectIntoUtils.constructTargetPath(sourcePath, deviceTemplate,
measurementTemplate));
+ } else {
+ throw new RuntimeException(
+ new UnsupportedViewException(
+ "Cannot create views using data sources with calculated
expressions while using into item."));
+ }
+ }
+ this.targetPaths.setFullPathList(targetPathsList);
+ }
+ }
+
// endregion
// region Interfaces for checking