Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -850,6 +851,22 @@ protected Scope visitExplain(Explain node, Optional<Scope> context) {
return visitQuery((Query) node.getStatement(), context);
}

@Override
protected Scope visitDescribeQuery(DescribeQuery node, Optional<Scope> context) {
analysis.setFinishQueryAfterAnalyze();
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);
}
Comment on lines +860 to +864
Copy link

Copilot AI Mar 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid System.out.println in the analyzer path. This will write to stdout for every DESCRIBE and can be noisy in production; use the project logger at an appropriate level or store the extracted column metadata in Analysis for the planner/operator to consume instead of printing.

Copilot uses AI. Check for mistakes.

Comment on lines +859 to +865
Copy link

Copilot AI Mar 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

visitDescribeQuery calls analysis.getOutputDescriptor() after analyzing the inner query, but the analysis scope is set on node.getQuery() (see visitQuery), not on the DescribeQuery statement node. This will throw when Analysis tries to resolve the root scope. Use analysis.getOutputDescriptor(node.getQuery()) (or the returned scope) and also assign a scope to the DescribeQuery node if it is the root statement.

Suggested change
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);
}
// Retrieve output descriptor for the analyzed inner query
RelationType outputDescriptor = analysis.getOutputDescriptor(node.getQuery());
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);
}
// Assign a scope to the DescribeQuery node when it is the root statement
if (!context.isPresent()) {
analysis.setScope(node, scope);
}

Copilot uses AI. Check for mistakes.
analysis.setDescribe(true);
return scope;
}

@Override
protected Scope visitExplainAnalyze(ExplainAnalyze node, Optional<Scope> context) {
queryContext.setExplainType(ExplainType.EXPLAIN_ANALYZE);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Copy link

Copilot AI Mar 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Apache license header looks malformed: it currently reads Version 2.0 (the followed by License"); (missing the opening quote before License). Please fix the header to match the standard ... (the "License"); ... form used elsewhere in the codebase.

Suggested change
* License"); you may not use this file except in compliance
* "License"); you may not use this file except in compliance

Copilot uses AI. Check for mistakes.
* 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, C> R accept(AstVisitor<R, C> visitor, C context) {
return visitor.visitDescribeQuery(this, context);
}

@Override
public List<Node> getChildren() {
return ImmutableList.of(query);
}

@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Comment on lines +58 to +59
Copy link

Copilot AI Mar 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

equals uses single-line if statements without braces (e.g., if (this == obj) return true;). This violates the repo Checkstyle NeedBraces rule and will fail style checks. Add braces for these conditionals.

Suggested change
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}

Copilot uses AI. Check for mistakes.
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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -914,6 +914,7 @@ queryStatement
: query #statementDefault
| EXPLAIN query #explain
| EXPLAIN ANALYZE VERBOSE? query #explainAnalyze
| DESCRIBE QUERY query #describeQuery
Copy link

Copilot AI Mar 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DESCRIBE QUERY is added to the grammar, but there is no corresponding AST builder override (e.g., in AstBuilder) to construct a DescribeQuery node. With the default ANTLR visitor behavior, this alternative will likely return the inner query AST directly, causing DESCRIBE QUERY ... to execute the query instead of describing it. Add an AstBuilder#visitDescribeQuery(...) that wraps the parsed query in the new DescribeQuery statement.

Suggested change
| DESCRIBE QUERY query #describeQuery

Copilot uses AI. Check for mistakes.
;

query
Expand Down
Loading