Add large number format function
This commit is contained in:
parent
e16c83d946
commit
69c3ac0805
|
|
@ -104,6 +104,7 @@ import io.prestosql.operator.scalar.DataSizeFunctions;
|
|||
import io.prestosql.operator.scalar.DateTimeFunctions;
|
||||
import io.prestosql.operator.scalar.EmptyMapConstructor;
|
||||
import io.prestosql.operator.scalar.FailureFunction;
|
||||
import io.prestosql.operator.scalar.FormatNumberFunction;
|
||||
import io.prestosql.operator.scalar.HmacFunctions;
|
||||
import io.prestosql.operator.scalar.HyperLogLogFunctions;
|
||||
import io.prestosql.operator.scalar.JoniRegexpCasts;
|
||||
|
|
@ -496,6 +497,7 @@ public class BuiltInFunctionNamespaceManager
|
|||
.scalar(MathFunctions.Floor.class)
|
||||
.scalars(BitwiseFunctions.class)
|
||||
.scalars(DateTimeFunctions.class)
|
||||
.scalars(FormatNumberFunction.class)
|
||||
.scalars(JsonFunctions.class)
|
||||
.scalars(ColorFunctions.class)
|
||||
.scalars(ColorOperators.class)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* Copyright (C) 2018-2021. Huawei Technologies Co., Ltd. All rights reserved.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.prestosql.operator.scalar;
|
||||
|
||||
import io.airlift.slice.Slice;
|
||||
import io.prestosql.spi.function.Description;
|
||||
import io.prestosql.spi.function.ScalarFunction;
|
||||
import io.prestosql.spi.function.SqlType;
|
||||
import io.prestosql.spi.type.StandardTypes;
|
||||
|
||||
import java.math.RoundingMode;
|
||||
import java.text.DecimalFormat;
|
||||
|
||||
import static io.airlift.slice.Slices.utf8Slice;
|
||||
|
||||
public class FormatNumberFunction
|
||||
{
|
||||
private static final DecimalFormat FORMAT_NUMBER_3 = new DecimalFormat("#.##");
|
||||
private static final DecimalFormat FORMAT_NUMBER_2 = new DecimalFormat("#.#");
|
||||
private static final DecimalFormat FORMAT_NUMBER_1 = new DecimalFormat("#");
|
||||
|
||||
public FormatNumberFunction()
|
||||
{
|
||||
FORMAT_NUMBER_3.setRoundingMode(RoundingMode.HALF_UP);
|
||||
FORMAT_NUMBER_2.setRoundingMode(RoundingMode.HALF_UP);
|
||||
FORMAT_NUMBER_1.setRoundingMode(RoundingMode.HALF_UP);
|
||||
}
|
||||
|
||||
@ScalarFunction
|
||||
@Description("Formats large number using a unit symbol")
|
||||
@SqlType(StandardTypes.VARCHAR)
|
||||
public Slice formatNumber(@SqlType(StandardTypes.BIGINT) long value)
|
||||
{
|
||||
return utf8Slice(format(value));
|
||||
}
|
||||
|
||||
@ScalarFunction
|
||||
@Description("Formats large number using a unit symbol")
|
||||
@SqlType(StandardTypes.VARCHAR)
|
||||
public Slice formatNumber(@SqlType(StandardTypes.DOUBLE) double value)
|
||||
{
|
||||
return utf8Slice(format((long) value));
|
||||
}
|
||||
|
||||
private String format(long count)
|
||||
{
|
||||
double fractional = count;
|
||||
String unit = "";
|
||||
if (fractional >= 1000 || fractional <= -1000) {
|
||||
fractional /= 1000;
|
||||
unit = "K";
|
||||
}
|
||||
if (fractional >= 1000 || fractional <= -1000) {
|
||||
fractional /= 1000;
|
||||
unit = "M";
|
||||
}
|
||||
if (fractional >= 1000 || fractional <= -1000) {
|
||||
fractional /= 1000;
|
||||
unit = "B";
|
||||
}
|
||||
if (fractional >= 1000 || fractional <= -1000) {
|
||||
fractional /= 1000;
|
||||
unit = "T";
|
||||
}
|
||||
if (fractional >= 1000 || fractional <= -1000) {
|
||||
fractional /= 1000;
|
||||
unit = "Q";
|
||||
}
|
||||
|
||||
return getFormat(fractional).format(fractional) + unit;
|
||||
}
|
||||
|
||||
private DecimalFormat getFormat(double value)
|
||||
{
|
||||
if (value < 10) {
|
||||
// show up to two decimals to get 3 significant digits
|
||||
return FORMAT_NUMBER_3;
|
||||
}
|
||||
if (value < 100) {
|
||||
// show up to one decimal to get 3 significant digits
|
||||
return FORMAT_NUMBER_2;
|
||||
}
|
||||
// show no decimals -- we have enough digits in the integer part
|
||||
return FORMAT_NUMBER_1;
|
||||
}
|
||||
}
|
||||
|
|
@ -57,7 +57,7 @@ public final class ScalarFromAnnotationsParser
|
|||
ImmutableList.Builder<SqlScalarFunction> builder = ImmutableList.builder();
|
||||
for (ScalarHeaderAndMethods methods : findScalarsInFunctionSetClass(clazz)) {
|
||||
// Non-static function only makes sense in classes annotated with @ScalarFunction or @ScalarOperator.
|
||||
builder.add(parseParametricScalar(methods, Optional.empty()));
|
||||
builder.add(parseParametricScalar(methods, FunctionsParserHelper.findConstructor(clazz)));
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* Copyright (C) 2018-2021. Huawei Technologies Co., Ltd. All rights reserved.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.prestosql.operator.scalar;
|
||||
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import static io.prestosql.spi.type.VarcharType.VARCHAR;
|
||||
|
||||
public class TestFormatNumberFunction
|
||||
extends AbstractTestFunctions
|
||||
{
|
||||
@Test
|
||||
public void testFormatNumber()
|
||||
{
|
||||
assertFunction("format_number(TINYINT '123')", VARCHAR, "123");
|
||||
assertFunction("format_number(SMALLINT '12345')", VARCHAR, "12.3K");
|
||||
assertFunction("format_number(SMALLINT '12399')", VARCHAR, "12.4K");
|
||||
assertFunction("format_number(INTEGER '12345678')", VARCHAR, "12.3M");
|
||||
assertFunction("format_number(INTEGER '12399999')", VARCHAR, "12.4M");
|
||||
assertFunction("format_number(BIGINT '12345678901')", VARCHAR, "12.3B");
|
||||
assertFunction("format_number(BIGINT '12399999999')", VARCHAR, "12.4B");
|
||||
|
||||
assertFunction("format_number(DOUBLE '1234.5')", VARCHAR, "1.23K");
|
||||
assertFunction("format_number(DOUBLE '1239.9')", VARCHAR, "1.24K");
|
||||
assertFunction("format_number(REAL '1234567.8')", VARCHAR, "1.23M");
|
||||
assertFunction("format_number(REAL '1239999.9')", VARCHAR, "1.24M");
|
||||
assertFunction("format_number(DECIMAL '1234567890.1')", VARCHAR, "1.23B");
|
||||
assertFunction("format_number(DECIMAL '1239999999.9')", VARCHAR, "1.24B");
|
||||
|
||||
assertFunction("format_number(-999)", VARCHAR, "-999");
|
||||
assertFunction("format_number(-1000)", VARCHAR, "-1K");
|
||||
assertFunction("format_number(-999999)", VARCHAR, "-1000K");
|
||||
assertFunction("format_number(-1000000)", VARCHAR, "-1M");
|
||||
assertFunction("format_number(-999999999)", VARCHAR, "-1000M");
|
||||
assertFunction("format_number(-1000000000)", VARCHAR, "-1B");
|
||||
assertFunction("format_number(-999999999999)", VARCHAR, "-1000B");
|
||||
assertFunction("format_number(-1000000000000)", VARCHAR, "-1T");
|
||||
assertFunction("format_number(-999999999999999)", VARCHAR, "-1000T");
|
||||
assertFunction("format_number(-1000000000000000)", VARCHAR, "-1Q");
|
||||
assertFunction("format_number(-9223372036854775808)", VARCHAR, "-9223.37Q");
|
||||
|
||||
assertFunction("format_number(0)", VARCHAR, "0");
|
||||
assertFunction("format_number(999)", VARCHAR, "999");
|
||||
assertFunction("format_number(1000)", VARCHAR, "1K");
|
||||
assertFunction("format_number(999999)", VARCHAR, "1000K");
|
||||
assertFunction("format_number(1000000)", VARCHAR, "1M");
|
||||
assertFunction("format_number(999999999)", VARCHAR, "1000M");
|
||||
assertFunction("format_number(1000000000)", VARCHAR, "1B");
|
||||
assertFunction("format_number(999999999999)", VARCHAR, "1000B");
|
||||
assertFunction("format_number(1000000000000)", VARCHAR, "1T");
|
||||
assertFunction("format_number(999999999999999)", VARCHAR, "1000T");
|
||||
assertFunction("format_number(1000000000000000)", VARCHAR, "1Q");
|
||||
assertFunction("format_number(9223372036854775807)", VARCHAR, "9223Q");
|
||||
|
||||
assertFunction("format_number(CAST(NULL AS TINYINT))", VARCHAR, null);
|
||||
assertFunction("format_number(CAST(NULL AS SMALLINT))", VARCHAR, null);
|
||||
assertFunction("format_number(CAST(NULL AS INTEGER))", VARCHAR, null);
|
||||
assertFunction("format_number(CAST(NULL AS DOUBLE))", VARCHAR, null);
|
||||
assertFunction("format_number(CAST(NULL AS REAL))", VARCHAR, null);
|
||||
assertFunction("format_number(CAST(NULL AS DECIMAL))", VARCHAR, null);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = RuntimeException.class)
|
||||
public void testVarcharFormatFunction()
|
||||
{
|
||||
assertFunction("format_number('abc')", VARCHAR, "");
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = RuntimeException.class)
|
||||
public void testDateFormatFunction()
|
||||
{
|
||||
assertFunction("format_number(DATE '2015-09-01')", VARCHAR, "");
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = RuntimeException.class)
|
||||
public void testTimestampFormatFunction()
|
||||
{
|
||||
assertFunction("format_number(TIMESTAMP '2015-05-10 12:45:31')", VARCHAR, "");
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = RuntimeException.class)
|
||||
public void testBooleanFormatFunction()
|
||||
{
|
||||
assertFunction("format_number(true)", VARCHAR, "");
|
||||
assertFunction("format_number(false)", VARCHAR, "");
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = RuntimeException.class)
|
||||
public void testNumberAsVarcharFormatFunction()
|
||||
{
|
||||
assertFunction("format_number('123')", VARCHAR, "");
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue