diff --git a/core/src/main/java/org/apache/calcite/avatica/util/AbstractCursor.java b/core/src/main/java/org/apache/calcite/avatica/util/AbstractCursor.java
index 2a4cd64cec..2c5653ae09 100644
--- a/core/src/main/java/org/apache/calcite/avatica/util/AbstractCursor.java
+++ b/core/src/main/java/org/apache/calcite/avatica/util/AbstractCursor.java
@@ -154,7 +154,7 @@ protected Accessor createAccessor(ColumnMetaData columnMetaData,
case PRIMITIVE_INT:
case INTEGER:
case NUMBER:
- return new TimeFromNumberAccessor(getter, localCalendar);
+ return new TimeFromNumberAccessor(getter, localCalendar, columnMetaData.precision);
case JAVA_SQL_TIME:
return new TimeAccessor(getter, localCalendar);
default:
@@ -165,11 +165,11 @@ protected Accessor createAccessor(ColumnMetaData columnMetaData,
case PRIMITIVE_LONG:
case LONG:
case NUMBER:
- return new TimestampFromNumberAccessor(getter, localCalendar);
+ return new TimestampFromNumberAccessor(getter, localCalendar, columnMetaData.precision);
case JAVA_SQL_TIMESTAMP:
- return new TimestampAccessor(getter, localCalendar);
+ return new TimestampAccessor(getter, localCalendar, columnMetaData.precision);
case JAVA_UTIL_DATE:
- return new TimestampFromUtilDateAccessor(getter, localCalendar);
+ return new TimestampFromUtilDateAccessor(getter, localCalendar, columnMetaData.precision);
default:
throw new AssertionError("bad " + columnMetaData.type.rep);
}
@@ -241,11 +241,11 @@ protected Accessor createAccessor(ColumnMetaData columnMetaData,
/** Accesses a timestamp value as a string.
* The timestamp is in SQL format (e.g. "2013-09-22 22:30:32"),
* not Java format ("2013-09-22 22:30:32.123"). */
- private static String timestampAsString(long v, Calendar calendar) {
+ private static String timestampAsString(long v, Calendar calendar, int precision) {
if (calendar != null) {
v -= calendar.getTimeZone().getOffset(v);
}
- return DateTimeUtils.unixTimestampToString(v);
+ return DateTimeUtils.unixTimestampToString(v, precision);
}
/** Accesses a date value as a string, e.g. "2013-09-22". */
@@ -255,11 +255,11 @@ private static String dateAsString(int v, Calendar calendar) {
}
/** Accesses a time value as a string, e.g. "22:30:32". */
- private static String timeAsString(int v, Calendar calendar) {
+ private static String timeAsString(int v, Calendar calendar, int precision) {
if (calendar != null) {
v -= calendar.getTimeZone().getOffset(v);
}
- return DateTimeUtils.unixTimeToString(v);
+ return DateTimeUtils.unixTimeToString(v, precision);
}
/** Implementation of {@link Cursor.Accessor}. */
@@ -955,10 +955,12 @@ protected Number getNumber() throws SQLException {
*/
static class TimeFromNumberAccessor extends NumberAccessor {
private final Calendar localCalendar;
+ private final int precision;
- TimeFromNumberAccessor(Getter getter, Calendar localCalendar) {
+ TimeFromNumberAccessor(Getter getter, Calendar localCalendar, int precision) {
super(getter, 0);
this.localCalendar = localCalendar;
+ this.precision = precision;
}
@Override public Object getObject() throws SQLException {
@@ -986,7 +988,7 @@ static class TimeFromNumberAccessor extends NumberAccessor {
if (v == null) {
return null;
}
- return timeAsString(v.intValue(), null);
+ return timeAsString(v.intValue(), null, this.precision);
}
protected Number getNumber() throws SQLException {
@@ -1013,10 +1015,12 @@ protected Number getNumber() throws SQLException {
*/
static class TimestampFromNumberAccessor extends NumberAccessor {
private final Calendar localCalendar;
+ private final int precision;
- TimestampFromNumberAccessor(Getter getter, Calendar localCalendar) {
+ TimestampFromNumberAccessor(Getter getter, Calendar localCalendar, int precision) {
super(getter, 0);
this.localCalendar = localCalendar;
+ this.precision = precision;
}
@Override public Object getObject() throws SQLException {
@@ -1052,7 +1056,7 @@ static class TimestampFromNumberAccessor extends NumberAccessor {
if (v == null) {
return null;
}
- return timestampAsString(v.longValue(), null);
+ return timestampAsString(v.longValue(), null, this.precision);
}
protected Number getNumber() throws SQLException {
@@ -1155,7 +1159,8 @@ static class TimeAccessor extends ObjectAccessor {
return null;
}
final int unix = DateTimeUtils.sqlTimeToUnixTime(time, localCalendar);
- return timeAsString(unix, null);
+ // java.sql.Time only supports a precision of 0
+ return timeAsString(unix, null, 0);
}
@Override public long getLong() throws SQLException {
@@ -1178,10 +1183,12 @@ static class TimeAccessor extends ObjectAccessor {
*/
static class TimestampAccessor extends ObjectAccessor {
private final Calendar localCalendar;
+ private final int precision;
- TimestampAccessor(Getter getter, Calendar localCalendar) {
+ TimestampAccessor(Getter getter, Calendar localCalendar, int precision) {
super(getter);
this.localCalendar = localCalendar;
+ this.precision = precision;
}
@Override public Timestamp getTimestamp(Calendar calendar) throws SQLException {
@@ -1220,7 +1227,7 @@ static class TimestampAccessor extends ObjectAccessor {
}
final long unix =
DateTimeUtils.sqlTimestampToUnixTimestamp(timestamp, localCalendar);
- return timestampAsString(unix, null);
+ return timestampAsString(unix, null, this.precision);
}
@Override public long getLong() throws SQLException {
@@ -1241,11 +1248,13 @@ static class TimestampAccessor extends ObjectAccessor {
*/
static class TimestampFromUtilDateAccessor extends ObjectAccessor {
private final Calendar localCalendar;
+ private final int precision;
TimestampFromUtilDateAccessor(Getter getter,
- Calendar localCalendar) {
+ Calendar localCalendar, int precision) {
super(getter);
this.localCalendar = localCalendar;
+ this.precision = precision;
}
@Override public Timestamp getTimestamp(Calendar calendar) throws SQLException {
@@ -1282,7 +1291,7 @@ static class TimestampFromUtilDateAccessor extends ObjectAccessor {
return null;
}
final long unix = DateTimeUtils.utilDateToUnixTimestamp(date, localCalendar);
- return timestampAsString(unix, null);
+ return timestampAsString(unix, null, this.precision);
}
@Override public long getLong() throws SQLException {
diff --git a/core/src/test/java/org/apache/calcite/avatica/util/TimeFromNumberAccessorTest.java b/core/src/test/java/org/apache/calcite/avatica/util/TimeFromNumberAccessorTest.java
index 87f557dc8f..efa7a87094 100644
--- a/core/src/test/java/org/apache/calcite/avatica/util/TimeFromNumberAccessorTest.java
+++ b/core/src/test/java/org/apache/calcite/avatica/util/TimeFromNumberAccessorTest.java
@@ -48,7 +48,7 @@ public class TimeFromNumberAccessorTest {
final AbstractCursor.Getter getter = new LocalGetter();
localCalendar = Calendar.getInstance(TimeZone.getDefault(), Locale.ROOT);
instance = new AbstractCursor.TimeFromNumberAccessor(getter,
- localCalendar);
+ localCalendar, 0);
}
/**
@@ -156,4 +156,26 @@ private class LocalGetter implements AbstractCursor.Getter {
return value == null;
}
}
+
+ /**
+ * Test case for [CALCITE-6282]
+ * Avatica ignores time precision when returning TIME results. */
+ @Test public void testPrecision() throws SQLException {
+ final AbstractCursor.Getter getter = new AbstractCursor.Getter() {
+ @Override
+ public Object getObject() throws SQLException {
+ // This is the representation of TIME '12:42:25.34'
+ return 45745340;
+ }
+
+ @Override
+ public boolean wasNull() throws SQLException {
+ return false;
+ }
+ };
+ AbstractCursor.TimeFromNumberAccessor accessor = new AbstractCursor.TimeFromNumberAccessor(
+ getter, null, 2);
+ String string = accessor.getString();
+ assertThat(string, is("12:42:25.34"));
+ }
}
diff --git a/core/src/test/java/org/apache/calcite/avatica/util/TimestampAccessorTest.java b/core/src/test/java/org/apache/calcite/avatica/util/TimestampAccessorTest.java
index 98d20c00f4..573c59e6a8 100644
--- a/core/src/test/java/org/apache/calcite/avatica/util/TimestampAccessorTest.java
+++ b/core/src/test/java/org/apache/calcite/avatica/util/TimestampAccessorTest.java
@@ -60,7 +60,7 @@ public class TimestampAccessorTest {
@Before public void before() {
final AbstractCursor.Getter getter = new LocalGetter();
localCalendar = Calendar.getInstance(TimeZone.getDefault(), Locale.ROOT);
- instance = new AbstractCursor.TimestampAccessor(getter, localCalendar);
+ instance = new AbstractCursor.TimestampAccessor(getter, localCalendar, 0);
}
/**
diff --git a/core/src/test/java/org/apache/calcite/avatica/util/TimestampFromNumberAccessorTest.java b/core/src/test/java/org/apache/calcite/avatica/util/TimestampFromNumberAccessorTest.java
index d8fd819fbf..8ca94ff8f2 100644
--- a/core/src/test/java/org/apache/calcite/avatica/util/TimestampFromNumberAccessorTest.java
+++ b/core/src/test/java/org/apache/calcite/avatica/util/TimestampFromNumberAccessorTest.java
@@ -40,6 +40,10 @@ public class TimestampFromNumberAccessorTest {
// UTC: 2014-09-30 15:28:27.356
private static final long DST_INSTANT = 1412090907356L;
private static final String DST_STRING = "2014-09-30 15:28:27";
+ // With precision 2
+ private static final String DST_STRING_2 = "2014-09-30 15:28:27.35";
+ // With precision 3
+ private static final String DST_STRING_3 = "2014-09-30 15:28:27.356";
// UTC: 1500-04-30 12:00:00.123 (JULIAN CALENDAR)
private static final long PRE_GREG_INSTANT = -14821444799877L;
@@ -56,7 +60,7 @@ public class TimestampFromNumberAccessorTest {
@Before public void before() {
final AbstractCursor.Getter getter = new LocalGetter();
localCalendar = Calendar.getInstance(TimeZone.getDefault(), Locale.ROOT);
- instance = new AbstractCursor.TimestampFromNumberAccessor(getter, localCalendar);
+ instance = new AbstractCursor.TimestampFromNumberAccessor(getter, localCalendar, 0);
}
/**
@@ -72,6 +76,31 @@ public class TimestampFromNumberAccessorTest {
is(Timestamp.valueOf("1500-04-30 12:00:00")));
}
+ /**
+ * Test case for
+ * [CALCITE-6282] Avatica ignores time precision when returning TIME results. */
+ @Test public void testPrecision() throws SQLException {
+ final AbstractCursor.Getter getter = new AbstractCursor.Getter() {
+ @Override
+ public Object getObject() throws SQLException {
+ return DST_INSTANT;
+ }
+
+ @Override
+ public boolean wasNull() throws SQLException {
+ return false;
+ }
+ };
+ AbstractCursor.TimestampFromNumberAccessor accessor =
+ new AbstractCursor.TimestampFromNumberAccessor(getter, null, 2);
+ String string = accessor.getString();
+ assertThat(string, is(DST_STRING_2));
+ accessor = new AbstractCursor.TimestampFromNumberAccessor(
+ getter, null, 3);
+ string = accessor.getString();
+ assertThat(string, is(DST_STRING_3));
+ }
+
/**
* Test {@code getDate()} handles time zone conversions relative to the local calendar and not
* UTC.
diff --git a/core/src/test/java/org/apache/calcite/avatica/util/TimestampFromUtilDateAccessorTest.java b/core/src/test/java/org/apache/calcite/avatica/util/TimestampFromUtilDateAccessorTest.java
index bdc7db1fa2..ec214bb701 100644
--- a/core/src/test/java/org/apache/calcite/avatica/util/TimestampFromUtilDateAccessorTest.java
+++ b/core/src/test/java/org/apache/calcite/avatica/util/TimestampFromUtilDateAccessorTest.java
@@ -61,7 +61,7 @@ public class TimestampFromUtilDateAccessorTest {
@Before public void before() {
final AbstractCursor.Getter getter = new LocalGetter();
localCalendar = Calendar.getInstance(TimeZone.getDefault(), Locale.ROOT);
- instance = new AbstractCursor.TimestampFromUtilDateAccessor(getter, localCalendar);
+ instance = new AbstractCursor.TimestampFromUtilDateAccessor(getter, localCalendar, 0);
}
/**