diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/QueryExecution.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/QueryExecution.java index c63937996b922..77267b369f05f 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/QueryExecution.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/QueryExecution.java @@ -252,7 +252,7 @@ private ExecutionResult retry() { } private boolean skipExecute() { - return analysis.canSkipExecute(context); + return analysis.isFailed() || analysis.isFinishQueryAfterAnalyze(); } private void constructResultForMemorySource() { diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/memory/TableModelStatementMemorySourceVisitor.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/memory/TableModelStatementMemorySourceVisitor.java index 932d941979223..b3ee230d2eed7 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/memory/TableModelStatementMemorySourceVisitor.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/memory/TableModelStatementMemorySourceVisitor.java @@ -130,6 +130,61 @@ public StatementMemorySource visitCountDevice( node.getTsBlock(context.getAnalysis()), node.getDataSetHeader()); } + @Override + public StatementMemorySource visitDescribeQuery( + org.apache.iotdb.db.queryengine.plan.relational.sql.ast.DescribeQuery node, + TableModelStatementMemorySourceContext context) { + + java.util.List columnHeaders = + new java.util.ArrayList<>(); + columnHeaders.add( + new org.apache.iotdb.commons.schema.column.ColumnHeader( + "Column", org.apache.tsfile.enums.TSDataType.TEXT)); + columnHeaders.add( + new org.apache.iotdb.commons.schema.column.ColumnHeader( + "Type", org.apache.tsfile.enums.TSDataType.TEXT)); + + org.apache.iotdb.db.queryengine.common.header.DatasetHeader datasetHeader = + new org.apache.iotdb.db.queryengine.common.header.DatasetHeader(columnHeaders, true); + + java.util.List columnNames = new java.util.ArrayList<>(); + java.util.List columnTypes = new java.util.ArrayList<>(); + + context + .getAnalysis() + .getOutputDescriptor() + .getVisibleFields() + .forEach( + field -> { + columnNames.add(field.getName().orElse("unknown")); + columnTypes.add(field.getType().toString()); + }); + + org.apache.tsfile.read.common.block.TsBlockBuilder builder = + new org.apache.tsfile.read.common.block.TsBlockBuilder( + java.util.Arrays.asList( + org.apache.tsfile.enums.TSDataType.TEXT, org.apache.tsfile.enums.TSDataType.TEXT)); + + for (int i = 0; i < columnNames.size(); i++) { + builder.getTimeColumnBuilder().writeLong(0); + + builder + .getColumnBuilder(0) + .writeBinary( + new org.apache.tsfile.utils.Binary( + columnNames.get(i).getBytes(java.nio.charset.StandardCharsets.UTF_8))); + builder + .getColumnBuilder(1) + .writeBinary( + new org.apache.tsfile.utils.Binary( + columnTypes.get(i).getBytes(java.nio.charset.StandardCharsets.UTF_8))); + + builder.declarePosition(); + } + + return new StatementMemorySource(builder.build(), datasetHeader); + } + private List mergeExplainResults( Map, Pair>> cteExplainResults, List mainExplainResult) { diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/Analysis.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/Analysis.java index 4a0fe9daa570c..c0497b431423b 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/Analysis.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/Analysis.java @@ -257,6 +257,7 @@ public class Analysis implements IAnalysis { private boolean emptyDataSource = false; private boolean isQuery = false; + private boolean isDescribe = false; // SqlParser is needed during query planning phase for executing uncorrelated scalar subqueries // in advance (predicate folding). The planner needs to parse and execute these subqueries @@ -1552,6 +1553,14 @@ public void setInsert(Insert insert) { this.insert = insert; } + public void setDescribe(boolean isDescribe) { + this.isDescribe = isDescribe; + } + + public boolean isDescribe() { + return isDescribe; + } + public Insert getInsert() { return insert; } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/StatementAnalyzer.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/StatementAnalyzer.java index bc6d54c37e7fa..5a720b6361814 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/StatementAnalyzer.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/StatementAnalyzer.java @@ -80,6 +80,7 @@ import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Delete; import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.DeleteDevice; import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.DereferenceExpression; +import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.DescribeQuery; import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.DescribeTable; import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.DropColumn; import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.DropDB; @@ -850,6 +851,22 @@ protected Scope visitExplain(Explain node, Optional context) { return visitQuery((Query) node.getStatement(), context); } + @Override + protected Scope visitDescribeQuery(DescribeQuery node, Optional context) { + analysis.setFinishQueryAfterAnalyze(true); + Scope scope = visitQuery(node.getQuery(), context); + + RelationType outputDescriptor = analysis.getOutputDescriptor(); + for (Field field : outputDescriptor.getVisibleFields()) { + String name = field.getName().orElse("unknown"); + String type = field.getType().toString(); + System.out.println("DESCRIBE_DEBUG: Column=" + name + ", Type=" + type); + } + + analysis.setDescribe(true); + return scope; + } + @Override protected Scope visitExplainAnalyze(ExplainAnalyze node, Optional context) { queryContext.setExplainType(ExplainType.EXPLAIN_ANALYZE); diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/AstVisitor.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/AstVisitor.java index 13925ae392029..154e1d0a01a07 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/AstVisitor.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/AstVisitor.java @@ -449,6 +449,10 @@ protected R visitDescribeTable(DescribeTable node, C context) { return visitStatement(node, context); } + protected R visitDescribeQuery(DescribeQuery node, C context) { + return visitStatement(node, context); + } + protected R visitSetProperties(SetProperties node, C context) { return visitStatement(node, context); } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/DescribeQuery.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/DescribeQuery.java new file mode 100644 index 0000000000000..e715a8a1056e1 --- /dev/null +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/DescribeQuery.java @@ -0,0 +1,81 @@ +/* + * 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.db.queryengine.plan.relational.sql.ast; + +import com.google.common.collect.ImmutableList; +import org.apache.tsfile.utils.RamUsageEstimator; + +import java.util.List; +import java.util.Objects; + +import static java.util.Objects.requireNonNull; + +public class DescribeQuery extends Statement { + + private static final long INSTANCE_SIZE = + RamUsageEstimator.shallowSizeOfInstance(DescribeQuery.class); + + private final Query query; + + public DescribeQuery(NodeLocation location, Query query) { + super(requireNonNull(location, "location is null")); + this.query = requireNonNull(query, "query is null"); + } + + public Query getQuery() { + return query; + } + + @Override + public R accept(AstVisitor visitor, C context) { + return visitor.visitDescribeQuery(this, context); + } + + @Override + public List getChildren() { + return ImmutableList.of(query); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + DescribeQuery that = (DescribeQuery) obj; + return Objects.equals(query, that.query); + } + + @Override + public int hashCode() { + return Objects.hash(query); + } + + @Override + public String toString() { + return "DescribeQuery{" + "query=" + query + '}'; + } + + @Override + public long ramBytesUsed() { + long size = INSTANCE_SIZE; + size += AstMemoryEstimationHelper.getEstimatedSizeOfNodeLocation(getLocationInternal()); + size += AstMemoryEstimationHelper.getEstimatedSizeOfAccountableObject(query); + return size; + } +} diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/transformation/datastructure/tv/ElasticSerializableTVList.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/transformation/datastructure/tv/ElasticSerializableTVList.java index f0d4e3dd174eb..790e5cedaf517 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/transformation/datastructure/tv/ElasticSerializableTVList.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/transformation/datastructure/tv/ElasticSerializableTVList.java @@ -25,6 +25,7 @@ import org.apache.tsfile.block.column.Column; import org.apache.tsfile.common.conf.TSFileConfig; import org.apache.tsfile.enums.TSDataType; +import org.apache.tsfile.read.common.block.column.TimeColumn; import org.apache.tsfile.utils.Binary; import java.io.IOException; @@ -183,16 +184,16 @@ public void putColumn(Column timeColumn, Column valueColumn) throws IOException consumed = total; if (begin == 0) { // No need to copy if the columns do not split - insertedTimeColumn = timeColumn; + insertedTimeColumn = ensureTimeColumn(timeColumn); insertedValueColumn = valueColumn; } else { - insertedTimeColumn = timeColumn.getRegionCopy(begin, consumed); + insertedTimeColumn = ensureTimeColumn(timeColumn.getRegionCopy(begin, consumed)); insertedValueColumn = valueColumn.getRegionCopy(begin, consumed); } } else { consumed = internalTVListCapacity - pointCount % internalTVListCapacity; // Construct sub-regions - insertedTimeColumn = timeColumn.getRegionCopy(begin, consumed); + insertedTimeColumn = ensureTimeColumn(timeColumn.getRegionCopy(begin, consumed)); insertedValueColumn = valueColumn.getRegionCopy(begin, consumed); } @@ -284,4 +285,15 @@ public SerializableTVList get(int targetIndex) throws IOException { return internalTVList.get(targetIndex); } } + + private Column ensureTimeColumn(Column column) { + if (column instanceof TimeColumn) { + return column; + } + long[] times = new long[column.getPositionCount()]; + for (int i = 0; i < times.length; i++) { + times[i] = column.getLong(i); + } + return new TimeColumn(column.getPositionCount(), times); + } } diff --git a/iotdb-core/relational-grammar/src/main/antlr4/org/apache/iotdb/db/relational/grammar/sql/RelationalSql.g4 b/iotdb-core/relational-grammar/src/main/antlr4/org/apache/iotdb/db/relational/grammar/sql/RelationalSql.g4 index 08a8b4c2e82a1..ca3d50a7ff4d7 100644 --- a/iotdb-core/relational-grammar/src/main/antlr4/org/apache/iotdb/db/relational/grammar/sql/RelationalSql.g4 +++ b/iotdb-core/relational-grammar/src/main/antlr4/org/apache/iotdb/db/relational/grammar/sql/RelationalSql.g4 @@ -914,6 +914,7 @@ queryStatement : query #statementDefault | EXPLAIN query #explain | EXPLAIN ANALYZE VERBOSE? query #explainAnalyze + | DESCRIBE QUERY query #describeQuery ; query