Merge pull request #16337 from kitaisreal/uuid-safe-cast-functions-added

UUID safe cast functions added
This commit is contained in:
Anton Popov 2020-10-26 16:03:27 +03:00 committed by GitHub
commit 5fbca7d62d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 129 additions and 5 deletions

View File

@ -61,6 +61,54 @@ SELECT toUUID('61f0c404-5cb3-11e7-907b-a6006ad3dba0') AS uuid
└──────────────────────────────────────┘
```
## toUUIDOrNull (x) {#touuidornull-x}
It takes an argument of type String and tries to parse it into UUID. If failed, returns NULL.
``` sql
toUUIDOrNull(String)
```
**Returned value**
The Nullable(UUID) type value.
**Usage example**
``` sql
SELECT toUUIDOrNull('61f0c404-5cb3-11e7-907b-a6006ad3dba0T') AS uuid
```
``` text
┌─uuid─┐
│ ᴺᵁᴸᴸ │
└──────┘
```
## toUUIDOrZero (x) {#touuidorzero-x}
It takes an argument of type String and tries to parse it into UUID. If failed, returns zero UUID.
``` sql
toUUIDOrZero(String)
```
**Returned value**
The UUID type value.
**Usage example**
``` sql
SELECT toUUIDOrZero('61f0c404-5cb3-11e7-907b-a6006ad3dba0T') AS uuid
```
``` text
┌─────────────────────────────────uuid─┐
│ 00000000-0000-0000-0000-000000000000 │
└──────────────────────────────────────┘
```
## UUIDStringToNum {#uuidstringtonum}
Accepts a string containing 36 characters in the format `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`, and returns it as a set of bytes in a [FixedString(16)](../../sql-reference/data-types/fixedstring.md).

View File

@ -68,6 +68,8 @@ void registerFunctionsConversion(FunctionFactory & factory)
factory.registerFunction<FunctionToDecimal128OrZero>();
factory.registerFunction<FunctionToDecimal256OrZero>();
factory.registerFunction<FunctionToUUIDOrZero>();
factory.registerFunction<FunctionToUInt8OrNull>();
factory.registerFunction<FunctionToUInt16OrNull>();
factory.registerFunction<FunctionToUInt32OrNull>();
@ -90,6 +92,8 @@ void registerFunctionsConversion(FunctionFactory & factory)
factory.registerFunction<FunctionToDecimal128OrNull>();
factory.registerFunction<FunctionToDecimal256OrNull>();
factory.registerFunction<FunctionToUUIDOrNull>();
factory.registerFunction<FunctionParseDateTimeBestEffort>();
factory.registerFunction<FunctionParseDateTimeBestEffortUS>();
factory.registerFunction<FunctionParseDateTimeBestEffortOrZero>();

View File

@ -569,7 +569,7 @@ template <>
inline void parseImpl<DataTypeUUID>(DataTypeUUID::FieldType & x, ReadBuffer & rb, const DateLUTImpl *)
{
UUID tmp;
readText(tmp, rb);
readUUIDText(tmp, rb);
x = tmp;
}
@ -603,6 +603,17 @@ inline bool tryParseImpl<DataTypeDateTime>(DataTypeDateTime::FieldType & x, Read
return true;
}
template <>
inline bool tryParseImpl<DataTypeUUID>(DataTypeUUID::FieldType & x, ReadBuffer & rb, const DateLUTImpl *)
{
UUID tmp;
if (!tryReadUUIDText(tmp, rb))
return false;
x = tmp;
return true;
}
/** Throw exception with verbose message when string value is not parsed completely.
*/
@ -1755,6 +1766,7 @@ struct NameToDecimal32OrZero { static constexpr auto name = "toDecimal32OrZero";
struct NameToDecimal64OrZero { static constexpr auto name = "toDecimal64OrZero"; };
struct NameToDecimal128OrZero { static constexpr auto name = "toDecimal128OrZero"; };
struct NameToDecimal256OrZero { static constexpr auto name = "toDecimal256OrZero"; };
struct NameToUUIDOrZero { static constexpr auto name = "toUUIDOrZero"; };
using FunctionToUInt8OrZero = FunctionConvertFromString<DataTypeUInt8, NameToUInt8OrZero, ConvertFromStringExceptionMode::Zero>;
using FunctionToUInt16OrZero = FunctionConvertFromString<DataTypeUInt16, NameToUInt16OrZero, ConvertFromStringExceptionMode::Zero>;
@ -1776,6 +1788,7 @@ using FunctionToDecimal32OrZero = FunctionConvertFromString<DataTypeDecimal<Deci
using FunctionToDecimal64OrZero = FunctionConvertFromString<DataTypeDecimal<Decimal64>, NameToDecimal64OrZero, ConvertFromStringExceptionMode::Zero>;
using FunctionToDecimal128OrZero = FunctionConvertFromString<DataTypeDecimal<Decimal128>, NameToDecimal128OrZero, ConvertFromStringExceptionMode::Zero>;
using FunctionToDecimal256OrZero = FunctionConvertFromString<DataTypeDecimal<Decimal256>, NameToDecimal256OrZero, ConvertFromStringExceptionMode::Zero>;
using FunctionToUUIDOrZero = FunctionConvertFromString<DataTypeUUID, NameToUUIDOrZero, ConvertFromStringExceptionMode::Zero>;
struct NameToUInt8OrNull { static constexpr auto name = "toUInt8OrNull"; };
struct NameToUInt16OrNull { static constexpr auto name = "toUInt16OrNull"; };
@ -1797,6 +1810,7 @@ struct NameToDecimal32OrNull { static constexpr auto name = "toDecimal32OrNull";
struct NameToDecimal64OrNull { static constexpr auto name = "toDecimal64OrNull"; };
struct NameToDecimal128OrNull { static constexpr auto name = "toDecimal128OrNull"; };
struct NameToDecimal256OrNull { static constexpr auto name = "toDecimal256OrNull"; };
struct NameToUUIDOrNull { static constexpr auto name = "toUUIDOrNull"; };
using FunctionToUInt8OrNull = FunctionConvertFromString<DataTypeUInt8, NameToUInt8OrNull, ConvertFromStringExceptionMode::Null>;
using FunctionToUInt16OrNull = FunctionConvertFromString<DataTypeUInt16, NameToUInt16OrNull, ConvertFromStringExceptionMode::Null>;
@ -1818,6 +1832,7 @@ using FunctionToDecimal32OrNull = FunctionConvertFromString<DataTypeDecimal<Deci
using FunctionToDecimal64OrNull = FunctionConvertFromString<DataTypeDecimal<Decimal64>, NameToDecimal64OrNull, ConvertFromStringExceptionMode::Null>;
using FunctionToDecimal128OrNull = FunctionConvertFromString<DataTypeDecimal<Decimal128>, NameToDecimal128OrNull, ConvertFromStringExceptionMode::Null>;
using FunctionToDecimal256OrNull = FunctionConvertFromString<DataTypeDecimal<Decimal256>, NameToDecimal256OrNull, ConvertFromStringExceptionMode::Null>;
using FunctionToUUIDOrNull = FunctionConvertFromString<DataTypeUUID, NameToUUIDOrNull, ConvertFromStringExceptionMode::Null>;
struct NameParseDateTimeBestEffort { static constexpr auto name = "parseDateTimeBestEffort"; };
struct NameParseDateTimeBestEffortUS { static constexpr auto name = "parseDateTimeBestEffortUS"; };

View File

@ -619,9 +619,11 @@ inline bool tryReadDateText(DayNum & date, ReadBuffer & buf)
return readDateTextImpl<bool>(date, buf);
}
inline void readUUIDText(UUID & uuid, ReadBuffer & buf)
template <typename ReturnType = void>
inline ReturnType readUUIDTextImpl(UUID & uuid, ReadBuffer & buf)
{
static constexpr bool throw_exception = std::is_same_v<ReturnType, void>;
char s[36];
size_t size = buf.read(s, 32);
@ -634,21 +636,49 @@ inline void readUUIDText(UUID & uuid, ReadBuffer & buf)
if (size != 36)
{
s[size] = 0;
throw Exception(std::string("Cannot parse uuid ") + s, ErrorCodes::CANNOT_PARSE_UUID);
if constexpr (throw_exception)
{
throw Exception(std::string("Cannot parse uuid ") + s, ErrorCodes::CANNOT_PARSE_UUID);
}
else
{
return ReturnType(false);
}
}
parseUUID(reinterpret_cast<const UInt8 *>(s), std::reverse_iterator<UInt8 *>(reinterpret_cast<UInt8 *>(&uuid) + 16));
}
else
parseUUIDWithoutSeparator(reinterpret_cast<const UInt8 *>(s), std::reverse_iterator<UInt8 *>(reinterpret_cast<UInt8 *>(&uuid) + 16));
return ReturnType(true);
}
else
{
s[size] = 0;
throw Exception(std::string("Cannot parse uuid ") + s, ErrorCodes::CANNOT_PARSE_UUID);
if constexpr (throw_exception)
{
throw Exception(std::string("Cannot parse uuid ") + s, ErrorCodes::CANNOT_PARSE_UUID);
}
else
{
return ReturnType(false);
}
}
}
inline void readUUIDText(UUID & uuid, ReadBuffer & buf)
{
return readUUIDTextImpl<void>(uuid, buf);
}
inline bool tryReadUUIDText(UUID & uuid, ReadBuffer & buf)
{
return readUUIDTextImpl<bool>(uuid, buf);
}
template <typename T>
inline T parse(const char * data, size_t size);

View File

@ -0,0 +1,8 @@
61f0c404-5cb3-11e7-907b-a6006ad3dba0
\N
00000000-0000-0000-0000-000000000000
61f0c404-5cb3-11e7-907b-a6006ad3dba0
61f0c404-5cb3-11e7-907b-a6006ad3dba0
\N
61f0c404-5cb3-11e7-907b-a6006ad3dba0
00000000-0000-0000-0000-000000000000

View File

@ -0,0 +1,19 @@
DROP TABLE IF EXISTS to_uuid_test;
SELECT toUUID('61f0c404-5cb3-11e7-907b-a6006ad3dba0');
SELECT toUUID('61f0c404-5cb3-11e7-907b-a6006ad3dba0T'); --{serverError 6}
SELECT toUUIDOrNull('61f0c404-5cb3-11e7-907b-a6006ad3dba0T');
SELECT toUUIDOrZero('59f0c404-5cb3-11e7-907b-a6006ad3dba0T');
CREATE TABLE to_uuid_test (value String) ENGINE = TinyLog();
INSERT INTO to_uuid_test VALUES ('61f0c404-5cb3-11e7-907b-a6006ad3dba0');
SELECT toUUID(value) FROM to_uuid_test;
INSERT INTO to_uuid_test VALUES ('61f0c404-5cb3-11e7-907b-a6006ad3dba0T');
SELECT toUUID(value) FROM to_uuid_test; -- {serverError 6}
SELECT toUUIDOrNull(value) FROM to_uuid_test;
SELECT toUUIDOrZero(value) FROM to_uuid_test;
DROP TABLE to_uuid_test;