Skip to content

Commit 063d5fb

Browse files
mikepigottxhochy
authored andcommitted
ARROW-3923: [Java] JDBC Time Fetches Without Timezone
https://issues.apache.org/jira/browse/ARROW-3923 Hello! I was reading through the JDBC source code and I noticed that a java.util.Calendar was required for creating an Arrow Schema and Arrow Vectors from a JDBC ResultSet, when none is required. This change makes the Calendar optional. Unit Tests: The existing SureFire plugin configuration uses a UTC calendar for the database, which is the default Calendar in the existing code. Likewise, no changes to the unit tests are required to provide adequate coverage for the change. Author: Michael Pigott <mikepigott@users.noreply.github.com> Author: Mike Pigott <mpigott@gmail.com> Closes apache#3066 from mikepigott/jdbc-timestamp-no-calendar and squashes the following commits: 4d95da0 <Mike Pigott> ARROW-3923: Supporting a null Calendar in the config, and reverting the breaking change. cd9a230 <Mike Pigott> Merge branch 'master' into jdbc-timestamp-no-calendar 509a1cc <Michael Pigott> Merge pull request #5 from apache/master 789c8c8 <Michael Pigott> Merge pull request #4 from apache/master e5b19ee <Michael Pigott> Merge pull request #3 from apache/master 3b17c29 <Michael Pigott> Merge pull request #2 from apache/master 881c6c8 <Michael Pigott> Merge pull request #1 from apache/master 089cff4 <Mike Pigott> Format fixes a58a4a5 <Mike Pigott> Fixing calendar usage. e12832a <Mike Pigott> Allowing for timestamps without a time zone.
1 parent 5a7cec4 commit 063d5fb

File tree

5 files changed

+46
-28
lines changed

5 files changed

+46
-28
lines changed

java/adapter/jdbc/src/main/java/org/apache/arrow/adapter/jdbc/JdbcToArrow.java

+2-4
Original file line numberDiff line numberDiff line change
@@ -179,13 +179,12 @@ public static VectorSchemaRoot sqlToArrow(ResultSet resultSet, BaseAllocator all
179179
* For the given JDBC {@link ResultSet}, fetch the data from Relational DB and convert it to Arrow objects.
180180
*
181181
* @param resultSet ResultSet to use to fetch the data from underlying database
182-
* @param calendar Calendar instance to use for Date, Time and Timestamp datasets.
182+
* @param calendar Calendar instance to use for Date, Time and Timestamp datasets, or <code>null</code> if none.
183183
* @return Arrow Data Objects {@link VectorSchemaRoot}
184184
* @throws SQLException on error
185185
*/
186186
public static VectorSchemaRoot sqlToArrow(ResultSet resultSet, Calendar calendar) throws SQLException, IOException {
187187
Preconditions.checkNotNull(resultSet, "JDBC ResultSet object can not be null");
188-
Preconditions.checkNotNull(calendar, "Calendar object can not be null");
189188

190189
return sqlToArrow(resultSet, new JdbcToArrowConfig(new RootAllocator(Integer.MAX_VALUE), calendar));
191190
}
@@ -195,15 +194,14 @@ public static VectorSchemaRoot sqlToArrow(ResultSet resultSet, Calendar calendar
195194
*
196195
* @param resultSet ResultSet to use to fetch the data from underlying database
197196
* @param allocator Memory allocator to use.
198-
* @param calendar Calendar instance to use for Date, Time and Timestamp datasets.
197+
* @param calendar Calendar instance to use for Date, Time and Timestamp datasets, or <code>null</code> if none.
199198
* @return Arrow Data Objects {@link VectorSchemaRoot}
200199
* @throws SQLException on error
201200
*/
202201
public static VectorSchemaRoot sqlToArrow(ResultSet resultSet, BaseAllocator allocator, Calendar calendar)
203202
throws SQLException, IOException {
204203
Preconditions.checkNotNull(resultSet, "JDBC ResultSet object can not be null");
205204
Preconditions.checkNotNull(allocator, "Memory Allocator object can not be null");
206-
Preconditions.checkNotNull(calendar, "Calendar object can not be null");
207205

208206
return sqlToArrow(resultSet, new JdbcToArrowConfig(allocator, calendar));
209207
}

java/adapter/jdbc/src/main/java/org/apache/arrow/adapter/jdbc/JdbcToArrowConfig.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -48,15 +48,15 @@ public final class JdbcToArrowConfig {
4848
*/
4949
JdbcToArrowConfig(BaseAllocator allocator, Calendar calendar) {
5050
Preconditions.checkNotNull(allocator, "Memory allocator cannot be null");
51-
Preconditions.checkNotNull(calendar, "Calendar object can not be null");
5251

5352
this.allocator = allocator;
5453
this.calendar = calendar;
5554
}
5655

5756
/**
5857
* The calendar to use when defining Arrow Timestamp fields
59-
* and retrieving time-based fields from the database.
58+
* and retrieving {@link Date}, {@link Time}, or {@link Timestamp}
59+
* data types from the {@link ResultSet}, or <code>null</code> if not converting.
6060
* @return the calendar.
6161
*/
6262
public Calendar getCalendar() {

java/adapter/jdbc/src/main/java/org/apache/arrow/adapter/jdbc/JdbcToArrowConfigBuilder.java

+4-7
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public class JdbcToArrowConfigBuilder {
3232

3333
/**
3434
* Default constructor for the <code>JdbcToArrowConfigBuilder}</code>.
35-
* Use the setter methods for the allocator and calendar; both must be
35+
* Use the setter methods for the allocator and calendar; the allocator must be
3636
* set. Otherwise, {@link #build()} will throw a {@link NullPointerException}.
3737
*/
3838
public JdbcToArrowConfigBuilder() {
@@ -41,9 +41,9 @@ public JdbcToArrowConfigBuilder() {
4141
}
4242

4343
/**
44-
* Constructor for the <code>JdbcToArrowConfigBuilder</code>. Both the
45-
* allocator and calendar are required. A {@link NullPointerException}
46-
* will be thrown if one of the arguments is <code>null</code>.
44+
* Constructor for the <code>JdbcToArrowConfigBuilder</code>. The
45+
* allocator is required, and a {@link NullPointerException}
46+
* will be thrown if it is <code>null</code>.
4747
* <p>
4848
* The allocator is used to construct Arrow vectors from the JDBC ResultSet.
4949
* The calendar is used to determine the time zone of {@link java.sql.Timestamp}
@@ -59,7 +59,6 @@ public JdbcToArrowConfigBuilder(BaseAllocator allocator, Calendar calendar) {
5959
this();
6060

6161
Preconditions.checkNotNull(allocator, "Memory allocator cannot be null");
62-
Preconditions.checkNotNull(calendar, "Calendar object can not be null");
6362

6463
this.allocator = allocator;
6564
this.calendar = calendar;
@@ -82,10 +81,8 @@ public JdbcToArrowConfigBuilder setAllocator(BaseAllocator allocator) {
8281
* Arrow schema, and reading time-based fields from the JDBC <code>ResultSet</code>.
8382
*
8483
* @param calendar the calendar to set.
85-
* @exception NullPointerExeption if <code>calendar</code> is <code>null</code>.
8684
*/
8785
public JdbcToArrowConfigBuilder setCalendar(Calendar calendar) {
88-
Preconditions.checkNotNull(calendar, "Calendar object can not be null");
8986
this.calendar = calendar;
9087
return this;
9188
}

java/adapter/jdbc/src/main/java/org/apache/arrow/adapter/jdbc/JdbcToArrowUtils.java

+29-9
Original file line numberDiff line numberDiff line change
@@ -240,15 +240,15 @@ private static void allocateVectors(VectorSchemaRoot root, int size) {
240240
*
241241
* @param rs ResultSet to use to fetch the data from underlying database
242242
* @param root Arrow {@link VectorSchemaRoot} object to populate
243-
* @param calendar The calendar to use when reading time-based data.
243+
* @param calendar The calendar to use when reading {@link Date}, {@link Time}, or {@link Timestamp}
244+
* data types from the {@link ResultSet}, or <code>null</code> if not converting.
244245
* @throws SQLException on error
245246
*/
246247
public static void jdbcToArrowVectors(ResultSet rs, VectorSchemaRoot root, Calendar calendar)
247248
throws SQLException, IOException {
248249

249250
Preconditions.checkNotNull(rs, "JDBC ResultSet object can't be null");
250-
Preconditions.checkNotNull(root, "Vector Schema cannot be null");
251-
Preconditions.checkNotNull(calendar, "Calendar object can't be null");
251+
Preconditions.checkNotNull(root, "JDBC ResultSet object can't be null");
252252

253253
jdbcToArrowVectors(rs, root, new JdbcToArrowConfig(new RootAllocator(0), calendar));
254254
}
@@ -274,6 +274,8 @@ public static void jdbcToArrowVectors(ResultSet rs, VectorSchemaRoot root, JdbcT
274274

275275
allocateVectors(root, DEFAULT_BUFFER_SIZE);
276276

277+
final Calendar calendar = config.getCalendar();
278+
277279
int rowCount = 0;
278280
while (rs.next()) {
279281
for (int i = 1; i <= columnCount; i++) {
@@ -324,17 +326,35 @@ public static void jdbcToArrowVectors(ResultSet rs, VectorSchemaRoot root, JdbcT
324326
rs.getString(i), !rs.wasNull(), rowCount);
325327
break;
326328
case Types.DATE:
327-
updateVector((DateMilliVector) root.getVector(columnName),
328-
rs.getDate(i, config.getCalendar()), !rs.wasNull(), rowCount);
329+
final Date date;
330+
if (calendar != null) {
331+
date = rs.getDate(i, calendar);
332+
} else {
333+
date = rs.getDate(i);
334+
}
335+
336+
updateVector((DateMilliVector) root.getVector(columnName), date, !rs.wasNull(), rowCount);
329337
break;
330338
case Types.TIME:
331-
updateVector((TimeMilliVector) root.getVector(columnName),
332-
rs.getTime(i, config.getCalendar()), !rs.wasNull(), rowCount);
339+
final Time time;
340+
if (calendar != null) {
341+
time = rs.getTime(i, calendar);
342+
} else {
343+
time = rs.getTime(i);
344+
}
345+
346+
updateVector((TimeMilliVector) root.getVector(columnName), time, !rs.wasNull(), rowCount);
333347
break;
334348
case Types.TIMESTAMP:
349+
final Timestamp ts;
350+
if (calendar != null) {
351+
ts = rs.getTimestamp(i, calendar);
352+
} else {
353+
ts = rs.getTimestamp(i);
354+
}
355+
335356
// TODO: Need to handle precision such as milli, micro, nano
336-
updateVector((TimeStampVector) root.getVector(columnName),
337-
rs.getTimestamp(i, config.getCalendar()), !rs.wasNull(), rowCount);
357+
updateVector((TimeStampVector) root.getVector(columnName), ts, !rs.wasNull(), rowCount);
338358
break;
339359
case Types.BINARY:
340360
case Types.VARBINARY:

java/adapter/jdbc/src/test/java/org/apache/arrow/adapter/jdbc/JdbcToArrowConfigTest.java

+9-6
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,16 @@ public void testBuilderNullArguments() {
4242
new JdbcToArrowConfigBuilder(null, null);
4343
}
4444

45-
@Test(expected = NullPointerException.class)
4645
public void testConfigNullCalendar() {
47-
new JdbcToArrowConfig(allocator, null);
46+
JdbcToArrowConfig config = new JdbcToArrowConfig(allocator, null);
47+
assertNull(config.getCalendar());
4848
}
4949

50-
@Test(expected = NullPointerException.class)
50+
@Test
5151
public void testBuilderNullCalendar() {
52-
new JdbcToArrowConfigBuilder(allocator, null);
52+
JdbcToArrowConfigBuilder builder = new JdbcToArrowConfigBuilder(allocator, null);
53+
JdbcToArrowConfig config = builder.build();
54+
assertNull(config.getCalendar());
5355
}
5456

5557
@Test(expected = NullPointerException.class)
@@ -68,10 +70,11 @@ public void testSetNullAllocator() {
6870
builder.setAllocator(null);
6971
}
7072

71-
@Test(expected = NullPointerException.class)
73+
@Test
7274
public void testSetNullCalendar() {
7375
JdbcToArrowConfigBuilder builder = new JdbcToArrowConfigBuilder(allocator, calendar);
74-
builder.setCalendar(null);
76+
JdbcToArrowConfig config = builder.setCalendar(null).build();
77+
assertNull(config.getCalendar());
7578
}
7679

7780
@Test

0 commit comments

Comments
 (0)