Skip to content

Commit 635ac41

Browse files
authored
feat: support float32 (#1518)
* feat: support float32 Adds support for the FLOAT32 / real data type. * test: update tests to use new RandomResultSetGenerator * test: add more tests * deps: bump to Spanner 6.61.0 * test: enable pg_numeric test on emulator * test: skip setFloat(..) until float32 is supported * chore: address review comments
1 parent 1e7a4f7 commit 635ac41

19 files changed

+883
-61
lines changed

src/main/java/com/google/cloud/spanner/jdbc/AbstractJdbcPreparedStatement.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ public void setLong(int parameterIndex, long value) throws SQLException {
118118
@Override
119119
public void setFloat(int parameterIndex, float value) throws SQLException {
120120
checkClosed();
121-
parameters.setParameter(parameterIndex, value, Types.FLOAT);
121+
parameters.setParameter(parameterIndex, value, Types.REAL);
122122
}
123123

124124
@Override

src/main/java/com/google/cloud/spanner/jdbc/AbstractJdbcWrapper.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ static int extractColumnType(Type type) {
4949
return Types.BINARY;
5050
case DATE:
5151
return Types.DATE;
52+
case FLOAT32:
53+
return Types.REAL;
5254
case FLOAT64:
5355
return Types.DOUBLE;
5456
case INT64:
@@ -81,9 +83,13 @@ static String getSpannerTypeName(Type type, Dialect dialect) {
8183
*/
8284
@Deprecated
8385
static String getSpannerTypeName(int sqlType) {
86+
// TODO: Re-write to be dialect-aware (or remove all-together).
8487
if (sqlType == Types.BOOLEAN) return Type.bool().getCode().name();
8588
if (sqlType == Types.BINARY) return Type.bytes().getCode().name();
8689
if (sqlType == Types.DATE) return Type.date().getCode().name();
90+
if (sqlType == Types.REAL) {
91+
return Type.float32().getCode().name();
92+
}
8793
if (sqlType == Types.DOUBLE || sqlType == Types.FLOAT) return Type.float64().getCode().name();
8894
if (sqlType == Types.BIGINT
8995
|| sqlType == Types.INTEGER
@@ -109,6 +115,9 @@ static String getClassName(int sqlType) {
109115
if (sqlType == Types.BOOLEAN) return Boolean.class.getName();
110116
if (sqlType == Types.BINARY) return Byte[].class.getName();
111117
if (sqlType == Types.DATE) return Date.class.getName();
118+
if (sqlType == Types.REAL) {
119+
return Float.class.getName();
120+
}
112121
if (sqlType == Types.DOUBLE || sqlType == Types.FLOAT) return Double.class.getName();
113122
if (sqlType == Types.BIGINT
114123
|| sqlType == Types.INTEGER
@@ -137,6 +146,8 @@ static String getClassName(Type type) {
137146
return byte[].class.getName();
138147
case DATE:
139148
return Date.class.getName();
149+
case FLOAT32:
150+
return Float.class.getName();
140151
case FLOAT64:
141152
return Double.class.getName();
142153
case INT64:
@@ -158,6 +169,8 @@ static String getClassName(Type type) {
158169
return byte[][].class.getName();
159170
case DATE:
160171
return Date[].class.getName();
172+
case FLOAT32:
173+
return Float[].class.getName();
161174
case FLOAT64:
162175
return Double[].class.getName();
163176
case INT64:

src/main/java/com/google/cloud/spanner/jdbc/JdbcArray.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,9 @@ public ResultSet getResultSet(long startIndex, int count) throws SQLException {
188188
case DATE:
189189
builder = binder.to(JdbcTypeConverter.toGoogleDate((Date) value));
190190
break;
191+
case FLOAT32:
192+
builder = binder.to((Float) value);
193+
break;
191194
case FLOAT64:
192195
builder = binder.to((Double) value);
193196
break;

src/main/java/com/google/cloud/spanner/jdbc/JdbcDataType.java

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,47 @@ public Type getSpannerType() {
110110
return Type.date();
111111
}
112112
},
113+
FLOAT32 {
114+
@Override
115+
public int getSqlType() {
116+
return Types.REAL;
117+
}
118+
119+
@Override
120+
public int getScale() {
121+
return 7;
122+
}
123+
124+
@Override
125+
public int getPrecision() {
126+
return 7;
127+
}
128+
129+
@Override
130+
public int getDefaultColumnDisplaySize() {
131+
return 7;
132+
}
133+
134+
@Override
135+
public Class<Float> getJavaClass() {
136+
return Float.class;
137+
}
138+
139+
@Override
140+
public Code getCode() {
141+
return Code.FLOAT32;
142+
}
143+
144+
@Override
145+
public List<Float> getArrayElements(ResultSet rs, int columnIndex) {
146+
return rs.getFloatList(columnIndex);
147+
}
148+
149+
@Override
150+
public Type getSpannerType() {
151+
return Type.float32();
152+
}
153+
},
113154
FLOAT64 {
114155
private final Set<Class<?>> classes = new HashSet<>(Arrays.asList(Float.class, Double.class));
115156

@@ -371,6 +412,21 @@ public Type getSpannerType() {
371412

372413
public abstract Type getSpannerType();
373414

415+
// TODO: Implement and use this method for all types.
416+
public int getPrecision() {
417+
throw new UnsupportedOperationException();
418+
}
419+
420+
// TODO: Implement and use this method for all types.
421+
public int getScale() {
422+
throw new UnsupportedOperationException();
423+
}
424+
425+
// TODO: Implement and use this method for all types.
426+
public int getDefaultColumnDisplaySize() {
427+
throw new UnsupportedOperationException();
428+
}
429+
374430
/**
375431
* @param rs the result set to look up the elements
376432
* @param columnIndex zero based column index

src/main/java/com/google/cloud/spanner/jdbc/JdbcDatabaseMetaData.java

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1056,6 +1056,44 @@ public ResultSet getTypeInfo() {
10561056
.set("NUM_PREC_RADIX")
10571057
.to((Long) null)
10581058
.build(),
1059+
Struct.newBuilder()
1060+
.set("TYPE_NAME")
1061+
.to("FLOAT32")
1062+
.set("DATA_TYPE")
1063+
.to(Types.REAL) // 8
1064+
.set("PRECISION")
1065+
.to(7L)
1066+
.set("LITERAL_PREFIX")
1067+
.to((String) null)
1068+
.set("LITERAL_SUFFIX")
1069+
.to((String) null)
1070+
.set("CREATE_PARAMS")
1071+
.to((String) null)
1072+
.set("NULLABLE")
1073+
.to(DatabaseMetaData.typeNullable)
1074+
.set("CASE_SENSITIVE")
1075+
.to(false)
1076+
.set("SEARCHABLE")
1077+
.to(DatabaseMetaData.typePredBasic)
1078+
.set("UNSIGNED_ATTRIBUTE")
1079+
.to(false)
1080+
.set("FIXED_PREC_SCALE")
1081+
.to(false)
1082+
.set("AUTO_INCREMENT")
1083+
.to(false)
1084+
.set("LOCAL_TYPE_NAME")
1085+
.to("FLOAT32")
1086+
.set("MINIMUM_SCALE")
1087+
.to(0)
1088+
.set("MAXIMUM_SCALE")
1089+
.to(0)
1090+
.set("SQL_DATA_TYPE")
1091+
.to((Long) null)
1092+
.set("SQL_DATETIME_SUB")
1093+
.to((Long) null)
1094+
.set("NUM_PREC_RADIX")
1095+
.to(2)
1096+
.build(),
10591097
Struct.newBuilder()
10601098
.set("TYPE_NAME")
10611099
.to("FLOAT64")

src/main/java/com/google/cloud/spanner/jdbc/JdbcParameterMetaData.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ public boolean isSigned(int param) throws SQLException {
7676
int type = getParameterType(param);
7777
return type == Types.DOUBLE
7878
|| type == Types.FLOAT
79+
|| type == Types.REAL
7980
|| type == Types.BIGINT
8081
|| type == Types.INTEGER
8182
|| type == Types.SMALLINT
@@ -139,7 +140,7 @@ private int getParameterTypeFromValue(int param) {
139140
} else if (Long.class.isAssignableFrom(value.getClass())) {
140141
return Types.BIGINT;
141142
} else if (Float.class.isAssignableFrom(value.getClass())) {
142-
return Types.FLOAT;
143+
return Types.REAL;
143144
} else if (Double.class.isAssignableFrom(value.getClass())) {
144145
return Types.DOUBLE;
145146
} else if (BigDecimal.class.isAssignableFrom(value.getClass())) {

src/main/java/com/google/cloud/spanner/jdbc/JdbcParameterStore.java

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -452,8 +452,12 @@ private Builder setParamWithKnownType(ValueBinder<Builder> binder, Object value,
452452
return binder.to(((Number) value).longValue());
453453
}
454454
throw JdbcSqlExceptionFactory.of(value + " is not a valid long", Code.INVALID_ARGUMENT);
455-
case Types.FLOAT:
456455
case Types.REAL:
456+
if (value instanceof Number) {
457+
return binder.to(((Number) value).floatValue());
458+
}
459+
throw JdbcSqlExceptionFactory.of(value + " is not a valid float", Code.INVALID_ARGUMENT);
460+
case Types.FLOAT:
457461
case Types.DOUBLE:
458462
if (value instanceof Number) {
459463
return binder.to(((Number) value).doubleValue());
@@ -744,8 +748,9 @@ private Builder setArrayValue(ValueBinder<Builder> binder, int type, Object valu
744748
case Types.INTEGER:
745749
case Types.BIGINT:
746750
return binder.toInt64Array((long[]) null);
747-
case Types.FLOAT:
748751
case Types.REAL:
752+
return binder.toFloat32Array((float[]) null);
753+
case Types.FLOAT:
749754
case Types.DOUBLE:
750755
return binder.toFloat64Array((double[]) null);
751756
case Types.NUMERIC:
@@ -814,13 +819,9 @@ private Builder setArrayValue(ValueBinder<Builder> binder, int type, Object valu
814819
} else if (Long[].class.isAssignableFrom(value.getClass())) {
815820
return binder.toInt64Array(toLongList((Long[]) value));
816821
} else if (float[].class.isAssignableFrom(value.getClass())) {
817-
double[] l = new double[((float[]) value).length];
818-
for (int i = 0; i < l.length; i++) {
819-
l[i] = ((float[]) value)[i];
820-
}
821-
return binder.toFloat64Array(l);
822+
return binder.toFloat32Array((float[]) value);
822823
} else if (Float[].class.isAssignableFrom(value.getClass())) {
823-
return binder.toFloat64Array(toDoubleList((Float[]) value));
824+
return binder.toFloat32Array(toFloatList((Float[]) value));
824825
} else if (double[].class.isAssignableFrom(value.getClass())) {
825826
return binder.toFloat64Array((double[]) value);
826827
} else if (Double[].class.isAssignableFrom(value.getClass())) {
@@ -860,6 +861,14 @@ private List<Long> toLongList(Number[] input) {
860861
return res;
861862
}
862863

864+
private List<Float> toFloatList(Number[] input) {
865+
List<Float> res = new ArrayList<>(input.length);
866+
for (Number number : input) {
867+
res.add(number == null ? null : number.floatValue());
868+
}
869+
return res;
870+
}
871+
863872
private List<Double> toDoubleList(Number[] input) {
864873
List<Double> res = new ArrayList<>(input.length);
865874
for (Number number : input) {
@@ -901,9 +910,8 @@ private Builder setNullValue(ValueBinder<Builder> binder, Integer sqlType) {
901910
} else {
902911
return binder.to((BigDecimal) null);
903912
}
904-
case Types.DOUBLE:
905-
return binder.to((Double) null);
906913
case Types.FLOAT:
914+
case Types.DOUBLE:
907915
return binder.to((Double) null);
908916
case Types.INTEGER:
909917
return binder.to((Long) null);
@@ -920,7 +928,7 @@ private Builder setNullValue(ValueBinder<Builder> binder, Integer sqlType) {
920928
case Types.NVARCHAR:
921929
return binder.to((String) null);
922930
case Types.REAL:
923-
return binder.to((Double) null);
931+
return binder.to((Float) null);
924932
case Types.SMALLINT:
925933
return binder.to((Long) null);
926934
case Types.SQLXML:

0 commit comments

Comments
 (0)