Skip to content

Commit adca971

Browse files
committed
[CALCITE-6282] Avatica ignores time precision when returning TIME results
Signed-off-by: Mihai Budiu <[email protected]>
1 parent bc7ba9e commit adca971

File tree

5 files changed

+81
-21
lines changed

5 files changed

+81
-21
lines changed

core/src/main/java/org/apache/calcite/avatica/util/AbstractCursor.java

+26-17
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ protected Accessor createAccessor(ColumnMetaData columnMetaData,
154154
case PRIMITIVE_INT:
155155
case INTEGER:
156156
case NUMBER:
157-
return new TimeFromNumberAccessor(getter, localCalendar);
157+
return new TimeFromNumberAccessor(getter, localCalendar, columnMetaData.precision);
158158
case JAVA_SQL_TIME:
159159
return new TimeAccessor(getter, localCalendar);
160160
default:
@@ -165,11 +165,11 @@ protected Accessor createAccessor(ColumnMetaData columnMetaData,
165165
case PRIMITIVE_LONG:
166166
case LONG:
167167
case NUMBER:
168-
return new TimestampFromNumberAccessor(getter, localCalendar);
168+
return new TimestampFromNumberAccessor(getter, localCalendar, columnMetaData.precision);
169169
case JAVA_SQL_TIMESTAMP:
170-
return new TimestampAccessor(getter, localCalendar);
170+
return new TimestampAccessor(getter, localCalendar, columnMetaData.precision);
171171
case JAVA_UTIL_DATE:
172-
return new TimestampFromUtilDateAccessor(getter, localCalendar);
172+
return new TimestampFromUtilDateAccessor(getter, localCalendar, columnMetaData.precision);
173173
default:
174174
throw new AssertionError("bad " + columnMetaData.type.rep);
175175
}
@@ -241,11 +241,11 @@ protected Accessor createAccessor(ColumnMetaData columnMetaData,
241241
/** Accesses a timestamp value as a string.
242242
* The timestamp is in SQL format (e.g. "2013-09-22 22:30:32"),
243243
* not Java format ("2013-09-22 22:30:32.123"). */
244-
private static String timestampAsString(long v, Calendar calendar) {
244+
private static String timestampAsString(long v, Calendar calendar, int precision) {
245245
if (calendar != null) {
246246
v -= calendar.getTimeZone().getOffset(v);
247247
}
248-
return DateTimeUtils.unixTimestampToString(v);
248+
return DateTimeUtils.unixTimestampToString(v, precision);
249249
}
250250

251251
/** Accesses a date value as a string, e.g. "2013-09-22". */
@@ -255,11 +255,11 @@ private static String dateAsString(int v, Calendar calendar) {
255255
}
256256

257257
/** Accesses a time value as a string, e.g. "22:30:32". */
258-
private static String timeAsString(int v, Calendar calendar) {
258+
private static String timeAsString(int v, Calendar calendar, int precision) {
259259
if (calendar != null) {
260260
v -= calendar.getTimeZone().getOffset(v);
261261
}
262-
return DateTimeUtils.unixTimeToString(v);
262+
return DateTimeUtils.unixTimeToString(v, precision);
263263
}
264264

265265
/** Implementation of {@link Cursor.Accessor}. */
@@ -955,10 +955,12 @@ protected Number getNumber() throws SQLException {
955955
*/
956956
static class TimeFromNumberAccessor extends NumberAccessor {
957957
private final Calendar localCalendar;
958+
private final int precision;
958959

959-
TimeFromNumberAccessor(Getter getter, Calendar localCalendar) {
960+
TimeFromNumberAccessor(Getter getter, Calendar localCalendar, int precision) {
960961
super(getter, 0);
961962
this.localCalendar = localCalendar;
963+
this.precision = precision;
962964
}
963965

964966
@Override public Object getObject() throws SQLException {
@@ -986,7 +988,7 @@ static class TimeFromNumberAccessor extends NumberAccessor {
986988
if (v == null) {
987989
return null;
988990
}
989-
return timeAsString(v.intValue(), null);
991+
return timeAsString(v.intValue(), null, this.precision);
990992
}
991993

992994
protected Number getNumber() throws SQLException {
@@ -1013,10 +1015,12 @@ protected Number getNumber() throws SQLException {
10131015
*/
10141016
static class TimestampFromNumberAccessor extends NumberAccessor {
10151017
private final Calendar localCalendar;
1018+
private final int precision;
10161019

1017-
TimestampFromNumberAccessor(Getter getter, Calendar localCalendar) {
1020+
TimestampFromNumberAccessor(Getter getter, Calendar localCalendar, int precision) {
10181021
super(getter, 0);
10191022
this.localCalendar = localCalendar;
1023+
this.precision = precision;
10201024
}
10211025

10221026
@Override public Object getObject() throws SQLException {
@@ -1052,7 +1056,7 @@ static class TimestampFromNumberAccessor extends NumberAccessor {
10521056
if (v == null) {
10531057
return null;
10541058
}
1055-
return timestampAsString(v.longValue(), null);
1059+
return timestampAsString(v.longValue(), null, this.precision);
10561060
}
10571061

10581062
protected Number getNumber() throws SQLException {
@@ -1155,7 +1159,8 @@ static class TimeAccessor extends ObjectAccessor {
11551159
return null;
11561160
}
11571161
final int unix = DateTimeUtils.sqlTimeToUnixTime(time, localCalendar);
1158-
return timeAsString(unix, null);
1162+
// java.sql.Time only supports a precision of 0
1163+
return timeAsString(unix, null, 0);
11591164
}
11601165

11611166
@Override public long getLong() throws SQLException {
@@ -1178,10 +1183,12 @@ static class TimeAccessor extends ObjectAccessor {
11781183
*/
11791184
static class TimestampAccessor extends ObjectAccessor {
11801185
private final Calendar localCalendar;
1186+
private final int precision;
11811187

1182-
TimestampAccessor(Getter getter, Calendar localCalendar) {
1188+
TimestampAccessor(Getter getter, Calendar localCalendar, int precision) {
11831189
super(getter);
11841190
this.localCalendar = localCalendar;
1191+
this.precision = precision;
11851192
}
11861193

11871194
@Override public Timestamp getTimestamp(Calendar calendar) throws SQLException {
@@ -1220,7 +1227,7 @@ static class TimestampAccessor extends ObjectAccessor {
12201227
}
12211228
final long unix =
12221229
DateTimeUtils.sqlTimestampToUnixTimestamp(timestamp, localCalendar);
1223-
return timestampAsString(unix, null);
1230+
return timestampAsString(unix, null, this.precision);
12241231
}
12251232

12261233
@Override public long getLong() throws SQLException {
@@ -1241,11 +1248,13 @@ static class TimestampAccessor extends ObjectAccessor {
12411248
*/
12421249
static class TimestampFromUtilDateAccessor extends ObjectAccessor {
12431250
private final Calendar localCalendar;
1251+
private final int precision;
12441252

12451253
TimestampFromUtilDateAccessor(Getter getter,
1246-
Calendar localCalendar) {
1254+
Calendar localCalendar, int precision) {
12471255
super(getter);
12481256
this.localCalendar = localCalendar;
1257+
this.precision = precision;
12491258
}
12501259

12511260
@Override public Timestamp getTimestamp(Calendar calendar) throws SQLException {
@@ -1282,7 +1291,7 @@ static class TimestampFromUtilDateAccessor extends ObjectAccessor {
12821291
return null;
12831292
}
12841293
final long unix = DateTimeUtils.utilDateToUnixTimestamp(date, localCalendar);
1285-
return timestampAsString(unix, null);
1294+
return timestampAsString(unix, null, this.precision);
12861295
}
12871296

12881297
@Override public long getLong() throws SQLException {

core/src/test/java/org/apache/calcite/avatica/util/TimeFromNumberAccessorTest.java

+23-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ public class TimeFromNumberAccessorTest {
4848
final AbstractCursor.Getter getter = new LocalGetter();
4949
localCalendar = Calendar.getInstance(TimeZone.getDefault(), Locale.ROOT);
5050
instance = new AbstractCursor.TimeFromNumberAccessor(getter,
51-
localCalendar);
51+
localCalendar, 0);
5252
}
5353

5454
/**
@@ -156,4 +156,26 @@ private class LocalGetter implements AbstractCursor.Getter {
156156
return value == null;
157157
}
158158
}
159+
160+
/**
161+
* Test case for <a href="https://issues.apache.org/jira/browse/CALCITE-6282">[CALCITE-6282]
162+
* Avatica ignores time precision when returning TIME results</a>. */
163+
@Test public void testPrecision() throws SQLException {
164+
final AbstractCursor.Getter getter = new AbstractCursor.Getter() {
165+
@Override
166+
public Object getObject() throws SQLException {
167+
// This is the representation of TIME '12:42:25.34'
168+
return 45745340;
169+
}
170+
171+
@Override
172+
public boolean wasNull() throws SQLException {
173+
return false;
174+
}
175+
};
176+
AbstractCursor.TimeFromNumberAccessor accessor = new AbstractCursor.TimeFromNumberAccessor(
177+
getter, null, 2);
178+
String string = accessor.getString();
179+
assertThat(string, is("12:42:25.34"));
180+
}
159181
}

core/src/test/java/org/apache/calcite/avatica/util/TimestampAccessorTest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public class TimestampAccessorTest {
6060
@Before public void before() {
6161
final AbstractCursor.Getter getter = new LocalGetter();
6262
localCalendar = Calendar.getInstance(TimeZone.getDefault(), Locale.ROOT);
63-
instance = new AbstractCursor.TimestampAccessor(getter, localCalendar);
63+
instance = new AbstractCursor.TimestampAccessor(getter, localCalendar, 0);
6464
}
6565

6666
/**

core/src/test/java/org/apache/calcite/avatica/util/TimestampFromNumberAccessorTest.java

+30-1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ public class TimestampFromNumberAccessorTest {
4040
// UTC: 2014-09-30 15:28:27.356
4141
private static final long DST_INSTANT = 1412090907356L;
4242
private static final String DST_STRING = "2014-09-30 15:28:27";
43+
// With precision 2
44+
private static final String DST_STRING_2 = "2014-09-30 15:28:27.35";
45+
// With precision 3
46+
private static final String DST_STRING_3 = "2014-09-30 15:28:27.356";
4347

4448
// UTC: 1500-04-30 12:00:00.123 (JULIAN CALENDAR)
4549
private static final long PRE_GREG_INSTANT = -14821444799877L;
@@ -56,7 +60,7 @@ public class TimestampFromNumberAccessorTest {
5660
@Before public void before() {
5761
final AbstractCursor.Getter getter = new LocalGetter();
5862
localCalendar = Calendar.getInstance(TimeZone.getDefault(), Locale.ROOT);
59-
instance = new AbstractCursor.TimestampFromNumberAccessor(getter, localCalendar);
63+
instance = new AbstractCursor.TimestampFromNumberAccessor(getter, localCalendar, 0);
6064
}
6165

6266
/**
@@ -72,6 +76,31 @@ public class TimestampFromNumberAccessorTest {
7276
is(Timestamp.valueOf("1500-04-30 12:00:00")));
7377
}
7478

79+
/**
80+
* Test case for <a href="https://issues.apache.org/jira/browse/CALCITE-6282">
81+
* [CALCITE-6282] Avatica ignores time precision when returning TIME results</a>. */
82+
@Test public void testPrecision() throws SQLException {
83+
final AbstractCursor.Getter getter = new AbstractCursor.Getter() {
84+
@Override
85+
public Object getObject() throws SQLException {
86+
return DST_INSTANT;
87+
}
88+
89+
@Override
90+
public boolean wasNull() throws SQLException {
91+
return false;
92+
}
93+
};
94+
AbstractCursor.TimestampFromNumberAccessor accessor =
95+
new AbstractCursor.TimestampFromNumberAccessor(getter, null, 2);
96+
String string = accessor.getString();
97+
assertThat(string, is(DST_STRING_2));
98+
accessor = new AbstractCursor.TimestampFromNumberAccessor(
99+
getter, null, 3);
100+
string = accessor.getString();
101+
assertThat(string, is(DST_STRING_3));
102+
}
103+
75104
/**
76105
* Test {@code getDate()} handles time zone conversions relative to the local calendar and not
77106
* UTC.

core/src/test/java/org/apache/calcite/avatica/util/TimestampFromUtilDateAccessorTest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ public class TimestampFromUtilDateAccessorTest {
6161
@Before public void before() {
6262
final AbstractCursor.Getter getter = new LocalGetter();
6363
localCalendar = Calendar.getInstance(TimeZone.getDefault(), Locale.ROOT);
64-
instance = new AbstractCursor.TimestampFromUtilDateAccessor(getter, localCalendar);
64+
instance = new AbstractCursor.TimestampFromUtilDateAccessor(getter, localCalendar, 0);
6565
}
6666

6767
/**

0 commit comments

Comments
 (0)