Skip to content

Commit

Permalink
This is an automated cherry-pick of pingcap#5839
Browse files Browse the repository at this point in the history
Signed-off-by: ti-chi-bot <[email protected]>
  • Loading branch information
xzhangxian1008 authored and ti-chi-bot committed Sep 14, 2022
1 parent 0dfd01a commit 7a9d152
Show file tree
Hide file tree
Showing 3 changed files with 264 additions and 1 deletion.
18 changes: 17 additions & 1 deletion dbms/src/Functions/FunctionsLogical.h
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,23 @@ struct AssociativeOperationImpl
{
if (Op::isSaturable())
{
UInt8 a = vec[i];
// cast a: UInt8 -> bool -> UInt8 is a trick
// TiFlash converts columns with non-UInt8 type to UInt8 type and sets value to 0 or 1
// which correspond to false or true. However, for columns with UInt8 type,
// no more convertion will be executed on them and the values stored
// in them are 'origin' which means that they won't be converted to 0 or 1.
// For example:
// Input column with non-UInt8 type:
// column_values = {-2, 0, 2}
// then, they will be converted to:
// vec = {1, 0, 1} (here vec stores converted values)
//
// Input column with UInt8 type:
// column_values = {1, 0, 2}
// then, the vec will be:
// vec = {1, 0, 2} (error, we only want 0 or 1)
// See issue: https://github.com/pingcap/tidb/issues/37258
bool a = static_cast<bool>(vec[i]);
return Op::isSaturatedValue(a) ? a : continuation.apply(i);
}
else
Expand Down
169 changes: 169 additions & 0 deletions dbms/src/Functions/tests/gtest_logical.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
// Copyright 2022 PingCAP, Ltd.
//
// 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.

#include <Interpreters/Context.h>
#include <TestUtils/FunctionTestUtils.h>
#include <TestUtils/TiFlashTestBasic.h>

#include <string>
#include <vector>

namespace DB::tests
{
class Logical : public DB::tests::FunctionTest
{
};

TEST_F(Logical, andTest)
try
{
const String & func_name = "and";

// column, column
ASSERT_COLUMN_EQ(
createColumn<Nullable<UInt8>>({0, 1, 0, 0, {}, 0}),
executeFunction(
func_name,
createColumn<Nullable<UInt8>>({0, 1, 0, 1, {}, 0}),
createColumn<Nullable<UInt8>>({0, 1, 1, 0, 1, {}})));
// column, const
ASSERT_COLUMN_EQ(
createColumn<Nullable<UInt8>>({1, 0}),
executeFunction(
func_name,
createConstColumn<Nullable<UInt8>>(2, 1),
createColumn<Nullable<UInt8>>({1, 0})));
// const, const
ASSERT_COLUMN_EQ(
createConstColumn<UInt8>(1, 1),
executeFunction(
func_name,
createConstColumn<Nullable<UInt8>>(1, 1),
createConstColumn<Nullable<UInt8>>(1, 1)));
// only null
ASSERT_COLUMN_EQ(
createColumn<Nullable<UInt8>>({{}, 0}),
executeFunction(
func_name,
createOnlyNullColumnConst(2),
createColumn<Nullable<UInt8>>({1, 0})));
}
CATCH

TEST_F(Logical, orTest)
try
{
const String & func_name = "or";

// column, column
ASSERT_COLUMN_EQ(
createColumn<Nullable<UInt8>>({0, 1, 1, 1, 1, {}}),
executeFunction(
func_name,
createColumn<Nullable<UInt8>>({0, 1, 0, 1, {}, 0}),
createColumn<Nullable<UInt8>>({0, 1, 1, 0, 1, {}})));
// issue 5849
ASSERT_COLUMN_EQ(
createColumn<UInt8>({0, 1, 1, 1}),
executeFunction(
func_name,
createColumn<UInt8>({0, 123, 0, 41}),
createColumn<Int64>({0, 11, 221, 0})));
// column, const
ASSERT_COLUMN_EQ(
createColumn<Nullable<UInt8>>({1, 1}),
executeFunction(
func_name,
createConstColumn<Nullable<UInt8>>(2, 1),
createColumn<Nullable<UInt8>>({1, 0})));
// const, const
ASSERT_COLUMN_EQ(
createConstColumn<UInt8>(1, 1),
executeFunction(
func_name,
createConstColumn<Nullable<UInt8>>(1, 1),
createConstColumn<Nullable<UInt8>>(1, 0)));
// only null
ASSERT_COLUMN_EQ(
createColumn<Nullable<UInt8>>({1, {}}),
executeFunction(
func_name,
createOnlyNullColumnConst(2),
createColumn<Nullable<UInt8>>({1, 0})));
}
CATCH

TEST_F(Logical, xorTest)
try
{
const String & func_name = "xor";

// column, column
ASSERT_COLUMN_EQ(
createColumn<Nullable<UInt8>>({0, 0, 1, 1, {}, {}}),
executeFunction(
func_name,
createColumn<Nullable<UInt8>>({0, 1, 0, 1, {}, 0}),
createColumn<Nullable<UInt8>>({0, 1, 1, 0, 1, {}})));
// column, const
ASSERT_COLUMN_EQ(
createColumn<Nullable<UInt8>>({0, 1}),
executeFunction(
func_name,
createConstColumn<Nullable<UInt8>>(2, 1),
createColumn<Nullable<UInt8>>({1, 0})));
// const, const
ASSERT_COLUMN_EQ(
createConstColumn<UInt8>(1, 0),
executeFunction(
func_name,
createConstColumn<Nullable<UInt8>>(1, 1),
createConstColumn<Nullable<UInt8>>(1, 1)));
// only null
ASSERT_COLUMN_EQ(
createOnlyNullColumnConst(2),
executeFunction(
func_name,
createOnlyNullColumnConst(2),
createColumn<Nullable<UInt8>>({1, 0})));
}
CATCH

TEST_F(Logical, notTest)
try
{
const String & func_name = "not";

// column
ASSERT_COLUMN_EQ(
createColumn<Nullable<UInt8>>({1, 0, {}}),
executeFunction(
func_name,
createColumn<Nullable<UInt8>>({0, 1, {}})));
// const
ASSERT_COLUMN_EQ(
createConstColumn<UInt8>(1, 0),
executeFunction(
func_name,
createConstColumn<Nullable<UInt8>>(1, 1)));
// only null
ASSERT_COLUMN_EQ(
createOnlyNullColumnConst(1),
executeFunction(
func_name,
createOnlyNullColumnConst(1)));
}
CATCH

} // namespace DB::tests
78 changes: 78 additions & 0 deletions tests/fullstack-test/expr/logical_op.test
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
mysql> drop table if exists test.t1;
mysql> drop table if exists test.t2;
<<<<<<< HEAD
mysql> create table test.t1(a char(20),b double);
mysql> create table test.t2(a char(20));
mysql> insert into test.t1 values(1,null),('j',0),(1,12.991),(0,0),(0,0),('they',1.009),('can',-99),(0,12.991),(1,-9.183),(null,1);
Expand All @@ -9,6 +10,27 @@ mysql> alter table test.t2 set tiflash replica 1;

func> wait_table test t1
func> wait_table test t2
=======
mysql> drop table if exists test.t3;
mysql> drop table if exists test.t4;
mysql> create table test.t1(a char(20),b double);
mysql> create table test.t2(a char(20));
mysql> create table test.t3(a int);
mysql> create table test.t4(a tinyint(45) unsigned NOT NULL, b bigint(20) NOT NULL);
mysql> insert into test.t1 values(1,null),('j',0),(1,12.991),(0,0),(0,0),('they',1.009),('can',-99),(0,12.991),(1,-9.183),(null,1);
mysql> insert into test.t2 values(0),(0),(0),(0),(0),(0),(1),('with'),('see'),(null);
mysql> insert into test.t3 values(0),(1);
mysql> insert into test.t4 values(65, 1),(66, 2), (67, 3), (0, 0);
mysql> alter table test.t1 set tiflash replica 1;
mysql> alter table test.t2 set tiflash replica 1;
mysql> alter table test.t3 set tiflash replica 1;
mysql> alter table test.t4 set tiflash replica 1;

func> wait_table test t1
func> wait_table test t2
func> wait_table test t3
func> wait_table test t4
>>>>>>> 624a10ac01 (fix: the results of tikv and tiflash are different (#5839))

mysql> set session tidb_isolation_read_engines='tiflash'; select count(*) from test.t1 where (b between null and 100) is null;
+----------+
Expand All @@ -24,5 +46,61 @@ mysql> set session tidb_isolation_read_engines='tiflash'; select count(*) from t
| 10 |
+----------+

<<<<<<< HEAD
#mysql> drop table if exists test.t1;
#mysql> drop table if exists test.t2;
=======
mysql> set tidb_enforce_mpp=1; set tidb_isolation_read_engines='tiflash'; select null and a > 0, a from test.t3;
+----------------+------+
| null and a > 0 | a |
+----------------+------+
| 0 | 0 |
| NULL | 1 |
+----------------+------+

mysql> set tidb_enforce_mpp=1; set tidb_isolation_read_engines='tiflash'; select null or a > 0, a from test.t3;
+---------------+------+
| null or a > 0 | a |
+---------------+------+
| NULL | 0 |
| 1 | 1 |
+---------------+------+

mysql> set tidb_enforce_mpp=1; set tidb_isolation_read_engines='tiflash'; select null xor a > 0, a from test.t3;
+----------------+------+
| null xor a > 0 | a |
+----------------+------+
| NULL | 0 |
| NULL | 1 |
+----------------+------+

mysql> set tidb_enforce_mpp=1; set tidb_isolation_read_engines='tiflash'; select !null, a from test.t3;
+-------+------+
| !null | a |
+-------+------+
| NULL | 0 |
| NULL | 1 |
+-------+------+

mysql> set tidb_enforce_mpp=1; set tidb_isolation_read_engines='tiflash'; select count(*) from test.t3 group by a having min(null) and a > 0;
# empty

mysql> set tidb_enforce_mpp=1; set tidb_isolation_read_engines='tiflash'; select count(*) from test.t3 group by a having ifnull(null,count(*)) and min(null);
# empty

# issue 5849
mysql> set tidb_enforce_mpp=1; set tidb_isolation_read_engines='tiflash'; select a or b from test.t4;
+--------+
| a or b |
+--------+
| 1 |
| 1 |
| 1 |
| 0 |
+--------+

#mysql> drop table if exists test.t1;
#mysql> drop table if exists test.t2;
#mysql> drop table if exists test.t3;
#mysql> drop table if exists test.t4;
>>>>>>> 624a10ac01 (fix: the results of tikv and tiflash are different (#5839))

0 comments on commit 7a9d152

Please sign in to comment.