[ 
https://issues.apache.org/jira/browse/CALCITE-4708?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Vladimir Polukeev updated CALCITE-4708:
---------------------------------------
    Description: 
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}
Finanlly, I return type according to information retrieve 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?

  was:
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}

Finanlly, I return type according to information retrieve 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 fits to framework design? Can I create pull request in 
order to make such improvement?


> 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
>
> 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}
> Finanlly, I return type according to information retrieve 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.3.4#803005)

Reply via email to