Skip to content

Commit

Permalink
feat: support float32 (#1518)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
olavloite committed Mar 7, 2024
1 parent 1e7a4f7 commit 635ac41
Show file tree
Hide file tree
Showing 19 changed files with 883 additions and 61 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ public void setLong(int parameterIndex, long value) throws SQLException {
@Override
public void setFloat(int parameterIndex, float value) throws SQLException {
checkClosed();
parameters.setParameter(parameterIndex, value, Types.FLOAT);
parameters.setParameter(parameterIndex, value, Types.REAL);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ static int extractColumnType(Type type) {
return Types.BINARY;
case DATE:
return Types.DATE;
case FLOAT32:
return Types.REAL;
case FLOAT64:
return Types.DOUBLE;
case INT64:
Expand Down Expand Up @@ -81,9 +83,13 @@ static String getSpannerTypeName(Type type, Dialect dialect) {
*/
@Deprecated
static String getSpannerTypeName(int sqlType) {
// TODO: Re-write to be dialect-aware (or remove all-together).
if (sqlType == Types.BOOLEAN) return Type.bool().getCode().name();
if (sqlType == Types.BINARY) return Type.bytes().getCode().name();
if (sqlType == Types.DATE) return Type.date().getCode().name();
if (sqlType == Types.REAL) {
return Type.float32().getCode().name();
}
if (sqlType == Types.DOUBLE || sqlType == Types.FLOAT) return Type.float64().getCode().name();
if (sqlType == Types.BIGINT
|| sqlType == Types.INTEGER
Expand All @@ -109,6 +115,9 @@ static String getClassName(int sqlType) {
if (sqlType == Types.BOOLEAN) return Boolean.class.getName();
if (sqlType == Types.BINARY) return Byte[].class.getName();
if (sqlType == Types.DATE) return Date.class.getName();
if (sqlType == Types.REAL) {
return Float.class.getName();
}
if (sqlType == Types.DOUBLE || sqlType == Types.FLOAT) return Double.class.getName();
if (sqlType == Types.BIGINT
|| sqlType == Types.INTEGER
Expand Down Expand Up @@ -137,6 +146,8 @@ static String getClassName(Type type) {
return byte[].class.getName();
case DATE:
return Date.class.getName();
case FLOAT32:
return Float.class.getName();
case FLOAT64:
return Double.class.getName();
case INT64:
Expand All @@ -158,6 +169,8 @@ static String getClassName(Type type) {
return byte[][].class.getName();
case DATE:
return Date[].class.getName();
case FLOAT32:
return Float[].class.getName();
case FLOAT64:
return Double[].class.getName();
case INT64:
Expand Down
3 changes: 3 additions & 0 deletions src/main/java/com/google/cloud/spanner/jdbc/JdbcArray.java
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,9 @@ public ResultSet getResultSet(long startIndex, int count) throws SQLException {
case DATE:
builder = binder.to(JdbcTypeConverter.toGoogleDate((Date) value));
break;
case FLOAT32:
builder = binder.to((Float) value);
break;
case FLOAT64:
builder = binder.to((Double) value);
break;
Expand Down
56 changes: 56 additions & 0 deletions src/main/java/com/google/cloud/spanner/jdbc/JdbcDataType.java
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,47 @@ public Type getSpannerType() {
return Type.date();
}
},
FLOAT32 {
@Override
public int getSqlType() {
return Types.REAL;
}

@Override
public int getScale() {
return 7;
}

@Override
public int getPrecision() {
return 7;
}

@Override
public int getDefaultColumnDisplaySize() {
return 7;
}

@Override
public Class<Float> getJavaClass() {
return Float.class;
}

@Override
public Code getCode() {
return Code.FLOAT32;
}

@Override
public List<Float> getArrayElements(ResultSet rs, int columnIndex) {
return rs.getFloatList(columnIndex);
}

@Override
public Type getSpannerType() {
return Type.float32();
}
},
FLOAT64 {
private final Set<Class<?>> classes = new HashSet<>(Arrays.asList(Float.class, Double.class));

Expand Down Expand Up @@ -371,6 +412,21 @@ public Type getSpannerType() {

public abstract Type getSpannerType();

// TODO: Implement and use this method for all types.
public int getPrecision() {
throw new UnsupportedOperationException();
}

// TODO: Implement and use this method for all types.
public int getScale() {
throw new UnsupportedOperationException();
}

// TODO: Implement and use this method for all types.
public int getDefaultColumnDisplaySize() {
throw new UnsupportedOperationException();
}

/**
* @param rs the result set to look up the elements
* @param columnIndex zero based column index
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1056,6 +1056,44 @@ public ResultSet getTypeInfo() {
.set("NUM_PREC_RADIX")
.to((Long) null)
.build(),
Struct.newBuilder()
.set("TYPE_NAME")
.to("FLOAT32")
.set("DATA_TYPE")
.to(Types.REAL) // 8
.set("PRECISION")
.to(7L)
.set("LITERAL_PREFIX")
.to((String) null)
.set("LITERAL_SUFFIX")
.to((String) null)
.set("CREATE_PARAMS")
.to((String) null)
.set("NULLABLE")
.to(DatabaseMetaData.typeNullable)
.set("CASE_SENSITIVE")
.to(false)
.set("SEARCHABLE")
.to(DatabaseMetaData.typePredBasic)
.set("UNSIGNED_ATTRIBUTE")
.to(false)
.set("FIXED_PREC_SCALE")
.to(false)
.set("AUTO_INCREMENT")
.to(false)
.set("LOCAL_TYPE_NAME")
.to("FLOAT32")
.set("MINIMUM_SCALE")
.to(0)
.set("MAXIMUM_SCALE")
.to(0)
.set("SQL_DATA_TYPE")
.to((Long) null)
.set("SQL_DATETIME_SUB")
.to((Long) null)
.set("NUM_PREC_RADIX")
.to(2)
.build(),
Struct.newBuilder()
.set("TYPE_NAME")
.to("FLOAT64")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ public boolean isSigned(int param) throws SQLException {
int type = getParameterType(param);
return type == Types.DOUBLE
|| type == Types.FLOAT
|| type == Types.REAL
|| type == Types.BIGINT
|| type == Types.INTEGER
|| type == Types.SMALLINT
Expand Down Expand Up @@ -139,7 +140,7 @@ private int getParameterTypeFromValue(int param) {
} else if (Long.class.isAssignableFrom(value.getClass())) {
return Types.BIGINT;
} else if (Float.class.isAssignableFrom(value.getClass())) {
return Types.FLOAT;
return Types.REAL;
} else if (Double.class.isAssignableFrom(value.getClass())) {
return Types.DOUBLE;
} else if (BigDecimal.class.isAssignableFrom(value.getClass())) {
Expand Down
30 changes: 19 additions & 11 deletions src/main/java/com/google/cloud/spanner/jdbc/JdbcParameterStore.java
Original file line number Diff line number Diff line change
Expand Up @@ -452,8 +452,12 @@ private Builder setParamWithKnownType(ValueBinder<Builder> binder, Object value,
return binder.to(((Number) value).longValue());
}
throw JdbcSqlExceptionFactory.of(value + " is not a valid long", Code.INVALID_ARGUMENT);
case Types.FLOAT:
case Types.REAL:
if (value instanceof Number) {
return binder.to(((Number) value).floatValue());
}
throw JdbcSqlExceptionFactory.of(value + " is not a valid float", Code.INVALID_ARGUMENT);
case Types.FLOAT:
case Types.DOUBLE:
if (value instanceof Number) {
return binder.to(((Number) value).doubleValue());
Expand Down Expand Up @@ -744,8 +748,9 @@ private Builder setArrayValue(ValueBinder<Builder> binder, int type, Object valu
case Types.INTEGER:
case Types.BIGINT:
return binder.toInt64Array((long[]) null);
case Types.FLOAT:
case Types.REAL:
return binder.toFloat32Array((float[]) null);
case Types.FLOAT:
case Types.DOUBLE:
return binder.toFloat64Array((double[]) null);
case Types.NUMERIC:
Expand Down Expand Up @@ -814,13 +819,9 @@ private Builder setArrayValue(ValueBinder<Builder> binder, int type, Object valu
} else if (Long[].class.isAssignableFrom(value.getClass())) {
return binder.toInt64Array(toLongList((Long[]) value));
} else if (float[].class.isAssignableFrom(value.getClass())) {
double[] l = new double[((float[]) value).length];
for (int i = 0; i < l.length; i++) {
l[i] = ((float[]) value)[i];
}
return binder.toFloat64Array(l);
return binder.toFloat32Array((float[]) value);
} else if (Float[].class.isAssignableFrom(value.getClass())) {
return binder.toFloat64Array(toDoubleList((Float[]) value));
return binder.toFloat32Array(toFloatList((Float[]) value));
} else if (double[].class.isAssignableFrom(value.getClass())) {
return binder.toFloat64Array((double[]) value);
} else if (Double[].class.isAssignableFrom(value.getClass())) {
Expand Down Expand Up @@ -860,6 +861,14 @@ private List<Long> toLongList(Number[] input) {
return res;
}

private List<Float> toFloatList(Number[] input) {
List<Float> res = new ArrayList<>(input.length);
for (Number number : input) {
res.add(number == null ? null : number.floatValue());
}
return res;
}

private List<Double> toDoubleList(Number[] input) {
List<Double> res = new ArrayList<>(input.length);
for (Number number : input) {
Expand Down Expand Up @@ -901,9 +910,8 @@ private Builder setNullValue(ValueBinder<Builder> binder, Integer sqlType) {
} else {
return binder.to((BigDecimal) null);
}
case Types.DOUBLE:
return binder.to((Double) null);
case Types.FLOAT:
case Types.DOUBLE:
return binder.to((Double) null);
case Types.INTEGER:
return binder.to((Long) null);
Expand All @@ -920,7 +928,7 @@ private Builder setNullValue(ValueBinder<Builder> binder, Integer sqlType) {
case Types.NVARCHAR:
return binder.to((String) null);
case Types.REAL:
return binder.to((Double) null);
return binder.to((Float) null);
case Types.SMALLINT:
return binder.to((Long) null);
case Types.SQLXML:
Expand Down
Loading

0 comments on commit 635ac41

Please sign in to comment.