use of org.apache.calcite.rel.metadata.RelMetadataProvider in project calcite by apache.
the class VolcanoRelMetadataProvider method apply.
public <M extends Metadata> UnboundMetadata<M> apply(Class<? extends RelNode> relClass, final Class<? extends M> metadataClass) {
if (relClass != RelSubset.class) {
// let someone else further down the chain sort it out
return null;
}
return new UnboundMetadata<M>() {
public M bind(RelNode rel, RelMetadataQuery mq) {
final RelSubset subset = (RelSubset) rel;
final RelMetadataProvider provider = rel.getCluster().getMetadataProvider();
// this query, treat it as the most reliable.
if (subset.best != null) {
final UnboundMetadata<M> function = provider.apply(subset.best.getClass(), metadataClass);
if (function != null) {
final M metadata = function.bind(subset.best, mq);
if (metadata != null) {
return metadata;
}
}
}
// granularity).
if (subset.set.inMetadataQuery) {
return null;
}
subset.set.inMetadataQuery = true;
try {
for (RelNode relCandidate : subset.set.rels) {
final UnboundMetadata<M> function = provider.apply(relCandidate.getClass(), metadataClass);
if (function != null) {
final M result = function.bind(relCandidate, mq);
if (result != null) {
return result;
}
}
}
} finally {
subset.set.inMetadataQuery = false;
}
// Give up.
return null;
}
};
}
use of org.apache.calcite.rel.metadata.RelMetadataProvider in project calcite by apache.
the class Programs method of.
/**
* Creates a program that executes a {@link HepProgram}.
*/
public static Program of(final HepProgram hepProgram, final boolean noDag, final RelMetadataProvider metadataProvider) {
return new Program() {
public RelNode run(RelOptPlanner planner, RelNode rel, RelTraitSet requiredOutputTraits, List<RelOptMaterialization> materializations, List<RelOptLattice> lattices) {
final HepPlanner hepPlanner = new HepPlanner(hepProgram, null, noDag, null, RelOptCostImpl.FACTORY);
List<RelMetadataProvider> list = Lists.newArrayList();
if (metadataProvider != null) {
list.add(metadataProvider);
}
hepPlanner.registerMetadataProviders(list);
RelMetadataProvider plannerChain = ChainedRelMetadataProvider.of(list);
rel.getCluster().setMetadataProvider(plannerChain);
hepPlanner.setRoot(rel);
return hepPlanner.findBestExp();
}
};
}
use of org.apache.calcite.rel.metadata.RelMetadataProvider in project calcite by apache.
the class RelOptFixture method checkPlanning.
/**
* Checks the plan for a given {@link RelNode} supplier before/after executing
* a given rule, with a pre-program to prepare the tree.
*
* @param unchanged Whether the rule is to have no effect
*/
private void checkPlanning(boolean unchanged) {
final RelNode relInitial = toRel();
assertNotNull(relInitial);
List<RelMetadataProvider> list = new ArrayList<>();
list.add(DefaultRelMetadataProvider.INSTANCE);
RelMetadataProvider plannerChain = ChainedRelMetadataProvider.of(list);
final RelOptCluster cluster = relInitial.getCluster();
cluster.setMetadataProvider(plannerChain);
// Rather than a single mutable 'RelNode r', this method uses lots of
// final variables (relInitial, r1, relBefore, and so forth) so that the
// intermediate states of planning are visible in the debugger.
final RelNode r1;
if (preProgram == null) {
r1 = relInitial;
} else {
HepPlanner prePlanner = new HepPlanner(preProgram);
prePlanner.setRoot(relInitial);
r1 = prePlanner.findBestExp();
}
final RelNode relBefore = before.apply(this, r1);
assertThat(relBefore, notNullValue());
final String planBefore = NL + RelOptUtil.toString(relBefore);
final DiffRepository diffRepos = diffRepos();
diffRepos.assertEquals("planBefore", "${planBefore}", planBefore);
assertThat(relBefore, relIsValid());
final RelNode r2;
if (planner instanceof VolcanoPlanner) {
r2 = planner.changeTraits(relBefore, relBefore.getTraitSet().replace(EnumerableConvention.INSTANCE));
} else {
r2 = relBefore;
}
planner.setRoot(r2);
final RelNode r3 = planner.findBestExp();
final RelNode r4;
if (lateDecorrelate) {
final String planMid = NL + RelOptUtil.toString(r3);
diffRepos.assertEquals("planMid", "${planMid}", planMid);
assertThat(r3, relIsValid());
final RelBuilder relBuilder = RelFactories.LOGICAL_BUILDER.create(cluster, null);
r4 = RelDecorrelator.decorrelateQuery(r3, relBuilder);
} else {
r4 = r3;
}
final RelNode relAfter = after.apply(this, r4);
final String planAfter = NL + RelOptUtil.toString(relAfter);
if (unchanged) {
assertThat(planAfter, is(planBefore));
} else {
diffRepos.assertEquals("planAfter", "${planAfter}", planAfter);
if (planBefore.equals(planAfter)) {
throw new AssertionError("Expected plan before and after is the same.\n" + "You must use unchanged=true or call checkUnchanged");
}
}
assertThat(relAfter, relIsValid());
}
use of org.apache.calcite.rel.metadata.RelMetadataProvider in project calcite by apache.
the class RelMetadataTest method testMetadataHandlerCacheLimit.
/**
* Test case for
* <a href="https://issues.apache.org/jira/browse/CALCITE-1808">[CALCITE-1808]
* JaninoRelMetadataProvider loading cache might cause
* OutOfMemoryError</a>.
*
* <p>Too slow to run every day, and it does not reproduce the issue.
*/
@Tag("slow")
@Test
void testMetadataHandlerCacheLimit() {
assumeTrue(CalciteSystemProperty.METADATA_HANDLER_CACHE_MAXIMUM_SIZE.value() < 10_000, "If cache size is too large, this test may fail and the test won't be to blame");
final int iterationCount = 2_000;
final RelNode rel = sql("select * from emp").toRel();
final RelMetadataProvider metadataProvider = rel.getCluster().getMetadataProvider();
for (int i = 0; i < iterationCount; i++) {
RelMetadataProvider wrappedProvider = new RelMetadataProvider() {
// to be removed before 2.0
@Deprecated
@Override
@Nullable
public <M extends @Nullable Metadata> UnboundMetadata<M> apply(Class<? extends RelNode> relClass, Class<? extends M> metadataClass) {
return metadataProvider.apply(relClass, metadataClass);
}
// to be removed before 2.0
@Deprecated
@Override
public <M extends Metadata> Multimap<Method, MetadataHandler<M>> handlers(MetadataDef<M> def) {
return metadataProvider.handlers(def);
}
@Override
public List<MetadataHandler<?>> handlers(Class<? extends MetadataHandler<?>> handlerClass) {
return metadataProvider.handlers(handlerClass);
}
};
RelMetadataQuery.THREAD_PROVIDERS.set(JaninoRelMetadataProvider.of(wrappedProvider));
final RelMetadataQuery mq = rel.getCluster().getMetadataQuery();
final Double result = mq.getRowCount(rel);
assertThat(result, within(14d, 0.1d));
}
}
use of org.apache.calcite.rel.metadata.RelMetadataProvider in project calcite by apache.
the class RelMetadataTest method testCustomProviderWithRelMetadataQuery.
@Test
void testCustomProviderWithRelMetadataQuery() {
final List<String> buf = new ArrayList<>();
ColTypeImpl.THREAD_LIST.set(buf);
final String sql = "select deptno, count(*) from emp where deptno > 10 " + "group by deptno having count(*) = 0";
final RelMetadataFixture.MetadataConfig metadataConfig = fixture().metadataConfig;
final RelMetadataFixture fixture = sql(sql).withMetadataConfig(RelMetadataFixture.MetadataConfig.NOP).withCluster(cluster -> {
// Create a custom provider that includes ColType.
// Include the same provider twice just to be devious.
final ImmutableList<RelMetadataProvider> list = ImmutableList.of(ColTypeImpl.SOURCE, ColTypeImpl.SOURCE, requireNonNull(cluster.getMetadataProvider(), "cluster.metadataProvider"));
metadataConfig.applyMetadata(cluster, ChainedRelMetadataProvider.of(list), MyRelMetadataQuery::new);
return cluster;
});
final RelNode rel = fixture.toRel();
// Top node is a filter. Its metadata uses getColType(RelNode, int).
assertThat(rel, instanceOf(LogicalFilter.class));
assertThat(rel.getCluster().getMetadataQuery(), instanceOf(MyRelMetadataQuery.class));
final MyRelMetadataQuery mq = (MyRelMetadataQuery) rel.getCluster().getMetadataQuery();
assertThat(colType(mq, rel, 0), equalTo("DEPTNO-rel"));
assertThat(colType(mq, rel, 1), equalTo("EXPR$1-rel"));
// Next node is an aggregate. Its metadata uses
// getColType(LogicalAggregate, int).
final RelNode input = rel.getInput(0);
assertThat(input, instanceOf(LogicalAggregate.class));
assertThat(colType(mq, input, 0), equalTo("DEPTNO-agg"));
if (metadataConfig.isCaching()) {
// The metadata query is caching, only the first request for each piece of metadata
// generates a new call to the provider.
assertThat(buf.toString(), equalTo("[DEPTNO-rel, EXPR$1-rel, DEPTNO-agg]"));
assertThat(buf.size(), equalTo(3));
assertThat(colType(mq, input, 0), equalTo("DEPTNO-agg"));
assertThat(buf.size(), equalTo(3));
assertThat(colType(mq, input, 0), equalTo("DEPTNO-agg"));
assertThat(buf.size(), equalTo(3));
assertThat(colType(mq, input, 1), equalTo("EXPR$1-agg"));
assertThat(buf.size(), equalTo(4));
assertThat(colType(mq, input, 1), equalTo("EXPR$1-agg"));
assertThat(buf.size(), equalTo(4));
assertThat(colType(mq, input, 0), equalTo("DEPTNO-agg"));
assertThat(buf.size(), equalTo(4));
}
// Invalidate the metadata query triggers clearing of all the metadata.
rel.getCluster().invalidateMetadataQuery();
assertThat(rel.getCluster().getMetadataQuery(), instanceOf(MyRelMetadataQuery.class));
final MyRelMetadataQuery mq1 = (MyRelMetadataQuery) rel.getCluster().getMetadataQuery();
assertThat(colType(mq1, input, 0), equalTo("DEPTNO-agg"));
if (metadataConfig.isCaching()) {
assertThat(buf.size(), equalTo(5));
}
assertThat(colType(mq1, input, 0), equalTo("DEPTNO-agg"));
if (metadataConfig.isCaching()) {
assertThat(buf.size(), equalTo(5));
}
// Resets the RelMetadataQuery to default.
metadataConfig.applyMetadata(rel.getCluster());
}
Aggregations