[
https://issues.apache.org/jira/browse/IMPALA-10564?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17305798#comment-17305798
]
Wenzhe Zhou commented on IMPALA-10564:
--------------------------------------
FE evaluates the constant decimal expression, but it does not transfer the
materialized decimal value to BE so BE has to evaluate the decimal expression
again in that case. FE generate different plan trees for expression
with/without alias. The final result is determined by BE. I debug this issue
and found there are following three calling paths to handle INSERT,
INSERT-SELECT and CTAS statements.
Case 1: Insertion with constant decimal expression
Sample queries:
# create a table
create table t10 (id int, a decimal(28,10), b decimal(28,10), c decimal(28,10));
# queries with overlfowed decimal values:
insert into table t10 values(2, cast(754964565555555555559154.9565 as decimal
(28,10)), cast(84658554984 as decimal (28,10)), cast(88856788.8877 as decimal
(28,10)));
insert into table t10 select 3, cast(cast(654964569154.9565 as decimal
(28,7))*44658554984*2.111 as decimal (28,10)), cast(84658554984 as decimal
(28,10)), cast(88856788.8877 as decimal (28,10));
create table d1 stored as parquet as select cast(cast(654964569154.9565 as
decimal (28,7))*44658554984*2.111 as decimal (28,10));
Result for above queries with current Impala (without my fixing): return error
"Decimal expression overflowed" to client.
Case 2: Insertion by selecing from another source table
Sample queries:
# create source table, then insert some valid data
create table t10 (id int, a decimal(28,10), b decimal(28,10), c decimal(28,10));
insert into table t10 values(1, cast(654964569154.9565 as decimal (28,10)),
cast(44658554984 as decimal (28,10)), cast(56788.8877 as decimal (28,10)));
with overlfowed decimal values:
# queries with overlfowed decimal values:
create table t11 as select id, cast(a*b*c as decimal (28,10)) from t10;
insert into table t11 select id, cast(a*b*c as decimal (28,10)) from t10;
Result for above queries with current Impala: return error "Decimal expression
overflowed" to client.
Case 3: Insertion one row with aliases
Sample queries:
# queries with overlfowed decimal values:
create table t12 as select 1 as id, cast(a*44658554984*2.111 as decimal
(28,10)) as d_28 from (SELECT cast(654964569154.9565 as decimal (28,7)) as a) q;
insert into table t3 select 2, cast(a*44658554984*2.111 as decimal (28,10)) as
d_28 from (SELECT cast(654964569154.9565 as decimal (28,7)) as a) q;
Result for above queries with current Impala: NULLs are inserted into table
without error.
Case 3 is the only case we can re-produce the customer issue. But the first two
cases are more common.
I traced down the BE code and found the causes of results for above three
cases.
impala::DecimalOperators::ScaleDecimalValue() is function to evaluate decimal
expression. If it get invalid value like overflowed value, it will save the
error in RuntimeState object. The error is not directly retuned to the caller.
Later if RuntimeState::CheckQueryState() is called, it will return error if
there is one saved error. There are 9 places in BE to call
RuntimeState::CheckQueryState(), which make the query failed if
RuntimeState::CheckQueryState() return error. In the above first two cases,
RuntimeState::CheckQueryState() is called in functions HdfsTableSink::Send(),
KuduTableSink::Send(), and ExecNode::QueryMaintenance(). This cause BE to make
query failed and return error to client.
The following loop in function FragmentInstanceState::ExecInternal() is the
major piece of code to execute a query fragment.
do {
Status status;
row_batch_->Reset();
{
SCOPED_TIMER(plan_exec_timer);
RETURN_IF_ERROR(
exec_tree_->GetNext(runtime_state_, row_batch_.get(),
&exec_tree_complete));
}
UpdateState(StateEvent::BATCH_PRODUCED);
if (VLOG_ROW_IS_ON)
row_batch_->VLogRows("FragmentInstanceState::ExecInternal()");
COUNTER_ADD(rows_produced_counter_, row_batch_->num_rows());
RETURN_IF_ERROR(sink_->Send(runtime_state_, row_batch_.get()));
UpdateState(StateEvent::BATCH_SENT);
} while (!exec_tree_complete);
For case 1, exec_tree_->GetNext() (UnionNode::GetNext() for constant
expression) calls down to DecimalOperators::ScaleDecimalValue() to get
expression value. If there is decimal overflow issue, the error is saved in
RuntimeState object. When sink_->Send() (HdfsTableSink::Send() or
KuduTableSink::Send()) is called, it calls RuntimeState::CheckQueryState() and
returns error if there is a saved error. This cause BE to return error.
For case 2, the expression is evaluated util the column values are going to be
wrote to table in HdfsTextTableWriter::AppendRows(). When
RuntimeState::CheckQueryState() is called by sink_->Send() for one row_batch,
and there is no error saved in RuntimeState before, it return OK so that
HdfsTableSink::Send() continue to call HdfsTableSink::WriteRowsToPartition(),
then HdfsTextTableWriter::AppendRows() to write rows. The NULL could be
inserted to table for the invalid decimal values for the row_batch without
returning error. But when exec_tree_->GetNext() is called for next row_batch,
RuntimeState::CheckQueryState() is called in ExecNode::QueryMaintenance(). This
cause BE to return error. Also if sink_->Send() is called for next row_batch,
it returns error if there is error saved in RuntimeState when handling last
row_batch.
In my sample queries, exec_tree_->GetNext() is returned for the first row_batch
with exec_tree_complete as false even there is only one row in the source
table. So exec_tree_->GetNext() is called again after wrirting first row patch,
and hit RuntimeState::CheckQueryState().
For case 3, the calling path is same as case 2, but exec_tree_->GetNext() is
returned for the first row_batch with exec_tree_complete as true so
exec_tree_->GetNext() and sink_->Send() will not be called anymore so that BE
does not hit RuntimeState::CheckQueryState() and return OK to the client even
there is an error recorded in RuntimeState object. This is reason why the
current behaviors for case 3 are different from first two cases.
It is not like the intended behavior by design. Instead, it's more like a bug
that RuntimeState::CheckQueryState() is not called in a corner case.
Based on the analysis, I have two questions:
Q1: Is it necessary to introduce new query option
"use_null_for_decimal_errors"?
This is to keep the current behavior in case 3, which should no be used
frequently. Customer asked us to fix it.
We should set the default value as false for query option
"use_null_for_decimal_errors" since current Impala return error in most cases.
Q2: We have to support the query option in all cases. My current patch does not
work for case 2 when "use_null_for_decimal_errors" is set as true.
I don't have a good solution to fix it. To handle next row patch after hitting
an invalid decimal value, we have to clean the error saved in RuntimeState
after inserting NULL to the table. But this change is risky. We only save the
first error in RuntimeState, it's not safe to clean the error since we could
get more than one errors for one row batch. Another way is not to save error in
RuntimeState when getting invalid decimal values, but this change the behavior
of other queries, for example "select cast(a*44658554984*2.111 as decimal
(28,10)) as d_28 from (SELECT cast(654964569154.9565 as decimal (28,7)) as a)
q;".
> No error returned when inserting an overflowed value into a decimal column
> --------------------------------------------------------------------------
>
> Key: IMPALA-10564
> URL: https://issues.apache.org/jira/browse/IMPALA-10564
> Project: IMPALA
> Issue Type: Bug
> Components: Backend, Frontend
> Affects Versions: Impala 4.0
> Reporter: Wenzhe Zhou
> Assignee: Wenzhe Zhou
> Priority: Major
>
> When using CTAS statements or INSERT-SELECT statements to insert rows to
> table with decimal columns, Impala insert NULL for overflowed decimal values,
> instead of returning error. This issue happens when the data expression for
> the decimal column in SELECT sub-query consists at least one alias. This
> issue is similar as IMPALA-6340, but IMPALA-6340 only fixed the issue for the
> cases with the data expression for the decimal columns as constants so that
> the overflowed decimal values could be detected by frontend during expression
> analysis. If there is alias (variables) in the data expression for the
> decimal column, Frontend could not evaluate data expression in expression
> analysis phase. Only backend could evaluate the data expression when backend
> execute fragment instances for SELECT sub-queries. The log messages showed
> that the executor detected the decimal overflow error, but somehow it did not
> propagate the error to the coordinator, hence the error was not returned to
> the client.
--
This message was sent by Atlassian Jira
(v8.3.4#803005)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]