Thanks for your advice. My mock table inherits AbstractTable, so there is no convert. I solved the problem according to your suggestion.
BTW:I tried to add DDL statements and create a custom table (which inherits AbstractTable). However, it is obvious that some rules cannot be converted when CBO is started. Can you help provide some suggestions? Thank you very much! -----原始邮件----- 发件人:"Benchao Li" <libenc...@apache.org> 发送时间:2022-06-25 20:56:00 (星期六) 收件人: dev@calcite.apache.org, 8692182...@zju.edu.cn 抄送: 主题: Re: Looking for help: There are not enough rules to produce a node with desired properties hi 丰斌, The exception message has told you the reason: Missing conversion is LogicalTableScan[convention: NONE -> ENUMERABLE] This is mostly because your `MyRelOptSchema` returns a `Table` that cannot be transformed to Enumerable Convention. You can refer the code[1] to see why your Table cannot satisfy the requirements. [1] https://github.com/apache/calcite/blob/94dc303ed0a5ccd4e4f972abf7a41f155cbe5546/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableTableScanRule.java#L38 Julian Hyde <jhyde.apa...@gmail.com> 于2022年6月25日周六 00:40写道: I had to moderate your message. Can you subscribe to the list so that you receive updates. Julian > On Jun 24, 2022, at 09:37, 方丰斌 <8692182...@zju.edu.cn> wrote: > > Hey all, > > > > > I'm trying to use VolcanoPlanner. I have encountered the following > problems. I hope I can ask for some help. Thank you very much! > > Test code: > > ````` > > VolcanoPlanner planner = new VolcanoPlanner(); > planner.addRelTraitDef(ConventionTraitDef.INSTANCE); > > // Below two lines are important for the planner to use collation > trait and generate merge join > planner.addRelTraitDef(RelCollationTraitDef.INSTANCE); > planner.registerAbstractRelationalRules(); > > planner.addRule(EnumerableRules.ENUMERABLE_TABLE_SCAN_RULE); > planner.addRule(EnumerableRules.ENUMERABLE_PROJECT_RULE); > planner.addRule(CoreRules.PROJECT_TABLE_SCAN); > > RelOptCluster cluster = newCluster(planner); > > // NOTE:I mock x MyRelOptSchema to ensure that the SQL verification is > successful. > MyRelOptSchema relOptSchema = new MyRelOptSchema(); > RelBuilder relBuilder = RelFactories.LOGICAL_BUILDER.create(cluster, > relOptSchema); > RelNode logicalPlan = relBuilder > .scan("t1") > .project(relBuilder.field("attr1")) > .build(); > > RelTraitSet desiredTraits = > cluster.traitSet().replace(EnumerableConvention.INSTANCE); > final RelNode newRoot = planner.changeTraits(logicalPlan, > desiredTraits); > planner.setRoot(newRoot); > > RelNode bestExp = planner.findBestExp(); > System.out.println("Plan is: " + RelOptUtil.toString(bestExp)); > > ``` > > The exception is: > > ``` > > org.apache.calcite.plan.RelOptPlanner$CannotPlanException: There are not > enough rules to produce a node with desired properties: > convention=ENUMERABLE, sort=[]. > Missing conversion is LogicalTableScan[convention: NONE -> ENUMERABLE] > There is 1 empty subset: rel#7:RelSubset#0.ENUMERABLE.[], the relevant part > of the original plan is as follows > 0:LogicalTableScan(table=[[t1]]) > > Root: rel#5:RelSubset#1.ENUMERABLE.[] > Original rel: > LogicalProject(subset=[rel#5:RelSubset#1.ENUMERABLE.[]], attr1=[$0]): > rowcount = 1.0, cumulative cost = {1.0 rows, 1.0 cpu, 0.0 io}, id = 3 > LogicalTableScan(subset=[rel#2:RelSubset#0.NONE.[]], table=[[t1]]): rowcount > = 1.0, cumulative cost = {0.0 rows, 1.0 cpu, 0.0 io}, id = 0 > > Sets: > Set#0, type: com.dipeak.disql.query.SimpleSqlTest$MyRelOptSchema$1@67f77f6e > rel#2:RelSubset#0.NONE.[], best=null > rel#0:LogicalTableScan.NONE.[](table=[t1]), rowcount=1.0, cumulative > cost={inf} > rel#7:RelSubset#0.ENUMERABLE.[], best=null > Set#1, type: RecordType(INTEGER attr1) > rel#4:RelSubset#1.NONE.[], best=null > rel#3:LogicalProject.NONE.[](input=RelSubset#2,inputs=0), rowcount=1.0, > cumulative cost={inf} > rel#5:RelSubset#1.ENUMERABLE.[], best=null > rel#6:AbstractConverter.ENUMERABLE.[](input=RelSubset#4,convention=ENUMERABLE,sort=[]), > rowcount=1.0, cumulative cost={inf} > rel#8:EnumerableProject.ENUMERABLE.[](input=RelSubset#7,inputs=0), > rowcount=1.0, cumulative cost={inf} > > Graphviz: > digraph G { > root [style=filled,label="Root"]; > subgraph cluster0{ > label="Set 0 com.dipeak.disql.query.SimpleSqlTest$MyRelOptSchema$1@67f77f6e"; > rel0 [label="rel#0:LogicalTableScan\ntable=[t1]\nrows=1.0, > cost={inf}",shape=box] > subset2 [label="rel#2:RelSubset#0.NONE.[]"] > subset7 [label="rel#7:RelSubset#0.ENUMERABLE.[]",color=red] > } > subgraph cluster1{ > label="Set 1 RecordType(INTEGER attr1)"; > rel3 [label="rel#3:LogicalProject\ninput=RelSubset#2,inputs=0\nrows=1.0, > cost={inf}",shape=box] > rel6 > [label="rel#6:AbstractConverter\ninput=RelSubset#4,convention=ENUMERABLE,sort=[]\nrows=1.0, > cost={inf}",shape=box] > rel8 [label="rel#8:EnumerableProject\ninput=RelSubset#7,inputs=0\nrows=1.0, > cost={inf}",shape=box] > subset4 [label="rel#4:RelSubset#1.NONE.[]"] > subset5 [label="rel#5:RelSubset#1.ENUMERABLE.[]"] > } > root -> subset5; > subset2 -> rel0; > subset4 -> rel3; rel3 -> subset2; > subset5 -> rel6; rel6 -> subset4; > subset5 -> rel8; rel8 -> subset7; > } > > at > org.apache.calcite.plan.volcano.RelSubset$CheapestPlanReplacer.visit(RelSubset.java:709) > at > org.apache.calcite.plan.volcano.RelSubset.buildCheapestPlan(RelSubset.java:390) > at > org.apache.calcite.plan.volcano.VolcanoPlanner.findBestExp(VolcanoPlanner.java:533) > > > ``` -- Best, Benchao Li