Skip to content

Commit 6aa8677

Browse files
committed
fast decimal POC
1 parent 3f85871 commit 6aa8677

File tree

15 files changed

+1115
-42
lines changed

15 files changed

+1115
-42
lines changed

presto-benchmark/src/main/java/com/facebook/presto/benchmark/NumericBenchmarks.java

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,14 +53,15 @@ public static void main(String... args)
5353

5454
private static void runNumericBenchmarks(LocalQueryRunner localQueryRunner)
5555
{
56-
SimpleLineBenchmarkResultWriter writer = new SimpleLineBenchmarkResultWriter(System.out);
57-
numericBenchmarkAdd(localQueryRunner).runBenchmark(writer);
56+
SimpleLineBenchmarkResultWriter writer = null; //new SimpleLineBenchmarkResultWriter(System.out);
5857
numericBenchmarkAdd(localQueryRunner).runBenchmark(writer);
58+
numericBenchmarkManyAdd(localQueryRunner).runBenchmark(writer);
5959
numericBenchmarkSubtract(localQueryRunner).runBenchmark(writer);
6060
numericBenchmarkMultiply(localQueryRunner).runBenchmark(writer);
6161
numericBenchmarkDivide(localQueryRunner).runBenchmark(writer);
6262
numericBenchmarkSingleColumnCount(localQueryRunner).runBenchmark(writer);
6363
numericBenchmarkTwoColumnsCount(localQueryRunner).runBenchmark(writer);
64+
numericBenchmarkEightColumnsCount(localQueryRunner).runBenchmark(writer);
6465
}
6566

6667
public static SqlBenchmark numericBenchmarkAdd(LocalQueryRunner localQueryRunner)
@@ -69,6 +70,12 @@ public static SqlBenchmark numericBenchmarkAdd(LocalQueryRunner localQueryRunner
6970
"SELECT count(extendedprice + tax) from lineitem");
7071
}
7172

73+
public static SqlBenchmark numericBenchmarkManyAdd(LocalQueryRunner localQueryRunner)
74+
{
75+
return createSqlBenchmark(localQueryRunner, "numericBenchmarkManyAdd_" + queryNameSuffix(localQueryRunner),
76+
"SELECT count(extendedprice + tax + extendedprice + tax + extendedprice + tax + extendedprice + tax) from lineitem");
77+
}
78+
7279
public static SqlBenchmark numericBenchmarkSubtract(LocalQueryRunner localQueryRunner)
7380
{
7481
return createSqlBenchmark(localQueryRunner, "numericBenchmarkSubtract_" + queryNameSuffix(localQueryRunner),
@@ -99,6 +106,12 @@ public static SqlBenchmark numericBenchmarkTwoColumnsCount(LocalQueryRunner loca
99106
"SELECT count(extendedprice), count(tax) from lineitem");
100107
}
101108

109+
public static SqlBenchmark numericBenchmarkEightColumnsCount(LocalQueryRunner localQueryRunner)
110+
{
111+
return createSqlBenchmark(localQueryRunner, "numericBenchmarkEightColumnsCount_" + queryNameSuffix(localQueryRunner),
112+
"SELECT count(extendedprice), count(tax), count(extendedprice), count(tax), count(extendedprice), count(tax), count(extendedprice), count(tax) from lineitem");
113+
}
114+
102115
private static String queryNameSuffix(LocalQueryRunner localQueryRunner)
103116
{
104117
return localQueryRunner.getDefaultSession().getSchema().get();

presto-client/src/main/java/com/facebook/presto/client/QueryResults.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import static com.facebook.presto.spi.type.StandardTypes.DATE;
4141
import static com.facebook.presto.spi.type.StandardTypes.DECIMAL;
4242
import static com.facebook.presto.spi.type.StandardTypes.DOUBLE;
43+
import static com.facebook.presto.spi.type.StandardTypes.FAST_DECIMAL;
4344
import static com.facebook.presto.spi.type.StandardTypes.INTERVAL_DAY_TO_SECOND;
4445
import static com.facebook.presto.spi.type.StandardTypes.INTERVAL_YEAR_TO_MONTH;
4546
import static com.facebook.presto.spi.type.StandardTypes.JSON;
@@ -283,6 +284,7 @@ private static Object fixValue(String type, Object value)
283284
case INTERVAL_YEAR_TO_MONTH:
284285
case INTERVAL_DAY_TO_SECOND:
285286
case DECIMAL:
287+
case FAST_DECIMAL:
286288
return String.class.cast(value);
287289
default:
288290
// for now we assume that only the explicit types above are passed

presto-main/src/main/java/com/facebook/presto/metadata/FunctionRegistry.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@
8181
import com.facebook.presto.type.DateTimeOperators;
8282
import com.facebook.presto.type.DecimalOperators;
8383
import com.facebook.presto.type.DoubleOperators;
84+
import com.facebook.presto.type.FastDecimalOperators;
8485
import com.facebook.presto.type.HyperLogLogOperators;
8586
import com.facebook.presto.type.IntervalDayTimeOperators;
8687
import com.facebook.presto.type.IntervalYearMonthOperators;
@@ -361,6 +362,7 @@ public WindowFunctionSupplier load(SpecializedFunctionKey key)
361362
.scalar(JsonOperators.class)
362363
.scalar(FailureFunction.class)
363364
.scalar(DecimalOperators.class)
365+
.scalar(FastDecimalOperators.class)
364366
.functions(IDENTITY_CAST, CAST_FROM_UNKNOWN)
365367
.functions(ARRAY_CONTAINS, ARRAY_JOIN, ARRAY_JOIN_WITH_NULL_REPLACEMENT)
366368
.functions(ARRAY_MIN, ARRAY_MAX)

presto-main/src/main/java/com/facebook/presto/sql/analyzer/ExpressionAnalyzer.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
import com.facebook.presto.security.DenyAllAccessControl;
2424
import com.facebook.presto.spi.PrestoException;
2525
import com.facebook.presto.spi.StandardErrorCode;
26-
import com.facebook.presto.spi.type.DecimalType;
26+
import com.facebook.presto.spi.type.FastDecimalType;
2727
import com.facebook.presto.spi.type.Type;
2828
import com.facebook.presto.spi.type.TypeManager;
2929
import com.facebook.presto.spi.type.TypeSignature;
@@ -98,9 +98,9 @@
9898
import static com.facebook.presto.spi.type.BooleanType.BOOLEAN;
9999
import static com.facebook.presto.spi.type.DateType.DATE;
100100
import static com.facebook.presto.spi.type.DoubleType.DOUBLE;
101+
import static com.facebook.presto.spi.type.FastDecimalType.createDecimalType;
101102
import static com.facebook.presto.spi.type.IntervalDayTimeType.INTERVAL_DAY_TIME;
102103
import static com.facebook.presto.spi.type.IntervalYearMonthType.INTERVAL_YEAR_MONTH;
103-
import static com.facebook.presto.spi.type.ShortDecimalType.createDecimalType;
104104
import static com.facebook.presto.spi.type.TimeType.TIME;
105105
import static com.facebook.presto.spi.type.TimeWithTimeZoneType.TIME_WITH_TIME_ZONE;
106106
import static com.facebook.presto.spi.type.TimestampType.TIMESTAMP;
@@ -590,7 +590,7 @@ protected Type visitDoubleLiteral(DoubleLiteral node, StackableAstVisitorContext
590590
@Override
591591
protected Type visitDecimalLiteral(DecimalLiteral node, StackableAstVisitorContext<AnalysisContext> context)
592592
{
593-
DecimalType type = createDecimalType(node.getPrecision(), node.getScale());
593+
FastDecimalType type = createDecimalType(node.getPrecision(), node.getScale());
594594
expressionTypes.put(node, type);
595595
return type;
596596
}

presto-main/src/main/java/com/facebook/presto/sql/planner/LiteralInterpreter.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
import com.facebook.presto.operator.scalar.VarbinaryFunctions;
2222
import com.facebook.presto.spi.ConnectorSession;
2323
import com.facebook.presto.spi.block.Block;
24-
import com.facebook.presto.spi.type.DecimalType;
2524
import com.facebook.presto.spi.type.Type;
2625
import com.facebook.presto.spi.type.VarcharType;
2726
import com.facebook.presto.sql.analyzer.SemanticException;
@@ -57,6 +56,7 @@
5756
import static com.facebook.presto.metadata.FunctionKind.SCALAR;
5857
import static com.facebook.presto.spi.type.BigintType.BIGINT;
5958
import static com.facebook.presto.spi.type.BooleanType.BOOLEAN;
59+
import static com.facebook.presto.spi.type.DecimalArithmetic.decimal;
6060
import static com.facebook.presto.spi.type.DoubleType.DOUBLE;
6161
import static com.facebook.presto.spi.type.TypeSignature.parseTypeSignature;
6262
import static com.facebook.presto.spi.type.VarcharType.VARCHAR;
@@ -218,9 +218,9 @@ protected Double visitDoubleLiteral(DoubleLiteral node, ConnectorSession session
218218
}
219219

220220
@Override
221-
protected Object visitDecimalLiteral(DecimalLiteral node, ConnectorSession context)
221+
protected Slice visitDecimalLiteral(DecimalLiteral node, ConnectorSession context)
222222
{
223-
return DecimalType.unscaledValueToObject(node.getUnscaledValue(), node.getPrecision());
223+
return decimal(node.getUnscaledValue());
224224
}
225225

226226
@Override

presto-main/src/main/java/com/facebook/presto/sql/relational/SqlToRowExpressionTranslator.java

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
import com.facebook.presto.metadata.FunctionKind;
1818
import com.facebook.presto.metadata.FunctionRegistry;
1919
import com.facebook.presto.metadata.Signature;
20-
import com.facebook.presto.spi.type.DecimalType;
20+
import com.facebook.presto.spi.type.DecimalArithmetic;
2121
import com.facebook.presto.spi.type.TimeZoneKey;
2222
import com.facebook.presto.spi.type.Type;
2323
import com.facebook.presto.spi.type.TypeManager;
@@ -61,6 +61,7 @@
6161
import com.facebook.presto.type.UnknownType;
6262
import com.google.common.collect.ImmutableList;
6363
import com.google.common.collect.Lists;
64+
import io.airlift.slice.Slice;
6465

6566
import java.util.IdentityHashMap;
6667
import java.util.List;
@@ -69,7 +70,7 @@
6970
import static com.facebook.presto.spi.type.BigintType.BIGINT;
7071
import static com.facebook.presto.spi.type.BooleanType.BOOLEAN;
7172
import static com.facebook.presto.spi.type.DoubleType.DOUBLE;
72-
import static com.facebook.presto.spi.type.ShortDecimalType.createDecimalType;
73+
import static com.facebook.presto.spi.type.FastDecimalType.createDecimalType;
7374
import static com.facebook.presto.spi.type.TimeWithTimeZoneType.TIME_WITH_TIME_ZONE;
7475
import static com.facebook.presto.spi.type.TimestampWithTimeZoneType.TIMESTAMP_WITH_TIME_ZONE;
7576
import static com.facebook.presto.spi.type.TypeSignature.parseTypeSignature;
@@ -187,9 +188,7 @@ protected RowExpression visitDoubleLiteral(DoubleLiteral node, Void context)
187188
@Override
188189
protected RowExpression visitDecimalLiteral(DecimalLiteral node, Void context)
189190
{
190-
Object value;
191-
value = DecimalType.unscaledValueToObject(node.getUnscaledValue(), node.getPrecision());
192-
191+
Slice value = DecimalArithmetic.decimal(node.getUnscaledValue());
193192
return constant(value, createDecimalType(node.getPrecision(), node.getScale()));
194193
}
195194

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* Licensed under the Apache License, Version 2.0 (the "License");
3+
* you may not use this file except in compliance with the License.
4+
* You may obtain a copy of the License at
5+
*
6+
* http://www.apache.org/licenses/LICENSE-2.0
7+
*
8+
* Unless required by applicable law or agreed to in writing, software
9+
* distributed under the License is distributed on an "AS IS" BASIS,
10+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
* See the License for the specific language governing permissions and
12+
* limitations under the License.
13+
*/
14+
package com.facebook.presto.type;
15+
16+
import com.facebook.presto.operator.scalar.ScalarOperator;
17+
import com.facebook.presto.spi.type.DecimalArithmetic;
18+
import io.airlift.slice.Slice;
19+
20+
import static com.facebook.presto.metadata.OperatorType.ADD;
21+
import static com.facebook.presto.metadata.OperatorType.CAST;
22+
import static com.facebook.presto.metadata.OperatorType.MULTIPLY;
23+
24+
public final class FastDecimalOperators
25+
{
26+
private FastDecimalOperators() {}
27+
28+
@ScalarOperator(ADD)
29+
@LiteralParameters({"p", "s"})
30+
@SqlType("fast_decimal(min(38, p + 1), s)")
31+
public static Slice add(@SqlType("fast_decimal(p, s)") Slice a, @SqlType("fast_decimal(p, s)") Slice b)
32+
{
33+
return DecimalArithmetic.add(a, b);
34+
}
35+
36+
@ScalarOperator(MULTIPLY)
37+
@LiteralParameters({"a_precision", "a_scale", "b_precision", "b_scale"})
38+
@SqlType("fast_decimal(min(38, a_precision + b_precision), a_scale + b_scale)")
39+
public static Slice multiply(@SqlType("fast_decimal(a_precision, a_scale)") Slice a, @SqlType("fast_decimal(b_precision, b_scale)") Slice b)
40+
{
41+
return DecimalArithmetic.multiply(a, b);
42+
}
43+
44+
@ScalarOperator(CAST)
45+
@LiteralParameters({"p", "s"})
46+
@SqlType("fast_decimal(p, s)")
47+
public static Slice cast(@SqlType("fast_decimal(p, s)") Slice a)
48+
{
49+
return a;
50+
}
51+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/*
2+
* Licensed under the Apache License, Version 2.0 (the "License");
3+
* you may not use this file except in compliance with the License.
4+
* You may obtain a copy of the License at
5+
*
6+
* http://www.apache.org/licenses/LICENSE-2.0
7+
*
8+
* Unless required by applicable law or agreed to in writing, software
9+
* distributed under the License is distributed on an "AS IS" BASIS,
10+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
* See the License for the specific language governing permissions and
12+
* limitations under the License.
13+
*/
14+
15+
package com.facebook.presto.type;
16+
17+
import com.facebook.presto.spi.type.StandardTypes;
18+
import com.facebook.presto.spi.type.Type;
19+
import com.facebook.presto.spi.type.TypeParameter;
20+
import org.jetbrains.annotations.NotNull;
21+
22+
import java.util.List;
23+
24+
import static com.facebook.presto.spi.type.FastDecimalType.createDecimalType;
25+
import static com.facebook.presto.spi.type.FastDecimalType.createUnparametrizedDecimal;
26+
import static com.google.common.base.Preconditions.checkArgument;
27+
28+
public class FastDecimalParametricType
29+
implements ParametricType
30+
{
31+
public static final FastDecimalParametricType FAST_DECIMAL = new FastDecimalParametricType();
32+
33+
@Override
34+
public String getName()
35+
{
36+
return StandardTypes.FAST_DECIMAL;
37+
}
38+
39+
@Override
40+
public Type createType(List<TypeParameter> parameters)
41+
{
42+
if (parameters.size() == 0) {
43+
// we need support for that for support of unparametrized TypeSignatures which are
44+
// used for defining DECIMAL related functions. See e.g. DecimalOperators class.
45+
return createUnparametrizedDecimal();
46+
}
47+
48+
return createParametrizedDecimal(parameters);
49+
}
50+
51+
@NotNull
52+
private Type createParametrizedDecimal(List<TypeParameter> parameters)
53+
{
54+
checkArgument(parameters.size() == 2, "Expected 2 literal parameters for DECIMAL");
55+
TypeParameter precision = parameters.get(0);
56+
TypeParameter scale = parameters.get(1);
57+
checkArgument(precision.isLongLiteral() &&
58+
scale.isLongLiteral(), "Expected both literal parameters for DECIMAL to be numbers");
59+
60+
return createDecimalType(precision.getLongLiteral().intValue(), scale.getLongLiteral().intValue());
61+
}
62+
}

presto-main/src/main/java/com/facebook/presto/type/TypeRegistry.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import static com.facebook.presto.spi.type.IntervalYearMonthType.INTERVAL_YEAR_MONTH;
4444
import static com.facebook.presto.spi.type.P4HyperLogLogType.P4_HYPER_LOG_LOG;
4545
import static com.facebook.presto.spi.type.StandardTypes.DECIMAL;
46+
import static com.facebook.presto.spi.type.StandardTypes.FAST_DECIMAL;
4647
import static com.facebook.presto.spi.type.TimeType.TIME;
4748
import static com.facebook.presto.spi.type.TimeWithTimeZoneType.TIME_WITH_TIME_ZONE;
4849
import static com.facebook.presto.spi.type.TimestampType.TIMESTAMP;
@@ -106,6 +107,7 @@ public TypeRegistry(Set<Type> types)
106107
addType(JSON);
107108
addParametricType(VarcharParametricType.VARCHAR);
108109
addParametricType(DecimalParametricType.DECIMAL);
110+
addParametricType(FastDecimalParametricType.FAST_DECIMAL);
109111
addParametricType(ROW);
110112
addParametricType(ARRAY);
111113
addParametricType(MAP);
@@ -344,6 +346,19 @@ else if (secondType.getBase().equals(StandardTypes.VARCHAR) && firstType.getBase
344346
ImmutableList.of(TypeSignatureParameter.of(targetPrecision), TypeSignatureParameter.of(targetScale))));
345347
}
346348

349+
if (firstType.getBase().equals(FAST_DECIMAL) && secondType.getBase().equals(FAST_DECIMAL)) {
350+
long firstPrecision = firstType.getParameters().get(0).getLongLiteral();
351+
long secondPrecision = secondType.getParameters().get(0).getLongLiteral();
352+
long firstScale = firstType.getParameters().get(1).getLongLiteral();
353+
long secondScale = secondType.getParameters().get(1).getLongLiteral();
354+
long targetScale = Math.max(firstScale, secondScale);
355+
long targetPrecision = Math.max(firstPrecision - firstScale, secondPrecision - secondScale) + targetScale;
356+
targetPrecision = Math.min(38, targetPrecision); //we allow potential loss of precision here. Overflow checking is done in operators.
357+
return Optional.of(new TypeSignature(
358+
FAST_DECIMAL,
359+
ImmutableList.of(TypeSignatureParameter.of(targetPrecision), TypeSignatureParameter.of(targetScale))));
360+
}
361+
347362
if (firstTypeTypeParameters.size() != secondTypeTypeParameters.size()) {
348363
return Optional.empty();
349364
}
@@ -444,6 +459,19 @@ else if (actualType.getBase().equals(StandardTypes.VARCHAR) && expectedType.getB
444459
return actualScale == expectedScale && actualPrecision <= expectedPrecision;
445460
}
446461

462+
if (actualType.getBase().equals(FAST_DECIMAL) && expectedType.getBase().equals(FAST_DECIMAL)) {
463+
long actualPrecision = actualType.getParameters().get(0).getLongLiteral();
464+
long expectedPrecision = (long) expectedType.getParameters().get(0).getLongLiteral();
465+
long actualScale = (long) actualType.getParameters().get(1).getLongLiteral();
466+
long expectedScale = (long) expectedType.getParameters().get(1).getLongLiteral();
467+
468+
if (actualPrecision <= DecimalType.MAX_SHORT_PRECISION ^ expectedPrecision <= DecimalType.MAX_SHORT_PRECISION) {
469+
return false;
470+
}
471+
472+
return actualScale == expectedScale && actualPrecision <= expectedPrecision;
473+
}
474+
447475
return false;
448476
}
449477

0 commit comments

Comments
 (0)