This is an automated email from the ASF dual-hosted git repository.
yiguolei pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/master by this push:
new 9945067e3c [Bug](function) make VcompoundPred optimization work well
(#19870)
9945067e3c is described below
commit 9945067e3c9bc6a985bb834c631b22e1ef17fafd
Author: Pxl <[email protected]>
AuthorDate: Mon May 22 18:32:17 2023 +0800
[Bug](function) make VcompoundPred optimization work well (#19870)
make VcompoundPred optimization work well
#19818 this pr try to enable VcompoundPred optimization but get wrong
result on tpcds q28.
The reason is some nullable logic on mysql need special handling.
mysql [regression_test_tpcds_sf1_p1]>select null and false;
+----------------+
| NULL AND FALSE |
+----------------+
| 0 |
+----------------+
1 row in set (0.00 sec)
mysql [regression_test_tpcds_sf1_p1]>select null and true;
+---------------+
| NULL AND TRUE |
+---------------+
| NULL |
+---------------+
1 row in set (0.00 sec)
mysql [regression_test_tpcds_sf1_p1]>select null or false;
+---------------+
| NULL OR FALSE |
+---------------+
| NULL |
+---------------+
1 row in set (0.00 sec)
mysql [regression_test_tpcds_sf1_p1]>select null or true;
+--------------+
| NULL OR TRUE |
+--------------+
| 1 |
+--------------+
1 row in set (0.00 sec)
---
be/src/vec/exprs/vcompound_pred.h | 74 +++++++++++++---------
.../data/query_p0/sql_functions/test_predicate.out | 48 ++++++++++++++
.../query_p0/sql_functions/test_predicate.groovy | 57 +++++++++++++++++
3 files changed, 148 insertions(+), 31 deletions(-)
diff --git a/be/src/vec/exprs/vcompound_pred.h
b/be/src/vec/exprs/vcompound_pred.h
index 9ce992d0ec..47f12fa13e 100644
--- a/be/src/vec/exprs/vcompound_pred.h
+++ b/be/src/vec/exprs/vcompound_pred.h
@@ -54,9 +54,13 @@ public:
const std::string& expr_name() const override { return _expr_name; }
- Status execute(VExprContext* context, doris::vectorized::Block* block,
+ Status execute(VExprContext* context, vectorized::Block* block,
int* result_column_id) override {
- if (children().size() == 1 || !_all_child_is_compound_and_not_const())
{
+ if (children().size() == 1 || !_all_child_is_compound_and_not_const()
||
+ _children[0]->is_nullable() || _children[1]->is_nullable()) {
+ // TODO:
+ // When the child is nullable, make the optimization also take
effect, and the processing of this piece may be more complicated
+ // https://dev.mysql.com/doc/refman/8.0/en/logical-operators.html
return VectorizedFnCall::execute(context, block, result_column_id);
}
@@ -65,15 +69,14 @@ public:
RETURN_IF_ERROR(_children[0]->execute(context, block, &lhs_id));
ColumnPtr lhs_column = block->get_by_position(lhs_id).column;
- ColumnPtr rhs_column = nullptr;
-
size_t size = lhs_column->size();
uint8* __restrict data = _get_raw_data(lhs_column);
int filted = simd::count_zero_num((int8_t*)data, size);
bool full = filted == 0;
bool empty = filted == size;
- const uint8* __restrict data_rhs = nullptr;
+ ColumnPtr rhs_column = nullptr;
+ uint8* __restrict data_rhs = nullptr;
bool full_rhs = false;
bool empty_rhs = false;
@@ -82,15 +85,6 @@ public:
RETURN_IF_ERROR(_children[1]->execute(context, block,
&rhs_id));
rhs_column = block->get_by_position(rhs_id).column;
data_rhs = _get_raw_data(rhs_column);
- if (!empty) {
- if (const uint8* null_map =
-
_get_null_map(block->get_by_position(rhs_id).column);
- null_map != nullptr) {
- for (size_t i = 0; i < size; i++) {
- data[i] &= !null_map[i];
- }
- }
- }
int filted = simd::count_zero_num((int8_t*)data_rhs, size);
full_rhs = filted == 0;
empty_rhs = filted == size;
@@ -99,34 +93,54 @@ public:
};
if (_op == TExprOpcode::COMPOUND_AND) {
- if (!empty) { // empty and any = empty, so lhs should not empty
+ if (empty) {
+ // empty and any = empty, return lhs
+ *result_column_id = lhs_id;
+ } else {
RETURN_IF_ERROR(get_rhs_colum());
- if (empty_rhs) { // any and empty = empty
+
+ if (full) {
+ // full and any = any, return rhs
*result_column_id = rhs_id;
- return Status::OK();
- } else if (!full_rhs) { // any and full = any, so rhs should
not full.
+ } else if (empty_rhs) {
+ // any and empty = empty, return rhs
+ *result_column_id = rhs_id;
+ } else if (full_rhs) {
+ // any and full = any, return lhs
+ *result_column_id = lhs_id;
+ } else {
+ *result_column_id = lhs_id;
for (size_t i = 0; i < size; i++) {
data[i] &= data_rhs[i];
}
}
}
} else if (_op == TExprOpcode::COMPOUND_OR) {
- if (!full) { // full or any = full, so lhs should not full
+ if (full) {
+ // full or any = full, return lhs
+ *result_column_id = lhs_id;
+ } else {
RETURN_IF_ERROR(get_rhs_colum());
- if (full_rhs) { // any or full = full
+ if (empty) {
+ // empty or any = any, return rhs
+ *result_column_id = rhs_id;
+ } else if (full_rhs) {
+ // any or full = full, return rhs
*result_column_id = rhs_id;
- return Status::OK();
- } else if (!empty_rhs) { // any or empty = any, so rhs should
not empty
+ } else if (empty_rhs) {
+ // any or empty = any, return lhs
+ *result_column_id = lhs_id;
+ } else {
+ *result_column_id = lhs_id;
for (size_t i = 0; i < size; i++) {
data[i] |= data_rhs[i];
}
}
}
} else {
- LOG(FATAL) << "Compound operator must be AND or OR.";
+ return Status::InternalError("Compound operator must be AND or
OR.");
}
- *result_column_id = lhs_id;
return Status::OK();
}
@@ -151,28 +165,26 @@ private:
return false;
}
}
- return false;
+ return true;
}
uint8* _get_raw_data(ColumnPtr column) const {
if (column->is_nullable()) {
- return reinterpret_cast<ColumnUInt8*>(
+ return assert_cast<ColumnUInt8*>(
assert_cast<ColumnNullable*>(column->assume_mutable().get())
->get_nested_column_ptr()
.get())
->get_data()
.data();
} else {
- return
reinterpret_cast<ColumnUInt8*>(column->assume_mutable().get())
- ->get_data()
- .data();
+ return
assert_cast<ColumnUInt8*>(column->assume_mutable().get())->get_data().data();
}
}
uint8* _get_null_map(ColumnPtr column) const {
if (column->is_nullable()) {
- return reinterpret_cast<ColumnUInt8*>(
-
reinterpret_cast<ColumnNullable*>(column->assume_mutable().get())
+ return assert_cast<ColumnUInt8*>(
+
assert_cast<ColumnNullable*>(column->assume_mutable().get())
->get_null_map_column_ptr()
.get())
->get_data()
diff --git a/regression-test/data/query_p0/sql_functions/test_predicate.out
b/regression-test/data/query_p0/sql_functions/test_predicate.out
new file mode 100644
index 0000000000..77dfc15c6e
--- /dev/null
+++ b/regression-test/data/query_p0/sql_functions/test_predicate.out
@@ -0,0 +1,48 @@
+-- This file is automatically generated. You should know what you did if you
want to edit this
+-- !null_or_null --
+
+-- !true_or_null --
+1 2 3 \N
+
+-- !null_or_true --
+1 2 3 \N
+
+-- !false_or_null --
+
+-- !null_or_false --
+
+-- !false_or_true --
+1 2 3 \N
+
+-- !true_or_false --
+1 2 3 \N
+
+-- !null_and_null --
+
+-- !true_and_null --
+
+-- !null_and_true --
+
+-- !false_and_null --
+
+-- !null_and_false --
+
+-- !false_and_true --
+
+-- !true_and_false --
+
+-- !not_false --
+1 2 3 \N
+
+-- !not_null --
+
+-- !false_is_null --
+
+-- !null_is_null --
+1 2 3 \N
+
+-- !false_eq_false --
+1 2 3 \N
+
+-- !null_eq_false --
+
diff --git
a/regression-test/suites/query_p0/sql_functions/test_predicate.groovy
b/regression-test/suites/query_p0/sql_functions/test_predicate.groovy
new file mode 100644
index 0000000000..20b3c179ad
--- /dev/null
+++ b/regression-test/suites/query_p0/sql_functions/test_predicate.groovy
@@ -0,0 +1,57 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you 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.
+
+suite("test_predicate") {
+ sql """drop table if exists t1;"""
+ sql """
+ create table t1 (
+ k1 int null,
+ k2 int null,
+ k3 int null,
+ k4 int null
+ )
+ duplicate key (k1)
+ distributed BY hash(k1) buckets 3
+ properties("replication_num" = "1");
+ """
+ sql """ insert into t1 values(1,2,3,null); """
+
+ qt_null_or_null "select * from t1 where abs(k1)=null or abs(k1)=null;"
+ qt_true_or_null "select * from t1 where abs(k1)=1 or abs(k1)=null;"
+ qt_null_or_true "select * from t1 where abs(k1)=null or abs(k1)=1;"
+ qt_false_or_null "select * from t1 where abs(k1)!=1 or abs(k1)=null;"
+ qt_null_or_false "select * from t1 where abs(k1)=null or abs(k1)!=1;"
+ qt_false_or_true "select * from t1 where abs(k1)!=1 or abs(k1)=1;"
+ qt_true_or_false "select * from t1 where abs(k1)=1 or abs(k1)!=1;"
+
+ qt_null_and_null "select * from t1 where abs(k1)=null and abs(k1)=null;"
+ qt_true_and_null "select * from t1 where abs(k1)=1 and abs(k1)=null;"
+ qt_null_and_true "select * from t1 where abs(k1)=null and abs(k1)=1;"
+ qt_false_and_null "select * from t1 where abs(k1)!=1 and abs(k1)=null;"
+ qt_null_and_false "select * from t1 where abs(k1)!=null and abs(k1)=1;"
+ qt_false_and_true "select * from t1 where abs(k1)!=1 and abs(k1)=1;"
+ qt_true_and_false "select * from t1 where abs(k1)=1 and abs(k1)!=1;"
+
+ qt_not_false "select * from t1 where not (abs(k1)!=1);"
+ qt_not_null "select * from t1 where not (abs(k1)!=1 or null);"
+
+ qt_false_is_null "select * from t1 where (abs(k1)!=1) is null;"
+ qt_null_is_null "select * from t1 where (abs(k1)!=1 or null) is null;"
+
+ qt_false_eq_false "select * from t1 where (abs(k1)!=1)=false;"
+ qt_null_eq_false "select * from t1 where (abs(k1)!=1 or null)=false;"
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]