Skip to content
Permalink
Browse files
feat: add support for NUMERIC data type (#193)
* feat: add support for NUMERIC type

* feat: add support for NUMERIC in keys

* tests: add integration test for numeric

* fix: uncomment code

* test: remove integration tests from PR

* chore: remove whitespaces

* chore: solve merge conflicts
  • Loading branch information
olavloite committed Jul 15, 2020
1 parent d67f108 commit b38a91d8daac264b9dea327d6b31430d9599bd78
Showing with 990 additions and 36 deletions.
  1. +43 −1 google-cloud-spanner/clirr-ignored-differences.xml
  2. +42 −0 google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbstractResultSet.java
  3. +31 −0 google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbstractStructReader.java
  4. +21 −0 google-cloud-spanner/src/main/java/com/google/cloud/spanner/ForwardingStructReader.java
  5. +11 −0 google-cloud-spanner/src/main/java/com/google/cloud/spanner/Key.java
  6. +21 −0 google-cloud-spanner/src/main/java/com/google/cloud/spanner/ResultSets.java
  7. +15 −0 google-cloud-spanner/src/main/java/com/google/cloud/spanner/Struct.java
  8. +17 −0 google-cloud-spanner/src/main/java/com/google/cloud/spanner/StructReader.java
  9. +12 −0 google-cloud-spanner/src/main/java/com/google/cloud/spanner/Type.java
  10. +92 −5 google-cloud-spanner/src/main/java/com/google/cloud/spanner/Value.java
  11. +11 −0 google-cloud-spanner/src/main/java/com/google/cloud/spanner/ValueBinder.java
  12. +15 −0 google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/ChecksumResultSet.java
  13. +25 −0 google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/DirectExecuteResultSet.java
  14. +25 −0 ...oud-spanner/src/main/java/com/google/cloud/spanner/connection/ReplaceableForwardingResultSet.java
  15. +25 −0 google-cloud-spanner/src/test/java/com/google/cloud/spanner/AbstractStructReaderTypesTest.java
  16. +43 −0 google-cloud-spanner/src/test/java/com/google/cloud/spanner/GrpcResultSetTest.java
  17. +18 −2 google-cloud-spanner/src/test/java/com/google/cloud/spanner/KeyTest.java
  18. +9 −0 google-cloud-spanner/src/test/java/com/google/cloud/spanner/ReadFormatTestRunner.java
  19. +37 −14 google-cloud-spanner/src/test/java/com/google/cloud/spanner/ResultSetsTest.java
  20. +150 −0 google-cloud-spanner/src/test/java/com/google/cloud/spanner/SelectRandomBenchmark.java
  21. +5 −0 google-cloud-spanner/src/test/java/com/google/cloud/spanner/StandardBenchmarkMockServer.java
  22. +20 −0 google-cloud-spanner/src/test/java/com/google/cloud/spanner/TypeTest.java
  23. +9 −0 google-cloud-spanner/src/test/java/com/google/cloud/spanner/ValueBinderTest.java
  24. +152 −0 google-cloud-spanner/src/test/java/com/google/cloud/spanner/ValueTest.java
  25. +13 −0 ...e-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/DirectExecuteResultSetTest.java
  26. +9 −0 google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/RandomResultSetGenerator.java
  27. +89 −13 google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/ReadWriteTransactionTest.java
  28. +13 −0 ...spanner/src/test/java/com/google/cloud/spanner/connection/ReplaceableForwardingResultSetTest.java
  29. +17 −1 google-cloud-spanner/src/test/resources/com/google/cloud/spanner/read_tests.json
@@ -256,11 +256,53 @@
<className>com/google/cloud/spanner/spi/v1/SpannerRpc</className>
<method>com.google.api.gax.retrying.RetrySettings getPartitionedDmlRetrySettings()</method>
</difference>

<!-- Streaming PDML -->
<difference>
<differenceType>7012</differenceType>
<className>com/google/cloud/spanner/spi/v1/SpannerRpc</className>
<method>com.google.api.gax.rpc.ServerStream executeStreamingPartitionedDml(com.google.spanner.v1.ExecuteSqlRequest, java.util.Map, org.threeten.bp.Duration)</method>
</difference>

<!-- Add support for NUMERIC data type -->
<difference>
<differenceType>7013</differenceType>
<className>com/google/cloud/spanner/AbstractStructReader</className>
<method>java.math.BigDecimal getBigDecimalInternal(int)</method>
</difference>
<difference>
<differenceType>7013</differenceType>
<className>com/google/cloud/spanner/AbstractStructReader</className>
<method>java.util.List getBigDecimalListInternal(int)</method>
</difference>
<difference>
<differenceType>7012</differenceType>
<className>com/google/cloud/spanner/StructReader</className>
<method>java.math.BigDecimal getBigDecimal(int)</method>
</difference>
<difference>
<differenceType>7012</differenceType>
<className>com/google/cloud/spanner/StructReader</className>
<method>java.math.BigDecimal getBigDecimal(java.lang.String)</method>
</difference>
<difference>
<differenceType>7012</differenceType>
<className>com/google/cloud/spanner/StructReader</className>
<method>java.util.List getBigDecimalList(int)</method>
</difference>
<difference>
<differenceType>7012</differenceType>
<className>com/google/cloud/spanner/StructReader</className>
<method>java.util.List getBigDecimalList(java.lang.String)</method>
</difference>
<difference>
<differenceType>7013</differenceType>
<className>com/google/cloud/spanner/Value</className>
<method>java.math.BigDecimal getNumeric()</method>
</difference>
<difference>
<differenceType>7013</differenceType>
<className>com/google/cloud/spanner/Value</className>
<method>java.util.List getNumericArray()</method>
</difference>
</differences>
@@ -52,6 +52,7 @@
import io.opencensus.trace.Tracing;
import java.io.IOException;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.BitSet;
@@ -358,6 +359,9 @@ private Object writeReplace() {
case FLOAT64:
builder.set(fieldName).to((Double) value);
break;
case NUMERIC:
builder.set(fieldName).to((BigDecimal) value);
break;
case STRING:
builder.set(fieldName).to((String) value);
break;
@@ -381,6 +385,9 @@ private Object writeReplace() {
case FLOAT64:
builder.set(fieldName).toFloat64Array((Iterable<Double>) value);
break;
case NUMERIC:
builder.set(fieldName).toNumericArray((Iterable<BigDecimal>) value);
break;
case STRING:
builder.set(fieldName).toStringArray((Iterable<String>) value);
break;
@@ -457,6 +464,8 @@ private static Object decodeValue(Type fieldType, com.google.protobuf.Value prot
return Long.parseLong(proto.getStringValue());
case FLOAT64:
return valueProtoToFloat64(proto);
case NUMERIC:
return new BigDecimal(proto.getStringValue());
case STRING:
checkType(fieldType, proto, KindCase.STRING_VALUE);
return proto.getStringValue();
@@ -513,6 +522,18 @@ public Boolean apply(com.google.protobuf.Value input) {
return new Int64Array(listValue);
case FLOAT64:
return new Float64Array(listValue);
case NUMERIC:
{
// Materialize list: element conversion is expensive and should happen only once.
ArrayList<Object> list = new ArrayList<>(listValue.getValuesCount());
for (com.google.protobuf.Value value : listValue.getValuesList()) {
list.add(
value.getKindCase() == KindCase.NULL_VALUE
? null
: new BigDecimal(value.getStringValue()));
}
return list;
}
case STRING:
return Lists.transform(
listValue.getValuesList(),
@@ -620,6 +641,11 @@ protected double getDoubleInternal(int columnIndex) {
return (Double) rowData.get(columnIndex);
}

@Override
protected BigDecimal getBigDecimalInternal(int columnIndex) {
return (BigDecimal) rowData.get(columnIndex);
}

@Override
protected String getStringInternal(int columnIndex) {
return (String) rowData.get(columnIndex);
@@ -685,6 +711,12 @@ protected Float64Array getDoubleListInternal(int columnIndex) {
return (Float64Array) rowData.get(columnIndex);
}

@Override
@SuppressWarnings("unchecked") // We know ARRAY<NUMERIC> produces a List<BigDecimal>.
protected List<BigDecimal> getBigDecimalListInternal(int columnIndex) {
return (List<BigDecimal>) rowData.get(columnIndex);
}

@Override
@SuppressWarnings("unchecked") // We know ARRAY<STRING> produces a List<String>.
protected List<String> getStringListInternal(int columnIndex) {
@@ -1176,6 +1208,11 @@ protected double getDoubleInternal(int columnIndex) {
return currRow().getDoubleInternal(columnIndex);
}

@Override
protected BigDecimal getBigDecimalInternal(int columnIndex) {
return currRow().getBigDecimalInternal(columnIndex);
}

@Override
protected String getStringInternal(int columnIndex) {
return currRow().getStringInternal(columnIndex);
@@ -1226,6 +1263,11 @@ protected List<Double> getDoubleListInternal(int columnIndex) {
return currRow().getDoubleListInternal(columnIndex);
}

@Override
protected List<BigDecimal> getBigDecimalListInternal(int columnIndex) {
return currRow().getBigDecimalListInternal(columnIndex);
}

@Override
protected List<String> getStringListInternal(int columnIndex) {
return currRow().getStringListInternal(columnIndex);
@@ -21,6 +21,7 @@
import com.google.cloud.ByteArray;
import com.google.cloud.Date;
import com.google.cloud.Timestamp;
import java.math.BigDecimal;
import java.util.List;

/**
@@ -38,6 +39,8 @@ public abstract class AbstractStructReader implements StructReader {

protected abstract double getDoubleInternal(int columnIndex);

protected abstract BigDecimal getBigDecimalInternal(int columnIndex);

protected abstract String getStringInternal(int columnIndex);

protected abstract ByteArray getBytesInternal(int columnIndex);
@@ -58,6 +61,8 @@ public abstract class AbstractStructReader implements StructReader {

protected abstract List<Double> getDoubleListInternal(int columnIndex);

protected abstract List<BigDecimal> getBigDecimalListInternal(int columnIndex);

protected abstract List<String> getStringListInternal(int columnIndex);

protected abstract List<ByteArray> getBytesListInternal(int columnIndex);
@@ -127,6 +132,19 @@ public double getDouble(String columnName) {
return getDoubleInternal(columnIndex);
}

@Override
public BigDecimal getBigDecimal(int columnIndex) {
checkNonNullOfType(columnIndex, Type.numeric(), columnIndex);
return getBigDecimalInternal(columnIndex);
}

@Override
public BigDecimal getBigDecimal(String columnName) {
int columnIndex = getColumnIndex(columnName);
checkNonNullOfType(columnIndex, Type.numeric(), columnName);
return getBigDecimalInternal(columnIndex);
}

@Override
public String getString(int columnIndex) {
checkNonNullOfType(columnIndex, Type.string(), columnIndex);
@@ -257,6 +275,19 @@ public List<Double> getDoubleList(String columnName) {
return getDoubleListInternal(columnIndex);
}

@Override
public List<BigDecimal> getBigDecimalList(int columnIndex) {
checkNonNullOfType(columnIndex, Type.array(Type.numeric()), columnIndex);
return getBigDecimalListInternal(columnIndex);
}

@Override
public List<BigDecimal> getBigDecimalList(String columnName) {
int columnIndex = getColumnIndex(columnName);
checkNonNullOfType(columnIndex, Type.array(Type.numeric()), columnName);
return getBigDecimalListInternal(columnIndex);
}

@Override
public List<String> getStringList(int columnIndex) {
checkNonNullOfType(columnIndex, Type.array(Type.string()), columnIndex);
@@ -22,6 +22,7 @@
import com.google.common.base.Preconditions;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import java.math.BigDecimal;
import java.util.List;

/** Forwarding implements of StructReader */
@@ -133,6 +134,16 @@ public double getDouble(String columnName) {
return delegate.get().getDouble(columnName);
}

@Override
public BigDecimal getBigDecimal(int columnIndex) {
return delegate.get().getBigDecimal(columnIndex);
}

@Override
public BigDecimal getBigDecimal(String columnName) {
return delegate.get().getBigDecimal(columnName);
}

@Override
public String getString(int columnIndex) {
checkValidState();
@@ -253,6 +264,16 @@ public List<Double> getDoubleList(String columnName) {
return delegate.get().getDoubleList(columnName);
}

@Override
public List<BigDecimal> getBigDecimalList(int columnIndex) {
return delegate.get().getBigDecimalList(columnIndex);
}

@Override
public List<BigDecimal> getBigDecimalList(String columnName) {
return delegate.get().getBigDecimalList(columnName);
}

@Override
public List<String> getStringList(int columnIndex) {
checkValidState();
@@ -26,6 +26,7 @@
import com.google.protobuf.NullValue;
import com.google.protobuf.Value;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -131,6 +132,11 @@ public Builder append(@Nullable Double value) {
buffer.add(value);
return this;
}
/** Appends a {@code NUMERIC} value to the key. */
public Builder append(@Nullable BigDecimal value) {
buffer.add(value);
return this;
}
/** Appends a {@code STRING} value to the key. */
public Builder append(@Nullable String value) {
buffer.add(value);
@@ -172,6 +178,8 @@ public Builder appendObject(@Nullable Object value) {
append((Float) value);
} else if (value instanceof Double) {
append((Double) value);
} else if (value instanceof BigDecimal) {
append((BigDecimal) value);
} else if (value instanceof String) {
append((String) value);
} else if (value instanceof ByteArray) {
@@ -215,6 +223,7 @@ public int size() {
* <li>{@code BOOL} is represented by {@code Boolean}
* <li>{@code INT64} is represented by {@code Long}
* <li>{@code FLOAT64} is represented by {@code Double}
* <li>{@code NUMERIC} is represented by {@code BigDecimal}
* <li>{@code STRING} is represented by {@code String}
* <li>{@code BYTES} is represented by {@link ByteArray}
* <li>{@code TIMESTAMP} is represented by {@link Timestamp}
@@ -276,6 +285,8 @@ ListValue toProto() {
builder.addValuesBuilder().setStringValue(part.toString());
} else if (part instanceof Double) {
builder.addValuesBuilder().setNumberValue((Double) part);
} else if (part instanceof BigDecimal) {
builder.addValuesBuilder().setStringValue(part.toString());
} else if (part instanceof String) {
builder.addValuesBuilder().setStringValue((String) part);
} else if (part instanceof ByteArray) {
@@ -27,6 +27,7 @@
import com.google.common.collect.Lists;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.google.spanner.v1.ResultSetStats;
import java.math.BigDecimal;
import java.util.List;

/** Utility methods for working with {@link com.google.cloud.spanner.ResultSet}. */
@@ -186,6 +187,16 @@ public double getDouble(String columnName) {
return getCurrentRowAsStruct().getDouble(columnName);
}

@Override
public BigDecimal getBigDecimal(int columnIndex) {
return getCurrentRowAsStruct().getBigDecimal(columnIndex);
}

@Override
public BigDecimal getBigDecimal(String columnName) {
return getCurrentRowAsStruct().getBigDecimal(columnName);
}

@Override
public String getString(int columnIndex) {
return getCurrentRowAsStruct().getString(columnIndex);
@@ -286,6 +297,16 @@ public List<Double> getDoubleList(String columnName) {
return getCurrentRowAsStruct().getDoubleList(columnName);
}

@Override
public List<BigDecimal> getBigDecimalList(int columnIndex) {
return getCurrentRowAsStruct().getBigDecimalList(columnIndex);
}

@Override
public List<BigDecimal> getBigDecimalList(String columnName) {
return getCurrentRowAsStruct().getBigDecimalList(columnName);
}

@Override
public List<String> getStringList(int columnIndex) {
return getCurrentRowAsStruct().getStringList(columnIndex);

0 comments on commit b38a91d

Please sign in to comment.