Skip to content

Commit

Permalink
[CALCITE-1703] Functions on TIME or TIMESTAMP column can throw ClassC…
Browse files Browse the repository at this point in the history
…astException
  • Loading branch information
ijokarumawak committed Dec 14, 2018
1 parent f3655e1 commit c2056f6
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -636,13 +636,13 @@ public Expression fieldReference(

public Expression fieldReference(
Expression expression, int field, Type storageType) {
Type fieldType;
Class fieldType;
if (storageType == null) {
storageType = fieldClass(field);
fieldType = null;
} else {
fieldType = fieldClass(field);
if (fieldType != java.sql.Date.class) {
if (!java.util.Date.class.isAssignableFrom(fieldType)) {
fieldType = null;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1020,6 +1020,18 @@ public static Expression convert(Expression operand, Type fromType,
} else {
return Expressions.convert_(operand, toType);
}
} else if (fromType == java.sql.Time.class) {
if (toBox == Primitive.INT) {
return Expressions.call(BuiltInMethod.TIME_TO_INT.method, operand);
} else {
return Expressions.convert_(operand, toType);
}
} else if (fromType == java.sql.Timestamp.class) {
if (toBox == Primitive.LONG) {
return Expressions.call(BuiltInMethod.TIMESTAMP_TO_LONG.method, operand);
} else {
return Expressions.convert_(operand, toType);
}
} else if (toType == java.sql.Date.class) {
// E.g. from "int" or "Integer" to "java.sql.Date",
// generate "SqlFunctions.internalToDate".
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1610,6 +1610,7 @@ public static long toLong(Object o) {
return o instanceof Long ? (Long) o
: o instanceof Number ? toLong((Number) o)
: o instanceof String ? toLong((String) o)
: o instanceof java.util.Date ? toLong((java.util.Date) o)
: (Long) cannotConvert(o, long.class);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package org.apache.calcite.test;

import org.apache.calcite.adapter.java.AbstractQueryableTable;
import org.apache.calcite.jdbc.CalciteConnection;
import org.apache.calcite.jdbc.JavaTypeFactoryImpl;
import org.apache.calcite.linq4j.Enumerable;
import org.apache.calcite.linq4j.EnumerableDefaults;
import org.apache.calcite.linq4j.Linq4j;
import org.apache.calcite.linq4j.QueryProvider;
import org.apache.calcite.linq4j.Queryable;
import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.rel.type.RelDataTypeFactory;
import org.apache.calcite.rel.type.RelDataTypeSystem;
import org.apache.calcite.schema.SchemaPlus;
import org.apache.calcite.schema.Table;
import org.junit.Test;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Arrays;
import java.util.Collections;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

public class ObjectArrayTableTest {

/** Test case for
* <a href="https://issues.apache.org/jira/browse/CALCITE-1703">[CALCITE-1703]
* Functions on TIME and TIMESTAMP column can throw ClassCastException</a>. */
@Test public void testJavaSqlDateColumnReference() throws SQLException {

try (
Connection connection = DriverManager.getConnection("jdbc:calcite:");
final CalciteConnection calciteConnection = connection.unwrap(CalciteConnection.class)
) {
final SchemaPlus rootSchema = calciteConnection.getRootSchema();

final JavaTypeFactoryImpl typeFactory =
new JavaTypeFactoryImpl(RelDataTypeSystem.DEFAULT);

final RelDataType rowType =typeFactory.createStructType(
Arrays.asList(
typeFactory.createJavaType(java.sql.Date.class),
typeFactory.createJavaType(java.sql.Time.class),
typeFactory.createJavaType(java.sql.Timestamp.class)
),
Arrays.asList("dt", "tm", "ts")
);

final Enumerable<Object[]> enumerable =
Linq4j.asEnumerable(
Collections.singletonList(new Object[]{
java.sql.Date.valueOf("2018-12-14"),
java.sql.Time.valueOf("18:29:34"),
java.sql.Timestamp.valueOf("2018-12-14 18:29:34.123")}));

final Table table = new AbstractQueryableTable(Object[].class) {
@Override
@SuppressWarnings({"unchecked", "rawtypes"})
public Queryable<Object[]> asQueryable(QueryProvider queryProvider, SchemaPlus schema, String tableName) {
return EnumerableDefaults.asOrderedQueryable(enumerable);
}

@Override
public RelDataType getRowType(RelDataTypeFactory typeFactory) {
return rowType;
}
};

rootSchema.add("java_sql_date_types", table);

// 'extract' function expects numeric date representation.
// RexToLixTranslator.convert() handles Java type to numeric conversion.
final Statement statement = connection.createStatement();
String sql = "select extract(year from \"dt\")," +
" extract(hour from \"tm\")," +
" extract(day from \"ts\") from \"java_sql_date_types\"";

ResultSet resultSet = statement.executeQuery(sql);
assertTrue(resultSet.next());
assertEquals(2018, resultSet.getInt(1));
// Although using 'extract' function against time value doesn't make sense, this confirms time column can be converted to int.
assertEquals(0, resultSet.getInt(2));
assertEquals(14, resultSet.getInt(3));

}
}

}

0 comments on commit c2056f6

Please sign in to comment.