[Using Apache Calcite 1.30.0]
With query: SELECT * FROM mydb.employees
I can see that when I relNode.explain( .. )
the *
is expanded into the correct columns for the database, so I know that the connection to the database is working (somewhat) as expected, from the model.json
schema.
LogicalProject(emp_no=[$0], birth_date=[$1], first_name=[$2], last_name=[$3], gender=[$4], hire_date=[$5]): rowcount = 100.0, cumulative cost = {200.0 rows, 701.0 cpu, 0.0 io}, id = 4
JdbcTableScan(table=[[mydb, employees]]): rowcount = 100.0, cumulative cost = {100.0 rows, 101.0 cpu, 0.0 io}, id = 3
However, if I try: ResultSet resultSet = run.executeQuery();
, it throws:
java.sql.SQLException: exception while executing query: Cannot invoke "org.apache.calcite.schema.SchemaPlus.unwrap(java.lang.Class)" because the return value of "org.apache.calcite.schema.SchemaPlus.getSubSchema(String)" is null
What am I missing from the connection/model/schema?
Model.json :
{
version: '1.0',
defaultSchema: 'mydb',
schemas: [
{
name: 'mydb',
type: 'custom',
factory: 'org.apache.calcite.adapter.jdbc.JdbcSchema$Factory',
operand: {
jdbcDriver: 'com.mysql.jdbc.Driver',
jdbcUrl: 'jdbc:mysql://127.0.0.1/mydb',
jdbcUser: 'username',
jdbcPassword: 'password'
}
}
]
}
Main Code Snippet :
Properties properties = new Properties();
properties.setProperty(CalciteConnectionProperty.CASE_SENSITIVE.camelName(), "true");
properties.setProperty(CalciteConnectionProperty.QUOTED_CASING.camelName(), Casing.UNCHANGED.name());
properties.setProperty(CalciteConnectionProperty.UNQUOTED_CASING.camelName(), Casing.UNCHANGED.name());
Connection connection = DriverManager.getConnection("jdbc:calcite:model=src/main/resources/model.json", properties);
CalciteConnection calciteConnection = connection.unwrap(CalciteConnection.class);
SchemaPlus rootSchema = calciteConnection.getRootSchema();
SqlParser.Config caseSensitiveParser = SqlParser.configBuilder().setUnquotedCasing(Casing.UNCHANGED).setQuotedCasing(Casing.UNCHANGED).setCaseSensitive(true).build();
FrameworkConfig frameworkConfig = Frameworks.newConfigBuilder()
.parserConfig(caseSensitiveParser)
.defaultSchema(rootSchema)
.build();
Planner planner = Frameworks.getPlanner(frameworkConfig);
String query = "SELECT * FROM mydb.employees";
SqlNode sqlNode = planner.parse(query);
SqlNode sqlNodeValidated = planner.validate(sqlNode);
RelRoot relRoot = planner.rel(sqlNodeValidated);
RelNode relNode = relRoot.project();
final RelWriter relWriter = new RelWriterImpl(new PrintWriter(System.out), SqlExplainLevel.ALL_ATTRIBUTES, false);
relNode.explain(relWriter);
PreparedStatement run = RelRunners.run(relNode);
ResultSet resultSet = run.executeQuery();
You need to unwrap RelRunner from the connection instead of using the dummy connection i.e RelRunners.run(relNode);
Try this
RelRunner runner = connection.unwrap(RelRunner.class);
ResultSet resultSet = runner.prepareStatement(relNode).executeQuery();