diff --git a/velox/exec/fuzzer/PrestoQueryRunner.cpp b/velox/exec/fuzzer/PrestoQueryRunner.cpp index c8bba9cdb64d..d30a315db4d2 100644 --- a/velox/exec/fuzzer/PrestoQueryRunner.cpp +++ b/velox/exec/fuzzer/PrestoQueryRunner.cpp @@ -33,6 +33,7 @@ #include "velox/functions/prestosql/types/IPAddressType.h" #include "velox/functions/prestosql/types/IPPrefixType.h" #include "velox/functions/prestosql/types/JsonType.h" +#include "velox/functions/prestosql/types/UuidType.h" #include "velox/serializers/PrestoSerializer.h" #include "velox/type/parser/TypeParser.h" @@ -426,18 +427,19 @@ bool PrestoQueryRunner::isConstantExprSupported( const core::TypedExprPtr& expr) { if (std::dynamic_pointer_cast(expr)) { // TODO: support constant literals of these types. Complex-typed constant - // literals require support of converting them to SQL. Json, Ipaddress, and - // Ipprefix can be enabled after we're able to generate valid input values, - // because when these types are used as the type of a constant literal in - // SQL, Presto implicitly invoke json_parse(), cast(x as Ipaddress), and - // cast(x as Ipprefix) on it, which makes the behavior of Presto different - // from Velox. Timestamp constant literals require further investigation to - // ensure Presto uses the same timezone as Velox. Interval type cannot be - // used as the type of constant literals in Presto SQL. + // literals require support of converting them to SQL. Json, Ipaddress, + // Ipprefix, and Uuid can be enabled after we're able to generate valid + // input values, because when these types are used as the type of a constant + // literal in SQL, Presto implicitly invokes json_parse(), + // cast(x as Ipaddress), cast(x as Ipprefix) and cast(x as uuid) on it, + // which makes the behavior of Presto different from Velox. Timestamp + // constant literals require further investigation to ensure Presto uses the + // same timezone as Velox. Interval type cannot be used as the type of + // constant literals in Presto SQL. auto& type = expr->type(); return type->isPrimitiveType() && !type->isTimestamp() && !isJsonType(type) && !type->isIntervalDayTime() && - !isIPAddressType(type) && !isIPPrefixType(type); + !isIPAddressType(type) && !isIPPrefixType(type) && !isUuidType(type); } return true; } @@ -448,16 +450,17 @@ bool PrestoQueryRunner::isSupported(const exec::FunctionSignature& signature) { // cast-to or constant literals. Hyperloglog can only be casted from varbinary // and cannot be used as the type of constant literals. Interval year to month // can only be casted from NULL and cannot be used as the type of constant - // literals. Json, Ipaddress, and Ipprefix require special handling, because - // Presto requires literals of these types to be valid, and doesn't allow - // creating HIVE columns of these types. + // literals. Json, Ipaddress, Ipprefix, and UUID require special handling, + // because Presto requires literals of these types to be valid, and doesn't + // allow creating HIVE columns of these types. return !( usesTypeName(signature, "interval year to month") || usesTypeName(signature, "hugeint") || usesTypeName(signature, "hyperloglog") || usesInputTypeName(signature, "json") || usesInputTypeName(signature, "ipaddress") || - usesInputTypeName(signature, "ipprefix")); + usesInputTypeName(signature, "ipprefix") || + usesInputTypeName(signature, "uuid")); } std::optional PrestoQueryRunner::toSql( diff --git a/velox/functions/prestosql/UuidFunctions.h b/velox/functions/prestosql/UuidFunctions.h index 9e4b319a7fff..4da630e986f2 100644 --- a/velox/functions/prestosql/UuidFunctions.h +++ b/velox/functions/prestosql/UuidFunctions.h @@ -20,10 +20,29 @@ #include "velox/functions/Macros.h" #include "velox/functions/Registerer.h" +#include "velox/functions/prestosql/Comparisons.h" #include "velox/functions/prestosql/types/UuidType.h" namespace facebook::velox::functions { +#define VELOX_GEN_BINARY_EXPR_UUID(Name, uuidCompExpr) \ + template \ + struct Name##Uuid { \ + VELOX_DEFINE_FUNCTION_TYPES(T); \ + \ + FOLLY_ALWAYS_INLINE void \ + call(bool& result, const arg_type& lhs, const arg_type& rhs) { \ + result = (uuidCompExpr); \ + } \ + }; + +VELOX_GEN_BINARY_EXPR_UUID(LtFunction, (uint128_t)lhs < (uint128_t)rhs); +VELOX_GEN_BINARY_EXPR_UUID(GtFunction, (uint128_t)lhs > (uint128_t)rhs); +VELOX_GEN_BINARY_EXPR_UUID(LteFunction, (uint128_t)lhs <= (uint128_t)rhs); +VELOX_GEN_BINARY_EXPR_UUID(GteFunction, (uint128_t)lhs >= (uint128_t)rhs); + +#undef VELOX_GEN_BINARY_EXPR_UUID + template struct UuidFunction { VELOX_DEFINE_FUNCTION_TYPES(T); @@ -42,6 +61,10 @@ struct UuidFunction { inline void registerUuidFunctions(const std::string& prefix) { registerUuidType(); registerFunction({prefix + "uuid"}); + registerFunction({prefix + "lt"}); + registerFunction({prefix + "gt"}); + registerFunction({prefix + "lte"}); + registerFunction({prefix + "gte"}); } } // namespace facebook::velox::functions diff --git a/velox/functions/prestosql/tests/UuidFunctionsTest.cpp b/velox/functions/prestosql/tests/UuidFunctionsTest.cpp index 4fc636d966f3..6afbe2b82747 100644 --- a/velox/functions/prestosql/tests/UuidFunctionsTest.cpp +++ b/velox/functions/prestosql/tests/UuidFunctionsTest.cpp @@ -108,5 +108,119 @@ TEST_F(UuidFunctionsTest, unsupportedCast) { evaluate("cast(123 as uuid())", input), "Cannot cast BIGINT to UUID."); } +TEST_F(UuidFunctionsTest, comparisons) { + const auto uuidEval = [&](const std::optional& lhs, + const std::string& operation, + const std::optional& rhs) { + return evaluateOnce( + fmt::format("cast(c0 as uuid) {} cast(c1 as uuid)", operation), + lhs, + rhs); + }; + + ASSERT_EQ( + true, + uuidEval( + "33355449-2c7d-43d7-967a-f53cd23215ad", + "<", + "ffffffff-ffff-ffff-ffff-ffffffffffff")); + ASSERT_EQ( + false, + uuidEval( + "33355449-2c7d-43d7-967a-f53cd23215ad", + "<", + "00000000-0000-0000-0000-000000000000")); + ASSERT_EQ( + true, + uuidEval( + "f768f36d-4f09-4da7-a298-3564d8f3c986", + ">", + "00000000-0000-0000-0000-000000000000")); + ASSERT_EQ( + false, + uuidEval( + "f768f36d-4f09-4da7-a298-3564d8f3c986", + ">", + "ffffffff-ffff-ffff-ffff-ffffffffffff")); + + ASSERT_EQ( + true, + uuidEval( + "33355449-2c7d-43d7-967a-f53cd23215ad", + "<=", + "33355449-2c7d-43d7-967a-f53cd23215ad")); + ASSERT_EQ( + true, + uuidEval( + "33355449-2c7d-43d7-967a-f53cd23215ad", + "<=", + "ffffffff-ffff-ffff-ffff-ffffffffffff")); + ASSERT_EQ( + true, + uuidEval( + "33355449-2c7d-43d7-967a-f53cd23215ad", + ">=", + "33355449-2c7d-43d7-967a-f53cd23215ad")); + ASSERT_EQ( + true, + uuidEval( + "ffffffff-ffff-ffff-ffff-ffffffffffff", + ">=", + "33355449-2c7d-43d7-967a-f53cd23215ad")); + + ASSERT_EQ( + true, + uuidEval( + "f768f36d-4f09-4da7-a298-3564d8f3c986", + "==", + "f768f36d-4f09-4da7-a298-3564d8f3c986")); + ASSERT_EQ( + true, + uuidEval( + "eed9f812-4b0c-472f-8a10-4ae7bff79a47", + "!=", + "f768f36d-4f09-4da7-a298-3564d8f3c986")); + + ASSERT_EQ( + true, + uuidEval( + "11000000-0000-0022-0000-000000000000", + "<", + "22000000-0000-0011-0000-000000000000")); + ASSERT_EQ( + true, + uuidEval( + "00000000-0000-0000-2200-000000000011", + ">", + "00000000-0000-0000-1100-000000000022")); + ASSERT_EQ( + false, + uuidEval( + "00000000-0000-0000-0000-000000000011", + ">", + "22000000-0000-0000-0000-000000000000")); + ASSERT_EQ( + false, + uuidEval( + "11000000-0000-0000-0000-000000000000", + "<", + "00000000-0000-0000-0000-000000000022")); + + std::string lhs = "12342345-3456-4567-5678-678978908901"; + std::string rhs = "23451234-4567-3456-6789-567889017890"; + ASSERT_EQ(true, uuidEval(lhs, "<", rhs)); + + for (vector_size_t i = 0; i < lhs.size(); i++) { + if (lhs[i] == '-') { + continue; + } + lhs[i] = '0'; + rhs[i] = '0'; + bool expected = boost::lexical_cast(lhs) < + boost::lexical_cast(rhs); + ASSERT_EQ(expected, uuidEval(lhs, "<", rhs)); + } +} + } // namespace } // namespace facebook::velox::functions::prestosql