diff --git a/CHANGELOG.md b/CHANGELOG.md index ecae72cdfff..80821cf0052 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ ### Fixed * ([#????](https://github.com/realm/realm-core/issues/????), since v?.?.?) +* Allow numeric substitutions into a geospatial query. Example `location GEOWITHIN geoCircle([$0, $1], $2)`. ([#6662](https://github.com/realm/realm-core/issues/6662)) * Access token refresh for websockets was not updating the location metadata ([#6630](https://github.com/realm/realm-core/issues/6630), since v13.9.3) * Fix several UBSan failures which did not appear to result in functional bugs ([#6649](https://github.com/realm/realm-core/pull/6649)). * Fix an out-of-bounds read in sectioned results when sectioned are removed by modifying all objects in that section to no longer appear in that section ([#6649](https://github.com/realm/realm-core/pull/6649), since v13.12.0) diff --git a/src/realm/parser/driver.cpp b/src/realm/parser/driver.cpp index d9f203b0cda..f1b75b4d3a8 100644 --- a/src/realm/parser/driver.cpp +++ b/src/realm/parser/driver.cpp @@ -1575,7 +1575,7 @@ ParserDriver::~ParserDriver() yylex_destroy(m_yyscanner); } -Mixed ParserDriver::get_arg_for_index(std::string i) +Mixed ParserDriver::get_arg_for_index(const std::string& i) { REALM_ASSERT(i[0] == '$'); size_t arg_no = size_t(strtol(i.substr(1).c_str(), nullptr, 10)); @@ -1586,15 +1586,38 @@ Mixed ParserDriver::get_arg_for_index(std::string i) switch (type) { case type_Int: return int64_t(m_args.long_for_argument(arg_no)); - break; case type_String: return m_args.string_for_argument(arg_no); - break; default: throw InvalidQueryError("Invalid index type"); } } +double ParserDriver::get_arg_for_coordinate(const std::string& str) +{ + REALM_ASSERT(str[0] == '$'); + size_t arg_no = size_t(strtol(str.substr(1).c_str(), nullptr, 10)); + if (m_args.is_argument_null(arg_no)) { + throw InvalidQueryError(util::format("NULL cannot be used in coordinate at argument '%1'", str)); + } + if (m_args.is_argument_list(arg_no)) { + throw InvalidQueryError(util::format("A list cannot be used in a coordinate at argument '%1'", str)); + } + + auto type = m_args.type_for_argument(arg_no); + switch (type) { + case type_Int: + return double(m_args.long_for_argument(arg_no)); + case type_Double: + return m_args.double_for_argument(arg_no); + case type_Float: + return double(m_args.float_for_argument(arg_no)); + default: + throw InvalidQueryError(util::format("Invalid parameter '%1' used in coordinate at argument '%2'", + get_data_type_name(type), str)); + } +} + auto ParserDriver::cmp(const std::vector& values) -> std::pair { SubexprPtr left; diff --git a/src/realm/parser/driver.hpp b/src/realm/parser/driver.hpp index e540260e9f5..5a7828452ca 100644 --- a/src/realm/parser/driver.hpp +++ b/src/realm/parser/driver.hpp @@ -623,7 +623,8 @@ class ParserDriver { parse_error = true; } - Mixed get_arg_for_index(std::string); + Mixed get_arg_for_index(const std::string&); + double get_arg_for_coordinate(const std::string&); template Query simple_query(int op, ColKey col_key, T val, bool case_sensitive); diff --git a/src/realm/parser/generated/query_bison.cpp b/src/realm/parser/generated/query_bison.cpp index 0d1a77eb1a6..68d82c85e36 100644 --- a/src/realm/parser/generated/query_bison.cpp +++ b/src/realm/parser/generated/query_bison.cpp @@ -1728,171 +1728,175 @@ namespace yy { { yylhs.value.as < double > () = double(strtoll(yystack_[0].value.as < std::string > ().c_str(), nullptr, 0)); } break; - case 37: // geopoint: '[' coordinate ',' coordinate ']' + case 37: // coordinate: "argument" + { yylhs.value.as < double > () = drv.get_arg_for_coordinate(yystack_[0].value.as < std::string > ()); } + break; + + case 38: // geopoint: '[' coordinate ',' coordinate ']' { yylhs.value.as < std::optional > () = GeoPoint{yystack_[3].value.as < double > (), yystack_[1].value.as < double > ()}; } break; - case 38: // geopoint: '[' coordinate ',' coordinate ',' "float" ']' + case 39: // geopoint: '[' coordinate ',' coordinate ',' "float" ']' { yylhs.value.as < std::optional > () = GeoPoint{yystack_[5].value.as < double > (), yystack_[3].value.as < double > (), strtod(yystack_[1].value.as < std::string > ().c_str(), nullptr)}; } break; - case 39: // geoloop_content: geopoint + case 40: // geoloop_content: geopoint { yylhs.value.as < GeospatialNode* > () = drv.m_parse_nodes.create(GeospatialNode::Loop{}, *yystack_[0].value.as < std::optional > ()); } break; - case 40: // geoloop_content: geoloop_content ',' geopoint + case 41: // geoloop_content: geoloop_content ',' geopoint { yystack_[2].value.as < GeospatialNode* > ()->add_point_to_loop(*yystack_[0].value.as < std::optional > ()); yylhs.value.as < GeospatialNode* > () = yystack_[2].value.as < GeospatialNode* > (); } break; - case 41: // geoloop: '{' geoloop_content '}' + case 42: // geoloop: '{' geoloop_content '}' { yylhs.value.as < GeospatialNode* > () = yystack_[1].value.as < GeospatialNode* > (); } break; - case 42: // geopoly_content: geoloop + case 43: // geopoly_content: geoloop { yylhs.value.as < GeospatialNode* > () = yystack_[0].value.as < GeospatialNode* > (); } break; - case 43: // geopoly_content: geopoly_content ',' geoloop + case 44: // geopoly_content: geopoly_content ',' geoloop { yystack_[2].value.as < GeospatialNode* > ()->add_loop_to_polygon(yystack_[0].value.as < GeospatialNode* > ()); yylhs.value.as < GeospatialNode* > () = yystack_[2].value.as < GeospatialNode* > (); } break; - case 44: // geospatial: "geobox" '(' geopoint ',' geopoint ')' + case 45: // geospatial: "geobox" '(' geopoint ',' geopoint ')' { yylhs.value.as < GeospatialNode* > () = drv.m_parse_nodes.create(GeospatialNode::Box{}, *yystack_[3].value.as < std::optional > (), *yystack_[1].value.as < std::optional > ()); } break; - case 45: // geospatial: "geocircle" '(' geopoint ',' coordinate ')' + case 46: // geospatial: "geocircle" '(' geopoint ',' coordinate ')' { yylhs.value.as < GeospatialNode* > () = drv.m_parse_nodes.create(GeospatialNode::Circle{}, *yystack_[3].value.as < std::optional > (), yystack_[1].value.as < double > ()); } break; - case 46: // geospatial: "geopolygon" '(' geopoly_content ')' + case 47: // geospatial: "geopolygon" '(' geopoly_content ')' { yylhs.value.as < GeospatialNode* > () = yystack_[1].value.as < GeospatialNode* > (); } break; - case 47: // post_query: %empty + case 48: // post_query: %empty { yylhs.value.as < DescriptorOrderingNode* > () = drv.m_parse_nodes.create();} break; - case 48: // post_query: post_query sort + case 49: // post_query: post_query sort { yystack_[1].value.as < DescriptorOrderingNode* > ()->add_descriptor(yystack_[0].value.as < DescriptorNode* > ()); yylhs.value.as < DescriptorOrderingNode* > () = yystack_[1].value.as < DescriptorOrderingNode* > (); } break; - case 49: // post_query: post_query distinct + case 50: // post_query: post_query distinct { yystack_[1].value.as < DescriptorOrderingNode* > ()->add_descriptor(yystack_[0].value.as < DescriptorNode* > ()); yylhs.value.as < DescriptorOrderingNode* > () = yystack_[1].value.as < DescriptorOrderingNode* > (); } break; - case 50: // post_query: post_query limit + case 51: // post_query: post_query limit { yystack_[1].value.as < DescriptorOrderingNode* > ()->add_descriptor(yystack_[0].value.as < DescriptorNode* > ()); yylhs.value.as < DescriptorOrderingNode* > () = yystack_[1].value.as < DescriptorOrderingNode* > (); } break; - case 51: // distinct: "distinct" '(' distinct_param ')' + case 52: // distinct: "distinct" '(' distinct_param ')' { yylhs.value.as < DescriptorNode* > () = yystack_[1].value.as < DescriptorNode* > (); } break; - case 52: // distinct_param: path + case 53: // distinct_param: path { yylhs.value.as < DescriptorNode* > () = drv.m_parse_nodes.create(DescriptorNode::DISTINCT); yylhs.value.as < DescriptorNode* > ()->add(yystack_[0].value.as < PathNode* > ());} break; - case 53: // distinct_param: distinct_param ',' path + case 54: // distinct_param: distinct_param ',' path { yystack_[2].value.as < DescriptorNode* > ()->add(yystack_[0].value.as < PathNode* > ()); yylhs.value.as < DescriptorNode* > () = yystack_[2].value.as < DescriptorNode* > (); } break; - case 54: // sort: "sort" '(' sort_param ')' + case 55: // sort: "sort" '(' sort_param ')' { yylhs.value.as < DescriptorNode* > () = yystack_[1].value.as < DescriptorNode* > (); } break; - case 55: // sort_param: path direction + case 56: // sort_param: path direction { yylhs.value.as < DescriptorNode* > () = drv.m_parse_nodes.create(DescriptorNode::SORT); yylhs.value.as < DescriptorNode* > ()->add(yystack_[1].value.as < PathNode* > (), yystack_[0].value.as < bool > ());} break; - case 56: // sort_param: sort_param ',' path direction + case 57: // sort_param: sort_param ',' path direction { yystack_[3].value.as < DescriptorNode* > ()->add(yystack_[1].value.as < PathNode* > (), yystack_[0].value.as < bool > ()); yylhs.value.as < DescriptorNode* > () = yystack_[3].value.as < DescriptorNode* > (); } break; - case 57: // limit: "limit" '(' "natural0" ')' + case 58: // limit: "limit" '(' "natural0" ')' { yylhs.value.as < DescriptorNode* > () = drv.m_parse_nodes.create(DescriptorNode::LIMIT, yystack_[1].value.as < std::string > ()); } break; - case 58: // direction: "ascending" + case 59: // direction: "ascending" { yylhs.value.as < bool > () = true; } break; - case 59: // direction: "descending" + case 60: // direction: "descending" { yylhs.value.as < bool > () = false; } break; - case 60: // list: '{' list_content '}' + case 61: // list: '{' list_content '}' { yylhs.value.as < ListNode* > () = yystack_[1].value.as < ListNode* > (); } break; - case 61: // list: comp_type '{' list_content '}' + case 62: // list: comp_type '{' list_content '}' { yystack_[1].value.as < ListNode* > ()->set_comp_type(ExpressionComparisonType(yystack_[3].value.as < int > ())); yylhs.value.as < ListNode* > () = yystack_[1].value.as < ListNode* > (); } break; - case 62: // list_content: constant + case 63: // list_content: constant { yylhs.value.as < ListNode* > () = drv.m_parse_nodes.create(yystack_[0].value.as < ConstantNode* > ()); } break; - case 63: // list_content: %empty + case 64: // list_content: %empty { yylhs.value.as < ListNode* > () = drv.m_parse_nodes.create(); } break; - case 64: // list_content: list_content ',' constant + case 65: // list_content: list_content ',' constant { yystack_[2].value.as < ListNode* > ()->add_element(yystack_[0].value.as < ConstantNode* > ()); yylhs.value.as < ListNode* > () = yystack_[2].value.as < ListNode* > (); } break; - case 65: // constant: primary_key + case 66: // constant: primary_key { yylhs.value.as < ConstantNode* > () = yystack_[0].value.as < ConstantNode* > (); } break; - case 66: // constant: "infinity" + case 67: // constant: "infinity" { yylhs.value.as < ConstantNode* > () = drv.m_parse_nodes.create(ConstantNode::INFINITY_VAL, yystack_[0].value.as < std::string > ()); } break; - case 67: // constant: "NaN" + case 68: // constant: "NaN" { yylhs.value.as < ConstantNode* > () = drv.m_parse_nodes.create(ConstantNode::NAN_VAL, yystack_[0].value.as < std::string > ()); } break; - case 68: // constant: "base64" + case 69: // constant: "base64" { yylhs.value.as < ConstantNode* > () = drv.m_parse_nodes.create(ConstantNode::BASE64, yystack_[0].value.as < std::string > ()); } break; - case 69: // constant: "float" + case 70: // constant: "float" { yylhs.value.as < ConstantNode* > () = drv.m_parse_nodes.create(ConstantNode::FLOAT, yystack_[0].value.as < std::string > ()); } break; - case 70: // constant: "date" + case 71: // constant: "date" { yylhs.value.as < ConstantNode* > () = drv.m_parse_nodes.create(ConstantNode::TIMESTAMP, yystack_[0].value.as < std::string > ()); } break; - case 71: // constant: "link" + case 72: // constant: "link" { yylhs.value.as < ConstantNode* > () = drv.m_parse_nodes.create(ConstantNode::LINK, yystack_[0].value.as < std::string > ()); } break; - case 72: // constant: "typed link" + case 73: // constant: "typed link" { yylhs.value.as < ConstantNode* > () = drv.m_parse_nodes.create(ConstantNode::TYPED_LINK, yystack_[0].value.as < std::string > ()); } break; - case 73: // constant: "true" + case 74: // constant: "true" { yylhs.value.as < ConstantNode* > () = drv.m_parse_nodes.create(ConstantNode::TRUE, ""); } break; - case 74: // constant: "false" + case 75: // constant: "false" { yylhs.value.as < ConstantNode* > () = drv.m_parse_nodes.create(ConstantNode::FALSE, ""); } break; - case 75: // constant: "null" + case 76: // constant: "null" { yylhs.value.as < ConstantNode* > () = drv.m_parse_nodes.create(ConstantNode::NULL_VAL, ""); } break; - case 76: // constant: "argument" + case 77: // constant: "argument" { yylhs.value.as < ConstantNode* > () = drv.m_parse_nodes.create(ConstantNode::ARG, yystack_[0].value.as < std::string > ()); } break; - case 77: // constant: comp_type "argument" + case 78: // constant: comp_type "argument" { yylhs.value.as < ConstantNode* > () = drv.m_parse_nodes.create(ExpressionComparisonType(yystack_[1].value.as < int > ()), yystack_[0].value.as < std::string > ()); } break; - case 78: // constant: "obj" '(' "string" ',' primary_key ')' + case 79: // constant: "obj" '(' "string" ',' primary_key ')' { auto tmp = yystack_[1].value.as < ConstantNode* > (); tmp->add_table(yystack_[3].value.as < std::string > ()); @@ -1900,199 +1904,199 @@ namespace yy { } break; - case 79: // primary_key: "natural0" + case 80: // primary_key: "natural0" { yylhs.value.as < ConstantNode* > () = drv.m_parse_nodes.create(ConstantNode::NUMBER, yystack_[0].value.as < std::string > ()); } break; - case 80: // primary_key: "number" + case 81: // primary_key: "number" { yylhs.value.as < ConstantNode* > () = drv.m_parse_nodes.create(ConstantNode::NUMBER, yystack_[0].value.as < std::string > ()); } break; - case 81: // primary_key: "string" + case 82: // primary_key: "string" { yylhs.value.as < ConstantNode* > () = drv.m_parse_nodes.create(ConstantNode::STRING, yystack_[0].value.as < std::string > ()); } break; - case 82: // primary_key: "UUID" + case 83: // primary_key: "UUID" { yylhs.value.as < ConstantNode* > () = drv.m_parse_nodes.create(ConstantNode::UUID_T, yystack_[0].value.as < std::string > ()); } break; - case 83: // primary_key: "ObjectId" + case 84: // primary_key: "ObjectId" { yylhs.value.as < ConstantNode* > () = drv.m_parse_nodes.create(ConstantNode::OID, yystack_[0].value.as < std::string > ()); } break; - case 84: // boolexpr: "truepredicate" + case 85: // boolexpr: "truepredicate" { yylhs.value.as < TrueOrFalseNode* > () = drv.m_parse_nodes.create(true); } break; - case 85: // boolexpr: "falsepredicate" + case 86: // boolexpr: "falsepredicate" { yylhs.value.as < TrueOrFalseNode* > () = drv.m_parse_nodes.create(false); } break; - case 86: // comp_type: "any" + case 87: // comp_type: "any" { yylhs.value.as < int > () = int(ExpressionComparisonType::Any); } break; - case 87: // comp_type: "all" + case 88: // comp_type: "all" { yylhs.value.as < int > () = int(ExpressionComparisonType::All); } break; - case 88: // comp_type: "none" + case 89: // comp_type: "none" { yylhs.value.as < int > () = int(ExpressionComparisonType::None); } break; - case 89: // post_op: %empty + case 90: // post_op: %empty { yylhs.value.as < PostOpNode* > () = nullptr; } break; - case 90: // post_op: '.' "@size" + case 91: // post_op: '.' "@size" { yylhs.value.as < PostOpNode* > () = drv.m_parse_nodes.create(yystack_[0].value.as < std::string > (), PostOpNode::SIZE);} break; - case 91: // post_op: '.' "@type" + case 92: // post_op: '.' "@type" { yylhs.value.as < PostOpNode* > () = drv.m_parse_nodes.create(yystack_[0].value.as < std::string > (), PostOpNode::TYPE);} break; - case 92: // aggr_op: '.' "@max" + case 93: // aggr_op: '.' "@max" { yylhs.value.as < int > () = int(AggrNode::MAX);} break; - case 93: // aggr_op: '.' "@min" + case 94: // aggr_op: '.' "@min" { yylhs.value.as < int > () = int(AggrNode::MIN);} break; - case 94: // aggr_op: '.' "@sun" + case 95: // aggr_op: '.' "@sun" { yylhs.value.as < int > () = int(AggrNode::SUM);} break; - case 95: // aggr_op: '.' "@average" + case 96: // aggr_op: '.' "@average" { yylhs.value.as < int > () = int(AggrNode::AVG);} break; - case 96: // equality: "==" + case 97: // equality: "==" { yylhs.value.as < int > () = CompareNode::EQUAL; } break; - case 97: // equality: "!=" + case 98: // equality: "!=" { yylhs.value.as < int > () = CompareNode::NOT_EQUAL; } break; - case 98: // equality: "in" + case 99: // equality: "in" { yylhs.value.as < int > () = CompareNode::IN; } break; - case 99: // relational: "<" + case 100: // relational: "<" { yylhs.value.as < int > () = CompareNode::LESS; } break; - case 100: // relational: "<=" + case 101: // relational: "<=" { yylhs.value.as < int > () = CompareNode::LESS_EQUAL; } break; - case 101: // relational: ">" + case 102: // relational: ">" { yylhs.value.as < int > () = CompareNode::GREATER; } break; - case 102: // relational: ">=" + case 103: // relational: ">=" { yylhs.value.as < int > () = CompareNode::GREATER_EQUAL; } break; - case 103: // stringop: "beginswith" + case 104: // stringop: "beginswith" { yylhs.value.as < int > () = CompareNode::BEGINSWITH; } break; - case 104: // stringop: "endswith" + case 105: // stringop: "endswith" { yylhs.value.as < int > () = CompareNode::ENDSWITH; } break; - case 105: // stringop: "contains" + case 106: // stringop: "contains" { yylhs.value.as < int > () = CompareNode::CONTAINS; } break; - case 106: // stringop: "like" + case 107: // stringop: "like" { yylhs.value.as < int > () = CompareNode::LIKE; } break; - case 107: // path: path_elem + case 108: // path: path_elem { yylhs.value.as < PathNode* > () = drv.m_parse_nodes.create(yystack_[0].value.as < PathElem > ()); } break; - case 108: // path: path '.' path_elem + case 109: // path: path '.' path_elem { yystack_[2].value.as < PathNode* > ()->add_element(yystack_[0].value.as < PathElem > ()); yylhs.value.as < PathNode* > () = yystack_[2].value.as < PathNode* > (); } break; - case 109: // path_elem: id + case 110: // path_elem: id { yylhs.value.as < PathElem > () = PathElem{yystack_[0].value.as < std::string > ()}; } break; - case 110: // path_elem: id '[' "natural0" ']' + case 111: // path_elem: id '[' "natural0" ']' { yylhs.value.as < PathElem > () = PathElem{yystack_[3].value.as < std::string > (), int64_t(strtoll(yystack_[1].value.as < std::string > ().c_str(), nullptr, 0))}; } break; - case 111: // path_elem: id '[' "string" ']' + case 112: // path_elem: id '[' "string" ']' { yylhs.value.as < PathElem > () = PathElem{yystack_[3].value.as < std::string > (), yystack_[1].value.as < std::string > ().substr(1, yystack_[1].value.as < std::string > ().size() - 2)}; } break; - case 112: // path_elem: id '[' "argument" ']' + case 113: // path_elem: id '[' "argument" ']' { yylhs.value.as < PathElem > () = PathElem{yystack_[3].value.as < std::string > (), drv.get_arg_for_index(yystack_[1].value.as < std::string > ())}; } break; - case 113: // id: "identifier" + case 114: // id: "identifier" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } break; - case 114: // id: "@links" + case 115: // id: "@links" { yylhs.value.as < std::string > () = std::string("@links"); } break; - case 115: // id: "beginswith" + case 116: // id: "beginswith" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } break; - case 116: // id: "endswith" + case 117: // id: "endswith" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } break; - case 117: // id: "contains" + case 118: // id: "contains" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } break; - case 118: // id: "like" + case 119: // id: "like" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } break; - case 119: // id: "between" + case 120: // id: "between" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } break; - case 120: // id: "key or value" + case 121: // id: "key or value" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } break; - case 121: // id: "sort" + case 122: // id: "sort" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } break; - case 122: // id: "distinct" + case 123: // id: "distinct" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } break; - case 123: // id: "limit" + case 124: // id: "limit" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } break; - case 124: // id: "ascending" + case 125: // id: "ascending" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } break; - case 125: // id: "descending" + case 126: // id: "descending" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } break; - case 126: // id: "in" + case 127: // id: "in" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } break; - case 127: // id: "fulltext" + case 128: // id: "fulltext" { yylhs.value.as < std::string > () = yystack_[0].value.as < std::string > (); } break; @@ -2444,78 +2448,78 @@ namespace yy { } - const short parser::yypact_ninf_ = -192; + const short parser::yypact_ninf_ = -193; const signed char parser::yytable_ninf_ = -1; const short parser::yypact_[] = { - 106, -192, -192, -59, -192, -192, -192, -192, -192, -192, - -192, 106, -192, -192, -192, -192, -192, -192, -192, -192, - -192, -192, -192, -192, -192, -192, -192, -192, -192, -192, - -192, -192, -192, -24, -192, -192, -192, -192, -192, -192, - 106, 428, 14, 9, -192, 234, 49, 26, -192, -192, - -192, -192, -192, -192, 372, -2, -192, 18, 495, -192, - 71, -7, 12, -56, -192, 37, -192, 106, 106, 74, - -192, -192, -192, -192, -192, -192, -192, 223, 223, 223, - 223, 167, 223, -192, -192, -192, 340, -192, 11, 284, - 63, -192, 428, 38, 453, -192, 67, 1, 89, 97, - 101, -192, -192, 428, -192, -192, 146, 111, 127, 129, - -192, -192, -192, 223, 20, -192, -192, 20, -192, -192, - 223, 126, 126, -192, -192, 124, 340, -192, 131, 153, - 160, -192, -192, -53, 474, -192, -192, -192, -192, -192, - -192, -192, -192, 495, 156, 163, 164, 495, 495, 68, - -192, 495, 495, 200, 54, 126, -192, 168, 165, 168, - -192, -192, -192, -192, -192, 181, 184, 53, -3, 65, - 97, 185, 130, 206, 168, -192, 113, 213, 106, -192, - -192, 495, -192, -192, -192, -192, 495, -192, -192, -192, - 214, 168, -192, -29, -192, 165, 130, 13, -3, 97, - 130, 186, 168, -192, -192, 219, 220, -192, 123, -192, - -192, -192, 228, 256, -192, -192, 235, -192 + 106, -193, -193, -59, -193, -193, -193, -193, -193, -193, + -193, 106, -193, -193, -193, -193, -193, -193, -193, -193, + -193, -193, -193, -193, -193, -193, -193, -193, -193, -193, + -193, -193, -193, 19, -193, -193, -193, -193, -193, -193, + 106, 428, 33, -9, -193, 234, 49, 14, -193, -193, + -193, -193, -193, -193, 372, 10, -193, 36, 495, -193, + 71, -7, 12, -33, -193, 37, -193, 106, 106, 138, + -193, -193, -193, -193, -193, -193, -193, 223, 223, 223, + 223, 167, 223, -193, -193, -193, 340, -193, 11, 284, + 63, -193, 428, 66, 453, -193, 67, 1, 89, 97, + 101, -193, -193, 428, -193, -193, 146, 129, 130, 131, + -193, -193, -193, 223, 65, -193, -193, 65, -193, -193, + 223, 126, 126, -193, -193, 105, 340, -193, 153, 160, + 161, -193, -193, -12, 474, -193, -193, -193, -193, -193, + -193, -193, -193, 495, 163, 164, 165, 495, 495, 68, + -193, 495, 495, 201, 54, 126, -193, 168, 178, 168, + -193, -193, -193, -193, -193, 182, 185, -25, -3, 53, + 97, 186, -23, 206, 168, -193, 99, 213, 106, -193, + -193, 495, -193, -193, -193, -193, 495, -193, -193, -193, + -193, 214, 168, -193, 15, -193, 178, -23, 13, -3, + 97, -23, 219, 168, -193, -193, 220, 226, -193, 111, + -193, -193, -193, 229, 267, -193, -193, 235, -193 }; - const signed char + const unsigned char parser::yydefact_[] = { - 0, 84, 85, 0, 73, 74, 75, 86, 87, 88, - 114, 0, 113, 81, 68, 66, 67, 79, 80, 69, - 70, 82, 83, 71, 72, 76, 115, 116, 117, 127, - 118, 119, 126, 0, 121, 122, 123, 124, 125, 120, - 0, 63, 0, 47, 3, 0, 18, 25, 27, 28, - 26, 24, 65, 8, 0, 89, 107, 109, 0, 6, - 0, 0, 0, 0, 62, 0, 1, 0, 0, 2, - 96, 97, 99, 101, 102, 100, 98, 0, 0, 0, - 0, 0, 0, 103, 104, 105, 0, 106, 0, 0, - 0, 77, 63, 89, 0, 29, 32, 0, 0, 33, - 0, 7, 19, 0, 60, 5, 4, 0, 0, 0, - 49, 48, 50, 0, 22, 18, 25, 23, 20, 21, + 0, 85, 86, 0, 74, 75, 76, 87, 88, 89, + 115, 0, 114, 82, 69, 67, 68, 80, 81, 70, + 71, 83, 84, 72, 73, 77, 116, 117, 118, 128, + 119, 120, 127, 0, 122, 123, 124, 125, 126, 121, + 0, 64, 0, 48, 3, 0, 18, 25, 27, 28, + 26, 24, 66, 8, 0, 90, 108, 110, 0, 6, + 0, 0, 0, 0, 63, 0, 1, 0, 0, 2, + 97, 98, 100, 102, 103, 101, 99, 0, 0, 0, + 0, 0, 0, 104, 105, 106, 0, 107, 0, 0, + 0, 78, 64, 90, 0, 29, 32, 0, 0, 33, + 0, 7, 19, 0, 61, 5, 4, 0, 0, 0, + 50, 49, 51, 0, 22, 18, 25, 23, 20, 21, 0, 9, 11, 13, 15, 0, 0, 12, 0, 0, - 0, 17, 16, 0, 0, 30, 92, 93, 94, 95, - 90, 91, 108, 0, 0, 0, 0, 0, 0, 0, - 64, 0, 0, 0, 0, 10, 14, 0, 0, 0, - 61, 31, 111, 110, 112, 0, 0, 0, 0, 0, - 52, 0, 0, 0, 0, 42, 0, 0, 0, 78, - 54, 0, 58, 59, 55, 51, 0, 57, 36, 35, - 0, 0, 39, 0, 46, 0, 0, 0, 0, 53, - 0, 0, 0, 41, 43, 0, 0, 56, 0, 44, - 40, 45, 0, 0, 37, 34, 0, 38 + 0, 17, 16, 0, 0, 30, 93, 94, 95, 96, + 91, 92, 109, 0, 0, 0, 0, 0, 0, 0, + 65, 0, 0, 0, 0, 10, 14, 0, 0, 0, + 62, 31, 112, 111, 113, 0, 0, 0, 0, 0, + 53, 0, 0, 0, 0, 43, 0, 0, 0, 79, + 55, 0, 59, 60, 56, 52, 0, 58, 36, 35, + 37, 0, 0, 40, 0, 47, 0, 0, 0, 0, + 54, 0, 0, 0, 42, 44, 0, 0, 57, 0, + 45, 41, 46, 0, 0, 38, 34, 0, 39 }; const short parser::yypgoto_[] = { - -192, -192, -10, -192, -32, 0, 2, -192, -192, -192, - -191, -139, -192, 109, -192, -192, -192, -192, -192, -192, - -192, -192, 108, 221, 215, -31, 159, -192, -37, 217, - -192, -192, -192, -192, -51, -63, -87 + -193, -193, -10, -193, -32, 0, 2, -193, -193, -193, + -192, -140, -193, 110, -193, -193, -193, -193, -193, -193, + -193, -193, 108, 221, 216, -31, 162, -193, -37, 217, + -193, -193, -193, -193, -51, -63, -16 }; const unsigned char parser::yydefgoto_[] = { 0, 42, 43, 44, 45, 115, 116, 48, 98, 49, - 190, 173, 193, 175, 176, 132, 69, 110, 169, 111, + 191, 173, 194, 175, 176, 132, 69, 110, 169, 111, 167, 112, 184, 50, 63, 51, 52, 53, 54, 95, 96, 81, 82, 89, 55, 56, 57 }; @@ -2523,38 +2527,38 @@ namespace yy { const unsigned char parser::yytable_[] = { - 46, 59, 47, 93, 65, 205, 58, 99, 62, 208, - 64, 46, 103, 47, 66, 103, 104, 67, 68, 160, - 177, 70, 71, 72, 73, 74, 75, 7, 8, 9, - 61, 142, 144, 67, 68, 192, 145, 67, 68, 202, - 46, 60, 47, 203, 146, 114, 117, 118, 119, 121, - 122, 125, 201, 182, 183, 65, 161, 105, 106, 101, - 165, 64, 76, 210, 148, 94, 65, 46, 46, 47, - 47, 142, 150, 77, 78, 79, 80, 90, 102, 206, - 91, 154, 41, 79, 80, 142, 123, 97, 155, 127, + 46, 59, 47, 93, 65, 206, 58, 99, 62, 209, + 64, 46, 188, 47, 189, 67, 68, 67, 68, 177, + 190, 70, 71, 72, 73, 74, 75, 7, 8, 9, + 61, 142, 144, 66, 193, 103, 145, 67, 68, 104, + 46, 180, 47, 181, 146, 114, 117, 118, 119, 121, + 122, 125, 202, 182, 183, 65, 103, 105, 106, 101, + 160, 64, 76, 211, 148, 90, 65, 46, 46, 47, + 47, 142, 150, 77, 78, 79, 80, 94, 102, 207, + 91, 154, 41, 203, 60, 142, 123, 204, 155, 127, 128, 129, 130, 83, 84, 85, 86, 87, 88, 13, - 168, 170, 100, 17, 18, 134, 131, 21, 22, 1, - 2, 3, 4, 5, 6, 77, 78, 79, 80, 180, - 102, 181, 7, 8, 9, 10, 156, 107, 108, 109, - 198, 185, 11, 186, 143, 199, 12, 13, 14, 15, + 168, 170, 100, 17, 18, 97, 131, 21, 22, 1, + 2, 3, 4, 5, 6, 77, 78, 79, 80, 185, + 102, 186, 7, 8, 9, 10, 156, 161, 79, 80, + 199, 165, 11, 134, 143, 200, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 147, 33, 34, - 35, 36, 37, 38, 148, 188, 39, 189, 197, 149, - 67, 40, 3, 4, 5, 6, 151, 41, 46, 194, - 47, 195, 120, 7, 8, 9, 10, 77, 78, 79, - 80, 213, 152, 214, 153, 92, 157, 12, 13, 14, + 35, 36, 37, 38, 148, 195, 39, 196, 198, 149, + 67, 40, 3, 4, 5, 6, 92, 41, 46, 214, + 47, 215, 120, 7, 8, 9, 10, 77, 78, 79, + 80, 107, 108, 109, 151, 152, 153, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 29, 30, 31, 32, 158, 33, - 34, 35, 36, 37, 38, 159, 162, 39, 3, 4, - 5, 6, 113, 163, 164, 171, 174, 172, 41, 7, - 8, 9, 10, 70, 71, 72, 73, 74, 75, 178, - 179, 187, 209, 12, 13, 14, 15, 16, 17, 18, + 25, 26, 27, 28, 29, 30, 31, 32, 157, 33, + 34, 35, 36, 37, 38, 158, 159, 39, 3, 4, + 5, 6, 113, 162, 163, 164, 171, 172, 41, 7, + 8, 9, 10, 70, 71, 72, 73, 74, 75, 174, + 178, 179, 187, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, - 29, 30, 31, 32, 191, 33, 34, 35, 36, 37, - 38, 196, 200, 39, 76, 211, 215, 212, 113, 3, - 4, 5, 6, 216, 41, 77, 78, 79, 80, 126, - 7, 8, 9, 10, 204, 217, 207, 133, 166, 124, - 135, 0, 0, 0, 12, 13, 14, 15, 16, 17, + 29, 30, 31, 32, 192, 33, 34, 35, 36, 37, + 38, 197, 201, 39, 76, 210, 212, 216, 113, 3, + 4, 5, 6, 213, 41, 77, 78, 79, 80, 126, + 7, 8, 9, 10, 217, 218, 205, 208, 133, 124, + 135, 166, 0, 0, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 0, 33, 34, 35, 36, 37, 38, 0, 0, 39, 3, 4, 5, 6, 0, @@ -2584,38 +2588,38 @@ namespace yy { const short parser::yycheck_[] = { - 0, 11, 0, 54, 41, 196, 65, 58, 40, 200, - 41, 11, 68, 11, 0, 68, 72, 24, 25, 72, - 159, 9, 10, 11, 12, 13, 14, 16, 17, 18, - 40, 94, 31, 24, 25, 174, 35, 24, 25, 68, - 40, 65, 40, 72, 43, 77, 78, 79, 80, 81, - 82, 88, 191, 56, 57, 92, 143, 67, 68, 66, - 147, 92, 50, 202, 67, 67, 103, 67, 68, 67, - 68, 134, 103, 61, 62, 63, 64, 51, 66, 66, - 43, 113, 71, 63, 64, 148, 86, 69, 120, 89, + 0, 11, 0, 54, 41, 197, 65, 58, 40, 201, + 41, 11, 35, 11, 37, 24, 25, 24, 25, 159, + 43, 9, 10, 11, 12, 13, 14, 16, 17, 18, + 40, 94, 31, 0, 174, 68, 35, 24, 25, 72, + 40, 66, 40, 68, 43, 77, 78, 79, 80, 81, + 82, 88, 192, 56, 57, 92, 68, 67, 68, 66, + 72, 92, 50, 203, 67, 51, 103, 67, 68, 67, + 68, 134, 103, 61, 62, 63, 64, 67, 66, 66, + 43, 113, 71, 68, 65, 148, 86, 72, 120, 89, 27, 28, 29, 44, 45, 46, 47, 48, 49, 31, - 151, 152, 31, 35, 36, 67, 43, 39, 40, 3, + 151, 152, 31, 35, 36, 69, 43, 39, 40, 3, 4, 5, 6, 7, 8, 61, 62, 63, 64, 66, - 66, 68, 16, 17, 18, 19, 126, 53, 54, 55, - 181, 66, 26, 68, 67, 186, 30, 31, 32, 33, + 66, 68, 16, 17, 18, 19, 126, 143, 63, 64, + 181, 147, 26, 67, 67, 186, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 68, 52, 53, - 54, 55, 56, 57, 67, 35, 60, 37, 178, 68, - 24, 65, 5, 6, 7, 8, 65, 71, 178, 66, - 178, 68, 15, 16, 17, 18, 19, 61, 62, 63, - 64, 68, 65, 70, 65, 71, 65, 30, 31, 32, + 54, 55, 56, 57, 67, 66, 60, 68, 178, 68, + 24, 65, 5, 6, 7, 8, 71, 71, 178, 68, + 178, 70, 15, 16, 17, 18, 19, 61, 62, 63, + 64, 53, 54, 55, 65, 65, 65, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 65, 52, - 53, 54, 55, 56, 57, 65, 70, 60, 5, 6, - 7, 8, 65, 70, 70, 35, 71, 69, 71, 16, - 17, 18, 19, 9, 10, 11, 12, 13, 14, 68, - 66, 66, 66, 30, 31, 32, 33, 34, 35, 36, + 53, 54, 55, 56, 57, 65, 65, 60, 5, 6, + 7, 8, 65, 70, 70, 70, 35, 69, 71, 16, + 17, 18, 19, 9, 10, 11, 12, 13, 14, 71, + 68, 66, 66, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 68, 52, 53, 54, 55, 56, - 57, 68, 68, 60, 50, 66, 58, 67, 65, 5, - 6, 7, 8, 37, 71, 61, 62, 63, 64, 15, - 16, 17, 18, 19, 195, 70, 198, 92, 149, 88, - 93, -1, -1, -1, 30, 31, 32, 33, 34, 35, + 57, 68, 68, 60, 50, 66, 66, 58, 65, 5, + 6, 7, 8, 67, 71, 61, 62, 63, 64, 15, + 16, 17, 18, 19, 37, 70, 196, 199, 92, 88, + 93, 149, -1, -1, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, -1, 52, 53, 54, 55, 56, 57, -1, -1, 60, 5, 6, 7, 8, -1, @@ -2664,9 +2668,9 @@ namespace yy { 72, 109, 70, 70, 70, 109, 99, 93, 107, 91, 107, 35, 69, 84, 71, 86, 87, 84, 68, 66, 66, 68, 56, 57, 95, 66, 68, 66, 35, 37, - 83, 68, 84, 85, 66, 68, 68, 75, 107, 107, - 68, 84, 68, 72, 86, 83, 66, 95, 83, 66, - 84, 66, 67, 68, 70, 58, 37, 70 + 43, 83, 68, 84, 85, 66, 68, 68, 75, 107, + 107, 68, 84, 68, 72, 86, 83, 66, 95, 83, + 66, 84, 66, 67, 68, 70, 58, 37, 70 }; const signed char @@ -2675,16 +2679,16 @@ namespace yy { 0, 73, 74, 75, 75, 75, 75, 75, 75, 76, 76, 76, 76, 76, 76, 76, 76, 76, 77, 77, 77, 77, 77, 77, 78, 78, 78, 78, 78, 79, - 79, 80, 80, 81, 82, 83, 83, 84, 84, 85, - 85, 86, 87, 87, 88, 88, 88, 89, 89, 89, - 89, 90, 91, 91, 92, 93, 93, 94, 95, 95, - 96, 96, 97, 97, 97, 98, 98, 98, 98, 98, - 98, 98, 98, 98, 98, 98, 98, 98, 98, 99, - 99, 99, 99, 99, 100, 100, 101, 101, 101, 102, - 102, 102, 103, 103, 103, 103, 104, 104, 104, 105, - 105, 105, 105, 106, 106, 106, 106, 107, 107, 108, - 108, 108, 108, 109, 109, 109, 109, 109, 109, 109, - 109, 109, 109, 109, 109, 109, 109, 109 + 79, 80, 80, 81, 82, 83, 83, 83, 84, 84, + 85, 85, 86, 87, 87, 88, 88, 88, 89, 89, + 89, 89, 90, 91, 91, 92, 93, 93, 94, 95, + 95, 96, 96, 97, 97, 97, 98, 98, 98, 98, + 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, + 99, 99, 99, 99, 99, 100, 100, 101, 101, 101, + 102, 102, 102, 103, 103, 103, 103, 104, 104, 104, + 105, 105, 105, 105, 106, 106, 106, 106, 107, 107, + 108, 108, 108, 108, 109, 109, 109, 109, 109, 109, + 109, 109, 109, 109, 109, 109, 109, 109, 109 }; const signed char @@ -2693,16 +2697,16 @@ namespace yy { 0, 2, 2, 1, 3, 3, 2, 3, 1, 3, 4, 3, 3, 3, 4, 3, 3, 3, 1, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 2, - 3, 4, 2, 1, 10, 1, 1, 5, 7, 1, - 3, 3, 1, 3, 6, 6, 4, 0, 2, 2, - 2, 4, 1, 3, 4, 2, 4, 4, 1, 1, - 3, 4, 1, 0, 3, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 2, 6, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, - 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, - 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1 + 3, 4, 2, 1, 10, 1, 1, 1, 5, 7, + 1, 3, 3, 1, 3, 6, 6, 4, 0, 2, + 2, 2, 4, 1, 3, 4, 2, 4, 4, 1, + 1, 3, 4, 1, 0, 3, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 6, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 2, 2, 2, 2, 2, 2, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, + 1, 4, 4, 4, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1 }; @@ -2744,16 +2748,16 @@ namespace yy { 0, 187, 187, 190, 191, 192, 193, 194, 195, 198, 199, 204, 205, 206, 207, 212, 213, 214, 217, 218, 219, 220, 221, 222, 225, 226, 227, 228, 229, 232, - 233, 236, 240, 246, 249, 252, 253, 256, 257, 260, - 261, 263, 266, 267, 270, 271, 272, 275, 276, 277, - 278, 280, 283, 284, 286, 289, 290, 292, 295, 296, - 298, 299, 302, 303, 304, 307, 308, 309, 310, 311, - 312, 313, 314, 315, 316, 317, 318, 319, 320, 328, - 329, 330, 331, 332, 335, 336, 339, 340, 341, 344, - 345, 346, 349, 350, 351, 352, 355, 356, 357, 360, - 361, 362, 363, 366, 367, 368, 369, 372, 373, 376, - 377, 378, 379, 382, 383, 384, 385, 386, 387, 388, - 389, 390, 391, 392, 393, 394, 395, 396 + 233, 236, 240, 246, 249, 252, 253, 254, 257, 258, + 261, 262, 264, 267, 268, 271, 272, 273, 276, 277, + 278, 279, 281, 284, 285, 287, 290, 291, 293, 296, + 297, 299, 300, 303, 304, 305, 308, 309, 310, 311, + 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, + 329, 330, 331, 332, 333, 336, 337, 340, 341, 342, + 345, 346, 347, 350, 351, 352, 353, 356, 357, 358, + 361, 362, 363, 364, 367, 368, 369, 370, 373, 374, + 377, 378, 379, 380, 383, 384, 385, 386, 387, 388, + 389, 390, 391, 392, 393, 394, 395, 396, 397 }; void diff --git a/src/realm/parser/generated/query_bison.hpp b/src/realm/parser/generated/query_bison.hpp index 2d35253fa1d..84fe32a2c23 100644 --- a/src/realm/parser/generated/query_bison.hpp +++ b/src/realm/parser/generated/query_bison.hpp @@ -2528,7 +2528,7 @@ switch (yykind) // YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. // Performed when YYTABLE does not specify something else to do. Zero // means the default is an error. - static const signed char yydefact_[]; + static const unsigned char yydefact_[]; // YYPGOTO[NTERM-NUM]. static const short yypgoto_[]; diff --git a/src/realm/parser/query_bison.yy b/src/realm/parser/query_bison.yy index 9957f13425d..810733ae4f1 100644 --- a/src/realm/parser/query_bison.yy +++ b/src/realm/parser/query_bison.yy @@ -251,6 +251,7 @@ subquery coordinate : FLOAT { $$ = strtod($1.c_str(), nullptr); } | NATURAL0 { $$ = double(strtoll($1.c_str(), nullptr, 0)); } + | ARG { $$ = drv.get_arg_for_coordinate($1); } geopoint : '[' coordinate ',' coordinate ']' { $$ = GeoPoint{$2, $4}; } diff --git a/test/test_parser.cpp b/test/test_parser.cpp index 949f74bea8a..4ea504e87c8 100644 --- a/test/test_parser.cpp +++ b/test/test_parser.cpp @@ -5741,6 +5741,22 @@ TEST(Parser_Geospatial) verify_query_sub(test_context, table, "location GEOWITHIN $1", args, 4); verify_query_sub(test_context, table, "location GEOWITHIN $2", args, 1); + GeoCircle c = circle.get(); + std::vector coord_args = {Mixed{c.center.longitude}, Mixed{c.center.latitude}, Mixed{c.radius_radians}}; + verify_query_sub(test_context, table, "location GEOWITHIN geoCircle([$0, $1], $2)", coord_args, 4); + GeoPolygon p = polygon.get(); + coord_args = {Mixed{p.points[0][0].longitude}, Mixed{p.points[0][0].latitude}, Mixed{p.points[0][1].longitude}, + Mixed{p.points[0][1].latitude}, Mixed{p.points[0][2].longitude}, Mixed{p.points[0][2].latitude}, + Mixed{p.points[0][3].longitude}, Mixed{p.points[0][3].latitude}, Mixed{p.points[0][4].longitude}, + Mixed{p.points[0][4].latitude}}; + verify_query_sub(test_context, table, + "location GEOWITHIN geoPolygon({[$0, $1], [$2, $3], [$4, $5], [$6, $7], [$8, $9]})", coord_args, + 1); + GeoBox b = box.get(); + coord_args = {b.lo.longitude, b.lo.latitude, b.hi.longitude, b.hi.latitude}; + verify_query_sub(test_context, table, "location GEOWITHIN geoBox([$0, $1], [$2, $3])", coord_args, 1); + + CHECK_THROW_EX( verify_query(test_context, table, "_id geoWithin geoBox([0.2, 0.2], [0.7, 0.7])", 1), query_parser::InvalidQueryError, @@ -5786,6 +5802,19 @@ TEST(Parser_Geospatial) query_parser::InvalidQueryError, CHECK(std::string(e.what()).find("The right hand side of 'geoWithin' must be a valid " "Geospatial value, got 'NULL'") != std::string::npos)); + CHECK_THROW_EX( + verify_query_sub(test_context, table, "location GEOWITHIN geoCircle([$1, $2], $3)", args, 0), + query_parser::InvalidQueryError, + CHECK(std::string(e.what()).find("Invalid parameter 'geospatial' used in coordinate at argument '$1'") != + std::string::npos)); + CHECK_THROW_EX( + verify_query_sub(test_context, table, "location GEOWITHIN geoCircle([$4, $4], $4)", args, 0), + query_parser::InvalidQueryError, + CHECK(std::string(e.what()).find("NULL cannot be used in coordinate at argument '$4'") != std::string::npos)); + CHECK_THROW_EX(verify_query_sub(test_context, table, "location GEOWITHIN geoCircle([$7, $7], $7)", args, 0), + query_parser::InvalidQueryError, + CHECK(std::string(e.what()).find( + "Invalid parameter 'string' used in coordinate at argument '$7'") != std::string::npos)); #endif }