Make UUID as a strong type

This commit is contained in:
Guillaume Tassery 2017-07-06 16:42:27 +02:00
parent c6a5083419
commit 2ec96fe822
8 changed files with 59 additions and 17 deletions

View File

@ -69,12 +69,12 @@ public:
{
case Null: return "Null";
case UInt64: return "UInt64";
case UInt128: return "UInt128";
case Int64: return "Int64";
case Float64: return "Float64";
case String: return "String";
case Array: return "Array";
case Tuple: return "Tuple";
case UInt128: return "UInt128";
default:
throw Exception("Bad type of Field", ErrorCodes::BAD_TYPE_OF_FIELD);
@ -236,12 +236,12 @@ public:
{
case Types::Null: return false;
case Types::UInt64: return get<UInt64>() < rhs.get<UInt64>();
case Types::UInt128: return get<UInt128>() < rhs.get<UInt128>();
case Types::Int64: return get<Int64>() < rhs.get<Int64>();
case Types::Float64: return get<Float64>() < rhs.get<Float64>();
case Types::String: return get<String>() < rhs.get<String>();
case Types::Array: return get<Array>() < rhs.get<Array>();
case Types::Tuple: return get<Tuple>() < rhs.get<Tuple>();
case Types::UInt128: return get<UInt128>() < rhs.get<UInt128>();
default:
throw Exception("Bad type of Field", ErrorCodes::BAD_TYPE_OF_FIELD);
@ -264,12 +264,13 @@ public:
{
case Types::Null: return true;
case Types::UInt64: return get<UInt64>() <= rhs.get<UInt64>();
case Types::UInt128: return get<UInt128>() <= rhs.get<UInt128>();
case Types::Int64: return get<Int64>() <= rhs.get<Int64>();
case Types::Float64: return get<Float64>() <= rhs.get<Float64>();
case Types::String: return get<String>() <= rhs.get<String>();
case Types::Array: return get<Array>() <= rhs.get<Array>();
case Types::Tuple: return get<Tuple>() <= rhs.get<Tuple>();
case Types::UInt128: return get<UInt128>() <= rhs.get<UInt128>();
default:
throw Exception("Bad type of Field", ErrorCodes::BAD_TYPE_OF_FIELD);
@ -343,12 +344,12 @@ private:
{
case Types::Null: f(field.template get<Null>()); return;
case Types::UInt64: f(field.template get<UInt64>()); return;
case Types::UInt128: f(field.template get<UInt128>()); return;
case Types::Int64: f(field.template get<Int64>()); return;
case Types::Float64: f(field.template get<Float64>()); return;
case Types::String: f(field.template get<String>()); return;
case Types::Array: f(field.template get<Array>()); return;
case Types::Tuple: f(field.template get<Tuple>()); return;
case Types::UInt128: f(field.template get<UInt128>()); return;
default:
throw Exception("Bad type of Field", ErrorCodes::BAD_TYPE_OF_FIELD);
@ -405,7 +406,6 @@ private:
case Types::Tuple:
destroy<Tuple>();
break;
default:
break;
}
@ -426,21 +426,21 @@ private:
template <> struct Field::TypeToEnum<Null> { static const Types::Which value = Types::Null; };
template <> struct Field::TypeToEnum<UInt64> { static const Types::Which value = Types::UInt64; };
template <> struct Field::TypeToEnum<UInt128> { static const Types::Which value = Types::UInt128; };
template <> struct Field::TypeToEnum<Int64> { static const Types::Which value = Types::Int64; };
template <> struct Field::TypeToEnum<Float64> { static const Types::Which value = Types::Float64; };
template <> struct Field::TypeToEnum<String> { static const Types::Which value = Types::String; };
template <> struct Field::TypeToEnum<Array> { static const Types::Which value = Types::Array; };
template <> struct Field::TypeToEnum<Tuple> { static const Types::Which value = Types::Tuple; };
template <> struct Field::TypeToEnum<UInt128> { static const Types::Which value = Types::UInt128; };
template <> struct Field::EnumToType<Field::Types::Null> { using Type = Null; };
template <> struct Field::EnumToType<Field::Types::UInt64> { using Type = UInt64; };
template <> struct Field::EnumToType<Field::Types::UInt128> { using Type = UInt128; };
template <> struct Field::EnumToType<Field::Types::Int64> { using Type = Int64; };
template <> struct Field::EnumToType<Field::Types::Float64> { using Type = Float64; };
template <> struct Field::EnumToType<Field::Types::String> { using Type = String; };
template <> struct Field::EnumToType<Field::Types::Array> { using Type = Array; };
template <> struct Field::EnumToType<Field::Types::Tuple> { using Type = Tuple; };
template <> struct Field::EnumToType<Field::Types::UInt128> { using Type = UInt128; };
template <typename T>

View File

@ -5,6 +5,6 @@
namespace DB
{
using UUID = DB::UInt128;
STRONG_TYPEDEF(UInt128, UUID);
}

View File

@ -324,6 +324,12 @@ template <> inline void parseImpl<DataTypeDateTime>(DataTypeDateTime::FieldType
x = tmp;
}
template <> inline void parseImpl<DataTypeUUID>(DataTypeUUID::FieldType & x, ReadBuffer & rb, const DateLUTImpl * time_zone)
{
UUID tmp;
readText(tmp, rb);
x = tmp;
}
/** Throw exception with verbose message when string value is not parsed completely.
*/

View File

@ -41,7 +41,7 @@ void parseUUID(const UInt8 * src36, UInt8 * dst16)
parseHex(&src36[24], &dst16[10], 6);
}
void parseUUID(const UInt8 * src36, UUID & uuid)
void parseUUID(const UInt8 * src36, UInt128 & uuid)
{
char s[16 + 1];

View File

@ -38,6 +38,7 @@ namespace ErrorCodes
extern const int CANNOT_PARSE_UUID;
extern const int CANNOT_READ_ARRAY_FROM_TEXT;
extern const int CANNOT_PARSE_NUMBER;
extern const int ILLEGAL_TYPE_OF_ARGUMENT;
}
/// Helper functions for formatted input.
@ -558,7 +559,7 @@ struct NullSink
};
void parseUUID(const UInt8 * src36, UInt8 * dst16);
void parseUUID(const UInt8 * src36, UUID & uuid);
void parseUUID(const UInt8 * src36, UInt128 & uuid);
void formatHex(const UInt8 * __restrict src, UInt8 * __restrict dst, const size_t num_bytes);
/// In YYYY-MM-DD format
@ -701,7 +702,13 @@ inline void readText(String & x, ReadBuffer & buf) { readEscapedString(x, buf);
inline void readText(LocalDate & x, ReadBuffer & buf) { readDateText(x, buf); }
inline void readText(LocalDateTime & x, ReadBuffer & buf) { readDateTimeText(x, buf); }
inline void readText(UUID & x, ReadBuffer & buf) { readUUIDText(x, buf); }
inline void readText(UInt128 & x, ReadBuffer & buf)
{
/** Because UInt128 isn't a natural type, without arithmetic operator and only use as an intermediary type -for UUID-
* it should never arrive here. But because we used the DataTypeNumber class we should have at least a definition of it.
*/
throw Exception("UInt128 cannot be read as a text", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
}
/// Generic methods to read value in text format,
/// possibly in single quotes (only for data types that use quotes in VALUES format of INSERT statement in SQL).
@ -774,7 +781,13 @@ inline void readCSV(String & x, ReadBuffer & buf, const char delimiter = ',') {
inline void readCSV(LocalDate & x, ReadBuffer & buf) { readCSVSimple(x, buf); }
inline void readCSV(LocalDateTime & x, ReadBuffer & buf) { readCSVSimple(x, buf); }
inline void readCSV(UUID & x, ReadBuffer & buf) { readCSVSimple(x, buf); }
inline void readCSV(UInt128 & x, ReadBuffer & buf)
{
/** Because UInt128 isn't a natural type, without arithmetic operator and only use as an intermediary type -for UUID-
* it should never arrive here. But because we used the DataTypeNumber class we should have at least a definition of it.
*/
throw Exception("UInt128 cannot be read as a text", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
}
template <typename T>
void readBinary(std::vector<T> & x, ReadBuffer & buf)

View File

@ -48,7 +48,7 @@ void formatUUID(const UInt8 * src16, UInt8 * dst36)
formatHex(&src16[10], &dst36[24], 6);
}
void formatUUID(const UUID & uuid, UInt8 * dst36)
void formatUUID(const UInt128 & uuid, UInt8 * dst36)
{
char s[16+1];
@ -67,6 +67,7 @@ void formatUUID(const UUID & uuid, UInt8 * dst36)
memcpy(&dst36[19], &s[0], 4);
memcpy(&dst36[24], &s[4], 12);
}

View File

@ -30,6 +30,7 @@ namespace DB
namespace ErrorCodes
{
extern const int CANNOT_PRINT_FLOAT_OR_DOUBLE_NUMBER;
extern const int ILLEGAL_TYPE_OF_ARGUMENT;
}
/// Helper functions for formatted and binary output.
@ -475,7 +476,7 @@ inline void writeXMLString(const StringRef & s, WriteBuffer & buf)
void formatHex(const UInt8 * __restrict src, UInt8 * __restrict dst, const size_t num_bytes);
void formatUUID(const UInt8 * src16, UInt8 * dst36);
void formatUUID(const UUID & uuid, UInt8 * dst36);
void formatUUID(const UInt128 & uuid, UInt8 * dst36);
inline void writeUUIDText(const UUID & uuid, WriteBuffer & buf)
{
@ -624,6 +625,13 @@ inline void writeText(const char * x, size_t size, WriteBuffer & buf) { writeEsc
inline void writeText(const LocalDate & x, WriteBuffer & buf) { writeDateText(x, buf); }
inline void writeText(const LocalDateTime & x, WriteBuffer & buf) { writeDateTimeText(x, buf); }
inline void writeText(const UUID & x, WriteBuffer & buf) { writeUUIDText(x, buf); }
inline void writeText(const UInt128 & x, WriteBuffer & buf)
{
/** Because UInt128 isn't a natural type, without arithmetic operator and only use as an intermediary type -for UUID-
* it should never arrive here. But because we used the DataTypeNumber class we should have at least a definition of it.
*/
throw Exception("UInt128 cannot be write as a text", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
}
/// String, date, datetime are in single quotes with C-style escaping. Numbers - without.
template <typename T>
@ -668,6 +676,13 @@ inline void writeDoubleQuoted(const LocalDateTime & x, WriteBuffer & buf)
writeChar('"', buf);
}
inline void writeDoubleQuoted(const UUID & x, WriteBuffer & buf)
{
writeChar('"', buf);
writeText(x, buf);
writeChar('"', buf);
}
/// String - in double quotes and with CSV-escaping; date, datetime - in double quotes. Numbers - without.
template <typename T>
@ -677,7 +692,14 @@ writeCSV(const T & x, WriteBuffer & buf) { writeText(x, buf); }
inline void writeCSV(const String & x, WriteBuffer & buf) { writeCSVString<>(x, buf); }
inline void writeCSV(const LocalDate & x, WriteBuffer & buf) { writeDoubleQuoted(x, buf); }
inline void writeCSV(const LocalDateTime & x, WriteBuffer & buf) { writeDoubleQuoted(x, buf); }
inline void writeCSV(const UUID & x, WriteBuffer & buf) { writeDoubleQuoted(x, buf); }
inline void writeCSV(const UInt128, WriteBuffer & buf)
{
/** Because UInt128 isn't a natural type, without arithmetic operator and only use as an intermediary type -for UUID-
* it should never arrive here. But because we used the DataTypeNumber class we should have at least a definition of it.
*/
throw Exception("UInt128 cannot be write as a text", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
}
template <typename T>
void writeBinary(const std::vector<T> & x, WriteBuffer & buf)

View File

@ -89,7 +89,7 @@ UInt64 stringToDateTime(const String & s)
return UInt64(date_time);
}
UUID stringToUUID(const String & s)
UInt128 stringToUUID(const String & s)
{
ReadBufferFromString in(s);
UUID uuid;
@ -98,7 +98,7 @@ UUID stringToUUID(const String & s)
if (!in.eof())
throw Exception("String is too long for UUID: " + s);
return uuid;
return UInt128(uuid);
}