mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-21 15:12:02 +00:00
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:
parent
6dc5cb166f
commit
440ae2bc57
@ -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}
|
## 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).
|
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).
|
||||||
|
@ -68,6 +68,8 @@ void registerFunctionsConversion(FunctionFactory & factory)
|
|||||||
factory.registerFunction<FunctionToDecimal128OrZero>();
|
factory.registerFunction<FunctionToDecimal128OrZero>();
|
||||||
factory.registerFunction<FunctionToDecimal256OrZero>();
|
factory.registerFunction<FunctionToDecimal256OrZero>();
|
||||||
|
|
||||||
|
factory.registerFunction<FunctionToUUIDOrZero>();
|
||||||
|
|
||||||
factory.registerFunction<FunctionToUInt8OrNull>();
|
factory.registerFunction<FunctionToUInt8OrNull>();
|
||||||
factory.registerFunction<FunctionToUInt16OrNull>();
|
factory.registerFunction<FunctionToUInt16OrNull>();
|
||||||
factory.registerFunction<FunctionToUInt32OrNull>();
|
factory.registerFunction<FunctionToUInt32OrNull>();
|
||||||
@ -90,6 +92,8 @@ void registerFunctionsConversion(FunctionFactory & factory)
|
|||||||
factory.registerFunction<FunctionToDecimal128OrNull>();
|
factory.registerFunction<FunctionToDecimal128OrNull>();
|
||||||
factory.registerFunction<FunctionToDecimal256OrNull>();
|
factory.registerFunction<FunctionToDecimal256OrNull>();
|
||||||
|
|
||||||
|
factory.registerFunction<FunctionToUUIDOrNull>();
|
||||||
|
|
||||||
factory.registerFunction<FunctionParseDateTimeBestEffort>();
|
factory.registerFunction<FunctionParseDateTimeBestEffort>();
|
||||||
factory.registerFunction<FunctionParseDateTimeBestEffortUS>();
|
factory.registerFunction<FunctionParseDateTimeBestEffortUS>();
|
||||||
factory.registerFunction<FunctionParseDateTimeBestEffortOrZero>();
|
factory.registerFunction<FunctionParseDateTimeBestEffortOrZero>();
|
||||||
|
@ -568,7 +568,7 @@ template <>
|
|||||||
inline void parseImpl<DataTypeUUID>(DataTypeUUID::FieldType & x, ReadBuffer & rb, const DateLUTImpl *)
|
inline void parseImpl<DataTypeUUID>(DataTypeUUID::FieldType & x, ReadBuffer & rb, const DateLUTImpl *)
|
||||||
{
|
{
|
||||||
UUID tmp;
|
UUID tmp;
|
||||||
readText(tmp, rb);
|
readUUIDText(tmp, rb);
|
||||||
x = tmp;
|
x = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -602,6 +602,17 @@ inline bool tryParseImpl<DataTypeDateTime>(DataTypeDateTime::FieldType & x, Read
|
|||||||
return true;
|
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.
|
/** 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 NameToDecimal64OrZero { static constexpr auto name = "toDecimal64OrZero"; };
|
||||||
struct NameToDecimal128OrZero { static constexpr auto name = "toDecimal128OrZero"; };
|
struct NameToDecimal128OrZero { static constexpr auto name = "toDecimal128OrZero"; };
|
||||||
struct NameToDecimal256OrZero { static constexpr auto name = "toDecimal256OrZero"; };
|
struct NameToDecimal256OrZero { static constexpr auto name = "toDecimal256OrZero"; };
|
||||||
|
struct NameToUUIDOrZero { static constexpr auto name = "toUUIDOrZero"; };
|
||||||
|
|
||||||
using FunctionToUInt8OrZero = FunctionConvertFromString<DataTypeUInt8, NameToUInt8OrZero, ConvertFromStringExceptionMode::Zero>;
|
using FunctionToUInt8OrZero = FunctionConvertFromString<DataTypeUInt8, NameToUInt8OrZero, ConvertFromStringExceptionMode::Zero>;
|
||||||
using FunctionToUInt16OrZero = FunctionConvertFromString<DataTypeUInt16, NameToUInt16OrZero, 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 FunctionToDecimal64OrZero = FunctionConvertFromString<DataTypeDecimal<Decimal64>, NameToDecimal64OrZero, ConvertFromStringExceptionMode::Zero>;
|
||||||
using FunctionToDecimal128OrZero = FunctionConvertFromString<DataTypeDecimal<Decimal128>, NameToDecimal128OrZero, ConvertFromStringExceptionMode::Zero>;
|
using FunctionToDecimal128OrZero = FunctionConvertFromString<DataTypeDecimal<Decimal128>, NameToDecimal128OrZero, ConvertFromStringExceptionMode::Zero>;
|
||||||
using FunctionToDecimal256OrZero = FunctionConvertFromString<DataTypeDecimal<Decimal256>, NameToDecimal256OrZero, 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 NameToUInt8OrNull { static constexpr auto name = "toUInt8OrNull"; };
|
||||||
struct NameToUInt16OrNull { static constexpr auto name = "toUInt16OrNull"; };
|
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 NameToDecimal64OrNull { static constexpr auto name = "toDecimal64OrNull"; };
|
||||||
struct NameToDecimal128OrNull { static constexpr auto name = "toDecimal128OrNull"; };
|
struct NameToDecimal128OrNull { static constexpr auto name = "toDecimal128OrNull"; };
|
||||||
struct NameToDecimal256OrNull { static constexpr auto name = "toDecimal256OrNull"; };
|
struct NameToDecimal256OrNull { static constexpr auto name = "toDecimal256OrNull"; };
|
||||||
|
struct NameToUUIDOrNull { static constexpr auto name = "toUUIDOrNull"; };
|
||||||
|
|
||||||
using FunctionToUInt8OrNull = FunctionConvertFromString<DataTypeUInt8, NameToUInt8OrNull, ConvertFromStringExceptionMode::Null>;
|
using FunctionToUInt8OrNull = FunctionConvertFromString<DataTypeUInt8, NameToUInt8OrNull, ConvertFromStringExceptionMode::Null>;
|
||||||
using FunctionToUInt16OrNull = FunctionConvertFromString<DataTypeUInt16, NameToUInt16OrNull, 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 FunctionToDecimal64OrNull = FunctionConvertFromString<DataTypeDecimal<Decimal64>, NameToDecimal64OrNull, ConvertFromStringExceptionMode::Null>;
|
||||||
using FunctionToDecimal128OrNull = FunctionConvertFromString<DataTypeDecimal<Decimal128>, NameToDecimal128OrNull, ConvertFromStringExceptionMode::Null>;
|
using FunctionToDecimal128OrNull = FunctionConvertFromString<DataTypeDecimal<Decimal128>, NameToDecimal128OrNull, ConvertFromStringExceptionMode::Null>;
|
||||||
using FunctionToDecimal256OrNull = FunctionConvertFromString<DataTypeDecimal<Decimal256>, NameToDecimal256OrNull, 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 NameParseDateTimeBestEffort { static constexpr auto name = "parseDateTimeBestEffort"; };
|
||||||
struct NameParseDateTimeBestEffortUS { static constexpr auto name = "parseDateTimeBestEffortUS"; };
|
struct NameParseDateTimeBestEffortUS { static constexpr auto name = "parseDateTimeBestEffortUS"; };
|
||||||
|
@ -619,9 +619,11 @@ inline bool tryReadDateText(DayNum & date, ReadBuffer & buf)
|
|||||||
return readDateTextImpl<bool>(date, buf);
|
return readDateTextImpl<bool>(date, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename ReturnType = void>
|
||||||
inline void readUUIDText(UUID & uuid, ReadBuffer & buf)
|
inline ReturnType readUUIDTextImpl(UUID & uuid, ReadBuffer & buf)
|
||||||
{
|
{
|
||||||
|
static constexpr bool throw_exception = std::is_same_v<ReturnType, void>;
|
||||||
|
|
||||||
char s[36];
|
char s[36];
|
||||||
size_t size = buf.read(s, 32);
|
size_t size = buf.read(s, 32);
|
||||||
|
|
||||||
@ -634,21 +636,49 @@ inline void readUUIDText(UUID & uuid, ReadBuffer & buf)
|
|||||||
if (size != 36)
|
if (size != 36)
|
||||||
{
|
{
|
||||||
s[size] = 0;
|
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));
|
parseUUID(reinterpret_cast<const UInt8 *>(s), std::reverse_iterator<UInt8 *>(reinterpret_cast<UInt8 *>(&uuid) + 16));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
parseUUIDWithoutSeparator(reinterpret_cast<const UInt8 *>(s), std::reverse_iterator<UInt8 *>(reinterpret_cast<UInt8 *>(&uuid) + 16));
|
parseUUIDWithoutSeparator(reinterpret_cast<const UInt8 *>(s), std::reverse_iterator<UInt8 *>(reinterpret_cast<UInt8 *>(&uuid) + 16));
|
||||||
|
|
||||||
|
return ReturnType(true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
s[size] = 0;
|
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>
|
template <typename T>
|
||||||
inline T parse(const char * data, size_t size);
|
inline T parse(const char * data, size_t size);
|
||||||
|
@ -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
|
19
tests/queries/0_stateless/01528_to_uuid_or_null_or_zero.sql
Normal file
19
tests/queries/0_stateless/01528_to_uuid_or_null_or_zero.sql
Normal 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;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user