Optimize the code and streamline the functionality by retaining only the feature of automatically recognizing UInt64 as Int64.

This commit is contained in:
chen768959 2023-08-09 23:03:50 +08:00
parent 12d262ed7a
commit efb041c4d5
6 changed files with 61 additions and 114 deletions

View File

@ -582,6 +582,9 @@
M(697, CANNOT_RESTORE_TO_NONENCRYPTED_DISK) \
M(698, INVALID_REDIS_STORAGE_TYPE) \
M(699, INVALID_REDIS_TABLE_STRUCTURE) \
M(700, USER_SESSION_LIMIT_EXCEEDED) \
M(701, CLUSTER_DOESNT_EXIST) \
M(702, OPPOSITE_SIGN_DATA_TYPE_NOT_FOUND) \
\
M(999, KEEPER_EXCEPTION) \
M(1000, POCO_EXCEPTION) \

View File

@ -18,9 +18,10 @@ class DataTypeNumber final : public DataTypeNumberBase<T>
public:
DataTypeNumber() = default;
explicit DataTypeNumber(DataTypes data_types)
explicit DataTypeNumber(DataTypePtr opposite_sign_data_type_)
: DataTypeNumberBase<T>()
, possible_data_types(std::move(data_types))
, opposite_sign_data_type(std::move(opposite_sign_data_type_))
, has_opposite_sign_data_type(true)
{
}
@ -39,15 +40,23 @@ public:
return std::make_shared<PromotedType>();
}
bool hasOppositeSignDataType() const override { return has_opposite_sign_data_type; }
DataTypePtr oppositeSignDataType() const override
{
if (!has_opposite_sign_data_type)
IDataType::oppositeSignDataType();
return opposite_sign_data_type;
}
SerializationPtr doGetDefaultSerialization() const override
{
return std::make_shared<SerializationNumber<T>>();
}
DataTypes getPossiblePtr() const override { return possible_data_types; }
private:
DataTypes possible_data_types;
DataTypePtr opposite_sign_data_type;
bool has_opposite_sign_data_type = false;
};
using DataTypeUInt8 = DataTypeNumber<UInt8>;

View File

@ -33,34 +33,19 @@ DataTypePtr FieldToDataType<on_error>::operator() (const Null &) const
template <LeastSupertypeOnError on_error>
DataTypePtr FieldToDataType<on_error>::operator() (const UInt64 & x) const
{
if (x <= std::numeric_limits<Int8>::max()) return std::make_shared<DataTypeUInt8>(DataTypes{ std::make_shared<DataTypeInt8>() });
if (x <= std::numeric_limits<UInt8>::max()) return std::make_shared<DataTypeUInt8>();
if (x <= std::numeric_limits<Int16>::max()) return std::make_shared<DataTypeUInt16>(DataTypes{ std::make_shared<DataTypeInt16>() });
if (x <= std::numeric_limits<UInt16>::max()) return std::make_shared<DataTypeUInt16>();
if (x <= std::numeric_limits<Int32>::max()) return std::make_shared<DataTypeUInt32>(DataTypes{ std::make_shared<DataTypeInt32>() });
if (x <= std::numeric_limits<UInt32>::max()) return std::make_shared<DataTypeUInt32>();
if (x <= std::numeric_limits<Int64>::max()) return std::make_shared<DataTypeUInt64>(DataTypes{ std::make_shared<DataTypeInt64>() });
if (x <= std::numeric_limits<Int64>::max()) return std::make_shared<DataTypeUInt64>(std::make_shared<DataTypeInt64>());
return std::make_shared<DataTypeUInt64>();
}
template <LeastSupertypeOnError on_error>
DataTypePtr FieldToDataType<on_error>::operator() (const Int64 & x) const
{
if (x >= 0)
{
if (x <= std::numeric_limits<Int8>::max()) return std::make_shared<DataTypeInt8>();
if (x <= std::numeric_limits<UInt8>::max()) return std::make_shared<DataTypeInt16>(DataTypes{ std::make_shared<DataTypeUInt8>() });
if (x <= std::numeric_limits<Int16>::max()) return std::make_shared<DataTypeInt16>();
if (x <= std::numeric_limits<UInt16>::max()) return std::make_shared<DataTypeInt32>(DataTypes{ std::make_shared<DataTypeUInt16>() });
if (x <= std::numeric_limits<Int32>::max()) return std::make_shared<DataTypeInt32>();
if (x <= std::numeric_limits<UInt32>::max()) return std::make_shared<DataTypeInt64>(DataTypes{ std::make_shared<DataTypeUInt32>() });
}
else
{
if (x >= std::numeric_limits<Int8>::min()) return std::make_shared<DataTypeInt8>();
if (x >= std::numeric_limits<Int16>::min()) return std::make_shared<DataTypeInt16>();
if (x >= std::numeric_limits<Int32>::min()) return std::make_shared<DataTypeInt32>();
}
if (x <= std::numeric_limits<Int8>::max() && x >= std::numeric_limits<Int8>::min()) return std::make_shared<DataTypeInt8>();
if (x <= std::numeric_limits<Int16>::max() && x >= std::numeric_limits<Int16>::min()) return std::make_shared<DataTypeInt16>();
if (x <= std::numeric_limits<Int32>::max() && x >= std::numeric_limits<Int32>::min()) return std::make_shared<DataTypeInt32>();
return std::make_shared<DataTypeInt64>();
}

View File

@ -23,6 +23,7 @@ namespace ErrorCodes
{
extern const int LOGICAL_ERROR;
extern const int DATA_TYPE_CANNOT_BE_PROMOTED;
extern const int OPPOSITE_SIGN_DATA_TYPE_NOT_FOUND;
extern const int ILLEGAL_COLUMN;
}
@ -71,6 +72,11 @@ DataTypePtr IDataType::promoteNumericType() const
throw Exception(ErrorCodes::DATA_TYPE_CANNOT_BE_PROMOTED, "Data type {} can't be promoted.", getName());
}
DataTypePtr IDataType::oppositeSignDataType() const
{
throw Exception(ErrorCodes::OPPOSITE_SIGN_DATA_TYPE_NOT_FOUND, "Opposite sign data type not found for {}.", getName());
}
size_t IDataType::getSizeOfValueInMemory() const
{
throw Exception(ErrorCodes::LOGICAL_ERROR, "Value of type {} in memory is not of fixed size.", getName());

View File

@ -73,8 +73,6 @@ public:
DataTypePtr getPtr() const { return shared_from_this(); }
virtual DataTypes getPossiblePtr() const { return {}; }
/// Name of data type family (example: FixedString, Array).
virtual const char * getFamilyName() const = 0;
/// Name of corresponding data type in MySQL (exampe: Bigint, Blob, etc)
@ -160,6 +158,15 @@ public:
*/
virtual DataTypePtr promoteNumericType() const;
/** The data type has an opposite sign DataTypePtr type.
* Data types that can have an opposite sign are typically signed or unsigned types.
*/
virtual bool hasOppositeSignDataType() const { return false; }
/** Return the opposite sign data type of the current data type. Throw an exception if `hasOppositeSignDataType() == false`.
*/
virtual DataTypePtr oppositeSignDataType() const;
/** Directly insert default value into a column. Default implementation use method IColumn::insertDefault.
* This should be overridden if data type default value differs from column default value (example: Enum data types).
*/

View File

@ -605,113 +605,50 @@ DataTypePtr getLeastSupertype(const DataTypes & types, bool optimize_type_ids)
void optimizeTypeIds(const DataTypes & types, TypeIndexSet & type_ids)
{
// Determine whether the type_id is UInt
auto is_unsigned = [](const TypeIndex & type_id)
auto is_signed_int = [](const TypeIndex & type_id)
{
switch (type_id)
{
case TypeIndex::UInt8:
case TypeIndex::UInt16:
case TypeIndex::UInt32:
case TypeIndex::UInt64:
case TypeIndex::Int8:
case TypeIndex::Int16:
case TypeIndex::Int32:
case TypeIndex::Int64:
return true;
default:
return false;
}
};
bool only_unsigned = false;
bool only_signed = false;
bool both = false;
bool has_unsigned = false;
bool has_signed = false;
bool has_signed_int = false;
bool has_uint64_and_has_opposite = false;
TypeIndexSet opposite_type_ids;
// Determine the distribution of maximum signed and unsigned, Example:
// Int64, Int64 = only_signed.
// UInt64, UInt64 = only_unsigned.
// UInt64(possible: Int64), Int64(possible: UInt64) = both.
// UInt64(possible: Int64), Int64 = both, only_signed.
// Determine whether UInt64 in type_ids needs to change its sign.
for (const auto & type : types)
{
TypeIndex type_id = type->getTypeId();
bool type_is_unsigned = is_unsigned(type_id);
bool type_is_both = false;
for (const auto & possible_type : type->getPossiblePtr())
auto type_id = type->getTypeId();
if (!has_signed_int)
has_signed_int = is_signed_int(type_id);
if (type_id == TypeIndex::UInt64)
{
if (type_is_unsigned != is_unsigned(possible_type->getTypeId()))
if (!type->hasOppositeSignDataType())
{
type_is_both = true;
break;
has_uint64_and_has_opposite = false;
break ;
}else
{
has_uint64_and_has_opposite = true;
opposite_type_ids.insert(type->oppositeSignDataType()->getTypeId());
}
}
if (type_is_unsigned)
has_unsigned = true;
else
has_signed = true;
if (type_is_both)
both = true;
else if (type_is_unsigned)
only_unsigned = true;
else
only_signed = true;
}
auto optimize_type_id = [&is_unsigned](const DataTypePtr & type, bool try_change_unsigned)
if (has_uint64_and_has_opposite && has_signed_int)
{
TypeIndex type_id = type->getTypeId();
switch (type_id)
{
case TypeIndex::UInt8:
case TypeIndex::UInt16:
case TypeIndex::UInt32:
case TypeIndex::UInt64:
if (try_change_unsigned)
return type_id;
break ;
case TypeIndex::Int8:
case TypeIndex::Int16:
case TypeIndex::Int32:
case TypeIndex::Int64:
if (!try_change_unsigned)
return type_id;
break ;
default:
return type_id;
}
for (const auto & other_type : type->getPossiblePtr())
{
TypeIndex other_type_id = other_type->getTypeId();
if ((try_change_unsigned && is_unsigned(other_type_id))
|| (!try_change_unsigned && !is_unsigned(other_type_id)))
{
return other_type_id;
}
}
return type_id;
};
// optimize type_ids
if (both)
{
// Example: Int64(possible: UInt32), UInt64 = UInt32, UInt64
if (only_unsigned && !only_signed)
{
type_ids.clear();
for (const auto & type : types)
type_ids.insert(optimize_type_id(type, true));
}
// Example: UInt64(possible: Int64), Int64 = Int64, Int64
// Int64(possible: UInt32), UInt64(possible: Int64) = Int64, Int64
else if ((only_signed && !only_unsigned) || (has_unsigned && has_signed && !only_signed && !only_unsigned))
{
type_ids.clear();
for (const auto & type : types)
type_ids.insert(optimize_type_id(type, false));
}
type_ids.erase(TypeIndex::UInt64);
type_ids.insert(opposite_type_ids.begin(), opposite_type_ids.end());
}
}