Technically allowed empty arrays of unspecified type [#CLICKHOUSE-2].

This commit is contained in:
Alexey Milovidov 2017-12-09 23:56:53 +03:00
parent ae2e250bc2
commit 6a568ab692
7 changed files with 67 additions and 83 deletions

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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))

View File

@ -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)

View File

@ -0,0 +1,6 @@
[[[[],[]]]]
[[1],[]]
[[[[],['']]]]
['Hello']
[1] [[],[]]
[] \N [[],[NULL],[NULL,'Hello']]

View 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;