-
Notifications
You must be signed in to change notification settings - Fork 181
Skipping codegen and compile for Scan only plan #3853
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
001ec18
220c2ba
b5189e4
32f18c4
b97a1b5
5c1b0dc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| /* | ||
| * Copyright OpenSearch Contributors | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| */ | ||
|
|
||
| package org.opensearch.sql.calcite.plan; | ||
|
|
||
| import org.apache.calcite.linq4j.Enumerable; | ||
| import org.checkerframework.checker.nullness.qual.Nullable; | ||
|
|
||
| /** | ||
| * The customized table scan is implemented in OpenSearch module, to invoke this scan() method in | ||
| * core module, we add this interface. Now the only implementation is CalciteEnumerableIndexScan. | ||
| * When a RelNode after optimization is a Scannable, we can directly invoke scan() method to get the | ||
| * result of the scan instead of codegen and compile via Linq4j expression. | ||
| */ | ||
| public interface Scannable { | ||
|
|
||
| public Enumerable<@Nullable Object> scan(); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -27,26 +27,35 @@ | |
|
|
||
| package org.opensearch.sql.calcite.utils; | ||
|
|
||
| import static java.util.Objects.requireNonNull; | ||
|
|
||
| import com.google.common.collect.ImmutableList; | ||
| import java.lang.reflect.Type; | ||
| import java.sql.Connection; | ||
| import java.sql.PreparedStatement; | ||
| import java.sql.SQLException; | ||
| import java.time.Instant; | ||
| import java.util.Properties; | ||
| import java.util.function.Consumer; | ||
| import org.apache.calcite.adapter.enumerable.EnumerableConvention; | ||
| import org.apache.calcite.adapter.enumerable.EnumerableRel; | ||
| import org.apache.calcite.adapter.java.JavaTypeFactory; | ||
| import org.apache.calcite.avatica.AvaticaConnection; | ||
| import org.apache.calcite.avatica.AvaticaFactory; | ||
| import org.apache.calcite.avatica.Meta; | ||
| import org.apache.calcite.avatica.UnregisteredDriver; | ||
| import org.apache.calcite.config.CalciteConnectionProperty; | ||
| import org.apache.calcite.interpreter.BindableConvention; | ||
| import org.apache.calcite.interpreter.Bindables; | ||
| import org.apache.calcite.jdbc.CalciteFactory; | ||
| import org.apache.calcite.jdbc.CalciteJdbc41Factory; | ||
| import org.apache.calcite.jdbc.CalcitePrepare; | ||
| import org.apache.calcite.jdbc.CalciteSchema; | ||
| import org.apache.calcite.jdbc.Driver; | ||
| import org.apache.calcite.linq4j.function.Function0; | ||
| import org.apache.calcite.plan.Context; | ||
| import org.apache.calcite.plan.Contexts; | ||
| import org.apache.calcite.plan.Convention; | ||
| import org.apache.calcite.plan.RelOptCluster; | ||
| import org.apache.calcite.plan.RelOptPlanner; | ||
| import org.apache.calcite.plan.RelOptSchema; | ||
|
|
@@ -55,30 +64,36 @@ | |
| import org.apache.calcite.prepare.CalcitePrepareImpl; | ||
| import org.apache.calcite.rel.RelHomogeneousShuttle; | ||
| import org.apache.calcite.rel.RelNode; | ||
| import org.apache.calcite.rel.RelRoot; | ||
| import org.apache.calcite.rel.RelShuttle; | ||
| import org.apache.calcite.rel.core.TableScan; | ||
| import org.apache.calcite.rel.logical.LogicalTableScan; | ||
| import org.apache.calcite.rel.type.RelDataType; | ||
| import org.apache.calcite.rel.type.RelDataTypeFactory; | ||
| import org.apache.calcite.rel.type.RelDataTypeSystem; | ||
| import org.apache.calcite.rex.RexBuilder; | ||
| import org.apache.calcite.rex.RexNode; | ||
| import org.apache.calcite.runtime.Bindable; | ||
| import org.apache.calcite.runtime.Hook; | ||
| import org.apache.calcite.schema.SchemaPlus; | ||
| import org.apache.calcite.server.CalciteServerStatement; | ||
| import org.apache.calcite.sql.SqlAggFunction; | ||
| import org.apache.calcite.sql.SqlKind; | ||
| import org.apache.calcite.sql.parser.SqlParserPos; | ||
| import org.apache.calcite.sql2rel.SqlRexConvertletTable; | ||
| import org.apache.calcite.tools.FrameworkConfig; | ||
| import org.apache.calcite.tools.Frameworks; | ||
| import org.apache.calcite.tools.RelBuilder; | ||
| import org.apache.calcite.tools.RelRunner; | ||
| import org.apache.calcite.util.Holder; | ||
| import org.apache.calcite.util.Util; | ||
| import org.opensearch.sql.calcite.CalcitePlanContext; | ||
| import org.opensearch.sql.calcite.plan.Scannable; | ||
| import org.opensearch.sql.calcite.udf.udaf.NullableSqlAvgAggFunction; | ||
|
|
||
| /** | ||
| * Calcite Tools Helper. This class is used to create customized: 1. Connection 2. JavaTypeFactory | ||
| * 3. RelBuilder 4. RelRunner TODO delete it in future if possible. | ||
| * 3. RelBuilder 4. RelRunner 5. CalcitePreparingStmt. TODO delete it in future if possible. | ||
| */ | ||
| public class CalciteToolsHelper { | ||
|
|
||
|
|
@@ -153,6 +168,11 @@ public Connection connect( | |
| this.handler.onConnectionInit(connection); | ||
| return connection; | ||
| } | ||
|
|
||
| @Override | ||
| protected Function0<CalcitePrepare> createPrepareFactory() { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: Looks like this method is marked as
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually we cannot use
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Em, maybe we could with casting. Anyway, let' keep current |
||
| return OpenSearchPrepareImpl::new; | ||
| } | ||
| } | ||
|
|
||
| /** do nothing, just extend for a public construct for new */ | ||
|
|
@@ -214,6 +234,104 @@ public <R> R perform( | |
| final RelOptCluster cluster = createCluster(planner, rexBuilder); | ||
| return action.apply(cluster, catalogReader, prepareContext.getRootSchema().plus(), statement); | ||
| } | ||
|
|
||
| /** | ||
| * Customize CalcitePreparingStmt. Override {@link CalcitePrepareImpl#getPreparingStmt} and | ||
| * return {@link OpenSearchCalcitePreparingStmt} | ||
| */ | ||
| @Override | ||
| protected CalcitePrepareImpl.CalcitePreparingStmt getPreparingStmt( | ||
| CalcitePrepare.Context context, | ||
| Type elementType, | ||
| CalciteCatalogReader catalogReader, | ||
| RelOptPlanner planner) { | ||
| final JavaTypeFactory typeFactory = context.getTypeFactory(); | ||
| final EnumerableRel.Prefer prefer; | ||
| if (elementType == Object[].class) { | ||
| prefer = EnumerableRel.Prefer.ARRAY; | ||
| } else { | ||
| prefer = EnumerableRel.Prefer.CUSTOM; | ||
| } | ||
| final Convention resultConvention = | ||
| enableBindable ? BindableConvention.INSTANCE : EnumerableConvention.INSTANCE; | ||
|
Comment on lines
+248
to
+256
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. add a comments if copy from calcite? e.g. |
||
| return new OpenSearchCalcitePreparingStmt( | ||
| this, | ||
| context, | ||
| catalogReader, | ||
| typeFactory, | ||
| context.getRootSchema(), | ||
| prefer, | ||
| createCluster(planner, new RexBuilder(typeFactory)), | ||
| resultConvention, | ||
| createConvertletTable()); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Similar to {@link CalcitePrepareImpl.CalcitePreparingStmt}. Customize the logic to convert an | ||
| * EnumerableTableScan to BindableTableScan. | ||
| */ | ||
| public static class OpenSearchCalcitePreparingStmt | ||
| extends CalcitePrepareImpl.CalcitePreparingStmt { | ||
|
|
||
| public OpenSearchCalcitePreparingStmt( | ||
| CalcitePrepareImpl prepare, | ||
| CalcitePrepare.Context context, | ||
| CatalogReader catalogReader, | ||
| RelDataTypeFactory typeFactory, | ||
| CalciteSchema schema, | ||
| EnumerableRel.Prefer prefer, | ||
| RelOptCluster cluster, | ||
| Convention resultConvention, | ||
| SqlRexConvertletTable convertletTable) { | ||
| super( | ||
| prepare, | ||
| context, | ||
| catalogReader, | ||
| typeFactory, | ||
| schema, | ||
| prefer, | ||
| cluster, | ||
| resultConvention, | ||
| convertletTable); | ||
| } | ||
|
|
||
| @Override | ||
| protected PreparedResult implement(RelRoot root) { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we leverage BindableConvention.INSTANCE and regsiter a rule for convertion?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, Bindable and Enumerable conventions cannot work together. The |
||
| Hook.PLAN_BEFORE_IMPLEMENTATION.run(root); | ||
| RelDataType resultType = root.rel.getRowType(); | ||
| boolean isDml = root.kind.belongsTo(SqlKind.DML); | ||
| if (root.rel instanceof Scannable scannable) { | ||
| final Bindable bindable = dataContext -> scannable.scan(); | ||
|
|
||
| return new PreparedResultImpl( | ||
| resultType, | ||
| requireNonNull(parameterRowType, "parameterRowType"), | ||
| requireNonNull(fieldOrigins, "fieldOrigins"), | ||
| root.collation.getFieldCollations().isEmpty() | ||
| ? ImmutableList.of() | ||
| : ImmutableList.of(root.collation), | ||
| root.rel, | ||
| mapTableModOp(isDml, root.kind), | ||
| isDml) { | ||
| @Override | ||
| public String getCode() { | ||
| throw new UnsupportedOperationException(); | ||
| } | ||
|
|
||
| @Override | ||
| public Bindable getBindable(Meta.CursorFactory cursorFactory) { | ||
| return bindable; | ||
| } | ||
|
|
||
| @Override | ||
| public Type getElementType() { | ||
| return resultType.getFieldList().size() == 1 ? Object.class : Object[].class; | ||
| } | ||
| }; | ||
| } | ||
| return super.implement(root); | ||
| } | ||
| } | ||
|
|
||
| public static class OpenSearchRelRunners { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Add javadoc to explain
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done