UUID safe cast functions added

1. Added readUUIDTextImpl, readUUIDText, tryReadUUIDText functions in
ReadHelpers.
2. Added toUUIDOrNull, toUUIDOrZero functions based on ReadHelpers read
implementations.
3. Updated documentation.
This commit is contained in:
Maksim Kita 2020-10-25 11:45:29 +03:00
parent 6dc5cb166f
commit 440ae2bc57
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

@ -568,7 +568,7 @@ template <>
inline void parseImpl<DataTypeUUID>(DataTypeUUID::FieldType & x, ReadBuffer & rb, const DateLUTImpl *)
{
UUID tmp;
readText(tmp, rb);
readUUIDText(tmp, rb);
x = tmp;
}
@ -602,6 +602,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.
*/
@ -1754,6 +1765,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>;
@ -1775,6 +1787,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"; };
@ -1796,6 +1809,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>;
@ -1817,6 +1831,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,19 +636,47 @@ inline void readUUIDText(UUID & uuid, ReadBuffer & buf)
if (size != 36)
{
s[size] = 0;
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;
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);
}

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;