Skip to content

Commit 3af813b

Browse files
Support aliases in Content Filtered Topic (#6032)
* Refs #23689. Regression test Signed-off-by: Juan Lopez Fernandez <[email protected]> * Refs #23689. Support aliases in Content Filtered Topic Signed-off-by: Juan Lopez Fernandez <[email protected]> * Refs #23689. Update versions.md Signed-off-by: Juan Lopez Fernandez <[email protected]> * Refs #23689. Uncrustify Signed-off-by: Juan Lopez Fernandez <[email protected]> * Refs #23689. Beautify Signed-off-by: Juan Lopez Fernandez <[email protected]> * Refs #23689. Apply suggestion Signed-off-by: Juan Lopez Fernandez <[email protected]> --------- Signed-off-by: Juan Lopez Fernandez <[email protected]>
1 parent 50ff229 commit 3af813b

File tree

11 files changed

+1068
-240
lines changed

11 files changed

+1068
-240
lines changed

src/cpp/fastdds/topic/DDSSQLFilter/DDSFilterExpressionParserImpl/identifiers.hpp

Lines changed: 42 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -48,32 +48,57 @@ struct identifier_processor
4848
return process_bound(bound_seq[0]);
4949
}
5050

51+
static std::shared_ptr<xtypes::TypeIdentifier> resolve_type(
52+
const xtypes::TypeIdentifier& ti,
53+
const position& pos)
54+
{
55+
if (xtypes::EK_COMPLETE != ti._d())
56+
{
57+
return std::make_shared<xtypes::TypeIdentifier>(ti);
58+
}
59+
60+
std::shared_ptr<xtypes::TypeObject> type_object = std::make_shared<xtypes::TypeObject>();
61+
if (RETCODE_OK == DomainParticipantFactory::get_instance()->type_object_registry().get_type_object(
62+
ti, *type_object) && xtypes::EK_COMPLETE == type_object->_d())
63+
{
64+
if (xtypes::TK_ALIAS == type_object->complete()._d())
65+
{
66+
const xtypes::TypeIdentifier& aliased_id =
67+
type_object->complete().alias_type().body().common().related_type();
68+
return resolve_type(aliased_id, pos);
69+
}
70+
return std::make_shared<xtypes::TypeIdentifier>(ti);
71+
}
72+
throw parse_error("could not find type object definition", pos);
73+
}
74+
5175
static bool type_should_be_indexed(
5276
const xtypes::TypeIdentifier& ti,
5377
std::shared_ptr<xtypes::TypeIdentifier>& out_type,
54-
size_t& max_size)
78+
size_t& max_size,
79+
const position& pos)
5580
{
5681
max_size = 0;
5782

5883
switch (ti._d())
5984
{
6085
case xtypes::TI_PLAIN_ARRAY_SMALL:
61-
out_type = std::make_shared<xtypes::TypeIdentifier>(*ti.array_sdefn().element_identifier());
86+
out_type = resolve_type(*ti.array_sdefn().element_identifier(), pos);
6287
max_size = process_bounds(ti.array_sdefn().array_bound_seq());
6388
return true;
6489

6590
case xtypes::TI_PLAIN_ARRAY_LARGE:
66-
out_type = std::make_shared<xtypes::TypeIdentifier>(*ti.array_ldefn().element_identifier());
91+
out_type = resolve_type(*ti.array_ldefn().element_identifier(), pos);
6792
max_size = process_bounds(ti.array_ldefn().array_bound_seq());
6893
return true;
6994

7095
case xtypes::TI_PLAIN_SEQUENCE_SMALL:
71-
out_type = std::make_shared<xtypes::TypeIdentifier>(*ti.seq_sdefn().element_identifier());
96+
out_type = resolve_type(*ti.seq_sdefn().element_identifier(), pos);
7297
max_size = process_bound(ti.seq_sdefn().bound());
7398
return true;
7499

75100
case xtypes::TI_PLAIN_SEQUENCE_LARGE:
76-
out_type = std::make_shared<xtypes::TypeIdentifier>(*ti.seq_ldefn().element_identifier());
101+
out_type = resolve_type(*ti.seq_ldefn().element_identifier(), pos);
77102
max_size = process_bound(ti.seq_ldefn().bound());
78103
return true;
79104

@@ -111,11 +136,11 @@ struct identifier_processor
111136
throw parse_error("field not found", name_node.begin());
112137
}
113138

114-
const xtypes::TypeIdentifier& ti = members[member_index].common().member_type_id();
139+
auto ti = resolve_type(members[member_index].common().member_type_id(), name_node.begin());
115140
bool has_index = n->children.size() > 1;
116141
size_t max_size = 0;
117142
size_t array_index = std::numeric_limits<size_t>::max();
118-
if (type_should_be_indexed(ti, identifier_state.current_type, max_size))
143+
if (type_should_be_indexed(*ti, identifier_state.current_type, max_size, name_node.begin()))
119144
{
120145
if (!has_index)
121146
{
@@ -184,16 +209,11 @@ struct identifier_processor
184209
if (RETCODE_OK == DomainParticipantFactory::get_instance()->type_object_registry().get_type_object(
185210
ti, *type_object) && xtypes::EK_COMPLETE == type_object->_d())
186211
{
212+
assert(xtypes::TK_ALIAS != type_object->complete()._d()); // should be resolved already at this point
187213
if (xtypes::TK_ENUM == type_object->complete()._d())
188214
{
189215
return DDSFilterValue::ValueKind::ENUM;
190216
}
191-
if (xtypes::TK_ALIAS == type_object->complete()._d())
192-
{
193-
const xtypes::TypeIdentifier& aliasedId =
194-
type_object->complete().alias_type().body().common().related_type();
195-
return get_value_kind(aliasedId, pos);
196-
}
197217
}
198218
}
199219
break;
@@ -210,6 +230,11 @@ struct identifier_processor
210230
{
211231
if (n->is<fieldname>())
212232
{
233+
if (!state.current_type)
234+
{
235+
throw parse_error("undefined type identifier", n->begin());
236+
}
237+
213238
// Set data for fieldname node
214239
n->field_kind = get_value_kind(*state.current_type, n->end());
215240
n->field_access_path = state.access_path;
@@ -223,6 +248,10 @@ struct identifier_processor
223248
{
224249
if (!state.current_type)
225250
{
251+
if (!state.type_object)
252+
{
253+
throw parse_error("undefined type object", n->begin());
254+
}
226255
add_member_access(n, state, state.type_object->complete());
227256
}
228257
else

src/cpp/fastdds/topic/DDSSQLFilter/DDSFilterField.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,11 +212,12 @@ bool DDSFilterField::set_value_using_member_id(
212212

213213
case eprosima::fastdds::dds::xtypes::EK_COMPLETE:
214214
{
215+
// WARNING: this assumes EK_COMPLETE is always an enumeration, aliases should be resolved when parsing
215216
int32_t valueenum {0};
216217
ret = RETCODE_OK == data->get_int32_value(valueenum, member_id);
217218
signed_integer_value = valueenum;
218-
break;
219219
}
220+
break;
220221

221222
default:
222223
break;

test/unittest/dds/topic/DDSSQLFilter/DDSSQLFilterTests.cpp

Lines changed: 136 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -40,21 +40,22 @@ namespace dds {
4040
// Name of all the primitive fields used along the tests
4141
static const std::vector<std::pair<std::string, std::string>> primitive_fields
4242
{
43-
{"char_field", "CHAR"},
44-
{"uint8_field", "INT"},
45-
{"int16_field", "INT"},
46-
{"uint16_field", "INT"},
47-
{"int32_field", "INT"},
48-
{"uint32_field", "INT"},
49-
{"int64_field", "INT"},
50-
{"uint64_field", "INT"},
51-
{"float_field", "FLOAT"},
52-
{"double_field", "FLOAT"},
53-
{"long_double_field", "FLOAT"},
54-
{"bool_field", "BOOL"},
55-
{"string_field", "STRING"},
56-
{"enum_field", "ENUM"},
57-
{"enum2_field", "ENUM2"}
43+
{"char_field", "CHAR"},
44+
{"uint8_field", "INT"},
45+
{"int16_field", "INT"},
46+
{"uint16_field", "INT"},
47+
{"int32_field", "INT"},
48+
{"uint32_field", "INT"},
49+
{"int64_field", "INT"},
50+
{"uint64_field", "INT"},
51+
{"float_field", "FLOAT"},
52+
{"double_field", "FLOAT"},
53+
{"long_double_field", "FLOAT"},
54+
{"bool_field", "BOOL"},
55+
{"string_field", "STRING"},
56+
{"alias_string_field", "STRING"},
57+
{"enum_field", "ENUM"},
58+
{"enum2_field", "ENUM2"}
5859
};
5960

6061
static const std::map<std::string, std::set<std::string>> type_compatibility_matrix
@@ -961,13 +962,21 @@ class DDSSQLFilterValueGlobalData
961962
for (size_t i = 0; i < values.size(); ++i)
962963
{
963964
data[i].string_field(values[i]);
965+
data[i].alias_string_field(values[i]);
964966
data[i].struct_field().string_field(values[i]);
967+
data[i].struct_field().alias_string_field(values[i]);
965968
data[i].array_struct_field()[0].string_field(values[i]);
969+
data[i].array_struct_field()[0].alias_string_field(values[i]);
966970
data[i].bounded_sequence_struct_field()[0].string_field(values[i]);
971+
data[i].bounded_sequence_struct_field()[0].alias_string_field(values[i]);
967972
data[i].unbounded_sequence_struct_field()[0].string_field(values[i]);
973+
data[i].unbounded_sequence_struct_field()[0].alias_string_field(values[i]);
968974
data[i].array_string_field()[0] = values[i];
975+
data[i].array_alias_string_field()[0] = values[i];
969976
data[i].bounded_sequence_string_field().push_back(values[i]);
977+
data[i].bounded_sequence_alias_string_field().push_back(values[i]);
970978
data[i].unbounded_sequence_string_field().push_back(values[i]);
979+
data[i].unbounded_sequence_alias_string_field().push_back(values[i]);
971980
}
972981
}
973982

@@ -1504,6 +1513,112 @@ static std::vector<DDSSQLFilterValueParams> get_test_filtered_value_string_input
15041513
return inputs;
15051514
}
15061515

1516+
static std::vector<DDSSQLFilterValueParams> get_test_filtered_value_alias_string_inputs()
1517+
{
1518+
static const std::array<std::pair<std::string, std::string>, 5> values =
1519+
{
1520+
std::pair<std::string, std::string>{"''", "minus_2"},
1521+
std::pair<std::string, std::string>{"' '", "minus_1"},
1522+
std::pair<std::string, std::string>{"' AA'", "0"},
1523+
std::pair<std::string, std::string>{"' AZ'", "plus_1"},
1524+
std::pair<std::string, std::string>{"'ZZZ'", "plus_2"}
1525+
};
1526+
1527+
// Adding standard tests
1528+
std::vector<DDSSQLFilterValueParams> inputs;
1529+
inputs = get_test_filtered_value_inputs_given_values_and_results("alias_string_field", values);
1530+
1531+
// Adding tests for LIKE operator
1532+
DDSSQLFilterValueParams input;
1533+
input.test_case_name = "like_any_percent";
1534+
input.expression = "alias_string_field LIKE '%'";
1535+
input.samples_filtered.assign(5, true);
1536+
inputs.push_back(input);
1537+
1538+
input.test_case_name = "like_any_star";
1539+
input.expression = "alias_string_field LIKE '*'";
1540+
input.samples_filtered.assign(5, true);
1541+
inputs.push_back(input);
1542+
1543+
input.test_case_name = "like_space_percent";
1544+
input.expression = "alias_string_field LIKE ' %'";
1545+
input.samples_filtered.assign({ false, true, true, true, false });
1546+
inputs.push_back(input);
1547+
1548+
input.test_case_name = "like_space_star";
1549+
input.expression = "alias_string_field LIKE ' *'";
1550+
input.samples_filtered.assign({ false, true, true, true, false });
1551+
inputs.push_back(input);
1552+
1553+
input.test_case_name = "like_A_question";
1554+
input.expression = "alias_string_field LIKE '?A?'";
1555+
input.samples_filtered.assign({ false, false, true, true, false });
1556+
inputs.push_back(input);
1557+
1558+
input.test_case_name = "like_A_underscore";
1559+
input.expression = "alias_string_field LIKE '_A_'";
1560+
input.samples_filtered.assign({ false, false, true, true, false });
1561+
inputs.push_back(input);
1562+
1563+
input.test_case_name = "like_exact_empty";
1564+
input.expression = "alias_string_field LIKE ''";
1565+
input.samples_filtered.assign({ true, false, false, false, false });
1566+
inputs.push_back(input);
1567+
1568+
input.test_case_name = "like_exact_ZZZ";
1569+
input.expression = "alias_string_field LIKE 'ZZZ'";
1570+
input.samples_filtered.assign({ false, false, false, false, true });
1571+
inputs.push_back(input);
1572+
1573+
input.test_case_name = "like_exact_none";
1574+
input.expression = "alias_string_field LIKE 'BBB'";
1575+
input.samples_filtered.assign({ false, false, false, false, false });
1576+
inputs.push_back(input);
1577+
1578+
// Adding tests for MATCH operator
1579+
input.test_case_name = "match_any";
1580+
input.expression = "alias_string_field match '.*'";
1581+
input.samples_filtered.assign(5, true);
1582+
inputs.push_back(input);
1583+
1584+
input.test_case_name = "match_space";
1585+
input.expression = "alias_string_field match ' .*'";
1586+
input.samples_filtered.assign({ false, true, true, true, false });
1587+
inputs.push_back(input);
1588+
1589+
input.test_case_name = "match_A";
1590+
input.expression = "alias_string_field match '.A.'";
1591+
input.samples_filtered.assign({ false, false, true, true, false });
1592+
inputs.push_back(input);
1593+
1594+
input.test_case_name = "match_exact_empty";
1595+
input.expression = "alias_string_field match ''";
1596+
input.samples_filtered.assign({ true, false, false, false, false });
1597+
inputs.push_back(input);
1598+
1599+
input.test_case_name = "match_exact_ZZZ";
1600+
input.expression = "alias_string_field match 'ZZZ'";
1601+
input.samples_filtered.assign({ false, false, false, false, true });
1602+
inputs.push_back(input);
1603+
1604+
input.test_case_name = "match_exact_none";
1605+
input.expression = "alias_string_field match 'BBB'";
1606+
input.samples_filtered.assign({ false, false, false, false, false });
1607+
inputs.push_back(input);
1608+
1609+
input.test_case_name = "match_range";
1610+
input.expression = "alias_string_field match '([A-Z])+'";
1611+
input.samples_filtered.assign({ false, false, false, false, true });
1612+
inputs.push_back(input);
1613+
1614+
input.test_case_name = "match_space_and_range";
1615+
input.expression = "alias_string_field match ' ([A-Z])+'";
1616+
input.samples_filtered.assign({ false, false, true, true, false });
1617+
inputs.push_back(input);
1618+
1619+
return inputs;
1620+
}
1621+
15071622
static std::vector<DDSSQLFilterValueParams> get_test_filtered_value_boolean_inputs()
15081623
{
15091624
static const std::array<std::pair<std::string, std::string>, 5> values =
@@ -2062,6 +2177,12 @@ INSTANTIATE_TEST_SUITE_P(
20622177
::testing::ValuesIn(get_test_filtered_value_string_inputs()),
20632178
DDSSQLFilterValueTests::PrintToStringParamName());
20642179

2180+
INSTANTIATE_TEST_SUITE_P(
2181+
DDSSQLFilterValueTestsAliasString,
2182+
DDSSQLFilterValueTests,
2183+
::testing::ValuesIn(get_test_filtered_value_alias_string_inputs()),
2184+
DDSSQLFilterValueTests::PrintToStringParamName());
2185+
20652186
INSTANTIATE_TEST_SUITE_P(
20662187
DDSSQLFilterValueTestsBool,
20672188
DDSSQLFilterValueTests,

0 commit comments

Comments
 (0)