mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-09-30 05:30:51 +00:00
fix type map with integer keys
This commit is contained in:
parent
3429925338
commit
f1fa110d48
@ -29,6 +29,7 @@ namespace ErrorCodes
|
|||||||
{
|
{
|
||||||
extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH;
|
extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH;
|
||||||
extern const int CANNOT_READ_MAP_FROM_TEXT;
|
extern const int CANNOT_READ_MAP_FROM_TEXT;
|
||||||
|
extern const int BAD_ARGUMENTS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -38,6 +39,8 @@ DataTypeMap::DataTypeMap(const DataTypes & elems_)
|
|||||||
key_type = elems_[0];
|
key_type = elems_[0];
|
||||||
value_type = elems_[1];
|
value_type = elems_[1];
|
||||||
|
|
||||||
|
assertKeyType();
|
||||||
|
|
||||||
nested = std::make_shared<DataTypeArray>(
|
nested = std::make_shared<DataTypeArray>(
|
||||||
std::make_shared<DataTypeTuple>(DataTypes{key_type, value_type}, Names{"keys", "values"}));
|
std::make_shared<DataTypeTuple>(DataTypes{key_type, value_type}, Names{"keys", "values"}));
|
||||||
}
|
}
|
||||||
@ -45,7 +48,19 @@ DataTypeMap::DataTypeMap(const DataTypes & elems_)
|
|||||||
DataTypeMap::DataTypeMap(const DataTypePtr & key_type_, const DataTypePtr & value_type_)
|
DataTypeMap::DataTypeMap(const DataTypePtr & key_type_, const DataTypePtr & value_type_)
|
||||||
: key_type(key_type_), value_type(value_type_)
|
: key_type(key_type_), value_type(value_type_)
|
||||||
, nested(std::make_shared<DataTypeArray>(
|
, nested(std::make_shared<DataTypeArray>(
|
||||||
std::make_shared<DataTypeTuple>(DataTypes{key_type_, value_type_}, Names{"keys", "values"}))) {}
|
std::make_shared<DataTypeTuple>(DataTypes{key_type_, value_type_}, Names{"keys", "values"})))
|
||||||
|
{
|
||||||
|
assertKeyType();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataTypeMap::assertKeyType() const
|
||||||
|
{
|
||||||
|
if (!key_type->isValueRepresentedByInteger() && !isStringOrFixedString(*key_type) && !WhichDataType(key_type).isNothing())
|
||||||
|
throw Exception(ErrorCodes::BAD_ARGUMENTS,
|
||||||
|
"Type of Map key must be a type, that can be represented by integer or string,"
|
||||||
|
" but {} given", key_type->getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
std::string DataTypeMap::doGetName() const
|
std::string DataTypeMap::doGetName() const
|
||||||
{
|
{
|
||||||
|
@ -98,6 +98,8 @@ private:
|
|||||||
|
|
||||||
template <typename Reader>
|
template <typename Reader>
|
||||||
void deserializeTextImpl(IColumn & column, ReadBuffer & istr, bool need_safe_get_int_key, Reader && reader) const;
|
void deserializeTextImpl(IColumn & column, ReadBuffer & istr, bool need_safe_get_int_key, Reader && reader) const;
|
||||||
|
|
||||||
|
void assertKeyType() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -872,7 +872,7 @@ bool FunctionArrayElement::matchKeyToIndexNumberConst(
|
|||||||
if (!data_numeric)
|
if (!data_numeric)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (index.getType() != Field::Types::UInt64 && index.getType() != Field::Types::Int64)
|
if (index.getType() != Field::Types::UInt64 && index.getType() != Field::Types::Int64 && index.getType() != Field::Types::Int128)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
MatcherNumberConst<DataType> matcher{data_numeric->getData(), get<DataType>(index)};
|
MatcherNumberConst<DataType> matcher{data_numeric->getData(), get<DataType>(index)};
|
||||||
@ -910,6 +910,7 @@ bool FunctionArrayElement::matchKeyToIndex(
|
|||||||
|| matchKeyToIndexNumber<Int16>(data, offsets, arguments, matched_idxs)
|
|| matchKeyToIndexNumber<Int16>(data, offsets, arguments, matched_idxs)
|
||||||
|| matchKeyToIndexNumber<Int32>(data, offsets, arguments, matched_idxs)
|
|| matchKeyToIndexNumber<Int32>(data, offsets, arguments, matched_idxs)
|
||||||
|| matchKeyToIndexNumber<Int64>(data, offsets, arguments, matched_idxs)
|
|| matchKeyToIndexNumber<Int64>(data, offsets, arguments, matched_idxs)
|
||||||
|
|| matchKeyToIndexNumber<Int128>(data, offsets, arguments, matched_idxs)
|
||||||
|| matchKeyToIndexString(data, offsets, arguments, matched_idxs);
|
|| matchKeyToIndexString(data, offsets, arguments, matched_idxs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -925,6 +926,7 @@ bool FunctionArrayElement::matchKeyToIndexConst(
|
|||||||
|| matchKeyToIndexNumberConst<Int16>(data, offsets, index, matched_idxs)
|
|| matchKeyToIndexNumberConst<Int16>(data, offsets, index, matched_idxs)
|
||||||
|| matchKeyToIndexNumberConst<Int32>(data, offsets, index, matched_idxs)
|
|| matchKeyToIndexNumberConst<Int32>(data, offsets, index, matched_idxs)
|
||||||
|| matchKeyToIndexNumberConst<Int64>(data, offsets, index, matched_idxs)
|
|| matchKeyToIndexNumberConst<Int64>(data, offsets, index, matched_idxs)
|
||||||
|
|| matchKeyToIndexNumberConst<Int128>(data, offsets, index, matched_idxs)
|
||||||
|| matchKeyToIndexStringConst(data, offsets, index, matched_idxs);
|
|| matchKeyToIndexStringConst(data, offsets, index, matched_idxs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -945,11 +947,14 @@ ColumnPtr FunctionArrayElement::executeMap(
|
|||||||
indices_column->reserve(input_rows_count);
|
indices_column->reserve(input_rows_count);
|
||||||
auto & indices_data = assert_cast<ColumnVector<UInt64> &>(*indices_column).getData();
|
auto & indices_data = assert_cast<ColumnVector<UInt64> &>(*indices_column).getData();
|
||||||
|
|
||||||
|
std::cerr << "types: " << arguments[0].type->getName() << " " << arguments[1].type->getName() << "\n";
|
||||||
|
std::cerr << "columns: " << arguments[0].column->dumpStructure() << " " << arguments[1].column->dumpStructure() << "\n";
|
||||||
|
|
||||||
if (!isColumnConst(*arguments[1].column))
|
if (!isColumnConst(*arguments[1].column))
|
||||||
{
|
{
|
||||||
if (input_rows_count > 0 && !matchKeyToIndex(keys_data, offsets, arguments, indices_data))
|
if (input_rows_count > 0 && !matchKeyToIndex(keys_data, offsets, arguments, indices_data))
|
||||||
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,
|
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,
|
||||||
"Illegal types of arguments: {}, {} for function ",
|
"Illegal types of arguments: {}, {} for function {}",
|
||||||
arguments[0].type->getName(), arguments[1].type->getName(), getName());
|
arguments[0].type->getName(), arguments[1].type->getName(), getName());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#include <DataTypes/DataTypeDateTime64.h>
|
#include <DataTypes/DataTypeDateTime64.h>
|
||||||
#include <DataTypes/DataTypeEnum.h>
|
#include <DataTypes/DataTypeEnum.h>
|
||||||
#include <DataTypes/DataTypeNullable.h>
|
#include <DataTypes/DataTypeNullable.h>
|
||||||
|
#include <DataTypes/DataTypeMap.h>
|
||||||
|
|
||||||
#include <Core/AccurateComparison.h>
|
#include <Core/AccurateComparison.h>
|
||||||
#include <Common/FieldVisitors.h>
|
#include <Common/FieldVisitors.h>
|
||||||
@ -276,6 +277,40 @@ Field convertFieldToTypeImpl(const Field & src, const IDataType & type, const ID
|
|||||||
return have_unconvertible_element ? Field(Null()) : Field(res);
|
return have_unconvertible_element ? Field(Null()) : Field(res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (const DataTypeMap * type_map = typeid_cast<const DataTypeMap *>(&type))
|
||||||
|
{
|
||||||
|
if (src.getType() == Field::Types::Map)
|
||||||
|
{
|
||||||
|
const auto & src_map = src.get<Map>();
|
||||||
|
|
||||||
|
const auto & key_type = *type_map->getKeyType();
|
||||||
|
const auto & value_type = *type_map->getValueType();
|
||||||
|
|
||||||
|
bool have_unconvertible_element = false;
|
||||||
|
Map res(src_map.size());
|
||||||
|
|
||||||
|
for (size_t i = 0; i < src_map.size(); ++i)
|
||||||
|
{
|
||||||
|
const auto & src_tuple = src_map[i].safeGet<const Tuple &>();
|
||||||
|
assert(src_tuple.size() == 2);
|
||||||
|
Tuple res_tuple(2);
|
||||||
|
|
||||||
|
res_tuple[0] = convertFieldToType(src_tuple[0], key_type);
|
||||||
|
res_tuple[1] = convertFieldToType(src_tuple[1], value_type);
|
||||||
|
|
||||||
|
if ((res_tuple[0].isNull() && !key_type.isNullable())
|
||||||
|
|| (res_tuple[1].isNull() && !value_type.isNullable()))
|
||||||
|
{
|
||||||
|
// See the comment for Tuples above.
|
||||||
|
have_unconvertible_element = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
res[i] = std::move(res_tuple);
|
||||||
|
}
|
||||||
|
|
||||||
|
return have_unconvertible_element ? Field(Null()) : Field(res);
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (const DataTypeAggregateFunction * agg_func_type = typeid_cast<const DataTypeAggregateFunction *>(&type))
|
else if (const DataTypeAggregateFunction * agg_func_type = typeid_cast<const DataTypeAggregateFunction *>(&type))
|
||||||
{
|
{
|
||||||
if (src.getType() != Field::Types::AggregateFunctionState)
|
if (src.getType() != Field::Types::AggregateFunctionState)
|
||||||
|
@ -1979,7 +1979,6 @@ bool ParserExpressionElement::parseImpl(Pos & pos, ASTPtr & node, Expected & exp
|
|||||||
{
|
{
|
||||||
return ParserSubquery().parse(pos, node, expected)
|
return ParserSubquery().parse(pos, node, expected)
|
||||||
|| ParserTupleOfLiterals().parse(pos, node, expected)
|
|| ParserTupleOfLiterals().parse(pos, node, expected)
|
||||||
|| ParserMapOfLiterals().parse(pos, node, expected)
|
|
||||||
|| ParserParenthesisExpression().parse(pos, node, expected)
|
|| ParserParenthesisExpression().parse(pos, node, expected)
|
||||||
|| ParserArrayOfLiterals().parse(pos, node, expected)
|
|| ParserArrayOfLiterals().parse(pos, node, expected)
|
||||||
|| ParserArray().parse(pos, node, expected)
|
|| ParserArray().parse(pos, node, expected)
|
||||||
|
@ -324,18 +324,6 @@ protected:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class ParserMapOfLiterals : public IParserBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ParserCollectionOfLiterals<Map> map_parser{TokenType::OpeningCurlyBrace, TokenType::ClosingCurlyBrace};
|
|
||||||
protected:
|
|
||||||
const char * getName() const override { return "map"; }
|
|
||||||
bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override
|
|
||||||
{
|
|
||||||
return map_parser.parse(pos, node, expected);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class ParserArrayOfLiterals : public IParserBase
|
class ParserArrayOfLiterals : public IParserBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -203,12 +203,6 @@ private:
|
|||||||
if (not_null == array.end())
|
if (not_null == array.end())
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (literal->value.getType() == Field::Types::Map)
|
|
||||||
{
|
|
||||||
const Map & map = literal->value.get<Map>();
|
|
||||||
if (map.size() % 2)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
String column_name = "_dummy_" + std::to_string(replaced_literals.size());
|
String column_name = "_dummy_" + std::to_string(replaced_literals.size());
|
||||||
replaced_literals.emplace_back(literal, column_name, force_nullable);
|
replaced_literals.emplace_back(literal, column_name, force_nullable);
|
||||||
@ -481,14 +475,12 @@ bool ConstantExpressionTemplate::parseLiteralAndAssertType(ReadBuffer & istr, co
|
|||||||
/// TODO faster way to check types without using Parsers
|
/// TODO faster way to check types without using Parsers
|
||||||
ParserArrayOfLiterals parser_array;
|
ParserArrayOfLiterals parser_array;
|
||||||
ParserTupleOfLiterals parser_tuple;
|
ParserTupleOfLiterals parser_tuple;
|
||||||
ParserMapOfLiterals parser_map;
|
|
||||||
|
|
||||||
Tokens tokens_number(istr.position(), istr.buffer().end());
|
Tokens tokens_number(istr.position(), istr.buffer().end());
|
||||||
IParser::Pos iterator(tokens_number, settings.max_parser_depth);
|
IParser::Pos iterator(tokens_number, settings.max_parser_depth);
|
||||||
Expected expected;
|
Expected expected;
|
||||||
ASTPtr ast;
|
ASTPtr ast;
|
||||||
if (!parser_array.parse(iterator, ast, expected) && !parser_tuple.parse(iterator, ast, expected)
|
if (!parser_array.parse(iterator, ast, expected) && !parser_tuple.parse(iterator, ast, expected))
|
||||||
&& !parser_map.parse(iterator, ast, expected))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
istr.position() = const_cast<char *>(iterator->begin);
|
istr.position() = const_cast<char *>(iterator->begin);
|
||||||
|
Loading…
Reference in New Issue
Block a user