mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-21 15:12:02 +00:00
Technically allowed empty arrays of unspecified type [#CLICKHOUSE-2].
This commit is contained in:
parent
ae2e250bc2
commit
6a568ab692
@ -2,7 +2,6 @@
|
||||
#include <Columns/ColumnNullable.h>
|
||||
#include <Columns/ColumnsCommon.h>
|
||||
#include <DataTypes/DataTypeNullable.h>
|
||||
#include <DataStreams/isConvertableTypes.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
@ -107,33 +106,23 @@ void NullableAdapterBlockInputStream::buildActions(
|
||||
const auto & in_elem = in_sample.getByPosition(i);
|
||||
const auto & out_elem = out_sample.getByPosition(i);
|
||||
|
||||
if (isConvertableTypes(in_elem.type, out_elem.type))
|
||||
{
|
||||
bool is_in_nullable = in_elem.type->isNullable();
|
||||
bool is_out_nullable = out_elem.type->isNullable();
|
||||
bool is_in_nullable = in_elem.type->isNullable();
|
||||
bool is_out_nullable = out_elem.type->isNullable();
|
||||
|
||||
if (is_in_nullable && !is_out_nullable)
|
||||
actions.push_back(TO_ORDINARY);
|
||||
else if (!is_in_nullable && is_out_nullable)
|
||||
actions.push_back(TO_NULLABLE);
|
||||
else
|
||||
actions.push_back(NONE);
|
||||
|
||||
if (in_elem.name != out_elem.name)
|
||||
rename.emplace_back(std::make_optional(out_elem.name));
|
||||
else
|
||||
rename.emplace_back();
|
||||
|
||||
if (actions.back() != NONE || rename.back())
|
||||
must_transform = true;
|
||||
}
|
||||
if (is_in_nullable && !is_out_nullable)
|
||||
actions.push_back(TO_ORDINARY);
|
||||
else if (!is_in_nullable && is_out_nullable)
|
||||
actions.push_back(TO_NULLABLE);
|
||||
else
|
||||
{
|
||||
throw Exception{String("Types must be the same for columns at same position. ")
|
||||
+ "Column " + in_elem.name + " has type " + in_elem.type->getName()
|
||||
+ ", but column " + out_elem.name + " has type " + out_elem.type->getName(),
|
||||
ErrorCodes::TYPE_MISMATCH};
|
||||
}
|
||||
actions.push_back(NONE);
|
||||
|
||||
if (in_elem.name != out_elem.name)
|
||||
rename.emplace_back(std::make_optional(out_elem.name));
|
||||
else
|
||||
rename.emplace_back();
|
||||
|
||||
if (actions.back() != NONE || rename.back())
|
||||
must_transform = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,26 +0,0 @@
|
||||
#include <DataStreams/isConvertableTypes.h>
|
||||
|
||||
#include <DataTypes/DataTypeEnum.h>
|
||||
#include <DataTypes/DataTypeNullable.h>
|
||||
#include <DataTypes/DataTypeString.h>
|
||||
#include <Common/typeid_cast.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
bool isConvertableTypes(const DataTypePtr & from, const DataTypePtr & to)
|
||||
{
|
||||
auto from_nn = removeNullable(from);
|
||||
auto to_nn = removeNullable(to);
|
||||
|
||||
if ( dynamic_cast<const IDataTypeEnum *>(to_nn.get()) &&
|
||||
!dynamic_cast<const IDataTypeEnum *>(from_nn.get()))
|
||||
{
|
||||
if (from_nn->isString() || from_nn->isInteger())
|
||||
return true;
|
||||
}
|
||||
|
||||
return from_nn->equals(*to_nn);
|
||||
}
|
||||
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <DataTypes/IDataType.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
/// Check that type 'from' can be implicitly converted to type 'to'.
|
||||
bool isConvertableTypes(const DataTypePtr & from, const DataTypePtr & to);
|
||||
|
||||
}
|
@ -18,6 +18,7 @@
|
||||
#include <DataTypes/DataTypeArray.h>
|
||||
#include <DataTypes/DataTypeTuple.h>
|
||||
#include <DataTypes/DataTypeNullable.h>
|
||||
#include <DataTypes/DataTypeNothing.h>
|
||||
#include <DataTypes/DataTypeUUID.h>
|
||||
#include <DataTypes/DataTypeInterval.h>
|
||||
#include <Columns/ColumnString.h>
|
||||
@ -1388,6 +1389,16 @@ private:
|
||||
};
|
||||
}
|
||||
|
||||
WrapperType createNothingWrapper(const IDataType * to_type)
|
||||
{
|
||||
DataTypePtr to_type_clone = to_type->clone();
|
||||
return [to_type_clone] (Block & block, const ColumnNumbers &, const size_t result)
|
||||
{
|
||||
/// Column of Nothing type is trivially convertible to any other column
|
||||
block.getByPosition(result).column = to_type_clone->createConstColumn(block.rows(), to_type_clone->getDefault())->convertToFullColumnIfConst();
|
||||
};
|
||||
}
|
||||
|
||||
/// Actions to be taken when performing a conversion.
|
||||
struct NullableConversion
|
||||
{
|
||||
@ -1494,6 +1505,8 @@ private:
|
||||
{
|
||||
if (from_type->equals(*to_type))
|
||||
return createIdentityWrapper(from_type);
|
||||
else if (checkDataType<DataTypeNothing>(from_type.get()))
|
||||
return createNothingWrapper(to_type);
|
||||
else if (const auto to_actual_type = checkAndGetDataType<DataTypeUInt8>(to_type))
|
||||
return createWrapper(from_type, to_actual_type);
|
||||
else if (const auto to_actual_type = checkAndGetDataType<DataTypeUInt16>(to_type))
|
||||
|
@ -123,23 +123,23 @@ void ASTFunction::formatImplWithoutAlias(const FormatSettings & settings, Format
|
||||
{
|
||||
const char * operators[] =
|
||||
{
|
||||
"multiply", " * ",
|
||||
"divide", " / ",
|
||||
"modulo", " % ",
|
||||
"plus", " + ",
|
||||
"minus", " - ",
|
||||
"notEquals", " != ",
|
||||
"lessOrEquals", " <= ",
|
||||
"greaterOrEquals", " >= ",
|
||||
"less", " < ",
|
||||
"greater", " > ",
|
||||
"equals", " = ",
|
||||
"like", " LIKE ",
|
||||
"notLike", " NOT LIKE ",
|
||||
"in", " IN ",
|
||||
"notIn", " NOT IN ",
|
||||
"globalIn", " GLOBAL IN ",
|
||||
"globalNotIn", " GLOBAL NOT IN ",
|
||||
"multiply", " * ",
|
||||
"divide", " / ",
|
||||
"modulo", " % ",
|
||||
"plus", " + ",
|
||||
"minus", " - ",
|
||||
"notEquals", " != ",
|
||||
"lessOrEquals", " <= ",
|
||||
"greaterOrEquals", " >= ",
|
||||
"less", " < ",
|
||||
"greater", " > ",
|
||||
"equals", " = ",
|
||||
"like", " LIKE ",
|
||||
"notLike", " NOT LIKE ",
|
||||
"in", " IN ",
|
||||
"notIn", " NOT IN ",
|
||||
"globalIn", " GLOBAL IN ",
|
||||
"globalNotIn", " GLOBAL NOT IN ",
|
||||
nullptr
|
||||
};
|
||||
|
||||
@ -205,8 +205,8 @@ void ASTFunction::formatImplWithoutAlias(const FormatSettings & settings, Format
|
||||
{
|
||||
const char * operators[] =
|
||||
{
|
||||
"and", " AND ",
|
||||
"or", " OR ",
|
||||
"and", " AND ",
|
||||
"or", " OR ",
|
||||
nullptr
|
||||
};
|
||||
|
||||
@ -229,7 +229,7 @@ void ASTFunction::formatImplWithoutAlias(const FormatSettings & settings, Format
|
||||
}
|
||||
}
|
||||
|
||||
if (!written && arguments->children.size() >= 1 && 0 == strcmp(name.c_str(), "array"))
|
||||
if (!written && 0 == strcmp(name.c_str(), "array"))
|
||||
{
|
||||
settings.ostr << (settings.hilite ? hilite_operator : "") << '[' << (settings.hilite ? hilite_none : "");
|
||||
for (size_t i = 0; i < arguments->children.size(); ++i)
|
||||
|
@ -0,0 +1,6 @@
|
||||
[[[[],[]]]]
|
||||
[[1],[]]
|
||||
[[[[],['']]]]
|
||||
['Hello']
|
||||
[1] [[],[]]
|
||||
[] \N [[],[NULL],[NULL,'Hello']]
|
13
dbms/tests/queries/0_stateless/00530_arrays_of_nothing.sql
Normal file
13
dbms/tests/queries/0_stateless/00530_arrays_of_nothing.sql
Normal file
@ -0,0 +1,13 @@
|
||||
SELECT [[[[],[]]]];
|
||||
SELECT [[1], []];
|
||||
SELECT [[[[],['']]]];
|
||||
SELECT concat([], ['Hello'], []);
|
||||
SELECT arrayPushBack([], 1), arrayPushFront([[]], []);
|
||||
|
||||
DROP TABLE IF EXISTS test.arr;
|
||||
CREATE TABLE test.arr (x Array(String), y Nullable(String), z Array(Array(Nullable(String)))) ENGINE = TinyLog;
|
||||
|
||||
INSERT INTO test.arr SELECT [], NULL, [[], [NULL], [NULL, 'Hello']];
|
||||
SELECT * FROM test.arr;
|
||||
|
||||
DROP TABLE test.arr;
|
Loading…
Reference in New Issue
Block a user