Merge pull request #55211 from Priyansh121096/master

Add function byteSwap
This commit is contained in:
Robert Schulze 2023-10-13 16:54:28 +02:00 committed by GitHub
commit d02a718076
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 222 additions and 0 deletions

View File

@ -441,3 +441,40 @@ DB::Exception: Decimal result's scale is less than argument's one: While process
│ -12 │ 2.1 │ -5.7 │ -5.71428 │
└─────┴─────┴────────────────────────────────────────────────────────────┴────────────────────────────────────────────────────────────┘
```
## byteSwap
Reverses the bytes of an integer, i.e. changes its [endianness](https://en.wikipedia.org/wiki/Endianness). Currently, integers of up to 64 bit are supported.
**Syntax**
```sql
byteSwap(a)
```
**Example**
```sql
byteSwap(3351772109)
```
Result:
```result
┌─byteSwap(3351772109)─┐
│ 3455829959 │
└──────────────────────┘
```
The above example can be worked out in the following manner:
1. Convert the base-10 integer to its equivalent hexadecimal format in big-endian format, i.e. 3351772109 -> C7 C7 FB CD (4 bytes)
2. Reverse the bytes, i.e. C7 C7 FB CD -> CD FB C7 C7
3. Convert the result back to an integer assuming big-endian, i.e. CD FB C7 C7 -> 3455829959
One use case of this function is reversing IPv4s:
```result
┌─toIPv4(byteSwap(toUInt32(toIPv4('205.251.199.199'))))─┐
│ 199.199.251.205 │
└───────────────────────────────────────────────────────┘
```

View File

@ -0,0 +1,97 @@
#include <Functions/FunctionFactory.h>
#include <Functions/FunctionUnaryArithmetic.h>
namespace DB
{
namespace ErrorCodes
{
extern const int NOT_IMPLEMENTED;
}
namespace
{
template <typename T>
requires std::is_integral_v<T>
T byteSwap(T x)
{
return std::byteswap(x);
}
template <typename T>
T byteSwap(T)
{
throw Exception(ErrorCodes::NOT_IMPLEMENTED, "byteSwap() is not implemented for {} datatype", demangle(typeid(T).name()));
}
template <typename T>
struct ByteSwapImpl
{
using ResultType = T;
static constexpr const bool allow_string_or_fixed_string = false;
static T apply(T x) { return byteSwap<T>(x); }
#if USE_EMBEDDED_COMPILER
static constexpr bool compilable = false;
#endif
};
struct NameByteSwap
{
static constexpr auto name = "byteSwap";
};
using FunctionByteSwap = FunctionUnaryArithmetic<ByteSwapImpl, NameByteSwap, true>;
}
template <>
struct FunctionUnaryArithmeticMonotonicity<NameByteSwap>
{
static bool has() { return false; }
static IFunction::Monotonicity get(const Field &, const Field &) { return {}; }
};
REGISTER_FUNCTION(ByteSwap)
{
factory.registerFunction<FunctionByteSwap>(
FunctionDocumentation{
.description = R"(
Reverses the bytes of an integer, i.e. changes its [endianness](https://en.wikipedia.org/wiki/Endianness). Currently, integers of up to 64 bit are supported.
**Example**
```sql
byteSwap(3351772109)
```
Result:
```result
byteSwap(3351772109)
3455829959
```
The above example can be worked out in the following manner:
1. Convert the base-10 integer to its equivalent hexadecimal format in big-endian format, i.e. 3351772109 -> C7 C7 FB CD (4 bytes)
2. Reverse the bytes, i.e. C7 C7 FB CD -> CD FB C7 C7
3. Convert the result back to an integer assuming big-endian, i.e. CD FB C7 C7 -> 3455829959
One use-case of this function is reversing IPv4s:
```result
toIPv4(byteSwap(toUInt32(toIPv4('205.251.199.199'))))
199.199.251.205
```
)",
.examples{
{"8-bit", "SELECT byteSwap(54)", "54"},
{"16-bit", "SELECT byteSwap(4135)", "10000"},
{"32-bit", "SELECT byteSwap(3351772109)", "3455829959"},
{"64-bit", "SELECT byteSwap(123294967295)", "18439412204227788800"},
},
.categories{"Mathematical", "Arithmetic"}},
FunctionFactory::CaseInsensitive);
}
}

View File

@ -0,0 +1,29 @@
0
1
255
1
10000
4135
65535
256
3455829959
3351772109
4294967295
16777216
18439412204227788800
123294967295
18446744073709551615
0
-1
-128
32767
-9745
128
-8388609
855914552
128
-549755813889
4039370097989451775
128
0
1

View File

@ -0,0 +1,57 @@
SELECT byteSwap(0::UInt8);
SELECT byteSwap(1::UInt8);
SELECT byteSwap(255::UInt8);
SELECT byteSwap(256::UInt16);
SELECT byteSwap(4135::UInt16);
SELECT byteSwap(10000::UInt16);
SELECT byteSwap(65535::UInt16);
SELECT byteSwap(65536::UInt32);
SELECT byteSwap(3351772109::UInt32);
SELECT byteSwap(3455829959::UInt32);
SELECT byteSwap(4294967295::UInt32);
SELECT byteSwap(4294967296::UInt64);
SELECT byteSwap(123294967295::UInt64);
SELECT byteSwap(18439412204227788800::UInt64);
SELECT byteSwap(18446744073709551615::UInt64);
SELECT byteSwap(-0::Int8);
SELECT byteSwap(-1::Int8);
SELECT byteSwap(-128::Int8);
SELECT byteSwap(-129::Int16);
SELECT byteSwap(-4135::Int16);
SELECT byteSwap(-32768::Int16);
SELECT byteSwap(-32769::Int32);
SELECT byteSwap(-3351772109::Int32);
SELECT byteSwap(-2147483648::Int32);
SELECT byteSwap(-2147483649::Int64);
SELECT byteSwap(-1242525266376::Int64);
SELECT byteSwap(-9223372036854775808::Int64);
-- Booleans are interpreted as UInt8
SELECT byteSwap(false);
SELECT byteSwap(true);
-- Number of arguments should equal 1
SELECT byteSwap(); -- { serverError NUMBER_OF_ARGUMENTS_DOESNT_MATCH }
SELECT byteSwap(128, 129); -- { serverError NUMBER_OF_ARGUMENTS_DOESNT_MATCH }
-- Input should be integral
SELECT byteSwap('abc'); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT }
SELECT byteSwap(toFixedString('abc', 3)); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT }
SELECT byteSwap(toDate('2019-01-01')); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT }
SELECT byteSwap(toDate32('2019-01-01')); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT }
SELECT byteSwap(toDateTime32(1546300800)); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT }
SELECT byteSwap(toDateTime64(1546300800, 3)); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT }
SELECT byteSwap(generateUUIDv4()); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT }
SELECT byteSwap(toDecimal32(2, 4)); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT }
SELECT byteSwap(toFloat32(123.456)); -- { serverError NOT_IMPLEMENTED }
SELECT byteSwap(toFloat64(123.456)); -- { serverError NOT_IMPLEMENTED }
SELECT byteSwap(18446744073709551616::UInt128); -- { serverError NOT_IMPLEMENTED }
SELECT byteSwap(-9223372036854775809::Int128); -- { serverError NOT_IMPLEMENTED }

View File

@ -1178,6 +1178,7 @@ buildId
buildable
builtins
byteSize
byteSwap
bytebase
bytesToCutForIPv
editDistance
@ -1421,6 +1422,7 @@ encodeXMLComponent
encodings
encryptions
endian
endianness
endsWith
endsWithUTF
enum