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 @@ -81,6 +81,22 @@ public class CalcitePlanContext {
/** Whether we're currently inside a lambda context. */
@Getter @Setter private boolean inLambdaContext = false;

/**
* When enabled, tracks which RelNode ids were produced by each AST command. Each entry maps an
* AST node class name to the list of RelNode ids it produced (excluding children).
*/
@Getter @Setter private boolean trackingEnabled = false;

@Getter private final List<NodeIdMapping> nodeIdMappings = new ArrayList<>();

/** Records a mapping from an AST command to the RelNode ids it produced. */
public void recordMapping(String astNodeType, List<Integer> relNodeIds) {
nodeIdMappings.add(new NodeIdMapping(astNodeType, relNodeIds));
}

/** A mapping from one AST command to the RelNode ids it produced. */
public record NodeIdMapping(String astNodeType, List<Integer> relNodeIds) {}

private CalcitePlanContext(FrameworkConfig config, SysLimit sysLimit, QueryType queryType) {
this.config = config;
this.sysLimit = sysLimit;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -219,15 +219,47 @@ public CalciteRelNodeVisitor(DataSourceService dataSourceService) {
}

public RelNode analyze(UnresolvedPlan unresolved, CalcitePlanContext context) {
if (context.isTrackingEnabled()) {
int idBefore = context.relBuilder.size() > 0 ? context.relBuilder.peek().getId() : -1;
RelNode result = unresolved.accept(this, context);
int idAfter = context.relBuilder.peek().getId();
java.util.List<Integer> producedIds = new java.util.ArrayList<>();
for (int id = idBefore + 1; id <= idAfter; id++) {
producedIds.add(id);
}
context.recordMapping(unresolved.getClass().getSimpleName(), producedIds);
return result;
}
return unresolved.accept(this, context);
}

@Override
public RelNode visitChildren(Node node, CalcitePlanContext context) {
if (context.isTrackingEnabled() && node instanceof UnresolvedPlan) {
// Track each child's total contribution (the subtree it produces)
RelNode result = null;
for (org.opensearch.sql.ast.Node child : node.getChild()) {
int idBefore = context.relBuilder.size() > 0 ? context.relBuilder.peek().getId() : -1;
RelNode childResult = child.accept(this, context);
result = childResult;
// After child.accept returns, the child's visit* method has fully completed,
// so all RelNodes produced by that child (including ITS children) are on the stack.
int idAfter = context.relBuilder.peek().getId();
if (child instanceof UnresolvedPlan) {
java.util.List<Integer> producedIds = new java.util.ArrayList<>();
for (int id = idBefore + 1; id <= idAfter; id++) {
producedIds.add(id);
}
context.recordMapping(child.getClass().getSimpleName(), producedIds);
}
}
if (node instanceof UnresolvedPlan plan) {
mapPathMaterializer.materializePaths(plan, context);
}
return result;
}
RelNode result = super.visitChildren(node, context);
if (node instanceof UnresolvedPlan plan) {
// Materialize MAP dotted paths as flat columns after children are analyzed
// (so MAP/struct types are known) but before the command's own visit logic runs.
mapPathMaterializer.materializePaths(plan, context);
}
return result;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

package org.opensearch.sql.executor;

import java.util.List;
import lombok.Builder;
import lombok.Data;
import org.opensearch.sql.monitor.profile.QueryProfile;

@Data
@Builder
public class AnalyzeResponse {

private final String query;
// private final List<QuerySegment> querySegments;
// private final String ast;
private final List<String> logicalPlan;
private final List<String> physicalPlan;
private final QueryProfile profile;
private final List<OperatorNode> operator_tree;
private final List<String> recommendations;
private final List<SchemaColumn> schema;
private final Object[][] datarows;
private final long total;
private final long size;

@Data
@Builder
public static class SchemaColumn {
private final String name;
private final String type;
}

@Data
@Builder
public static class QuerySegment {
private final String nodeType;
private final String source;
}

@Data
@Builder
public static class OperatorNode {
private final String source;
private final List<String> node_type;
private final List<String> description;
private final String estimated_cost;
private final Long estimated_rows;
private final String actual_time_ms;
private final Long actual_rows;
private final Boolean is_pushed_down;
}
}
Loading
Loading