From 85b708b906c1325f7f4b722c26185d93c68dbed9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rgen=20Edelbo?= Date: Tue, 21 May 2024 15:27:43 +0200 Subject: [PATCH] Don't throw immediately when convertion of string to number fails The parser will throw later anyway if the comparison cannot be done. --- CHANGELOG.md | 1 + src/realm/parser/driver.cpp | 51 ++++++++++++------------------------- test/test_parser.cpp | 4 +-- 3 files changed, 19 insertions(+), 37 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ef9a963368..a7ab7a8fc54 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ ### Fixed * A non-streaming progress notifier would not immediately call its callback after registration. Instead you would have to wait for a download message to be received to get your first update - if you were already caught up when you registered the notifier you could end up waiting a long time for the server to deliver a download that would call/expire your notifier ([#7627](https://github.com/realm/realm-core/issues/7627), since v14.6.0). +* Comparing a numeric property with an argument list containing a string would throw. ([#7714](https://github.com/realm/realm-core/issues/7714), since v14.7.0) ### Breaking changes * None. diff --git a/src/realm/parser/driver.cpp b/src/realm/parser/driver.cpp index 82162373124..aa37e6c1001 100644 --- a/src/realm/parser/driver.cpp +++ b/src/realm/parser/driver.cpp @@ -127,34 +127,7 @@ inline bool try_parse_specials(std::string str, T& ret) } template -inline const char* get_type_name() -{ - return "unknown"; -} -template <> -inline const char* get_type_name() -{ - return "number"; -} -template <> -inline const char* get_type_name() -{ - return "floating point number"; -} -template <> -inline const char* get_type_name() -{ - return "floating point number"; -} - -template <> -inline const char* get_type_name() -{ - return "decimal number"; -} - -template -inline T string_to(const std::string& s) +inline std::optional string_to(const std::string& s) { std::istringstream iss(s); iss.imbue(std::locale::classic()); @@ -162,18 +135,18 @@ inline T string_to(const std::string& s) iss >> value; if (iss.fail()) { if (!try_parse_specials(s, value)) { - throw InvalidQueryArgError(util::format("Cannot convert '%1' to a %2", s, get_type_name())); + return {}; } } return value; } template <> -inline Decimal128 string_to(const std::string& s) +inline std::optional string_to(const std::string& s) { Decimal128 value(s); if (value.is_nan()) { - throw InvalidQueryArgError(util::format("Cannot convert '%1' to a %2", s, get_type_name())); + return {}; } return value; } @@ -1391,16 +1364,24 @@ std::unique_ptr ConstantNode::visit(ParserDriver* drv, DataType hint) StringData str = value.get_string(); switch (hint) { case type_Int: - value = string_to(str); + if (auto val = string_to(str)) { + value = *val; + } break; case type_Float: - value = string_to(str); + if (auto val = string_to(str)) { + value = *val; + } break; case type_Double: - value = string_to(str); + if (auto val = string_to(str)) { + value = *val; + } break; case type_Decimal: - value = string_to(str); + if (auto val = string_to(str)) { + value = *val; + } break; default: break; diff --git a/test/test_parser.cpp b/test/test_parser.cpp index 3cd3a26c688..233cfd2f88d 100644 --- a/test/test_parser.cpp +++ b/test/test_parser.cpp @@ -2266,7 +2266,7 @@ TEST(Parser_list_of_primitive_ints) message, "Unsupported comparison operator 'endswith' against type 'int', right side must be a string or binary type"); CHECK_THROW_ANY_GET_MESSAGE(verify_query(test_context, t, "integers == 'string'", 0), message); - CHECK_EQUAL(message, "Cannot convert 'string' to a number"); + CHECK_EQUAL(message, "Unsupported comparison between type 'int' and type 'string'"); } TEST_TYPES(Parser_list_of_primitive_strings, std::true_type, std::false_type) @@ -3346,7 +3346,7 @@ TEST(Parser_BacklinkCount) std::string message; // backlink count requires comparison to a numeric type CHECK_THROW_ANY_GET_MESSAGE(verify_query(test_context, items, "@links.@count == 'string'", -1), message); - CHECK_EQUAL(message, "Cannot convert 'string' to a number"); + CHECK_EQUAL(message, "Unsupported comparison between type 'int' and type 'string'"); CHECK_THROW_ANY_GET_MESSAGE(verify_query(test_context, items, "@links.@count == 2018-04-09@14:21:0", -1), message); CHECK_EQUAL(message, "Unsupported comparison between type 'int' and type 'timestamp'");