Allow different types inside IN subquery

This commit is contained in:
Maksim Kita 2020-12-02 13:09:13 +03:00
parent dff31e8de7
commit f4b8e8ef99
6 changed files with 62 additions and 10 deletions

View File

@ -515,15 +515,23 @@ inline bool NO_SANITIZE_UNDEFINED convertNumeric(From value, To & result)
return true;
}
if constexpr (std::is_floating_point_v<From> && std::is_floating_point_v<To>) {
/// Note that NaNs doesn't compare equal to anything, but they are still in range of any Float type.
if (isNaN(value) && std::is_floating_point_v<To>)
if (isNaN(value))
{
result = value;
return true;
}
}
if (accurate::greaterOp(value, std::numeric_limits<To>::max())
|| accurate::greaterOp(std::numeric_limits<To>::min(), value))
{
return false;
}
result = static_cast<To>(value);
return equalsOp(value, result);
return true;
}
}

View File

@ -2897,8 +2897,6 @@ public:
ColumnNumbers getArgumentsThatAreAlwaysConstant() const override { return {1}; }
protected:
FunctionBaseImplPtr build(const ColumnsWithTypeAndName & arguments, const DataTypePtr & return_type) const override
{
DataTypes data_types(arguments.size());
@ -2909,7 +2907,7 @@ protected:
auto monotonicity = MonotonicityHelper::getMonotonicityInformation(arguments.front().type, return_type.get());
return std::make_unique<FunctionCast>(name, std::move(monotonicity), data_types, return_type, std::optional<Diagnostic>(), true);
}
protected:
DataTypePtr getReturnType(const ColumnsWithTypeAndName & arguments) const override
{
const auto & column = arguments.back().column;

View File

@ -14,6 +14,8 @@
#include <DataTypes/DataTypeTuple.h>
#include <DataTypes/DataTypeNullable.h>
#include <Functions/FunctionsConversion.h>
#include <Parsers/ASTExpressionList.h>
#include <Parsers/ASTFunction.h>
#include <Parsers/ASTLiteral.h>
@ -30,6 +32,7 @@
#include <ext/range.h>
#include <DataTypes/DataTypeLowCardinality.h>
#include <iostream>
namespace DB
{
@ -254,8 +257,15 @@ ColumnPtr Set::execute(const Block & block, bool negative) const
for (size_t i = 0; i < num_key_columns; ++i)
{
checkTypesEqual(i, block.safeGetByPosition(i).type);
materialized_columns.emplace_back(block.safeGetByPosition(i).column->convertToFullColumnIfConst());
/// TODO: Optimize making cast only if types different
/// TODO: This case SELECT '1' IN (SELECT 1); should not work but with AccurateCastOrNull it works
auto & column_before_cast = block.safeGetByPosition(i);
ColumnWithTypeAndName column
= {column_before_cast.column->convertToFullColumnIfConst(), column_before_cast.type, column_before_cast.name};
auto accurate_cast = AccurateCastOverloadResolver().build({column}, data_types[i]);
auto accurate_cast_executable = accurate_cast->prepare({column});
auto casted_column = accurate_cast_executable->execute({column}, data_types[i], column.column->size());
materialized_columns.emplace_back() = casted_column;
key_columns.emplace_back() = materialized_columns.back().get();
}

View File

@ -825,6 +825,8 @@ bool KeyCondition::tryPrepareSetIndex(
const ASTPtr & right_arg = args[1];
/// TODO: Check this place after cast introduced in Set
SetPtr prepared_set;
if (right_arg->as<ASTSubquery>() || right_arg->as<ASTIdentifier>())
{

View File

@ -0,0 +1,6 @@
1
1
2
2
1
1

View File

@ -0,0 +1,28 @@
-- SELECT 1 IN (SELECT -1)
-- SELECT -1 IN (SELECT 1)
CREATE TABLE select_in_test(value UInt8) ENGINE=TinyLog;
INSERT INTO select_in_test VALUES (1), (2), (3);
SELECT value FROM select_in_test WHERE value IN (-1);
SELECT value FROM select_in_test WHERE value IN (SELECT -1);
SELECT value FROM select_in_test WHERE value IN (1);
SELECT value FROM select_in_test WHERE value IN (SELECT 1);
DROP TABLE select_in_test;
CREATE TABLE select_in_test(value Int8) ENGINE=TinyLog;
INSERT INTO select_in_test VALUES (-1), (2), (3);
SELECT value FROM select_in_test WHERE value IN (1);
SELECT value FROM select_in_test WHERE value IN (SELECT 1);
SELECT value FROM select_in_test WHERE value IN (2);
SELECT value FROM select_in_test WHERE value IN (SELECT 2);
DROP TABLE select_in_test;
SELECT 1 IN (1);
-- Right now this working because of accurate cast. Need to discuss.
SELECT '1' IN (SELECT 1);