use of org.apache.calcite.rel.metadata.RelMetadataProvider in project calcite by apache.
the class RelOptRulesTest method transitiveInference.
private void transitiveInference(RelOptRule... extraRules) throws Exception {
final DiffRepository diffRepos = getDiffRepos();
final String sql = diffRepos.expand(null, "${sql}");
final HepProgram program = new HepProgramBuilder().addRuleInstance(FilterJoinRule.DUMB_FILTER_ON_JOIN).addRuleInstance(FilterJoinRule.JOIN).addRuleInstance(FilterProjectTransposeRule.INSTANCE).addRuleInstance(FilterSetOpTransposeRule.INSTANCE).build();
final HepPlanner planner = new HepPlanner(program);
final RelRoot root = tester.convertSqlToRel(sql);
final RelNode relInitial = root.rel;
assertTrue(relInitial != null);
List<RelMetadataProvider> list = Lists.newArrayList();
list.add(DefaultRelMetadataProvider.INSTANCE);
planner.registerMetadataProviders(list);
RelMetadataProvider plannerChain = ChainedRelMetadataProvider.of(list);
relInitial.getCluster().setMetadataProvider(new CachingRelMetadataProvider(plannerChain, planner));
planner.setRoot(relInitial);
RelNode relBefore = planner.findBestExp();
String planBefore = NL + RelOptUtil.toString(relBefore);
diffRepos.assertEquals("planBefore", "${planBefore}", planBefore);
HepProgram program2 = new HepProgramBuilder().addMatchOrder(HepMatchOrder.BOTTOM_UP).addRuleInstance(FilterJoinRule.DUMB_FILTER_ON_JOIN).addRuleInstance(FilterJoinRule.JOIN).addRuleInstance(FilterProjectTransposeRule.INSTANCE).addRuleInstance(FilterSetOpTransposeRule.INSTANCE).addRuleInstance(JoinPushTransitivePredicatesRule.INSTANCE).addRuleCollection(Arrays.asList(extraRules)).build();
final HepPlanner planner2 = new HepPlanner(program2);
planner.registerMetadataProviders(list);
planner2.setRoot(relBefore);
RelNode relAfter = planner2.findBestExp();
String planAfter = NL + RelOptUtil.toString(relAfter);
diffRepos.assertEquals("planAfter", "${planAfter}", planAfter);
}
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>.
*/
@Test
public void testMetadataHandlerCacheLimit() {
Assume.assumeTrue("If cache size is too large, this test may fail and the " + "test won't be to blame", SaffronProperties.INSTANCE.metadataHandlerCacheMaximumSize().get() < 10_000);
final int iterationCount = 2_000;
final RelNode rel = convertSql("select * from emp");
final RelMetadataProvider metadataProvider = rel.getCluster().getMetadataProvider();
final RelOptPlanner planner = rel.getCluster().getPlanner();
for (int i = 0; i < iterationCount; i++) {
RelMetadataQuery.THREAD_PROVIDERS.set(JaninoRelMetadataProvider.of(new CachingRelMetadataProvider(metadataProvider, planner)));
final RelMetadataQuery mq = RelMetadataQuery.instance();
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 testCustomProvider.
@Test
public void testCustomProvider() {
final List<String> buf = Lists.newArrayList();
ColTypeImpl.THREAD_LIST.set(buf);
final String sql = "select deptno, count(*) from emp where deptno > 10 " + "group by deptno having count(*) = 0";
final RelRoot root = tester.withClusterFactory(new Function<RelOptCluster, RelOptCluster>() {
public RelOptCluster apply(RelOptCluster 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, cluster.getMetadataProvider());
cluster.setMetadataProvider(ChainedRelMetadataProvider.of(list));
return cluster;
}
}).convertSqlToRel(sql);
final RelNode rel = root.rel;
// Top node is a filter. Its metadata uses getColType(RelNode, int).
assertThat(rel, instanceOf(LogicalFilter.class));
final RelMetadataQuery mq = RelMetadataQuery.instance();
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"));
// There is no caching. Another request causes another 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(4));
// Now add a cache. Only the first request for each piece of metadata
// generates a new call to the provider.
final RelOptPlanner planner = rel.getCluster().getPlanner();
rel.getCluster().setMetadataProvider(new CachingRelMetadataProvider(rel.getCluster().getMetadataProvider(), planner));
assertThat(colType(mq, input, 0), equalTo("DEPTNO-agg"));
assertThat(buf.size(), equalTo(5));
assertThat(colType(mq, input, 0), equalTo("DEPTNO-agg"));
assertThat(buf.size(), equalTo(5));
assertThat(colType(mq, input, 1), equalTo("EXPR$1-agg"));
assertThat(buf.size(), equalTo(6));
assertThat(colType(mq, input, 1), equalTo("EXPR$1-agg"));
assertThat(buf.size(), equalTo(6));
assertThat(colType(mq, input, 0), equalTo("DEPTNO-agg"));
assertThat(buf.size(), equalTo(6));
// With a different timestamp, a metadata item is re-computed on first call.
long timestamp = planner.getRelMetadataTimestamp(rel);
assertThat(timestamp, equalTo(0L));
((MockRelOptPlanner) planner).setRelMetadataTimestamp(timestamp + 1);
assertThat(colType(mq, input, 0), equalTo("DEPTNO-agg"));
assertThat(buf.size(), equalTo(7));
assertThat(colType(mq, input, 0), equalTo("DEPTNO-agg"));
assertThat(buf.size(), equalTo(7));
}
use of org.apache.calcite.rel.metadata.RelMetadataProvider in project calcite by apache.
the class RelOptTestBase method checkPlanning.
/**
* Checks the plan for a SQL statement before/after executing a given rule,
* with a pre-program to prepare the tree.
*
* @param tester Tester
* @param preProgram Program to execute before comparing before state
* @param planner Planner
* @param sql SQL query
* @param unchanged Whether the rule is to have no effect
*/
protected void checkPlanning(Tester tester, HepProgram preProgram, RelOptPlanner planner, String sql, boolean unchanged) {
final DiffRepository diffRepos = getDiffRepos();
String sql2 = diffRepos.expand("sql", sql);
final RelRoot root = tester.convertSqlToRel(sql2);
final RelNode relInitial = root.rel;
assertTrue(relInitial != null);
List<RelMetadataProvider> list = Lists.newArrayList();
list.add(DefaultRelMetadataProvider.INSTANCE);
planner.registerMetadataProviders(list);
RelMetadataProvider plannerChain = ChainedRelMetadataProvider.of(list);
final RelOptCluster cluster = relInitial.getCluster();
cluster.setMetadataProvider(plannerChain);
RelNode relBefore;
if (preProgram == null) {
relBefore = relInitial;
} else {
HepPlanner prePlanner = new HepPlanner(preProgram);
prePlanner.setRoot(relInitial);
relBefore = prePlanner.findBestExp();
}
assertThat(relBefore, notNullValue());
final String planBefore = NL + RelOptUtil.toString(relBefore);
diffRepos.assertEquals("planBefore", "${planBefore}", planBefore);
SqlToRelTestBase.assertValid(relBefore);
planner.setRoot(relBefore);
RelNode r = planner.findBestExp();
if (tester.isLateDecorrelate()) {
final String planMid = NL + RelOptUtil.toString(r);
diffRepos.assertEquals("planMid", "${planMid}", planMid);
SqlToRelTestBase.assertValid(r);
final RelBuilder relBuilder = RelFactories.LOGICAL_BUILDER.create(cluster, null);
r = RelDecorrelator.decorrelateQuery(r, relBuilder);
}
final String planAfter = NL + RelOptUtil.toString(r);
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 checkPlanUnchanged");
}
}
SqlToRelTestBase.assertValid(r);
}
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;
}
};
}
Aggregations