Sorry I cannot make it work for INSERT/DELETE/UPDATE
This is the error for a DELETE
Qury: DELETE FROM MYTABLE where id=1
-- Logical Plan
LogicalTableModify(table=[[x, MYTABLE]], operation=[DELETE],
flattened=[true])
LogicalProject(id=[$0], name=[$1])
LogicalFilter(condition=[=($0, 1)])
LogicalTableScan(table=[[x, MYTABLE]])
Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 3.167 sec
<<< FAILURE!
test(PlannerExampleTest) Time elapsed: 3.034 sec <<< ERROR!
org.apache.calcite.plan.RelOptPlanner$CannotPlanException: Node
[rel#15:Subset#3.ENUMERABLE.[].any] could not be implemented; planner state:
Root: rel#15:Subset#3.ENUMERABLE.[].any
Original rel:
LogicalTableModify(subset=[rel#15:Subset#3.ENUMERABLE.[].any], table=[[x,
MYTABLE]], operation=[DELETE], flattened=[true]): rowcount = 2.25,
cumulative cost = {2.25 rows, 0.0 cpu, 0.0 io}, id = 13
LogicalProject(subset=[rel#12:Subset#2.NONE.[].any], id=[$0], name=[$1]):
rowcount = 2.25, cumulative cost = {2.25 rows, 4.5 cpu, 0.0 io}, id = 11
LogicalFilter(subset=[rel#10:Subset#1.NONE.[].any], condition=[=($0,
1)]): rowcount = 2.25, cumulative cost = {2.25 rows, 15.0 cpu, 0.0 io}, id
= 9
LogicalTableScan(subset=[rel#8:Subset#0.NONE.[].any], table=[[x,
MYTABLE]]): rowcount = 15.0, cumulative cost = {15.0 rows, 16.0 cpu, 0.0
io}, id = 4
Sets:
Set#0, type: RecordType(INTEGER id, INTEGER name)
rel#8:Subset#0.NONE.[].any, best=null, importance=0.7290000000000001
rel#4:LogicalTableScan.NONE.[].any(table=[x, MYTABLE]),
rowcount=15.0, cumulative cost={inf}
rel#21:Subset#0.ENUMERABLE.[].any, best=rel#26,
importance=0.36450000000000005
rel#26:EnumerableInterpreter.ENUMERABLE.[].any(input=rel#25:Subset#0.BINDABLE.[].any),
rowcount=15.0, cumulative cost={7.65 rows, 7.66 cpu, 0.0 io}
rel#25:Subset#0.BINDABLE.[].any, best=rel#24,
importance=0.36450000000000005
rel#24:BindableTableScan.BINDABLE.[].any(table=[x, MYTABLE]),
rowcount=15.0, cumulative cost={0.15 rows, 0.16 cpu, 0.0 io}
Set#1, type: RecordType(INTEGER id, INTEGER name)
rel#10:Subset#1.NONE.[].any, best=null, importance=0.81
rel#9:LogicalFilter.NONE.[].any(input=rel#8:Subset#0.NONE.[].any,condition==($0,
1)), rowcount=2.25, cumulative cost={inf}
rel#11:LogicalProject.NONE.[].any(input=rel#10:Subset#1.NONE.[].any,id=$0,name=$1),
rowcount=2.25, cumulative cost={inf}
rel#17:Subset#1.ENUMERABLE.[].any, best=rel#29,
importance=0.4510687500000001
rel#18:EnumerableProject.ENUMERABLE.[].any(input=rel#17:Subset#1.ENUMERABLE.[].any,id=$0,name=$1),
rowcount=15.0, cumulative cost={22.65 rows, 37.66 cpu, 0.0 io}
rel#22:EnumerableFilter.ENUMERABLE.[].any(input=rel#21:Subset#0.ENUMERABLE.[].any,condition==($0,
1)), rowcount=2.25, cumulative cost={9.9 rows, 22.66 cpu, 0.0 io}
rel#29:EnumerableInterpreter.ENUMERABLE.[].any(input=rel#20:Subset#1.BINDABLE.[].any),
rowcount=15.0, cumulative cost={7.65 rows, 7.66 cpu, 0.0 io}
rel#20:Subset#1.BINDABLE.[].any, best=rel#19, importance=0.405
rel#19:BindableTableScan.BINDABLE.[].any(table=[x,
MYTABLE],filters=[=($0, 1)]), rowcount=15.0, cumulative cost={0.15 rows,
0.16 cpu, 0.0 io}
Set#3, type: RecordType(BIGINT ROWCOUNT)
rel#14:Subset#3.NONE.[].any, best=null, importance=0.9
rel#13:LogicalTableModify.NONE.[].any(input=rel#10:Subset#1.NONE.[].any,table=[x,
MYTABLE],operation=DELETE,flattened=true), rowcount=2.25, cumulative
cost={inf}
rel#15:Subset#3.ENUMERABLE.[].any, best=null, importance=1.0
rel#16:AbstractConverter.ENUMERABLE.[].any(input=rel#14:Subset#3.NONE.[].any,convention=ENUMERABLE,sort=[],dist=any),
rowcount=2.25, cumulative cost={inf}
at
org.apache.calcite.plan.volcano.RelSubset$CheapestPlanReplacer.visit(RelSubset.java:441)
at
org.apache.calcite.plan.volcano.RelSubset.buildCheapestPlan(RelSubset.java:291)
at
org.apache.calcite.plan.volcano.VolcanoPlanner.findBestExp(VolcanoPlanner.java:666)
This is for an Insert
Qury: INSERT INTO MYTABLE(id,name) values(1,2)
-- Logical Plan
LogicalTableModify(table=[[x, MYTABLE]], operation=[INSERT],
flattened=[true])
LogicalValues(type=[RecordType(INTEGER id, INTEGER name)], tuples=[[{ 1,
2 }]])
Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 2.377 sec
<<< FAILURE!
test(PlannerExampleTest) Time elapsed: 2.214 sec <<< ERROR!
org.apache.calcite.plan.RelOptPlanner$CannotPlanException: Node
[rel#7:Subset#1.ENUMERABLE.[].any] could not be implemented; planner state:
Root: rel#7:Subset#1.ENUMERABLE.[].any
Original rel:
LogicalTableModify(subset=[rel#7:Subset#1.ENUMERABLE.[].any], table=[[x,
MYTABLE]], operation=[INSERT], flattened=[true]): rowcount = 1.0,
cumulative cost = {1.0 rows, 0.0 cpu, 0.0 io}, id = 5
LogicalValues(subset=[rel#4:Subset#0.NONE.[].any], tuples=[[{ 1, 2 }]]):
rowcount = 1.0, cumulative cost = {1.0 rows, 1.0 cpu, 0.0 io}, id = 2
Sets:
Set#0, type: RecordType(INTEGER id, INTEGER name)
rel#4:Subset#0.NONE.[].any, best=null, importance=0.81
rel#2:LogicalValues.NONE.[[0, 1], [1]].any(type=RecordType(INTEGER
id, INTEGER name),tuples=[{ 1, 2 }]), rowcount=1.0, cumulative cost={inf}
rel#10:Subset#0.ENUMERABLE.[].broadcast, best=rel#9, importance=0.405
rel#9:EnumerableValues.ENUMERABLE.[[0, 1],
[1]].broadcast(type=RecordType(INTEGER id, INTEGER name),tuples=[{ 1, 2
}]), rowcount=1.0, cumulative cost={1.0 rows, 1.0 cpu, 0.0 io}
Set#1, type: RecordType(BIGINT ROWCOUNT)
rel#6:Subset#1.NONE.[].any, best=null, importance=0.9
rel#5:LogicalTableModify.NONE.[].any(input=rel#4:Subset#0.NONE.[].any,table=[x,
MYTABLE],operation=INSERT,flattened=true), rowcount=1.0, cumulative
cost={inf}
rel#7:Subset#1.ENUMERABLE.[].any, best=null, importance=1.0
rel#8:AbstractConverter.ENUMERABLE.[].any(input=rel#6:Subset#1.NONE.[].any,convention=ENUMERABLE,sort=[],dist=any),
rowcount=1.0, cumulative cost={inf}
at
org.apache.calcite.plan.volcano.RelSubset$CheapestPlanReplacer.visit(RelSubset.java:441)
at
org.apache.calcite.plan.volcano.RelSubset.buildCheapestPlan(RelSubset.java:291)
at
org.apache.calcite.plan.volcano.VolcanoPlanner.findBestExp(VolcanoPlanner.java:666)
I really appreciate your help
Enrico
2017-11-09 9:43 GMT+01:00 Enrico Olivelli <[email protected]>:
> The example from Luis works like a charm.
> I have some questions,I will start separate threads
>
> Thank you
> Enrico
>
> 2017-11-08 21:51 GMT+01:00 Enrico Olivelli <[email protected]>:
>
>> Luis thank you,
>> my case is the second one. I want to use Calcite planner internally on a
>> database system. I will try with your suggestion
>>
>> Enrico
>>
>> Il mer 8 nov 2017, 20:14 Luis Fernando Kauer <[email protected]>
>> ha scritto:
>>
>>> If you intend to run a query then you should follow the tutorial and
>>> try to change the csv adapter. You can add the table to the schema at
>>> runtime using something like:
>>> ---------------------------------------------------------------------
>>>
>>> Class.forName("org.apache.calcite.jdbc.Driver");
>>> Properties info = new Properties();
>>> info.setProperty("lex", "MYSQL_ANSI");
>>>
>>> final Connection connection = DriverManager.getConnection("jdbc:calcite:",
>>> info);
>>> CalciteConnection conn = connection.unwrap(CalciteConnection.class);
>>> SchemaPlus root = conn.getRootSchema();
>>> root.add("MYTABLE", new TableImpl());
>>> Statement statement = conn.createStatement();
>>> ResultSet rs = statement.executeQuery("SELECT * FROM MYTABLE");
>>> ---------------------------------------------------------------------
>>>
>>> But if you only want to parse, validate and optimize the query plan, you
>>> can use something like:
>>> ---------------------------------------------------------------------
>>> Table table = new TableImpl();
>>> final SchemaPlus rootSchema = Frameworks.createRootSchema(true);
>>> SchemaPlus schema = rootSchema.add("x", new AbstractSchema());
>>> schema.add("MYTABLE", table);
>>> List<RelTraitDef> traitDefs = new ArrayList<>();
>>> traitDefs.add(ConventionTraitDef.INSTANCE);
>>> traitDefs.add(RelCollationTraitDef.INSTANCE);
>>> SqlParser.Config parserConfig =
>>> SqlParser.configBuilder(SqlParser.Config.DEFAULT)
>>> .setCaseSensitive(false)
>>> .build();
>>>
>>> final FrameworkConfig config = Frameworks.newConfigBuilder()
>>> .parserConfig(parserConfig)
>>> .defaultSchema(schema)
>>> .traitDefs(traitDefs)
>>> // define the rules you want to apply
>>>
>>> .programs(Programs.ofRules(Programs.RULE_SET))
>>> .build();
>>> Planner planner = Frameworks.getPlanner(config);
>>> SqlNode n = planner.parse(" SELECT * FROM MYTABLE WHERE ID < 10");
>>> n = planner.validate(n);
>>> RelNode root = planner.rel(n).project();
>>> System.out.println(RelOptUtil.dumpPlan("-- Logical Plan", root,
>>> SqlExplainFormat.TEXT,
>>> SqlExplainLevel.DIGEST_ATTRIBUTES));
>>> RelOptCluster cluster = root.getCluster();
>>> final RelOptPlanner optPlanner = cluster.getPlanner();
>>> RelTraitSet desiredTraits =
>>> cluster.traitSet().replace(EnumerableConvention.INSTANCE);
>>> final RelNode newRoot = optPlanner.changeTraits(root, desiredTraits);
>>> optPlanner.setRoot(newRoot);
>>> RelNode bestExp = optPlanner.findBestExp();
>>> System.out.println(RelOptUtil.dumpPlan("-- Best Plan", bestExp,
>>> SqlExplainFormat.TEXT,
>>> SqlExplainLevel.DIGEST_ATTRIBUTES));
>>> ---------------------------------------------------------------------
>>>
>>> The main problem was that you were not setting the desired trait to use
>>> EnumerableConvention.
>>> You can see that instead of implementing all the interfaces you should
>>> use the available builders and classes.
>>> Also for implementing Table I think you should extend AbstractTable
>>> instead of implementing Table interface and you can use Statistics.of
>>> instead of implementing Statistic interface if it is simple:
>>> ---------------------------------------------------------------------
>>>
>>> private static class TableImpl extends AbstractTable {
>>> public TableImpl() {}
>>> @Override public RelDataType getRowType(RelDataTypeFactory
>>> typeFactory) {
>>> Builder builder = new RelDataTypeFactory.Builder(typeFactory);
>>> return builder.add("id", typeFactory.createSqlType(SqlT
>>> ypeName.INTEGER))
>>> .add("name", typeFactory.createSqlType(SqlT
>>> ypeName.VARCHAR)).build();
>>> }
>>> @Override
>>> public Statistic getStatistic() {
>>> return Statistics.of(15D, ImmutableList.<ImmutableBitSet>of(),
>>> ImmutableList.of(RelCollations.of(0), RelCollations.of(1)));
>>> }
>>>
>>> }
>>> ---------------------------------------------------------------------
>>>
>>>
>>> Em quarta-feira, 8 de novembro de 2017 12:15:34 BRST, Enrico
>>> Olivelli <[email protected]> escreveu:
>>>
>>> Hi,
>>> I am playing with the planner but I can't get it work for a very simple
>>> query.
>>> Th table is
>>> MYTABLE(id integer, name varchar) definition is given in code
>>> snippet
>>> the query is "SELECT * FROM MYTABLE"
>>>
>>> The error is:
>>> org.apache.calcite.plan.RelOptPlanner$CannotPlanException: Node
>>> [rel#7:Subset#0.NONE.[0, 1].any] could not be implemented; planner state:
>>>
>>> Root: rel#7:Subset#0.NONE.[0, 1].any
>>> Original rel:
>>> LogicalProject(subset=[rel#6:Subset#1.NONE.[0, 1].any], id=[$0],
>>> name=[$1]): rowcount = 15.0, cumulative cost = {15.0 rows, 30.0 cpu, 0.0
>>> io}, id = 5
>>> EnumerableTableScan(subset=[rel#4:Subset#0.ENUMERABLE.[0, 1].any],
>>> table=[[default, MYTABLE]]): rowcount = 15.0, cumulative cost = {15.0
>>> rows,
>>> 16.0 cpu, 0.0 io}, id = 2
>>>
>>> Sets:
>>> Set#0, type: RecordType(INTEGER id, VARCHAR name)
>>> rel#4:Subset#0.ENUMERABLE.[0, 1].any, best=rel#2, importance=0.9
>>> rel#2:EnumerableTableScan.ENUMERABLE.[[0,
>>> 1]].any(table=[default,
>>> MYTABLE]), rowcount=15.0, cumulative cost={15.0 rows, 16.0 cpu, 0.0 io}
>>> rel#9:EnumerableProject.ENUMERABLE.[[0,
>>> 1]].any(input=rel#4:Subset#0.ENUMERABLE.[0, 1].any,id=$0,name=$1),
>>> rowcount=15.0, cumulative cost={30.0 rows, 46.0 cpu, 0.0 io}
>>> rel#7:Subset#0.NONE.[0, 1].any, best=null, importance=1.0
>>> rel#5:LogicalProject.NONE.[[0,
>>> 1]].any(input=rel#4:Subset#0.ENUMERABLE.[0, 1].any,id=$0,name=$1),
>>> rowcount=15.0, cumulative cost={inf}
>>> rel#8:AbstractConverter.NONE.[0,
>>> 1].any(input=rel#4:Subset#0.ENUMERABLE.[0,
>>> 1].any,convention=NONE,sort=[0,
>>> 1],dist=any), rowcount=15.0, cumulative cost={inf}
>>>
>>> Does anybody has an hint for me ?
>>> I am using currert master of Calcite (1.15-SNAPSHOT)
>>>
>>> Thank you
>>>
>>> Enrico
>>>
>>>
>>> My code is:
>>> @Test
>>> public void test() throws Exception {
>>> Table table = new TableImpl();
>>> CalciteSchema schema = CalciteSchema.createRootSchema(true,
>>> true,
>>> "default");
>>> schema.add("MYTABLE", table);
>>> SchemaPlus rootSchema = schema.plus();
>>> SqlRexConvertletTable convertletTable =
>>> StandardConvertletTable.INSTANCE;
>>> SqlToRelConverter.Config config = SqlToRelConverter.Config.DEFAU
>>> LT;
>>> FrameworkConfig frameworkConfig = new FrameworkConfigImpl(config,
>>> rootSchema, convertletTable);
>>> Planner imp = Frameworks.getPlanner(frameworkConfig);
>>> SqlNode sqlNode = imp.parse("SELECT * FROM MYTABLE");
>>> sqlNode = imp.validate(sqlNode);
>>> RelRoot relRoot = imp.rel(sqlNode);
>>> RelNode project = relRoot.project();
>>> RelOptPlanner planner = project.getCluster().getPlanner();
>>> planner.setRoot(project);
>>> RelNode findBestExp = planner.findBestExp();
>>> System.out.println("best:" + findBestExp);
>>> }
>>>
>>> private class FrameworkConfigImpl implements FrameworkConfig {
>>>
>>> private final SqlToRelConverter.Config config;
>>> private final SchemaPlus rootSchema;
>>> private final SqlRexConvertletTable convertletTable;
>>>
>>> public FrameworkConfigImpl(SqlToRelConverter.Config config,
>>> SchemaPlus rootSchema, SqlRexConvertletTable convertletTable) {
>>> this.config = config;
>>> this.rootSchema = rootSchema;
>>> this.convertletTable = convertletTable;
>>> }
>>>
>>> @Override
>>> public SqlParser.Config getParserConfig() {
>>> return SqlParser.Config.DEFAULT;
>>> }
>>>
>>> @Override
>>> public SqlToRelConverter.Config getSqlToRelConverterConfig() {
>>> return config;
>>> }
>>>
>>> @Override
>>> public SchemaPlus getDefaultSchema() {
>>> return rootSchema;
>>> }
>>>
>>> @Override
>>> public RexExecutor getExecutor() {
>>> return new RexExecutorImpl(new DataContextImpl());
>>> }
>>>
>>> @Override
>>> public ImmutableList<Program> getPrograms() {
>>> return ImmutableList.of(Programs.standard());
>>> }
>>>
>>> @Override
>>> public SqlOperatorTable getOperatorTable() {
>>> return new SqlStdOperatorTable();
>>> }
>>>
>>> @Override
>>> public RelOptCostFactory getCostFactory() {
>>> return null;
>>> }
>>>
>>> @Override
>>> public ImmutableList<RelTraitDef> getTraitDefs() {
>>>
>>> return ImmutableList.of(ConventionTraitDef.INSTANCE,
>>> RelCollationTraitDef.INSTANCE,
>>> RelDistributionTraitDef.INSTANCE
>>> );
>>> }
>>>
>>> @Override
>>> public SqlRexConvertletTable getConvertletTable() {
>>> return convertletTable;
>>> }
>>>
>>> @Override
>>> public Context getContext() {
>>> return new ContextImpl();
>>> }
>>>
>>> @Override
>>> public RelDataTypeSystem getTypeSystem() {
>>> return RelDataTypeSystem.DEFAULT;
>>> }
>>>
>>> class DataContextImpl implements DataContext {
>>>
>>> public DataContextImpl() {
>>> }
>>>
>>> @Override
>>> public SchemaPlus getRootSchema() {
>>> return rootSchema;
>>> }
>>>
>>> @Override
>>> public JavaTypeFactory getTypeFactory() {
>>> throw new UnsupportedOperationException("Not supported
>>> yet."); //To change body of generated methods, choose Tools | Templates.
>>> }
>>>
>>> @Override
>>> public QueryProvider getQueryProvider() {
>>> throw new UnsupportedOperationException("Not supported
>>> yet."); //To change body of generated methods, choose Tools | Templates.
>>> }
>>>
>>> @Override
>>> public Object get(String name) {
>>> throw new UnsupportedOperationException("Not supported
>>> yet."); //To change body of generated methods, choose Tools | Templates.
>>> }
>>>
>>> }
>>>
>>> private class ContextImpl implements Context {
>>>
>>> public ContextImpl() {
>>> }
>>>
>>> @Override
>>> public <C> C unwrap(Class<C> aClass) {
>>> return null;
>>> }
>>> }
>>> }
>>>
>>> private static class TableImpl implements Table {
>>>
>>> public TableImpl() {
>>> }
>>>
>>> @Override
>>> public RelDataType getRowType(RelDataTypeFactory typeFactory) {
>>> return typeFactory
>>> .builder()
>>> .add("id",
>>> typeFactory.createSqlType(SqlTypeName.INTEGER))
>>> .add("name",
>>> typeFactory.createSqlType(SqlTypeName.VARCHAR))
>>> .build();
>>> }
>>>
>>> @Override
>>> public Statistic getStatistic() {
>>> return new StatisticImpl();
>>> }
>>>
>>> @Override
>>> public Schema.TableType getJdbcTableType() {
>>> throw new UnsupportedOperationException("Not supported
>>> yet.");
>>> //To change body of generated methods, choose Tools | Templates.
>>> }
>>>
>>> @Override
>>> public boolean isRolledUp(String column) {
>>> return true;
>>> }
>>>
>>> @Override
>>> public boolean rolledUpColumnValidInsideAgg(String column,
>>> SqlCall
>>> call, SqlNode parent, CalciteConnectionConfig config) {
>>> return false;
>>> }
>>>
>>> class StatisticImpl implements Statistic {
>>>
>>> public StatisticImpl() {
>>> }
>>>
>>> @Override
>>> public Double getRowCount() {
>>> return 15d;
>>> }
>>>
>>> @Override
>>> public boolean isKey(ImmutableBitSet columns) {
>>> return false;
>>> }
>>>
>>> @Override
>>> public List<RelReferentialConstraint>
>>> getReferentialConstraints() {
>>> return Collections.emptyList();
>>> }
>>>
>>> @Override
>>> public List<RelCollation> getCollations() {
>>> RelCollation c = new RelCollationImpl(
>>> ImmutableList.of(
>>> new RelFieldCollation(0,
>>> RelFieldCollation.Direction.ASCENDING),
>>> new RelFieldCollation(1,
>>> RelFieldCollation.Direction.ASCENDING)
>>> )) {
>>> };
>>> return Arrays.asList(c);
>>> }
>>>
>>> @Override
>>> public RelDistribution getDistribution() {
>>> return RelDistributions.ANY;
>>> }
>>> }
>>> }
>>>
>>>
>>>
>>>
>>> 2017-11-06 19:48 GMT+01:00 Julian Hyde <[email protected]>:
>>>
>>> > Yes that is definitely possible. I am too busy to write a code snippet
>>> but
>>> > you should take a look at PlannerTest.
>>> >
>>> > > On Nov 6, 2017, at 3:05 AM, Stéphane Campinas <
>>> > [email protected]> wrote:
>>> > >
>>> > > Hi,
>>> > >
>>> > > I am trying to use the Volcano planner in order to optimise queries
>>> based
>>> > > on statistics but I am having some issues understanding how to
>>> achieve
>>> > > this, even after looking at the Github repository for tests.
>>> > > A first goal I would like to achieve would be to choose a join
>>> > > implementation based on its cost.
>>> > >
>>> > > For example, a query tree can have several joins, and depending on
>>> the
>>> > > position of the join in the tree, an certain implementation would be
>>> more
>>> > > efficient than another.
>>> > > Would that be possible ? If so, could you share a code snippet ?
>>> > >
>>> > > Thanks
>>> > >
>>> > > --
>>> > > Campinas Stéphane
>>> >
>>> >
>>
>> --
>>
>>
>> -- Enrico Olivelli
>>
>
>