summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarlos Garnacho <carlosg@gnome.org>2022-03-26 20:27:11 +0100
committerCarlos Garnacho <carlosg@gnome.org>2022-03-27 21:34:36 +0200
commitf1a328292d4ca2619c04beb5a901adcab50cfc11 (patch)
tree7f5c2f21359594a7e9e061c83712af74efae2369
parente47d94a89269b91c4c765445d105cbcebe411102 (diff)
downloadtracker-f1a328292d4ca2619c04beb5a901adcab50cfc11.tar.gz
libtracker-data: Fix negated property paths
Fix some brokenness in dealing with the parse tree, and make the algebra actually equivalent to the spec. There were two rough points: - Negated inverse paths cannot be implemented on top of the inverse path implementation. "<a> !^:prop <b>" must match all properties from <b> to <a> that are not :prop. - The combination of inverse and regular paths in a negated path (e.g. "<a> !(:prop|^:prop) <b>") must intersect the inverse and regular paths separately and join those with an alternate '|' path. This makes negated property paths consistent with the definition at https://www.w3.org/TR/sparql11-query/#sparqlTranslatePathExpressions and following algebra.
-rw-r--r--src/libtracker-data/tracker-sparql-types.c6
-rw-r--r--src/libtracker-data/tracker-sparql-types.h1
-rw-r--r--src/libtracker-data/tracker-sparql.c128
3 files changed, 91 insertions, 44 deletions
diff --git a/src/libtracker-data/tracker-sparql-types.c b/src/libtracker-data/tracker-sparql-types.c
index 9211ddbf2..50ad62c05 100644
--- a/src/libtracker-data/tracker-sparql-types.c
+++ b/src/libtracker-data/tracker-sparql-types.c
@@ -560,7 +560,8 @@ tracker_path_element_property_new (TrackerPathOperator op,
g_return_val_if_fail (TRACKER_IS_PROPERTY (prop), NULL);
g_return_val_if_fail (op == TRACKER_PATH_OPERATOR_NONE ||
- op == TRACKER_PATH_OPERATOR_NEGATED, NULL);
+ op == TRACKER_PATH_OPERATOR_NEGATED ||
+ op == TRACKER_PATH_OPERATOR_NEGATED_INVERSE, NULL);
elem = g_new0 (TrackerPathElement, 1);
elem->op = op;
@@ -631,6 +632,9 @@ tracker_path_element_set_unique_name (TrackerPathElement *elem,
case TRACKER_PATH_OPERATOR_INTERSECTION:
name = "intersect";
break;
+ case TRACKER_PATH_OPERATOR_NEGATED_INVERSE:
+ name = "neg_inv";
+ break;
default:
g_assert_not_reached ();
}
diff --git a/src/libtracker-data/tracker-sparql-types.h b/src/libtracker-data/tracker-sparql-types.h
index 3829fd1d6..23bb06ea0 100644
--- a/src/libtracker-data/tracker-sparql-types.h
+++ b/src/libtracker-data/tracker-sparql-types.h
@@ -160,6 +160,7 @@ typedef enum {
TRACKER_PATH_OPERATOR_ZEROORMORE, /* * */
TRACKER_PATH_OPERATOR_NEGATED, /* ! */
TRACKER_PATH_OPERATOR_INTERSECTION, /* Used for negated paths */
+ TRACKER_PATH_OPERATOR_NEGATED_INVERSE, /* !^, used for negated paths */
} TrackerPathOperator;
struct _TrackerPathElement {
diff --git a/src/libtracker-data/tracker-sparql.c b/src/libtracker-data/tracker-sparql.c
index d32005212..98cd0711e 100644
--- a/src/libtracker-data/tracker-sparql.c
+++ b/src/libtracker-data/tracker-sparql.c
@@ -1093,12 +1093,22 @@ _prepend_path_element (TrackerSparql *sparql,
path_elem->data.composite.child1->name);
break;
case TRACKER_PATH_OPERATOR_NEGATED:
- _append_string_printf (sparql,
- "\"%s\" (ID, value, graph, ID_type, value_type) AS "
- "(SELECT subject AS ID, object AS value, graph, %d, object_type "
- "FROM \"tracker_triples\" ",
- path_elem->name,
- TRACKER_PROPERTY_TYPE_RESOURCE);
+ case TRACKER_PATH_OPERATOR_NEGATED_INVERSE:
+ if (path_elem->op == TRACKER_PATH_OPERATOR_NEGATED) {
+ _append_string_printf (sparql,
+ "\"%s\" (ID, value, graph, ID_type, value_type) AS "
+ "(SELECT subject AS ID, object_raw AS value, graph, %d, object_type "
+ "FROM \"tracker_triples\" ",
+ path_elem->name,
+ TRACKER_PROPERTY_TYPE_RESOURCE);
+ } else {
+ _append_string_printf (sparql,
+ "\"%s\" (ID, value, graph, ID_type, value_type) AS "
+ "(SELECT object_raw AS ID, subject AS value, graph, object_type, %d "
+ "FROM \"tracker_triples\" ",
+ path_elem->name,
+ TRACKER_PROPERTY_TYPE_RESOURCE);
+ }
if (!tracker_token_is_empty (&sparql->current_state->graph) &&
tracker_sparql_find_graph (sparql, tracker_token_get_idstring (&sparql->current_state->graph))) {
@@ -6928,6 +6938,45 @@ translate_PathPrimary (TrackerSparql *sparql,
return TRUE;
}
+static TrackerPathElement *
+intersect_path_elements (TrackerSparql *sparql,
+ GPtrArray *path_elems)
+{
+ TrackerPathElement *elem;
+
+ if (path_elems->len == 0)
+ return NULL;
+
+ if (path_elems->len == 1)
+ return g_ptr_array_index (path_elems, 0);
+
+ if (path_elems->len > 1) {
+ guint i;
+
+ elem = tracker_path_element_operator_new (TRACKER_PATH_OPERATOR_INTERSECTION,
+ tracker_token_get_idstring (&sparql->current_state->graph),
+ g_ptr_array_index (path_elems, 0),
+ g_ptr_array_index (path_elems, 1));
+ tracker_select_context_add_path_element (TRACKER_SELECT_CONTEXT (sparql->context),
+ elem);
+ _prepend_path_element (sparql, elem);
+
+ for (i = 2; i < path_elems->len; i++) {
+ TrackerPathElement *child;
+
+ child = g_ptr_array_index (path_elems, i);
+ elem = tracker_path_element_operator_new (TRACKER_PATH_OPERATOR_INTERSECTION,
+ tracker_token_get_idstring (&sparql->current_state->graph),
+ child, elem);
+ tracker_select_context_add_path_element (TRACKER_SELECT_CONTEXT (sparql->context),
+ elem);
+ _prepend_path_element (sparql, elem);
+ }
+ }
+
+ return elem;
+}
+
static gboolean
translate_PathNegatedPropertySet (TrackerSparql *sparql,
GError **error)
@@ -6939,45 +6988,47 @@ translate_PathNegatedPropertySet (TrackerSparql *sparql,
if (_check_in_rule (sparql, NAMED_RULE_PathOneInPropertySet))
_call_rule (sparql, NAMED_RULE_PathOneInPropertySet, error);
else if (_accept (sparql, RULE_TYPE_LITERAL, LITERAL_OPEN_PARENS)) {
- GPtrArray *path_elems;
+ TrackerPathElement *negated, *negated_inverse;
+ GPtrArray *negated_elems, *negated_inverse_elems;
- path_elems = g_ptr_array_new ();
+ negated_elems = g_ptr_array_new ();
+ negated_inverse_elems = g_ptr_array_new ();
- _call_rule (sparql, NAMED_RULE_PathEltOrInverse, error);
- g_ptr_array_add (path_elems, sparql->current_state->path);
+ _call_rule (sparql, NAMED_RULE_PathOneInPropertySet, error);
+ g_ptr_array_add (sparql->current_state->path->op == TRACKER_PATH_OPERATOR_NEGATED ?
+ negated_elems : negated_inverse_elems,
+ sparql->current_state->path);
- while (_check_in_rule (sparql, NAMED_RULE_PathOneInPropertySet)) {
+ while (_accept (sparql, RULE_TYPE_LITERAL, LITERAL_PATH_ALTERNATIVE)) {
_call_rule (sparql, NAMED_RULE_PathOneInPropertySet, error);
- g_ptr_array_add (path_elems, sparql->current_state->path);
+ g_ptr_array_add (sparql->current_state->path->op == TRACKER_PATH_OPERATOR_NEGATED ?
+ negated_elems : negated_inverse_elems,
+ sparql->current_state->path);
}
- if (path_elems->len > 1) {
- guint i;
+ negated = intersect_path_elements (sparql, negated_elems);
+ negated_inverse = intersect_path_elements (sparql, negated_inverse_elems);
- path_elem = tracker_path_element_operator_new (TRACKER_PATH_OPERATOR_INTERSECTION,
+ if (negated && negated_inverse) {
+ path_elem = tracker_path_element_operator_new (TRACKER_PATH_OPERATOR_ALTERNATIVE,
tracker_token_get_idstring (&sparql->current_state->graph),
- g_ptr_array_index (path_elems, 0),
- g_ptr_array_index (path_elems, 1));
+ negated, negated_inverse);
tracker_select_context_add_path_element (TRACKER_SELECT_CONTEXT (sparql->context),
path_elem);
_prepend_path_element (sparql, path_elem);
-
- for (i = 2; i < path_elems->len; i++) {
- TrackerPathElement *child;
-
- child = g_ptr_array_index (path_elems, i);
- path_elem = tracker_path_element_operator_new (TRACKER_PATH_OPERATOR_INTERSECTION,
- tracker_token_get_idstring (&sparql->current_state->graph),
- child, path_elem);
- tracker_select_context_add_path_element (TRACKER_SELECT_CONTEXT (sparql->context),
- path_elem);
- _prepend_path_element (sparql, path_elem);
- }
-
- sparql->current_state->path = path_elem;
+ } else if (negated) {
+ path_elem = negated;
+ } else if (negated_inverse) {
+ path_elem = negated_inverse;
+ } else {
+ g_assert_not_reached ();
}
+ sparql->current_state->path = path_elem;
+
_expect (sparql, RULE_TYPE_LITERAL, LITERAL_CLOSE_PARENS);
+ g_ptr_array_unref (negated_elems);
+ g_ptr_array_unref (negated_inverse_elems);
} else {
g_assert_not_reached ();
}
@@ -7024,7 +7075,9 @@ translate_PathOneInPropertySet (TrackerSparql *sparql,
prop);
if (!path_elem) {
- path_elem = tracker_path_element_property_new (TRACKER_PATH_OPERATOR_NEGATED,
+ path_elem = tracker_path_element_property_new (inverse ?
+ TRACKER_PATH_OPERATOR_NEGATED_INVERSE :
+ TRACKER_PATH_OPERATOR_NEGATED,
tracker_token_get_idstring (&sparql->current_state->graph),
prop);
tracker_select_context_add_path_element (TRACKER_SELECT_CONTEXT (sparql->context),
@@ -7038,17 +7091,6 @@ translate_PathOneInPropertySet (TrackerSparql *sparql,
g_assert_not_reached ();
}
- if (inverse) {
- path_elem = tracker_path_element_operator_new (TRACKER_PATH_OPERATOR_INVERSE,
- tracker_token_get_idstring (&sparql->current_state->graph),
- sparql->current_state->path,
- NULL);
- tracker_select_context_add_path_element (TRACKER_SELECT_CONTEXT (sparql->context),
- path_elem);
- _prepend_path_element (sparql, path_elem);
- sparql->current_state->path = path_elem;
- }
-
return TRUE;
}