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
[FLINK-23614][table-planner] The resulting scale of TRUNCATE(DECIMAL,… #16740
Conversation
Thanks a lot for your contribution to the Apache Flink project. I'm the @flinkbot. I help the community Automated ChecksLast check on commit aceb2a2 (Fri Aug 06 10:17:54 UTC 2021) Warnings:
Mention the bot in a comment to re-run the automated checks. Review Progress
Please see the Pull Request Review Guide for a full explanation of the review process. The Bot is tracking the review progress through labels. Labels are applied according to the order of the review items. For consensus, approval by a Flink committer of PMC member is required Bot commandsThe @flinkbot bot supports the following commands:
|
new SqlFunction( | ||
"TRUNCATE", | ||
SqlKind.OTHER_FUNCTION, | ||
FlinkReturnTypes.ROUND_FUNCTION_NULLABLE, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we're reusing this strategy, the name doesn't seem appropriate anymore. We should rename this to something that explains what it's doing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you look into this method you'll find that it is calling LogicalTypeMerging#findRoundDecimalType
. In that method there is a line stating that
// NOTE: rounding may increase the digits by 1, therefore we need +1 on precisions.
return new DecimalType(false, 1 + precision - scale + round, round);
However for truncate
function the number of digits will not increase, thus FlinkReturnTypes.ROUND_FUNCTION_NULLABLE
is not the best choice to use here.
What I'll suggest is that you create a new method in LogicalTypeMerging
called findTruncateDecimalType
. This method and findRoundDecimalType
can together reuse some code. Then you might want to create FlinkReturnTypes.TRUNCATE_FUNCTION_NULLABLE
which will also reuse a lot of code with ROUND_FUNCTION_NULLABLE
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
According to the second review request below, if round and truncate could use the same logic, could I refactor those method name to things like 'findRoundOrTruncateDecimalType'?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer "ROUNDING_NULLABLE", as "rounding" is a more general behavior (we can round down or round up), not specified to a function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK. I'll keep it the same as the round method.
new SqlFunction( | ||
"TRUNCATE", | ||
SqlKind.OTHER_FUNCTION, | ||
FlinkReturnTypes.ROUND_FUNCTION_NULLABLE, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you look into this method you'll find that it is calling LogicalTypeMerging#findRoundDecimalType
. In that method there is a line stating that
// NOTE: rounding may increase the digits by 1, therefore we need +1 on precisions.
return new DecimalType(false, 1 + precision - scale + round, round);
However for truncate
function the number of digits will not increase, thus FlinkReturnTypes.ROUND_FUNCTION_NULLABLE
is not the best choice to use here.
What I'll suggest is that you create a new method in LogicalTypeMerging
called findTruncateDecimalType
. This method and findRoundDecimalType
can together reuse some code. Then you might want to create FlinkReturnTypes.TRUNCATE_FUNCTION_NULLABLE
which will also reuse a lot of code with ROUND_FUNCTION_NULLABLE
.
DataTypes.DECIMAL(8, 2).notNull()), | ||
TestSpec.forFunction(BuiltInFunctionDefinitions.TRUNCATE) | ||
.onFieldsWithData(new BigDecimal("123.456")) | ||
// TRUNCATE(DECIMAL(6, 3) NOT NULL, 2) => DECIMAL(6, 2) NOT NULL | ||
.testResult( | ||
$("f0").truncate(2), | ||
"TRUNCATE(f0, 2)", | ||
new BigDecimal("123.45"), | ||
DataTypes.DECIMAL(6, 2).notNull())); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This MathFunctionITCase
, as stated in the java docs, is for BuiltInFunctionDefinitions
. If you follow the usage of BuiltinFunctionDefinitions
you'll see that it is converted to FlinkSqlOperatorTable.TRUNCATE
. For Flink SQL scalar functions we always add tests in ScalarFunctionsTest
. Please add your tests there.
A thorough test for a function should include all data types it supported as well as their corresponding null values. The tests in ScalarFunctionTest#testTruncate
may not be complete so please complete them with all supported data types. See FlinkSqlOperatorTable.TRUNCATE
to get all its supported types.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @tsreaper ,
Thank you for your advice.
In flink-table/flink-table-runtime/src/main/java/org/apache/flink/table/runtime/functions/SqlFunctionUtils.java
there is an implementation of truncating method designed for DecimalData
:
public static DecimalData struncate(DecimalData b0, int b1) {
if (b1 >= b0.scale()) {
return b0;
}
BigDecimal b2 =
b0.toBigDecimal()
.movePointRight(b1)
.setScale(0, RoundingMode.DOWN)
.movePointLeft(b1);
int p = b0.precision();
int s = b0.scale();
if (b1 < 0) {
return DecimalData.fromBigDecimal(b2, Math.min(38, 1 + p - s), 0);
} else {
return DecimalData.fromBigDecimal(b2, 1 + p - s + b1, b1);
}
}
It uses the same logic as the round method.
After I thought over this issue, I suggest that we should add 1 on precision (same logic as round method). If we did not do that, for example, given a number f1 0.333 with the type of DECIMAL(3, 3), if we call truncate(f1, 0), the precision of the result would be 0, which would trigger an exception of 'Decimal precision must be between 1 and 38 (both inclusive)'.
Those info above is my point of view. If you have any suggestion, please comment below. Thanks a lot.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice catch. With this in mind we shall keep using FlinkReturnTypes.ROUND_FUNCTION_NULLABLE
instead of modifying it. Still the test cases should be moved to the appropriate place. You can also add this special "truncate to zero" test case in your test.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @tsreaper ,
I added several "truncated to zero" test cases.
@flinkbot run azure |
I've checked this issue again and found that adding tests to Also there are CI failures. Please keep an eye on the comment of @flinkbot for the results. If there are CI failures then the PR will never be merged. |
d7e70d6
to
56b3375
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me. @JingsongLi any other thoughts?
Hi @paul8263 , this PR is conflicting with the master branch. Please resolve the conflicts. |
Hi @tsreaper , |
… ...) is not correct
9296b4e
to
4a1e653
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me!
… is not correct This closes apache#16740
… ...) is not correct
What is the purpose of the change
Fixe the issue that the resulting scale of TRUNCATE(DECIMAL, ...) is not correct.
Brief change log
Verifying this change
This change added tests and can be verified as follows:
Does this pull request potentially affect one of the following parts:
@Public(Evolving)
: noDocumentation