Skip to content

Commit 16510a1

Browse files
Support aliases in Content Filtered Topic (#6032) (#6049)
Signed-off-by: Juan Lopez Fernandez <[email protected]> Co-authored-by: Juan Lopez Fernandez <[email protected]>
1 parent 2868bde commit 16510a1

13 files changed

+1356
-203
lines changed

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

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

51+
static const TypeIdentifier* resolve_type(
52+
const TypeIdentifier& ti,
53+
const position& pos)
54+
{
55+
if (EK_COMPLETE != ti._d())
56+
{
57+
return &ti;
58+
}
59+
60+
const TypeObject* type_object = TypeObjectFactory::get_instance()->get_type_object(&ti);
61+
if (nullptr != type_object && EK_COMPLETE == type_object->_d())
62+
{
63+
if (TK_ALIAS == type_object->complete()._d())
64+
{
65+
const TypeIdentifier& aliased_id = type_object->complete().alias_type().body().common().related_type();
66+
return resolve_type(aliased_id, pos);
67+
}
68+
return &ti;
69+
}
70+
throw parse_error("could not find type object definition", pos);
71+
}
72+
5173
static bool type_should_be_indexed(
5274
const TypeIdentifier& ti,
5375
const TypeIdentifier*& out_type,
54-
size_t& max_size)
76+
size_t& max_size,
77+
const position& pos)
5578
{
5679
max_size = 0;
5780

5881
switch (ti._d())
5982
{
6083
case TI_PLAIN_ARRAY_SMALL:
61-
out_type = ti.array_sdefn().element_identifier();
84+
out_type = resolve_type(*ti.array_sdefn().element_identifier(), pos);
6285
max_size = process_bounds(ti.array_sdefn().array_bound_seq());
6386
return true;
6487

6588
case TI_PLAIN_ARRAY_LARGE:
66-
out_type = ti.array_ldefn().element_identifier();
89+
out_type = resolve_type(*ti.array_ldefn().element_identifier(), pos);
6790
max_size = process_bounds(ti.array_ldefn().array_bound_seq());
6891
return true;
6992

7093
case TI_PLAIN_SEQUENCE_SMALL:
71-
out_type = ti.seq_sdefn().element_identifier();
94+
out_type = resolve_type(*ti.seq_sdefn().element_identifier(), pos);
7295
max_size = process_bound(ti.seq_sdefn().bound());
7396
return true;
7497

7598
case TI_PLAIN_SEQUENCE_LARGE:
76-
out_type = ti.seq_ldefn().element_identifier();
99+
out_type = resolve_type(*ti.seq_ldefn().element_identifier(), pos);
77100
max_size = process_bound(ti.seq_ldefn().bound());
78101
return true;
79102
}
@@ -109,11 +132,11 @@ struct identifier_processor
109132
throw parse_error("field not found", name_node.begin());
110133
}
111134

112-
const TypeIdentifier& ti = members[member_index].common().member_type_id();
135+
auto ti = resolve_type(members[member_index].common().member_type_id(), name_node.begin());
113136
bool has_index = n->children.size() > 1;
114137
size_t max_size = 0;
115138
size_t array_index = std::numeric_limits<size_t>::max();
116-
if (type_should_be_indexed(ti, identifier_state.current_type, max_size))
139+
if (type_should_be_indexed(*ti, identifier_state.current_type, max_size, name_node.begin()))
117140
{
118141
if (!has_index)
119142
{
@@ -176,16 +199,11 @@ struct identifier_processor
176199

177200
case EK_COMPLETE:
178201
const TypeObject* type_object = TypeObjectFactory::get_instance()->get_type_object(&ti);
202+
assert(TK_ALIAS != type_object->complete()._d()); // should be resolved already at this point
179203
if (TK_ENUM == type_object->complete()._d())
180204
{
181205
return DDSFilterValue::ValueKind::ENUM;
182206
}
183-
if (TK_ALIAS == type_object->complete()._d())
184-
{
185-
const TypeIdentifier& aliasedId =
186-
type_object->complete().alias_type().body().common().related_type();
187-
return get_value_kind(aliasedId, pos);
188-
}
189207
break;
190208

191209
}
@@ -201,6 +219,11 @@ struct identifier_processor
201219
{
202220
if (n->is<fieldname>())
203221
{
222+
if (!state.current_type)
223+
{
224+
throw parse_error("undefined type identifier", n->begin());
225+
}
226+
204227
// Set data for fieldname node
205228
n->field_kind = get_value_kind(*state.current_type, n->end());
206229
n->field_access_path = state.access_path;
@@ -214,6 +237,10 @@ struct identifier_processor
214237
{
215238
if (nullptr == state.current_type)
216239
{
240+
if (!state.type_object)
241+
{
242+
throw parse_error("undefined type object", n->begin());
243+
}
217244
add_member_access(n, state, state.type_object->complete());
218245
}
219246
else

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,11 +170,12 @@ bool DDSFilterField::set_value(
170170

171171
case EK_COMPLETE:
172172
{
173+
// WARNING: this assumes EK_COMPLETE is always an enumeration, aliases should be resolved when parsing
173174
uint32_t enum_value;
174175
ret = !!data->get_enum_value(enum_value, member_id);
175176
signed_integer_value = enum_value;
176-
break;
177177
}
178+
break;
178179

179180
default:
180181
ret = false;

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
@@ -954,13 +955,21 @@ class DDSSQLFilterValueGlobalData
954955
for (size_t i = 0; i < values.size(); ++i)
955956
{
956957
data[i].string_field(values[i]);
958+
data[i].alias_string_field(values[i]);
957959
data[i].struct_field().string_field(values[i]);
960+
data[i].struct_field().alias_string_field(values[i]);
958961
data[i].array_struct_field()[0].string_field(values[i]);
962+
data[i].array_struct_field()[0].alias_string_field(values[i]);
959963
data[i].bounded_sequence_struct_field()[0].string_field(values[i]);
964+
data[i].bounded_sequence_struct_field()[0].alias_string_field(values[i]);
960965
data[i].unbounded_sequence_struct_field()[0].string_field(values[i]);
966+
data[i].unbounded_sequence_struct_field()[0].alias_string_field(values[i]);
961967
data[i].array_string_field()[0] = values[i];
968+
data[i].array_alias_string_field()[0] = values[i];
962969
data[i].bounded_sequence_string_field().push_back(values[i]);
970+
data[i].bounded_sequence_alias_string_field().push_back(values[i]);
963971
data[i].unbounded_sequence_string_field().push_back(values[i]);
972+
data[i].unbounded_sequence_alias_string_field().push_back(values[i]);
964973
}
965974
}
966975

@@ -1460,6 +1469,112 @@ static std::vector<DDSSQLFilterValueParams> get_test_filtered_value_string_input
14601469
return inputs;
14611470
}
14621471

1472+
static std::vector<DDSSQLFilterValueParams> get_test_filtered_value_alias_string_inputs()
1473+
{
1474+
static const std::array<std::pair<std::string, std::string>, 5> values =
1475+
{
1476+
std::pair<std::string, std::string>{"''", "minus_2"},
1477+
std::pair<std::string, std::string>{"' '", "minus_1"},
1478+
std::pair<std::string, std::string>{"' AA'", "0"},
1479+
std::pair<std::string, std::string>{"' AZ'", "plus_1"},
1480+
std::pair<std::string, std::string>{"'ZZZ'", "plus_2"}
1481+
};
1482+
1483+
// Adding standard tests
1484+
std::vector<DDSSQLFilterValueParams> inputs;
1485+
inputs = get_test_filtered_value_inputs_given_values_and_results("alias_string_field", values);
1486+
1487+
// Adding tests for LIKE operator
1488+
DDSSQLFilterValueParams input;
1489+
input.test_case_name = "like_any_percent";
1490+
input.expression = "alias_string_field LIKE '%'";
1491+
input.samples_filtered.assign(5, true);
1492+
inputs.push_back(input);
1493+
1494+
input.test_case_name = "like_any_star";
1495+
input.expression = "alias_string_field LIKE '*'";
1496+
input.samples_filtered.assign(5, true);
1497+
inputs.push_back(input);
1498+
1499+
input.test_case_name = "like_space_percent";
1500+
input.expression = "alias_string_field LIKE ' %'";
1501+
input.samples_filtered.assign({ false, true, true, true, false });
1502+
inputs.push_back(input);
1503+
1504+
input.test_case_name = "like_space_star";
1505+
input.expression = "alias_string_field LIKE ' *'";
1506+
input.samples_filtered.assign({ false, true, true, true, false });
1507+
inputs.push_back(input);
1508+
1509+
input.test_case_name = "like_A_question";
1510+
input.expression = "alias_string_field LIKE '?A?'";
1511+
input.samples_filtered.assign({ false, false, true, true, false });
1512+
inputs.push_back(input);
1513+
1514+
input.test_case_name = "like_A_underscore";
1515+
input.expression = "alias_string_field LIKE '_A_'";
1516+
input.samples_filtered.assign({ false, false, true, true, false });
1517+
inputs.push_back(input);
1518+
1519+
input.test_case_name = "like_exact_empty";
1520+
input.expression = "alias_string_field LIKE ''";
1521+
input.samples_filtered.assign({ true, false, false, false, false });
1522+
inputs.push_back(input);
1523+
1524+
input.test_case_name = "like_exact_ZZZ";
1525+
input.expression = "alias_string_field LIKE 'ZZZ'";
1526+
input.samples_filtered.assign({ false, false, false, false, true });
1527+
inputs.push_back(input);
1528+
1529+
input.test_case_name = "like_exact_none";
1530+
input.expression = "alias_string_field LIKE 'BBB'";
1531+
input.samples_filtered.assign({ false, false, false, false, false });
1532+
inputs.push_back(input);
1533+
1534+
// Adding tests for MATCH operator
1535+
input.test_case_name = "match_any";
1536+
input.expression = "alias_string_field match '.*'";
1537+
input.samples_filtered.assign(5, true);
1538+
inputs.push_back(input);
1539+
1540+
input.test_case_name = "match_space";
1541+
input.expression = "alias_string_field match ' .*'";
1542+
input.samples_filtered.assign({ false, true, true, true, false });
1543+
inputs.push_back(input);
1544+
1545+
input.test_case_name = "match_A";
1546+
input.expression = "alias_string_field match '.A.'";
1547+
input.samples_filtered.assign({ false, false, true, true, false });
1548+
inputs.push_back(input);
1549+
1550+
input.test_case_name = "match_exact_empty";
1551+
input.expression = "alias_string_field match ''";
1552+
input.samples_filtered.assign({ true, false, false, false, false });
1553+
inputs.push_back(input);
1554+
1555+
input.test_case_name = "match_exact_ZZZ";
1556+
input.expression = "alias_string_field match 'ZZZ'";
1557+
input.samples_filtered.assign({ false, false, false, false, true });
1558+
inputs.push_back(input);
1559+
1560+
input.test_case_name = "match_exact_none";
1561+
input.expression = "alias_string_field match 'BBB'";
1562+
input.samples_filtered.assign({ false, false, false, false, false });
1563+
inputs.push_back(input);
1564+
1565+
input.test_case_name = "match_range";
1566+
input.expression = "alias_string_field match '([A-Z])+'";
1567+
input.samples_filtered.assign({ false, false, false, false, true });
1568+
inputs.push_back(input);
1569+
1570+
input.test_case_name = "match_space_and_range";
1571+
input.expression = "alias_string_field match ' ([A-Z])+'";
1572+
input.samples_filtered.assign({ false, false, true, true, false });
1573+
inputs.push_back(input);
1574+
1575+
return inputs;
1576+
}
1577+
14631578
static std::vector<DDSSQLFilterValueParams> get_test_filtered_value_boolean_inputs()
14641579
{
14651580
static const std::array<std::pair<std::string, std::string>, 5> values =
@@ -2018,6 +2133,12 @@ INSTANTIATE_TEST_SUITE_P(
20182133
::testing::ValuesIn(get_test_filtered_value_string_inputs()),
20192134
DDSSQLFilterValueTests::PrintToStringParamName());
20202135

2136+
INSTANTIATE_TEST_SUITE_P(
2137+
DDSSQLFilterValueTestsAliasString,
2138+
DDSSQLFilterValueTests,
2139+
::testing::ValuesIn(get_test_filtered_value_alias_string_inputs()),
2140+
DDSSQLFilterValueTests::PrintToStringParamName());
2141+
20212142
INSTANTIATE_TEST_SUITE_P(
20222143
DDSSQLFilterValueTestsBool,
20232144
DDSSQLFilterValueTests,

0 commit comments

Comments
 (0)