Skip to content

Commit 7b05343

Browse files
committed
Support for DB2 TIMESTAMP column type
1 parent b2cac47 commit 7b05343

File tree

7 files changed

+84
-40
lines changed

7 files changed

+84
-40
lines changed

vertx-db2-client/src/main/java/io/vertx/db2client/impl/drda/Cursor.java

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import java.sql.Timestamp;
3131
import java.sql.Types;
3232
import java.time.LocalDate;
33+
import java.time.LocalDateTime;
3334
import java.time.LocalTime;
3435
import java.time.format.DateTimeFormatter;
3536
import java.util.ArrayList;
@@ -58,8 +59,6 @@ public class Cursor {
5859
static final Charset UTF_8 = Charset.forName("UTF-8");
5960
static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1");
6061

61-
private static final DateTimeFormatter db2TimeFormat = DateTimeFormatter.ofPattern("HH.mm.ss");
62-
6362
// unused protocol element: SBCS_CLOB = 8;
6463
// unused protocol element: MBCS_CLOB = 9;
6564
// unused protocol element: DBCS_CLOB = 10;
@@ -501,7 +500,7 @@ private LocalDate get_DATE(int column) {
501500
// DATE column is always 10 chars long
502501
String dateString = dataBuffer_.getCharSequence(columnDataPosition_[column - 1],
503502
10, charset_[column - 1]).toString();
504-
return LocalDate.parse(dateString);
503+
return LocalDate.parse(dateString, DRDAConstants.DB2_DATE_FORMAT);
505504
// return DateTime.dateBytesToDate(dataBuffer_,
506505
// columnDataPosition_[column - 1],
507506
// cal,
@@ -513,23 +512,25 @@ private LocalTime get_TIME(int column) {
513512
// Time column is always 8 chars long
514513
String timeString = dataBuffer_.getCharSequence(columnDataPosition_[column - 1],
515514
8, charset_[column - 1]).toString();
516-
return LocalTime.parse(timeString, db2TimeFormat);
515+
return LocalTime.parse(timeString, DRDAConstants.DB2_TIME_FORMAT);
517516
// return DateTime.timeBytesToTime(dataBuffer_,
518517
// columnDataPosition_[column - 1],
519518
// cal,
520519
// charset_[column - 1]);
521520
}
522521

523-
// // Build a JDBC Timestamp object from the ISO TIMESTAMP field.
524-
// private final Timestamp getTIMESTAMP(int column, Calendar cal)
525-
// throws SQLException {
522+
// Build a JDBC Timestamp object from the ISO TIMESTAMP field.
523+
private final LocalDateTime get_TIMESTAMP(int column) {
524+
String timeString = dataBuffer_.getCharSequence(columnDataPosition_[column - 1],
525+
26, charset_[column - 1]).toString();
526+
return LocalDateTime.parse(timeString, DRDAConstants.DB2_TIMESTAMP_FORMAT);
526527
// return DateTime.timestampBytesToTimestamp(
527528
// dataBuffer_,
528529
// columnDataPosition_[column - 1],
529530
// cal,
530531
// charset_[column - 1],
531532
// agent_.connection_.serverSupportsTimestampNanoseconds());
532-
// }
533+
}
533534
//
534535
// // Build a JDBC Timestamp object from the ISO DATE field.
535536
// private final Timestamp getTimestampFromDATE(
@@ -1223,8 +1224,8 @@ public final Object getObject(int column) {
12231224
return get_DATE(column);
12241225
case Types.TIME:
12251226
return get_TIME(column);
1226-
// case Types.TIMESTAMP:
1227-
// return getTIMESTAMP(column, getRecyclableCalendar());
1227+
case Types.TIMESTAMP:
1228+
return get_TIMESTAMP(column);
12281229
case Types.CHAR:
12291230
return get_CHAR(column);
12301231
case Types.VARCHAR:

vertx-db2-client/src/main/java/io/vertx/db2client/impl/drda/DRDAConstants.java

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@
1515
*/
1616
package io.vertx.db2client.impl.drda;
1717

18+
import java.time.format.DateTimeFormatter;
19+
import java.time.format.DateTimeFormatterBuilder;
20+
import java.time.temporal.ChronoField;
21+
1822
public class DRDAConstants {
1923
// Value to use when padding non-character data in ddm objects.
2024
public static final byte NON_CHAR_DDM_DATA_PAD_BYTE = 0x00;
@@ -323,10 +327,9 @@ public class DRDAConstants {
323327
// DB2 and DRDA support timestamps with microseconds precision, but not
324328
// nanoseconds precision: yyyy-mm-dd-hh.mm.ss.ffffff
325329
// In contrast, JDBC supports full nanoseconds precision: yyyy-mm-dd-hh.mm.ss.fffffffff
326-
//
327330
public static final int DRDA_OLD_TIMESTAMP_LENGTH = 26;
328-
public static final int DRDA_TIMESTAMP_LENGTH = 29;
329-
public static final int JDBC_TIMESTAMP_LENGTH = 29;
331+
public static final int DRDA_TIMESTAMP_LENGTH = 26;
332+
public static final int JDBC_TIMESTAMP_LENGTH = 26;
330333

331334
// Values for the EXTDTA stream status byte.
332335
// The use of this status byte is a product specific extension. The same
@@ -348,6 +351,14 @@ public class DRDAConstants {
348351
public static final String PRDID = "JCC04250";
349352

350353
public static final String EXTNAM = "db2jcc_application " + PRDID + "300";
354+
355+
static final DateTimeFormatter DB2_DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy'-'MM'-'dd");
356+
static final DateTimeFormatter DB2_TIME_FORMAT = DateTimeFormatter.ofPattern("HH'.'mm'.'ss");
357+
static final DateTimeFormatter DB2_TIMESTAMP_FORMAT = new DateTimeFormatterBuilder()
358+
.append(DateTimeFormatter.ofPattern("yyyy'-'MM'-'dd'-'HH'.'mm'.'ss"))
359+
.appendFraction(ChronoField.NANO_OF_SECOND, 6, 9, true)
360+
.toFormatter();
361+
351362
//
352363
// // The server release level of this product.
353364
// // It will be prefixed with PRDID

vertx-db2-client/src/main/java/io/vertx/db2client/impl/drda/DRDAQueryRequest.java

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.sql.RowId;
2121
import java.sql.Types;
2222
import java.time.LocalDate;
23+
import java.time.LocalDateTime;
2324
import java.time.LocalTime;
2425
import java.util.ArrayList;
2526
import java.util.HashMap;
@@ -745,17 +746,14 @@ private void buildFDODTA(int[][] protocolTypesAndLengths, Object[] inputs) {
745746
}
746747
break;
747748
case DRDAConstants.DRDA_TYPE_NTIMESTAMP:
748-
throw new UnsupportedOperationException("DRDA_TYPE_NTIMESTAMP");
749-
// // The value may be a Timestamp if it comes from one of
750-
// // the methods that don't specify the calendar, or a
751-
// // DateTimeValue if it comes from a method that does
752-
// // specify the calendar. Convert to DateTimeValue if
753-
// // needed.
754-
// DateTimeValue tsVal = (inputs[i] instanceof Timestamp)
755-
// ? new DateTimeValue((Timestamp) inputs[i])
756-
// : (DateTimeValue) inputs[i];
757-
// writeTimestamp(tsVal);
758-
// break;
749+
if (inputs[i] instanceof LocalDateTime) {
750+
writeTimestamp((LocalDateTime) inputs[i]);
751+
} else if (inputs[i] instanceof java.sql.Timestamp) {
752+
writeTimestamp((java.sql.Timestamp) inputs[i]);
753+
} else {
754+
throw new UnsupportedOperationException("Unsupported input type for TIMESTAMP column: " + inputs[i].getClass());
755+
}
756+
break;
759757
case DRDAConstants.DRDA_TYPE_NINTEGER8:
760758
buffer.writeLong(((Long) inputs[i]).longValue());
761759
break;
@@ -1156,13 +1154,14 @@ private Hashtable computeProtocolTypesAndLengths(
11561154
lidAndLengths[i][1] = 8;
11571155
break;
11581156
case Types.TIMESTAMP:
1159-
throw new UnsupportedOperationException("Types.TIMESTAMP");
1160-
// // for input, output, and inout parameters
1161-
// // lid: PROTOCOL_TYPE_NTIMESTAMP, length overrid: 26 or 29
1162-
// // dataFormat: java.sql.Timestamp
1163-
// lidAndLengths[i][0] = DRDAConstants.DRDA_TYPE_NTIMESTAMP;
1164-
// lidAndLengths[i][1] = DateTime.getTimestampLength( netAgent_.netConnection_.serverSupportsTimestampNanoseconds() );
1165-
// break;
1157+
// for input, output, and inout parameters
1158+
// lid: PROTOCOL_TYPE_NTIMESTAMP, length overrid: 26 or 29
1159+
// dataFormat: java.sql.Timestamp
1160+
lidAndLengths[i][0] = DRDAConstants.DRDA_TYPE_NTIMESTAMP;
1161+
// @AGG assuming the server supports nanoseconds, otherwise use DRDAConstants.DRDA_OLD_TIMESTAMP_LENGTH
1162+
lidAndLengths[i][1] = DRDAConstants.JDBC_TIMESTAMP_LENGTH;
1163+
// DateTime.getTimestampLength( netAgent_.netConnection_.serverSupportsTimestampNanoseconds() );
1164+
break;
11661165
case Types.BIGINT:
11671166
// if SQLAM < 6 this should be mapped to decimal (19,0) in common layer
11681167
// if SQLAM >=6, lid: PROTOCOL_TYPE_NINTEGER8, length override: 8

vertx-db2-client/src/main/java/io/vertx/db2client/impl/drda/DRDARequest.java

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@
2222
import java.nio.charset.StandardCharsets;
2323
import java.sql.SQLException;
2424
import java.time.LocalDate;
25+
import java.time.LocalDateTime;
2526
import java.time.LocalTime;
27+
import java.time.format.DateTimeFormatter;
2628
import java.util.ArrayDeque;
2729
import java.util.Deque;
2830
import java.util.Hashtable;
@@ -480,12 +482,11 @@ final void writeLong6Bytes(long v) {
480482
}
481483

482484
/**
483-
* Writes a LocalDate to the buffer in the standard SQL format
484-
* of <code>YYYY-MM-DD</code> using UTF8 encoding
485+
* Writes a LocalDate to the buffer in the standard SQL format using UTF8 encoding
485486
*/
486487
final void writeDate(LocalDate date) {
487488
ensureLength(10);
488-
String d = String.format("%04d-%02d-%02d", date.getYear(), date.getMonthValue(), date.getDayOfMonth());
489+
String d = date.format(DRDAConstants.DB2_DATE_FORMAT);
489490
buffer.writeCharSequence(d, StandardCharsets.UTF_8);
490491
}
491492

@@ -494,19 +495,31 @@ final void writeDate(java.sql.Date date) {
494495
}
495496

496497
/**
497-
* Writes a LocalTime to the buffer in the standard SQL format
498-
* of <code>hh:mm:ss</code> using UTF8 encoding
498+
* Writes a LocalTime to the buffer in the standard SQL format using UTF8 encoding
499499
*/
500500
final void writeTime(LocalTime time) {
501501
ensureLength(8);
502-
String d = String.format("%02d:%02d:%02d", time.getHour(), time.getMinute(), time.getSecond());
503-
buffer.writeCharSequence(d, StandardCharsets.UTF_8);
502+
String t = time.format(DRDAConstants.DB2_TIME_FORMAT);
503+
buffer.writeCharSequence(t, StandardCharsets.UTF_8);
504504
}
505505

506506
final void writeTime(java.sql.Time time) {
507507
writeTime(time.toLocalTime());
508508
}
509509

510+
/**
511+
* Writes a LocalTime to the buffer in the standard SQL format using UTF8 encoding
512+
*/
513+
final void writeTimestamp(LocalDateTime ts) {
514+
ensureLength(26);
515+
String t = ts.format(DRDAConstants.DB2_TIMESTAMP_FORMAT);
516+
buffer.writeCharSequence(t, StandardCharsets.UTF_8);
517+
}
518+
519+
final void writeTimestamp(java.sql.Timestamp timestamp) {
520+
writeTimestamp(timestamp.toLocalDateTime());
521+
}
522+
510523
// insert a java.math.BigDecimal into the buffer.
511524
final void writeBigDecimal(BigDecimal v,
512525
int declaredPrecision,

vertx-db2-client/src/test/java/io/vertx/db2client/DB2DataTypeTest.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import static org.junit.Assume.assumeTrue;
1919

2020
import java.sql.RowId;
21+
import java.time.LocalDateTime;
2122
import java.util.Arrays;
2223

2324
import org.junit.Test;
@@ -113,6 +114,23 @@ public void testByteBufIntoVarchar(TestContext ctx) {
113114
}));
114115
}
115116

117+
@Test
118+
public void testTimestamp(TestContext ctx) {
119+
LocalDateTime now = LocalDateTime.now();
120+
connect(ctx.asyncAssertSuccess(conn -> {
121+
conn.preparedQuery("INSERT INTO db2_types (id,test_tstamp) VALUES (?,?)")
122+
.execute(Tuple.of(5, now), ctx.asyncAssertSuccess(insertResult -> {
123+
conn.preparedQuery("SELECT id,test_tstamp FROM db2_types WHERE id = ?")
124+
.execute(Tuple.of(5), ctx.asyncAssertSuccess(rows -> {
125+
ctx.assertEquals(1, rows.size());
126+
Row row = rows.iterator().next();
127+
ctx.assertEquals(5, row.getInteger(0));
128+
ctx.assertEquals(now, row.getLocalDateTime(1));
129+
}));
130+
}));
131+
}));
132+
}
133+
116134
@Test
117135
public void testRowId(TestContext ctx) {
118136
assumeTrue("Only DB2/Z supports the ROWID column type", rule.isZOS());

vertx-db2-client/src/test/resources/init.sql

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,8 @@ CREATE TABLE db2_types
112112
id INT,
113113
test_byte SMALLINT,
114114
test_float FLOAT,
115-
test_bytes VARCHAR(255) for bit data
115+
test_bytes VARCHAR(255) for bit data,
116+
test_tstamp TIMESTAMP
116117
);
117118

118119
-- Sequence used by QueryVariationsTest

vertx-db2-client/src/test/resources/init.zos.sql

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,8 @@ CREATE TABLE db2_types
122122
id INT,
123123
test_byte SMALLINT,
124124
test_float FLOAT,
125-
test_bytes VARCHAR(255) for bit data
125+
test_bytes VARCHAR(255) for bit data,
126+
test_tstamp TIMESTAMP
126127
);
127128

128129
-- Sequence used by QueryVariationsTest

0 commit comments

Comments
 (0)