Allow Nullable types in MySQL, ODBC and MongoDB external sources #3284

This commit is contained in:
Alexey Milovidov 2018-10-12 05:26:48 +03:00
parent d5bfe37879
commit 4bb8da039f
5 changed files with 50 additions and 22 deletions

View File

@ -29,37 +29,38 @@ void ExternalResultDescription::init(const Block & sample_block_)
if (elem.column->empty())
elem.column = elem.type->createColumnConstWithDefaultValue(1)->convertToFullColumnIfConst();
bool is_nullable = elem.type->isNullable();
DataTypePtr type_not_nullable = removeNullable(elem.type);
const IDataType * type = type_not_nullable.get();
if (typeid_cast<const DataTypeUInt8 *>(type))
types.push_back(ValueType::UInt8);
types.emplace_back(ValueType::UInt8, is_nullable);
else if (typeid_cast<const DataTypeUInt16 *>(type))
types.push_back(ValueType::UInt16);
types.emplace_back(ValueType::UInt16, is_nullable);
else if (typeid_cast<const DataTypeUInt32 *>(type))
types.push_back(ValueType::UInt32);
types.emplace_back(ValueType::UInt32, is_nullable);
else if (typeid_cast<const DataTypeUInt64 *>(type))
types.push_back(ValueType::UInt64);
types.emplace_back(ValueType::UInt64, is_nullable);
else if (typeid_cast<const DataTypeInt8 *>(type))
types.push_back(ValueType::Int8);
types.emplace_back(ValueType::Int8, is_nullable);
else if (typeid_cast<const DataTypeInt16 *>(type))
types.push_back(ValueType::Int16);
types.emplace_back(ValueType::Int16, is_nullable);
else if (typeid_cast<const DataTypeInt32 *>(type))
types.push_back(ValueType::Int32);
types.emplace_back(ValueType::Int32, is_nullable);
else if (typeid_cast<const DataTypeInt64 *>(type))
types.push_back(ValueType::Int64);
types.emplace_back(ValueType::Int64, is_nullable);
else if (typeid_cast<const DataTypeFloat32 *>(type))
types.push_back(ValueType::Float32);
types.emplace_back(ValueType::Float32, is_nullable);
else if (typeid_cast<const DataTypeFloat64 *>(type))
types.push_back(ValueType::Float64);
types.emplace_back(ValueType::Float64, is_nullable);
else if (typeid_cast<const DataTypeString *>(type))
types.push_back(ValueType::String);
types.emplace_back(ValueType::String, is_nullable);
else if (typeid_cast<const DataTypeDate *>(type))
types.push_back(ValueType::Date);
types.emplace_back(ValueType::Date, is_nullable);
else if (typeid_cast<const DataTypeDateTime *>(type))
types.push_back(ValueType::DateTime);
types.emplace_back(ValueType::DateTime, is_nullable);
else if (typeid_cast<const DataTypeUUID *>(type))
types.push_back(ValueType::UUID);
types.emplace_back(ValueType::UUID, is_nullable);
else
throw Exception{"Unsupported type " + type->getName(), ErrorCodes::UNKNOWN_TYPE};
}

View File

@ -25,14 +25,11 @@ struct ExternalResultDescription
String,
Date,
DateTime,
UUID
UUID,
};
/// For Nullable source types, these types correspond to their nested types.
std::vector<ValueType> types;
/// May contain Nullable types.
Block sample_block;
std::vector<std::pair<ValueType, bool /* is_nullable */>> types;
void init(const Block & sample_block_);
};

View File

@ -14,6 +14,7 @@
#include <Dictionaries/MongoDBBlockInputStream.h>
#include <Columns/ColumnString.h>
#include <Columns/ColumnsNumber.h>
#include <Columns/ColumnNullable.h>
#include <Common/FieldVisitors.h>
#include <IO/WriteHelpers.h>
#include <IO/ReadHelpers.h>
@ -185,7 +186,16 @@ Block MongoDBBlockInputStream::readImpl()
if (value.isNull() || value->type() == Poco::MongoDB::ElementTraits<Poco::MongoDB::NullValue>::TypeId)
insertDefaultValue(*columns[idx], *description.sample_block.getByPosition(idx).column);
else
insertValue(*columns[idx], description.types[idx], *value, name);
{
if (description.types[idx].second)
{
ColumnNullable & column_nullable = static_cast<ColumnNullable &>(*columns[idx]);
insertValue(column_nullable.getNestedColumn(), description.types[idx].first, *value, name);
column_nullable.getNullMapData().emplace_back(0);
}
else
insertValue(*columns[idx], description.types[idx].first, *value, name);
}
}
}

View File

@ -4,6 +4,7 @@
#include <Dictionaries/MySQLBlockInputStream.h>
#include <Columns/ColumnsNumber.h>
#include <Columns/ColumnString.h>
#include <Columns/ColumnNullable.h>
#include <IO/ReadHelpers.h>
#include <IO/WriteHelpers.h>
#include <ext/range.h>
@ -82,7 +83,16 @@ Block MySQLBlockInputStream::readImpl()
{
const auto value = row[idx];
if (!value.isNull())
insertValue(*columns[idx], description.types[idx], value);
{
if (description.types[idx].second)
{
ColumnNullable & column_nullable = static_cast<ColumnNullable &>(*columns[idx]);
insertValue(column_nullable.getNestedColumn(), description.types[idx].first, value);
column_nullable.getNullMapData().emplace_back(0);
}
else
insertValue(*columns[idx], description.types[idx].first, value);
}
else
insertDefaultValue(*columns[idx], *description.sample_block.getByPosition(idx).column);
}

View File

@ -2,6 +2,7 @@
#include <Columns/ColumnsNumber.h>
#include <Columns/ColumnString.h>
#include <Columns/ColumnNullable.h>
#include <IO/ReadHelpers.h>
#include <IO/WriteHelpers.h>
@ -91,7 +92,16 @@ Block ODBCBlockInputStream::readImpl()
const Poco::Dynamic::Var & value = row[idx];
if (!value.isEmpty())
insertValue(*columns[idx], description.types[idx], value);
{
if (description.types[idx].second)
{
ColumnNullable & column_nullable = static_cast<ColumnNullable &>(*columns[idx]);
insertValue(column_nullable.getNestedColumn(), description.types[idx].first, value);
column_nullable.getNullMapData().emplace_back(0);
}
else
insertValue(*columns[idx], description.types[idx].first, value);
}
else
insertDefaultValue(*columns[idx], *description.sample_block.getByPosition(idx).column);
}