OJDBC的工作之一是将Oracle数据类型映射到Java数据类型。但我们发现如果给定一个CHAR数据类型,它不会被映射到java.lang.String。表现出这种行为的版本为: OJDBC7 v12.1.0.2和OJDBC6 v12.1.0.1。旧版本确实将CHAR数据类型映射到java.lang.String。深入挖掘后,我们发现在OJDBC的oracle.jdbc.driver包中有一个StructMetaData类实现了Oracle数据类型到Java类型的映射。其中一个值得注意的方法是: 'getColumnClassName(int arg0)'。我们注意到对于OJDBC v7,映射到java.lang.String的情况如下:
然而,在旧版的OJDBC实现中,它看起来像这样:
如果我替换了旧版本的OJDBC jar文件(例如:11.2.0.3),那么相同的代码会返回:
int arg1 = this.getColumnType(arg0);
switch (arg1) {
case -104:
return "oracle.sql.INTERVALDS";
case -103:
return "oracle.sql.INTERVALYM";
case -102:
return "oracle.sql.TIMESTAMPLTZ";
case -101:
return "oracle.sql.TIMESTAMPTZ";
case -15:
case -9:
case 12:
return "java.lang.String";
...
然而,在旧版的OJDBC实现中,它看起来像这样:
int arg1 = this.getColumnType(arg0);
switch (arg1) {
case -104:
return "oracle.sql.INTERVALDS";
case -103:
return "oracle.sql.INTERVALYM";
case -102:
return "oracle.sql.TIMESTAMPLTZ";
case -101:
return "oracle.sql.TIMESTAMPTZ";
case -15:
case -9:
case 1:
case 12:
return "java.lang.String";
...
在后一种情况下,有一个额外的案例映射到java.lang.String
,即“case 1”。然而,在上面显示的第一段代码中,“case 1”并没有映射到java.lang.String
。
进一步查看发现,同一StructMetaData
类的getColumnTypeName(int arg0)
方法中将这个“case 1”映射到了CHAR
类型。
public String getColumnTypeName(int arg0) throws SQLException {
int arg1 = this.getColumnType(arg0);
int arg2 = this.getValidColumnIndex(arg0);
switch (arg1) {
case -104:
return "INTERVALDS";
case -103:
return "INTERVALYM";
case -102:
return "TIMESTAMP WITH LOCAL TIME ZONE";
case -101:
return "TIMESTAMP WITH TIME ZONE";
case -15:
return "NCHAR";
case -13:
return "BFILE";
case -9:
return "NVARCHAR";
case -2:
return "RAW";
case 1:
return "CHAR";
...
因此,如果我们使用OJDBC 7或OJDBC6 v12.1.0.1,并将CHAR
指定为列的数据类型,则以下代码在调用此列的索引时返回null
:
for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
...
resultSetMetaData.getColumnClassName(columnIndex)
...
如果我替换了旧版本的OJDBC jar文件(例如:11.2.0.3),那么相同的代码会返回:
java.lang.String
。这是一个bug还是被设计移除了?有没有人遇到过类似问题?