Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add BIGNUMERIC support #703

Merged
merged 4 commits into from Nov 19, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -61,6 +61,11 @@ public LegacySQLTypeName apply(String constant) {
*/
public static final LegacySQLTypeName NUMERIC =
type.createAndRegister("NUMERIC").setStandardType(StandardSQLTypeName.NUMERIC);
/**
* A decimal value with 76+ digits of precision (the 77th digit is partial) and 38 digits of scale
*/
public static final LegacySQLTypeName BIGNUMERIC =
type.createAndRegister("BIGNUMERIC").setStandardType(StandardSQLTypeName.BIGNUMERIC);
/** A Boolean value (true or false). */
public static final LegacySQLTypeName BOOLEAN =
type.createAndRegister("BOOLEAN").setStandardType(StandardSQLTypeName.BOOL);
Expand Down
Expand Up @@ -60,6 +60,7 @@
* <li>Double: StandardSQLTypeName.FLOAT64
* <li>Float: StandardSQLTypeName.FLOAT64
* <li>BigDecimal: StandardSQLTypeName.NUMERIC
* <li>BigNumeric: StandardSQLTypeName.BIGNUMERIC
* </ul>
*
* <p>No other types are supported through that entry point. The other types can be created by
Expand Down Expand Up @@ -197,7 +198,10 @@ public Map<String, QueryParameterValue> getStructTypes() {
@Nullable
abstract Map<String, QueryParameterValue> getStructTypesInner();

/** Creates a {@code QueryParameterValue} object with the given value and type. */
/**
* Creates a {@code QueryParameterValue} object with the given value and type. Note: this does not
* support BigNumeric
*/
public static <T> QueryParameterValue of(T value, Class<T> type) {
return of(value, classToType(type));
}
Expand Down Expand Up @@ -240,6 +244,11 @@ public static QueryParameterValue numeric(BigDecimal value) {
return of(value, StandardSQLTypeName.NUMERIC);
}

/** Creates a {@code QueryParameterValue} object with a type of BIGNUMERIC. */
public static QueryParameterValue bigNumeric(BigDecimal value) {
return of(value, StandardSQLTypeName.BIGNUMERIC);
}

/** Creates a {@code QueryParameterValue} object with a type of STRING. */
public static QueryParameterValue string(String value) {
return of(value, StandardSQLTypeName.STRING);
Expand Down Expand Up @@ -363,6 +372,7 @@ private static <T> String valueToStringOrNull(T value, StandardSQLTypeName type)
}
break;
case NUMERIC:
case BIGNUMERIC:
if (value instanceof BigDecimal) {
return value.toString();
}
Expand Down
Expand Up @@ -32,6 +32,10 @@ public enum StandardSQLTypeName {
FLOAT64,
/** A decimal value with 38 digits of precision and 9 digits of scale. */
NUMERIC,
/**
* A decimal value with 76+ digits of precision (the 77th digit is partial) and 38 digits of scale
*/
BIGNUMERIC,
/** Variable-length character (Unicode) data. */
STRING,
/** Variable-length binary data. */
Expand Down
Expand Up @@ -49,7 +49,8 @@ public class FieldValueListTest {
LegacySQLTypeName.RECORD,
Field.of("first", LegacySQLTypeName.FLOAT),
Field.of("second", LegacySQLTypeName.TIMESTAMP)),
Field.of("tenth", LegacySQLTypeName.NUMERIC));
Field.of("tenth", LegacySQLTypeName.NUMERIC),
Field.of("eleventh", LegacySQLTypeName.BIGNUMERIC));

private final Map<String, String> integerPb = ImmutableMap.of("v", "1");
private final Map<String, String> floatPb = ImmutableMap.of("v", "1.5");
Expand All @@ -62,6 +63,9 @@ public class FieldValueListTest {
private final Map<String, Object> recordPb =
ImmutableMap.<String, Object>of("f", ImmutableList.<Object>of(floatPb, timestampPb));
private final Map<String, String> numericPb = ImmutableMap.of("v", "123456789.123456789");
private final Map<String, String> bigNumericPb =
ImmutableMap.of(
"v", "99999999999999999999999999999999999999.99999999999999999999999999999999999999");

private final FieldValue booleanFv = FieldValue.of(Attribute.PRIMITIVE, "false");
private final FieldValue integerFv = FieldValue.of(Attribute.PRIMITIVE, "1");
Expand All @@ -78,6 +82,10 @@ public class FieldValueListTest {
FieldValueList.of(
ImmutableList.of(floatFv, timestampFv), schema.get("ninth").getSubFields()));
private final FieldValue numericFv = FieldValue.of(Attribute.PRIMITIVE, "123456789.123456789");
private final FieldValue bigNumericFv =
FieldValue.of(
Attribute.PRIMITIVE,
"99999999999999999999999999999999999999.99999999999999999999999999999999999999");

private final List<?> fieldValuesPb =
ImmutableList.of(
Expand All @@ -90,7 +98,8 @@ public class FieldValueListTest {
nullPb,
repeatedPb,
recordPb,
numericPb);
numericPb,
bigNumericPb);

private final FieldValueList fieldValues =
FieldValueList.of(
Expand All @@ -104,7 +113,8 @@ public class FieldValueListTest {
nullFv,
repeatedFv,
recordFv,
numericFv),
numericFv,
bigNumericFv),
schema);

@Test
Expand All @@ -116,7 +126,7 @@ public void testFromPb() {

@Test
public void testGetByIndex() {
assertEquals(10, fieldValues.size());
assertEquals(11, fieldValues.size());
assertEquals(booleanFv, fieldValues.get(0));
assertEquals(integerFv, fieldValues.get(1));
assertEquals(floatFv, fieldValues.get(2));
Expand All @@ -133,11 +143,12 @@ public void testGetByIndex() {
assertEquals(floatFv, fieldValues.get(8).getRecordValue().get(0));
assertEquals(timestampFv, fieldValues.get(8).getRecordValue().get(1));
assertEquals(numericFv, fieldValues.get(9));
assertEquals(bigNumericFv, fieldValues.get(10));
}

@Test
public void testGetByName() {
assertEquals(10, fieldValues.size());
assertEquals(11, fieldValues.size());
assertEquals(booleanFv, fieldValues.get("first"));
assertEquals(integerFv, fieldValues.get("second"));
assertEquals(floatFv, fieldValues.get("third"));
Expand All @@ -154,6 +165,7 @@ public void testGetByName() {
assertEquals(floatFv, fieldValues.get("ninth").getRecordValue().get("first"));
assertEquals(timestampFv, fieldValues.get("ninth").getRecordValue().get("second"));
assertEquals(numericFv, fieldValues.get("tenth"));
assertEquals(bigNumericFv, fieldValues.get("eleventh"));
}

@Test
Expand All @@ -170,7 +182,8 @@ public void testNullSchema() {
nullFv,
repeatedFv,
recordFv,
numericFv));
numericFv,
bigNumericFv));

assertEquals(fieldValues, fieldValuesNoSchema);

Expand Down
Expand Up @@ -27,6 +27,7 @@
import com.google.cloud.bigquery.TimePartitioning.Type;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import org.junit.Test;
Expand Down Expand Up @@ -101,8 +102,10 @@ public class QueryJobConfigurationTest {
QueryParameterValue.string("stringValue");
private static final QueryParameterValue TIMESTAMP_PARAMETER =
QueryParameterValue.timestamp("2014-01-01 07:00:00.000000+00:00");
private static final QueryParameterValue BIGNUMERIC_PARAMETER =
QueryParameterValue.bigNumeric(new BigDecimal(1 / 3));
private static final List<QueryParameterValue> POSITIONAL_PARAMETER =
ImmutableList.of(STRING_PARAMETER, TIMESTAMP_PARAMETER);
ImmutableList.of(STRING_PARAMETER, TIMESTAMP_PARAMETER, BIGNUMERIC_PARAMETER);
private static final Map<String, QueryParameterValue> NAME_PARAMETER =
ImmutableMap.of("string", STRING_PARAMETER, "timestamp", TIMESTAMP_PARAMETER);
private static final QueryJobConfiguration QUERY_JOB_CONFIGURATION =
Expand Down
Expand Up @@ -141,6 +141,49 @@ public void testNumeric() {
assertThat(value.getArrayValues()).isNull();
}

@Test
public void testBigNumeric() {
QueryParameterValue value =
QueryParameterValue.bigNumeric(new BigDecimal("0.33333333333333333333333333333333333333"));
QueryParameterValue value1 =
QueryParameterValue.bigNumeric(new BigDecimal("0.50000000000000000000000000000000000000"));
QueryParameterValue value2 =
QueryParameterValue.bigNumeric(new BigDecimal("0.00000000500000000000000000000000000000"));
QueryParameterValue value3 =
QueryParameterValue.bigNumeric(new BigDecimal("-0.00000000500000000000000000000000000000"));
stephaniewang526 marked this conversation as resolved.
Show resolved Hide resolved
QueryParameterValue value4 =
QueryParameterValue.bigNumeric(
new BigDecimal("0.33333333333333333333333333333333333333888888888888888"));
QueryParameterValue value5 = QueryParameterValue.bigNumeric(new BigDecimal("1e-38"));
QueryParameterValue value6 = QueryParameterValue.bigNumeric(new BigDecimal("-1e38"));
QueryParameterValue value7 =
QueryParameterValue.bigNumeric(
new BigDecimal(
"578960446186580977117854925043439539266.34992332820282019728792003956564819967"));
QueryParameterValue value8 =
QueryParameterValue.bigNumeric(
new BigDecimal(
"-578960446186580977117854925043439539266.34992332820282019728792003956564819968"));

assertThat(value.getValue()).isEqualTo("0.33333333333333333333333333333333333333");
assertThat(value1.getValue()).isEqualTo("0.50000000000000000000000000000000000000");
assertThat(value2.getValue()).isEqualTo("5.00000000000000000000000000000E-9");
assertThat(value3.getValue()).isEqualTo("-5.00000000000000000000000000000E-9");
assertThat(value4.getValue())
.isEqualTo("0.33333333333333333333333333333333333333888888888888888");
assertThat(value5.getValue()).isEqualTo("1E-38");
assertThat(value6.getValue()).isEqualTo("-1E+38");
assertThat(value7.getValue())
.isEqualTo(
"578960446186580977117854925043439539266.34992332820282019728792003956564819967");
assertThat(value8.getValue())
.isEqualTo(
"-578960446186580977117854925043439539266.34992332820282019728792003956564819968");
assertThat(value.getType()).isEqualTo(StandardSQLTypeName.BIGNUMERIC);
assertThat(value.getArrayType()).isNull();
assertThat(value.getArrayValues()).isNull();
}

@Test
public void testString() {
QueryParameterValue value = QueryParameterValue.string("foo");
Expand Down