[
https://issues.apache.org/jira/browse/CALCITE-4708?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17935326#comment-17935326
]
Julian Hyde commented on CALCITE-4708:
--------------------------------------
A lot of the confusion (including my own) is because no one knows what is
supposed to work. Is there any documentation on the web site how to write a
reflective schema? The PR should add (or update) documentation.
> Infer list generic type while Table instance is created at ReflectiveSchema
> class
> ---------------------------------------------------------------------------------
>
> Key: CALCITE-4708
> URL: https://issues.apache.org/jira/browse/CALCITE-4708
> Project: Calcite
> Issue Type: Improvement
> Components: core
> Affects Versions: 1.27.0
> Environment: Ubuntu 18.04
> Java 11
> Maven 3.6.0
> Reporter: Vladimir Polukeev
> Priority: Major
> Labels: pull-request-available
> Time Spent: 10m
> Remaining Estimate: 0h
>
> I have such code:
> {code:java}
> //
> public class Main {
> public static void main(String[] args) throws SQLException {
> // 1. Create calcite connection
> Properties info = new Properties();
> info.setProperty("lex", "JAVA");
> try(Connection connection =
> DriverManager.getConnection("jdbc:calcite:", info)) {
> Employee employee1 = new Employee("first name 1", "last name 1");
> Employee employee2 = new Employee("first name 2", "last name 2");
> Employee employee3 = new Employee("first name 3", "last name 3");
>
>
> List<Employee> employeeList = new LinkedList<>();
> employeeList.add(employee1);
> employeeList.add(employee2);
> employeeList.add(employee3);
> MyScheme myScheme = new MyScheme();
> myScheme.employees = employeeList;
> Schema schema = new ReflectiveSchema(myScheme);
> // 2. add scheme with data to root scheme
> CalciteConnection calciteConnection =
> connection.unwrap(CalciteConnection.class);
> SchemaPlus rootSchema = calciteConnection.getRootSchema();
> rootSchema.add("cache", schema);
> // 3. execute sql query against scheme
> String sql = "select e.* from cache.employees e";
> ResultSet resultSet =
> calciteConnection.createStatement().executeQuery(sql);
>
> // 4. read data from result set
> while (resultSet.next()) {
> printValues(resultSet);
> }
> }
> }
> public static class MyScheme {
> public List<Employee> employees;
> }
> @AllArgsConstructor
> public static class Employee {
> public String firstName;
> public String lastName;
> }
> public static void printValues(ResultSet resultSet) throws SQLException {
> System.out.println("--------------- row " + resultSet.getRow() + "
> ---------------");
> ResultSetMetaData metaData = resultSet.getMetaData();
> for (int i = 1; i <= metaData.getColumnCount(); i++) {
> String columnName = metaData.getColumnName(i);
> System.out.println(columnName + " : " +
> resultSet.getObject(columnName));
> }
> }
> }
> {code}
>
> Code execution output:
> {noformat}
> --------------- row 1 ---------------
> --------------- row 2 ---------------
> --------------- row 3 ---------------{noformat}
>
> Calcite correctly gets 3 rows, but there is no information about columns at
> output due to item class at Iterable collection infer as Object.class. Here
> is code from ReflectiveSchema.class:
>
> {code:java}
> //
> private static @Nullable Type getElementType(Class clazz) {
> if (clazz.isArray()) {
> return clazz.getComponentType();
> }
> if (Iterable.class.isAssignableFrom(clazz)) {
> return Object.class;
> }
> return null; // not a collection/array/iterable
> }
> {code}
>
>
> Information about columns is retured If I change List<Employee> to Employee[]
> at MyScheme.class. But I have to use List due to my task requirement.
> I manage this issue such way:
> Java compiler erise information about generic type at compile time. Therefore
> I supply information about class using annotation
> org.apache.calcite.adapter.java.Array:
> {code:java}
> //
> public static class MyScheme {
> + @Array(component = Employee.class)
> public List<Employee> employees;
> }
> {code}
> Than I read element type from annotation at runtime. Here is code from
> improved ReflectiveSchema.class:
> {code:java}
> //
> private <T> @Nullable Table fieldRelation(final Field field) {
> + Array arrayAnnotation = field.getAnnotation(Array.class);
> + Class<?> elementListClass = arrayAnnotation != null ?
> arrayAnnotation.component() : null;
> + final Type elementType = getElementType(field.getType(),
> elementListClass);
> ... // redundant method code is omitted
> }
> {code}
> Finally, I return type according to information retrieved from Array
> annotation:
> {code:java}
> //
> + private static @Nullable Type getElementType(Class clazz, Class<?>
> elementListClass) {
> if (clazz.isArray()) {
> return clazz.getComponentType();
> }
> if (Iterable.class.isAssignableFrom(clazz)) {
> + return elementListClass != null ? elementListClass : Object.class;
> }
> return null; // not a collection/array/iterable
> }
> {code}
>
> Now, code execution output:
> {noformat}
> --------------- row 1 ---------------
> firstName : first name 1
> lastName : last name 1
> --------------- row 2 ---------------
> firstName : first name 2
> lastName : last name 2
> --------------- row 3 ---------------
> firstName : first name 3
> lastName : last name 3{noformat}
>
> Does such improvement fit to framework design? Can I create pull request in
> order to make such improvement?
--
This message was sent by Atlassian Jira
(v8.20.10#820010)