Skip to content

Commit b2cac47

Browse files
authored
Merge pull request #591 from aguibert/db2-null-values
Fixes for initial compatibility with Hibernate RX
2 parents 83fc06d + 2639d74 commit b2cac47

File tree

20 files changed

+342
-62
lines changed

20 files changed

+342
-62
lines changed

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,12 @@ public int getColumnIndex(String name) {
9494
if (name == null) {
9595
throw new NullPointerException();
9696
}
97-
return rowDesc.columnNames().indexOf(name.toUpperCase()); // DB2 column names are always in uppercase
97+
int idx = rowDesc.columnIndex(name);
98+
if (idx >= 0) {
99+
return idx;
100+
}
101+
// Unless the column is renamed in the SQL query, the column name will be uppercase
102+
return rowDesc.columnIndex(name.toUpperCase());
98103
}
99104

100105
@Override
@@ -294,7 +299,7 @@ public UUID[] getUUIDArray(String name) {
294299
throw new UnsupportedOperationException();
295300
}
296301

297-
public Numeric getNumeric(int pos) {
302+
private Numeric getNumeric(int pos) {
298303
Object val = getValue(pos);
299304
if (val instanceof Numeric) {
300305
return (Numeric) val;

vertx-db2-client/src/main/java/io/vertx/db2client/impl/codec/DB2Decoder.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,9 @@ private int computeLength(ByteBuf in) {
6262
dssContinues &= (in.getByte(ridx + index + 3) & 0x40) == 0x40;
6363
else
6464
dssContinues = false;
65-
short dssLen = in.getShort(ridx + index);
65+
short dssLen = 11; // minimum length of DRDA message
66+
if (readableBytes >= index + 2)
67+
dssLen = in.getShort(ridx + index);
6668
index += dssLen;
6769
}
6870
return index;

vertx-db2-client/src/main/java/io/vertx/db2client/impl/codec/DB2ParamDesc.java

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

18+
import io.vertx.core.buffer.Buffer;
1819
import io.vertx.db2client.impl.drda.ClientTypes;
1920
import io.vertx.db2client.impl.drda.ColumnMetaData;
2021
import io.vertx.sqlclient.data.Numeric;
@@ -50,6 +51,8 @@ public String prepare(TupleInternal values) {
5051
}
5152

5253
private static boolean canConvert(Object val, int type) {
54+
if (val == null)
55+
return true;
5356
if (ClientTypes.canConvert(val, type))
5457
return true;
5558
Class<?> clazz = val.getClass();
@@ -62,6 +65,9 @@ private static boolean canConvert(Object val, int type) {
6265
case ClientTypes.REAL:
6366
case ClientTypes.SMALLINT:
6467
return clazz == Numeric.class;
68+
case ClientTypes.VARCHAR:
69+
case ClientTypes.VARBINARY:
70+
return Buffer.class.isAssignableFrom(clazz);
6571
}
6672
return false;
6773
}

vertx-db2-client/src/main/java/io/vertx/db2client/impl/codec/ExtendedQueryCommandBaseCodec.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.util.stream.Collector;
2020

2121
import io.netty.buffer.ByteBuf;
22+
import io.vertx.core.buffer.Buffer;
2223
import io.vertx.db2client.impl.codec.DB2PreparedStatement.QueryInstance;
2324
import io.vertx.db2client.impl.drda.DRDAQueryRequest;
2425
import io.vertx.db2client.impl.drda.DRDAQueryResponse;
@@ -106,6 +107,8 @@ private static Object[] sanitize(Tuple params) {
106107
Object val = params.getValue(i);
107108
if (val instanceof Numeric)
108109
val = ((Numeric) val).bigDecimalValue();
110+
if (val instanceof Buffer)
111+
val = ((Buffer) val).getByteBuf();
109112
inputs[i] = val;
110113
}
111114
return inputs;

vertx-db2-client/src/main/java/io/vertx/db2client/impl/codec/RowResultDecoder.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,15 @@ public boolean next() {
5656
protected Row decodeRow(int len, ByteBuf in) {
5757
Row row = new DB2RowImpl(rowDesc);
5858
for (int i = 1; i < rowDesc.columnDefinitions().columns_ + 1; i++) {
59+
int startingIdx = cursor.dataBuffer_.readerIndex();
5960
Object o = cursor.getObject(i);
61+
int endingIdx = cursor.dataBuffer_.readerIndex();
62+
// TODO: Remove this once all getObject paths are implemented safely
63+
// or add unit tests for this in the DRDA project
64+
if (startingIdx != endingIdx) {
65+
System.out.println("WARN: Reader index changed while getting data. Changed from " +
66+
startingIdx + " to " + endingIdx + " while obtaining object " + o);
67+
}
6068
if (o instanceof BigDecimal) {
6169
o = Numeric.create((BigDecimal) o);
6270
}

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

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
import java.sql.RowId;
2020
import java.sql.Types;
2121

22+
import io.netty.buffer.ByteBuf;
23+
2224
// This enumeration of types represents the typing scheme used by our jdbc driver.
2325
// Once this is finished, we need to review our switches to make sure they are exhaustive
2426
/**
@@ -211,21 +213,17 @@ static public int mapDB2TypeToDriverType(boolean isDescribed, int sqlType, long
211213
}
212214

213215
public static boolean canConvert(Object value, int toType) {
216+
if (value == null)
217+
return true;
218+
214219
Class<?> clazz = value.getClass();
215220
// Everything can convert to String
216221
if (clazz == String.class)
217222
return true;
218223
switch (toType) {
219-
case ClientTypes.BIGINT:
220-
case ClientTypes.BIT:
221-
case ClientTypes.BOOLEAN:
222-
case ClientTypes.CHAR:
223-
case ClientTypes.DECIMAL:
224-
case ClientTypes.DOUBLE:
225224
case ClientTypes.INTEGER:
225+
case ClientTypes.BIGINT:
226226
case ClientTypes.LONGVARCHAR:
227-
case ClientTypes.REAL:
228-
case ClientTypes.SMALLINT:
229227
return clazz == boolean.class ||
230228
clazz == Boolean.class ||
231229
clazz == double.class ||
@@ -239,6 +237,30 @@ public static boolean canConvert(Object value, int toType) {
239237
clazz == short.class ||
240238
clazz == Short.class ||
241239
clazz == BigDecimal.class;
240+
case ClientTypes.DOUBLE:
241+
case ClientTypes.REAL:
242+
case ClientTypes.DECIMAL:
243+
return clazz == double.class ||
244+
clazz == Double.class ||
245+
clazz == float.class ||
246+
clazz == Float.class;
247+
case ClientTypes.BIT:
248+
case ClientTypes.BOOLEAN:
249+
case ClientTypes.CHAR:
250+
case ClientTypes.SMALLINT:
251+
return clazz == boolean.class ||
252+
clazz == Boolean.class ||
253+
clazz == char.class ||
254+
clazz == Character.class ||
255+
clazz == int.class ||
256+
clazz == Integer.class ||
257+
clazz == long.class ||
258+
clazz == Long.class ||
259+
clazz == short.class ||
260+
clazz == Short.class ||
261+
clazz == byte.class ||
262+
clazz == Byte.class ||
263+
clazz == BigDecimal.class;
242264
case ClientTypes.BINARY:
243265
case ClientTypes.BLOB:
244266
return clazz == boolean.class ||
@@ -256,9 +278,10 @@ public static boolean canConvert(Object value, int toType) {
256278
return clazz == java.time.LocalDateTime.class ||
257279
clazz == java.sql.Timestamp.class;
258280
case ClientTypes.VARBINARY:
259-
return clazz == byte[].class;
260281
case ClientTypes.VARCHAR:
261-
return clazz == char[].class;
282+
return clazz == char[].class ||
283+
clazz == byte[].class ||
284+
ByteBuf.class.isAssignableFrom(clazz);
262285
case ClientTypes.ROWID:
263286
return clazz == RowId.class ||
264287
clazz == DB2RowId.class;

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -117,12 +117,12 @@ public List<String> getColumnNames() {
117117
public String getColumnName(int i) {
118118
if (i < 0)
119119
throw new IllegalArgumentException("Requested column name for negative index: " + i);
120-
// Prefer column names from SQLDXGRP if set
121-
if (sqlxName_ != null && i < sqlxName_.length && sqlxName_[i] != null)
122-
return sqlxName_[i];
123-
// Otherwise use column names from SQLDOPTGRP
124-
if (sqlName_ != null && i < sqlName_.length)
120+
// Prefer column names from SQLDOPTGRP if set
121+
if (sqlName_ != null && i < sqlName_.length && sqlName_[i] != null)
125122
return sqlName_[i];
123+
// Otherwise use column names from SQLDXGRP
124+
if (sqlxName_ != null && i < sqlxName_.length)
125+
return sqlxName_[i];
126126
return null;
127127
}
128128

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

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import java.util.HashMap;
3838

3939
import io.netty.buffer.ByteBuf;
40+
import io.netty.buffer.ByteBufUtil;
4041

4142
public class Cursor {
4243

@@ -65,6 +66,7 @@ public class Cursor {
6566
//-----------------------------internal state---------------------------------
6667

6768
//-------------Structures for holding and scrolling the data -----------------
69+
// TODO: Encapsulate this field
6870
public ByteBuf dataBuffer_;
6971
// public byte[] dataBuffer_;
7072
// public ByteArrayOutputStream dataBufferStream_ = new ByteArrayOutputStream();
@@ -452,15 +454,17 @@ private String get_VARCHAR(int column) {
452454
throw new IllegalStateException("SQLState.CHARACTER_CONVERTER_NOT_AVAILABLE");
453455
}
454456

455-
dataBuffer_.readerIndex(columnDataPosition_[column - 1] + 2);
456-
String tempString = dataBuffer_.readCharSequence(columnDataComputedLength_[column - 1] - 2, charset_[column - 1]).toString();
457+
int dataLength = columnDataComputedLength_[column - 1] - 2;
458+
if (maxFieldSize_ != 0 && maxFieldSize_ < dataLength)
459+
dataLength = maxFieldSize_;
460+
return dataBuffer_.getCharSequence(columnDataPosition_[column - 1] + 2,
461+
dataLength, charset_[column - 1]).toString();
457462
// String tempString = new String(dataBuffer_,
458463
// columnDataPosition_[column - 1] + 2,
459464
// columnDataComputedLength_[column - 1] - 2,
460465
// charset_[column - 1]);
461-
return (maxFieldSize_ == 0) ? tempString :
462-
tempString.substring(0, Math.min(maxFieldSize_,
463-
tempString.length()));
466+
// return (maxFieldSize_ == 0) ? tempString :
467+
// tempString.substring(0, Math.min(maxFieldSize_, tempString.length()));
464468
}
465469

466470
// Build a Java String from a database CHAR field.
@@ -478,22 +482,25 @@ private String get_CHAR(int column) {
478482
throw new IllegalStateException("SQLState.CHARACTER_CONVERTER_NOT_AVAILABLE");
479483
}
480484

481-
dataBuffer_.readerIndex(columnDataPosition_[column - 1]);
482-
String tempString = dataBuffer_.readCharSequence(columnDataComputedLength_[column - 1], charset_[column - 1]).toString();
485+
int dataLength = columnDataComputedLength_[column - 1];
486+
if (maxFieldSize_ != 0 && maxFieldSize_ < dataLength)
487+
dataLength = maxFieldSize_;
488+
return dataBuffer_.getCharSequence(columnDataPosition_[column - 1],
489+
dataLength, charset_[column - 1]).toString();
483490
// String tempString = new String(dataBuffer_,
484491
// columnDataPosition_[column - 1],
485492
// columnDataComputedLength_[column - 1],
486493
// charset_[column - 1]);
487-
return (maxFieldSize_ == 0) ? tempString :
488-
tempString.substring(0, Math.min(maxFieldSize_,
489-
tempString.length()));
494+
// return (maxFieldSize_ == 0) ? tempString :
495+
// tempString.substring(0, Math.min(maxFieldSize_,
496+
// tempString.length()));
490497
}
491498

492499
// Build a JDBC Date object from the ISO DATE field.
493500
private LocalDate get_DATE(int column) {
494-
dataBuffer_.readerIndex(columnDataPosition_[column - 1]);
495501
// DATE column is always 10 chars long
496-
String dateString = dataBuffer_.readCharSequence(10, charset_[column - 1]).toString();
502+
String dateString = dataBuffer_.getCharSequence(columnDataPosition_[column - 1],
503+
10, charset_[column - 1]).toString();
497504
return LocalDate.parse(dateString);
498505
// return DateTime.dateBytesToDate(dataBuffer_,
499506
// columnDataPosition_[column - 1],
@@ -503,9 +510,9 @@ private LocalDate get_DATE(int column) {
503510

504511
// Build a JDBC Time object from the ISO TIME field.
505512
private LocalTime get_TIME(int column) {
506-
dataBuffer_.readerIndex(columnDataPosition_[column - 1]);
507513
// Time column is always 8 chars long
508-
String timeString = dataBuffer_.readCharSequence(8, charset_[column - 1]).toString();
514+
String timeString = dataBuffer_.getCharSequence(columnDataPosition_[column - 1],
515+
8, charset_[column - 1]).toString();
509516
return LocalTime.parse(timeString, db2TimeFormat);
510517
// return DateTime.timeBytesToTime(dataBuffer_,
511518
// columnDataPosition_[column - 1],
@@ -583,7 +590,8 @@ private byte[] get_CHAR_FOR_BIT_DATA(int column) {
583590
Math.min(maxFieldSize_, columnDataComputedLength_[column - 1]);
584591

585592
byte[] bytes = new byte[columnLength];
586-
System.arraycopy(dataBuffer_, columnDataPosition_[column - 1], bytes, 0, columnLength);
593+
//System.arraycopy(dataBuffer_, columnDataPosition_[column - 1], bytes, 0, columnLength);
594+
dataBuffer_.getBytes(columnDataPosition_[column - 1], bytes);
587595
return bytes;
588596
}
589597

@@ -597,7 +605,8 @@ private byte[] get_VARCHAR_FOR_BIT_DATA(int column) {
597605
(maxFieldSize_ == 0) ? columnDataComputedLength_[column - 1] - 2 :
598606
Math.min(maxFieldSize_, columnDataComputedLength_[column - 1] - 2);
599607
bytes = new byte[columnLength];
600-
System.arraycopy(dataBuffer_, columnDataPosition_[column - 1] + 2, bytes, 0, bytes.length);
608+
// System.arraycopy(dataBuffer_, columnDataPosition_[column - 1] + 2, bytes, 0, bytes.length);
609+
dataBuffer_.getBytes(columnDataPosition_[column - 1] + 2, bytes);
601610
return bytes;
602611
}
603612

@@ -609,7 +618,8 @@ private Object get_UDT(int column) {
609618
(maxFieldSize_ == 0) ? columnDataComputedLength_[column - 1] - 2 :
610619
Math.min(maxFieldSize_, columnDataComputedLength_[column - 1] - 2);
611620
bytes = new byte[columnLength];
612-
System.arraycopy(dataBuffer_, columnDataPosition_[column - 1] + 2, bytes, 0, bytes.length);
621+
//System.arraycopy(dataBuffer_, columnDataPosition_[column - 1] + 2, bytes, 0, bytes.length);
622+
dataBuffer_.getBytes(columnDataPosition_[column - 1] + 2, bytes);
613623

614624
try {
615625
ByteArrayInputStream bais = new ByteArrayInputStream( bytes );
@@ -1738,11 +1748,8 @@ private boolean isNonTrivialDataLob(int index) {
17381748
byte[] lengthBytes = new byte[columnDataComputedLength_[index]];
17391749
byte[] longBytes = new byte[8];
17401750

1741-
System.arraycopy(dataBuffer_,
1742-
position,
1743-
lengthBytes,
1744-
0,
1745-
columnDataComputedLength_[index]);
1751+
// System.arraycopy(dataBuffer_, position, lengthBytes, 0, columnDataComputedLength_[index]);
1752+
dataBuffer_.getBytes(position, lengthBytes, 0, columnDataComputedLength_[index]);
17461753

17471754
// right-justify for BIG ENDIAN
17481755
int j = 0;

0 commit comments

Comments
 (0)