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 1 commit
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,9 @@ public LegacySQLTypeName apply(String constant) {
*/
public static final LegacySQLTypeName NUMERIC =
type.createAndRegister("NUMERIC").setStandardType(StandardSQLTypeName.NUMERIC);
/** A decimal value with 38 digits of precision 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,8 @@ public enum StandardSQLTypeName {
FLOAT64,
/** A decimal value with 38 digits of precision and 9 digits of scale. */
NUMERIC,
/** A decimal value with 38 digits of precision and 38 digits of scale. */
stephaniewang526 marked this conversation as resolved.
Show resolved Hide resolved
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,31 @@ 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"));

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(value.getType()).isEqualTo(StandardSQLTypeName.BIGNUMERIC);
assertThat(value.getArrayType()).isNull();
assertThat(value.getArrayValues()).isNull();
}

@Test
public void testString() {
QueryParameterValue value = QueryParameterValue.string("foo");
Expand Down
Expand Up @@ -208,6 +208,11 @@ public class ITBigQueryTest {
.setMode(Field.Mode.NULLABLE)
.setDescription("NumericDescription")
.build();
private static final Field BIGNUMERIC_FIELD_SCHEMA =
Field.newBuilder("BigNumericField", LegacySQLTypeName.BIGNUMERIC)
.setMode(Field.Mode.NULLABLE)
.setDescription("BigNumericDescription")
.build();
private static final Field STRING_FIELD_SCHEMA_WITH_POLICY =
Field.newBuilder("StringFieldWithPolicy", LegacySQLTypeName.STRING)
.setMode(Field.Mode.NULLABLE)
Expand All @@ -225,7 +230,8 @@ public class ITBigQueryTest {
INTEGER_FIELD_SCHEMA,
FLOAT_FIELD_SCHEMA,
GEOGRAPHY_FIELD_SCHEMA,
NUMERIC_FIELD_SCHEMA);
NUMERIC_FIELD_SCHEMA,
BIGNUMERIC_FIELD_SCHEMA);
private static final Schema SIMPLE_SCHEMA = Schema.of(STRING_FIELD_SCHEMA);
private static final Schema POLICY_SCHEMA =
Schema.of(STRING_FIELD_SCHEMA, STRING_FIELD_SCHEMA_WITH_POLICY, INTEGER_FIELD_SCHEMA);
Expand Down Expand Up @@ -283,7 +289,8 @@ public class ITBigQueryTest {
+ " \"IntegerField\": \"3\","
+ " \"FloatField\": \"1.2\","
+ " \"GeographyField\": \"POINT(-122.35022 47.649154)\","
+ " \"NumericField\": \"123456.789012345\""
+ " \"NumericField\": \"123456.789012345\","
+ " \"BigNumericField\": \"0.33333333333333333333333333333333333333\""
+ "}\n"
+ "{"
+ " \"TimestampField\": \"2014-08-19 07:41:35.220 -05:00\","
Expand All @@ -305,7 +312,8 @@ public class ITBigQueryTest {
+ " \"IntegerField\": \"3\","
+ " \"FloatField\": \"1.2\","
+ " \"GeographyField\": \"POINT(-122.35022 47.649154)\","
+ " \"NumericField\": \"123456.789012345\""
+ " \"NumericField\": \"123456.789012345\","
+ " \"BigNumericField\": \"0.33333333333333333333333333333333333333\""
+ "}";
private static final String KEY = "time_zone";
private static final String VALUE = "US/Eastern";
Expand Down Expand Up @@ -1477,7 +1485,8 @@ public void testPositionalQueryParameters() throws InterruptedException {
+ " AND IntegerField IN UNNEST(?)"
+ " AND IntegerField < ?"
+ " AND FloatField > ?"
+ " AND NumericField < ?";
+ " AND NumericField < ?"
+ " AND BigNumericField = ?";
QueryParameterValue stringParameter = QueryParameterValue.string("stringValue");
QueryParameterValue timestampParameter =
QueryParameterValue.timestamp("2014-01-01 07:00:00.000000+00:00");
Expand All @@ -1487,6 +1496,8 @@ public void testPositionalQueryParameters() throws InterruptedException {
QueryParameterValue float64Parameter = QueryParameterValue.float64(0.5);
QueryParameterValue numericParameter =
QueryParameterValue.numeric(new BigDecimal("234567890.123456"));
QueryParameterValue bigNumericParameter =
QueryParameterValue.bigNumeric(new BigDecimal("0.33333333333333333333333333333333333333"));
QueryJobConfiguration config =
QueryJobConfiguration.newBuilder(query)
.setDefaultDataset(DatasetId.of(DATASET))
Expand All @@ -1497,6 +1508,7 @@ public void testPositionalQueryParameters() throws InterruptedException {
.addPositionalParameter(int64Parameter)
.addPositionalParameter(float64Parameter)
.addPositionalParameter(numericParameter)
.addPositionalParameter(bigNumericParameter)
.build();
TableResult result = bigquery.query(config);
assertEquals(QUERY_RESULT_SCHEMA, result.getSchema());
Expand Down