Skip to content

Commit

Permalink
apache#3319 Provide physical plan for SQL explain
Browse files Browse the repository at this point in the history
  • Loading branch information
navis committed Aug 13, 2020
1 parent 50cac88 commit aa818d7
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 12 deletions.
2 changes: 1 addition & 1 deletion sql/src/main/codegen/templates/Parser.jj
Original file line number Diff line number Diff line change
Expand Up @@ -1173,7 +1173,7 @@ SqlExplain.Depth ExplainDepth() :
}
|
{
return SqlExplain.Depth.PHYSICAL;
return SqlExplain.Depth.LOGICAL;
}

)
Expand Down
30 changes: 21 additions & 9 deletions sql/src/main/java/io/druid/sql/calcite/planner/DruidPlanner.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

package io.druid.sql.calcite.planner;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.google.common.base.Function;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
Expand All @@ -36,6 +37,7 @@
import io.druid.java.util.common.guava.Sequence;
import io.druid.java.util.common.logger.Logger;
import io.druid.query.Query;
import io.druid.query.QueryInterruptedException;
import io.druid.query.QueryRunners;
import io.druid.segment.incremental.IncrementalIndexSchema;
import io.druid.sql.calcite.Utils;
Expand Down Expand Up @@ -290,17 +292,27 @@ public T next()

private PlannerResult handleExplain(final RelNode rel, final SqlExplain explain)
{
final String explanation = RelOptUtil.dumpPlan("", rel, explain.getFormat(), explain.getDetailLevel());
final Supplier<Sequence<Object[]>> resultsSupplier = Suppliers.ofInstance(
Sequences.simple(ImmutableList.of(new Object[]{explanation})));
final String explanation;
if (explain.withImplementation() && rel instanceof DruidRel) {
try {
plannerContext.disableQueryId();
Query query = ((DruidRel) rel).toDruidQuery(true).getQuery();
explanation = plannerContext.getObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(query);
}
catch (JsonProcessingException e) {
throw QueryInterruptedException.wrapIfNeeded(e);
}
} else {
explanation = RelOptUtil.dumpPlan("", rel, explain.getFormat(), explain.getDetailLevel());
}
final RelDataTypeFactory typeFactory = rel.getCluster().getTypeFactory();
return new PlannerResult(
resultsSupplier,
typeFactory.createStructType(
ImmutableList.of(typeFactory.createSqlType(SqlTypeName.VARCHAR)),
ImmutableList.of("PLAN")
)
final RelDataType resultType = typeFactory.createStructType(
ImmutableList.of(typeFactory.createSqlType(SqlTypeName.VARCHAR)),
ImmutableList.of("PLAN")
);
final Supplier<Sequence<Object[]>> resultsSupplier = Suppliers.ofInstance(
Sequences.simple(ImmutableList.of(new Object[]{explanation})));
return new PlannerResult(resultsSupplier, resultType);
}

@SuppressWarnings("unchecked")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,12 @@ public String getQueryId()
return (String) queryContext.get(Query.QUERYID);
}

// for explain with implementation
public void disableQueryId()
{
queryContext.remove(Query.QUERYID);
}

public DruidOperatorTable getOperatorTable()
{
return operatorTable;
Expand Down
3 changes: 2 additions & 1 deletion sql/src/main/java/io/druid/sql/http/SqlResource.java
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,8 @@ public Response explain(
@Context HttpServletRequest req
) throws SQLException, IOException
{
return execute(new SqlQuery(String.format("DESCRIBE %s", sqlQuery), null, false, contextFromParam(req)), req);
final String explain = String.format("EXPLAIN PLAN WITH IMPLEMENTATION FOR %s", sqlQuery);
return execute(new SqlQuery(explain, null, false, contextFromParam(req)), req);
}

@POST
Expand Down
53 changes: 52 additions & 1 deletion sql/src/test/java/io/druid/sql/calcite/CalciteQueryTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -2056,7 +2056,7 @@ public void testCountStarOnView() throws Exception
@Test
public void testExplainCountStarOnView() throws Exception
{
final String explanation =
String explanation =
"DruidQueryRel(query=["
+ "{\"queryType\":\"timeseries\","
+ "\"dataSource\":{\"type\":\"table\",\"name\":\"foo\"},"
Expand All @@ -2071,6 +2071,57 @@ public void testExplainCountStarOnView() throws Exception
new Object[]{explanation}
)
);

explanation = "{\n"
+ " \"queryType\" : \"timeseries\",\n"
+ " \"dataSource\" : {\n"
+ " \"type\" : \"table\",\n"
+ " \"name\" : \"foo\"\n"
+ " },\n"
+ " \"descending\" : false,\n"
+ " \"filter\" : {\n"
+ " \"type\" : \"and\",\n"
+ " \"fields\" : [ {\n"
+ " \"type\" : \"selector\",\n"
+ " \"dimension\" : \"dim2\",\n"
+ " \"value\" : \"a\"\n"
+ " }, {\n"
+ " \"type\" : \"not\",\n"
+ " \"field\" : {\n"
+ " \"type\" : \"selector\",\n"
+ " \"dimension\" : \"dim1\",\n"
+ " \"value\" : \"z\",\n"
+ " \"extractionFn\" : {\n"
+ " \"type\" : \"substring\",\n"
+ " \"index\" : 0,\n"
+ " \"length\" : 1\n"
+ " }\n"
+ " }\n"
+ " } ]\n"
+ " },\n"
+ " \"granularity\" : {\n"
+ " \"type\" : \"all\"\n"
+ " },\n"
+ " \"aggregations\" : [ {\n"
+ " \"type\" : \"count\",\n"
+ " \"name\" : \"a0\"\n"
+ " } ],\n"
+ " \"limitSpec\" : {\n"
+ " \"type\" : \"noop\"\n"
+ " },\n"
+ " \"outputColumns\" : [ \"a0\" ],\n"
+ " \"context\" : {\n"
+ " \"sqlCurrentTimestamp\" : \"2000-01-01T00:00:00Z\",\n"
+ " \"groupby.sort.on.time\" : false\n"
+ " }\n"
+ "}";
testQuery(
"EXPLAIN PLAN WITH IMPLEMENTATION FOR SELECT COUNT(*) FROM aview WHERE dim1_firstchar <> 'z'",
ImmutableList.of(),
ImmutableList.of(
new Object[]{explanation}
)
);
}

// @Test
Expand Down

0 comments on commit aa818d7

Please sign in to comment.