summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarlos Garnacho <carlosg@gnome.org>2019-01-13 14:41:19 +0100
committerCarlos Garnacho <carlosg@gnome.org>2019-01-13 14:41:19 +0100
commit41ee9d363a4b670891d712ba37a045847e2a706b (patch)
treea3b464bb3b8ee57c4b88045395875024af060c4d
parentfd083be75fc9c46613d4d392f638c2b37e71a22a (diff)
parent7e09abe116b4dcedf177f3cf8f66ce347a4a8075 (diff)
downloadtracker-41ee9d363a4b670891d712ba37a045847e2a706b.tar.gz
Merge branch 'wip/carlosg/property-paths'
-rw-r--r--src/libtracker-data/tracker-sparql-types.c136
-rw-r--r--src/libtracker-data/tracker-sparql-types.h44
-rw-r--r--src/libtracker-data/tracker-sparql.c357
-rw-r--r--tests/libtracker-data/property-paths/alternative-path-1.out5
-rw-r--r--tests/libtracker-data/property-paths/alternative-path-1.rq1
-rw-r--r--tests/libtracker-data/property-paths/alternative-path-2.out1
-rw-r--r--tests/libtracker-data/property-paths/alternative-path-2.rq1
-rw-r--r--tests/libtracker-data/property-paths/inverse-path-1.out2
-rw-r--r--tests/libtracker-data/property-paths/inverse-path-1.rq2
-rw-r--r--tests/libtracker-data/property-paths/mixed-inverse-and-sequence-3.out2
-rw-r--r--tests/libtracker-data/property-paths/mixed-inverse-and-sequence-3.rq1
-rw-r--r--tests/libtracker-data/property-paths/mixed-recursive-and-alternative-1.out7
-rw-r--r--tests/libtracker-data/property-paths/mixed-recursive-and-alternative-1.rq1
-rw-r--r--tests/libtracker-data/property-paths/mixed-recursive-and-alternative-2.out7
-rw-r--r--tests/libtracker-data/property-paths/mixed-recursive-and-alternative-2.rq1
-rw-r--r--tests/libtracker-data/property-paths/mixed-recursive-and-inverse-1.out1
-rw-r--r--tests/libtracker-data/property-paths/mixed-recursive-and-inverse-1.rq1
-rw-r--r--tests/libtracker-data/property-paths/mixed-recursive-and-inverse-2.out1
-rw-r--r--tests/libtracker-data/property-paths/mixed-recursive-and-inverse-2.rq1
-rw-r--r--tests/libtracker-data/property-paths/mixed-recursive-and-inverse-3.out1
-rw-r--r--tests/libtracker-data/property-paths/mixed-recursive-and-inverse-3.rq1
-rw-r--r--tests/libtracker-data/property-paths/mixed-recursive-and-sequence-1.out2
-rw-r--r--tests/libtracker-data/property-paths/mixed-recursive-and-sequence-1.rq1
-rw-r--r--tests/libtracker-data/property-paths/optional-path-1.out2
-rw-r--r--tests/libtracker-data/property-paths/optional-path-1.rq1
-rw-r--r--tests/libtracker-data/property-paths/recursive-path-1.out2
-rw-r--r--tests/libtracker-data/property-paths/recursive-path-1.rq1
-rw-r--r--tests/libtracker-data/property-paths/recursive-path-2.out1
-rw-r--r--tests/libtracker-data/property-paths/recursive-path-2.rq1
-rw-r--r--tests/libtracker-data/property-paths/sequence-path-1.rq2
-rw-r--r--tests/libtracker-data/tracker-sparql-test.c14
31 files changed, 528 insertions, 73 deletions
diff --git a/src/libtracker-data/tracker-sparql-types.c b/src/libtracker-data/tracker-sparql-types.c
index 1c6125f0f..c3c8eae3c 100644
--- a/src/libtracker-data/tracker-sparql-types.c
+++ b/src/libtracker-data/tracker-sparql-types.c
@@ -27,6 +27,7 @@ enum {
TOKEN_TYPE_LITERAL,
TOKEN_TYPE_VARIABLE,
TOKEN_TYPE_PARAMETER,
+ TOKEN_TYPE_PATH,
};
/* Helper structs */
@@ -198,6 +199,14 @@ tracker_token_parameter_init (TrackerToken *token,
}
void
+tracker_token_path_init (TrackerToken *token,
+ TrackerPathElement *path)
+{
+ token->type = TOKEN_TYPE_PATH;
+ token->content.path = path;
+}
+
+void
tracker_token_unset (TrackerToken *token)
{
if (token->type == TOKEN_TYPE_LITERAL)
@@ -237,6 +246,14 @@ tracker_token_get_parameter (TrackerToken *token)
return NULL;
}
+TrackerPathElement *
+tracker_token_get_path (TrackerToken *token)
+{
+ if (token->type == TOKEN_TYPE_PATH)
+ return token->content.path;
+ return NULL;
+}
+
const gchar *
tracker_token_get_idstring (TrackerToken *token)
{
@@ -244,6 +261,8 @@ tracker_token_get_idstring (TrackerToken *token)
return token->content.literal;
else if (token->type == TOKEN_TYPE_VARIABLE)
return token->content.var->sql_expression;
+ else if (token->type == TOKEN_TYPE_PATH)
+ return token->content.path->name;
else
return NULL;
}
@@ -530,6 +549,86 @@ tracker_variable_binding_get_class (TrackerVariableBinding *binding)
return binding->type;
}
+/* Path element */
+static void
+tracker_path_element_free (TrackerPathElement *elem)
+{
+ g_free (elem->name);
+ g_free (elem);
+}
+
+TrackerPathElement *
+tracker_path_element_property_new (TrackerProperty *prop)
+{
+ TrackerPathElement *elem;
+
+ g_return_val_if_fail (TRACKER_IS_PROPERTY (prop), NULL);
+
+ elem = g_new0 (TrackerPathElement, 1);
+ elem->op = TRACKER_PATH_OPERATOR_NONE;
+ elem->type = tracker_property_get_data_type (prop);
+ elem->data.property = prop;
+
+ return elem;
+}
+
+TrackerPathElement *
+tracker_path_element_operator_new (TrackerPathOperator op,
+ TrackerPathElement *child1,
+ TrackerPathElement *child2)
+{
+ TrackerPathElement *elem;
+
+ g_return_val_if_fail (op != TRACKER_PATH_OPERATOR_NONE, NULL);
+ g_return_val_if_fail (child1 != NULL, NULL);
+ g_return_val_if_fail (child2 == NULL ||
+ op == TRACKER_PATH_OPERATOR_SEQUENCE ||
+ op == TRACKER_PATH_OPERATOR_ALTERNATIVE, NULL);
+
+ elem = g_new0 (TrackerPathElement, 1);
+ elem->op = op;
+ elem->data.composite.child1 = child1;
+ elem->data.composite.child2 = child2;
+ elem->type = child2 ? child2->type : child1->type;
+
+ return elem;
+}
+
+static void
+tracker_path_element_set_unique_name (TrackerPathElement *elem,
+ gint id)
+{
+ const gchar *name = NULL;
+
+ switch (elem->op) {
+ case TRACKER_PATH_OPERATOR_NONE:
+ name = tracker_property_get_name (elem->data.property);
+ break;
+ case TRACKER_PATH_OPERATOR_INVERSE:
+ name = "inv";
+ break;
+ case TRACKER_PATH_OPERATOR_SEQUENCE:
+ name = "seq";
+ break;
+ case TRACKER_PATH_OPERATOR_ALTERNATIVE:
+ name = "alt";
+ break;
+ case TRACKER_PATH_OPERATOR_ZEROORONE:
+ name = "zeroorone";
+ break;
+ case TRACKER_PATH_OPERATOR_ZEROORMORE:
+ name = "zeroormore";
+ break;
+ case TRACKER_PATH_OPERATOR_ONEORMORE:
+ name = "oneormore";
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ elem->name = g_strdup_printf ("p%d_%s", id, name);
+}
+
/* Context */
G_DEFINE_TYPE (TrackerContext, tracker_context, G_TYPE_INITIALLY_UNOWNED)
@@ -627,6 +726,7 @@ tracker_select_context_finalize (GObject *object)
g_clear_pointer (&context->predicate_variables, g_hash_table_unref);
g_clear_pointer (&context->generated_variables, g_ptr_array_unref);
g_clear_pointer (&context->literal_bindings, g_ptr_array_unref);
+ g_clear_pointer (&context->path_elements, g_ptr_array_unref);
G_OBJECT_CLASS (tracker_select_context_parent_class)->finalize (object);
}
@@ -759,6 +859,42 @@ tracker_select_context_get_literal_binding_index (TrackerSelectContext *context
return -1;
}
+void
+tracker_select_context_add_path_element (TrackerSelectContext *context,
+ TrackerPathElement *path_elem)
+{
+ if (!context->path_elements) {
+ context->path_elements =
+ g_ptr_array_new_with_free_func ((GDestroyNotify) tracker_path_element_free);
+ }
+
+ g_ptr_array_add (context->path_elements, path_elem);
+ tracker_path_element_set_unique_name (path_elem,
+ context->path_elements->len);
+}
+
+TrackerPathElement *
+tracker_select_context_lookup_path_element_for_property (TrackerSelectContext *context,
+ TrackerProperty *property)
+{
+ guint i;
+
+ if (!context->path_elements)
+ return NULL;
+
+ for (i = 0; i < context->path_elements->len; i++) {
+ TrackerPathElement *path_elem;
+
+ path_elem = g_ptr_array_index (context->path_elements, i);
+
+ if (path_elem->op == TRACKER_PATH_OPERATOR_NONE &&
+ path_elem->data.property == property)
+ return path_elem;
+ }
+
+ return NULL;
+}
+
/* Triple context */
G_DEFINE_TYPE (TrackerTripleContext, tracker_triple_context, TRACKER_TYPE_CONTEXT)
diff --git a/src/libtracker-data/tracker-sparql-types.h b/src/libtracker-data/tracker-sparql-types.h
index 1df06764c..bf3484475 100644
--- a/src/libtracker-data/tracker-sparql-types.h
+++ b/src/libtracker-data/tracker-sparql-types.h
@@ -70,6 +70,7 @@ typedef struct _TrackerDataTable TrackerDataTable;
typedef struct _TrackerVariable TrackerVariable;
typedef struct _TrackerToken TrackerToken;
typedef struct _TrackerSolution TrackerSolution;
+typedef struct _TrackerPathElement TrackerPathElement;
typedef struct _TrackerPredicateVariable TrackerPredicateVariable;
struct _TrackerDataTable {
@@ -135,6 +136,7 @@ struct _TrackerToken {
gchar *literal;
gchar *parameter;
TrackerVariable *var;
+ TrackerPathElement *path;
} content;
};
@@ -153,6 +155,30 @@ struct _TrackerSolution {
int n_cols;
};
+typedef enum {
+ TRACKER_PATH_OPERATOR_NONE,
+ TRACKER_PATH_OPERATOR_INVERSE, /* ^ */
+ TRACKER_PATH_OPERATOR_SEQUENCE, /* / */
+ TRACKER_PATH_OPERATOR_ALTERNATIVE, /* | */
+ TRACKER_PATH_OPERATOR_ZEROORONE, /* ? */
+ TRACKER_PATH_OPERATOR_ONEORMORE, /* + */
+ TRACKER_PATH_OPERATOR_ZEROORMORE, /* * */
+} TrackerPathOperator;
+
+struct _TrackerPathElement {
+ TrackerPathOperator op;
+ TrackerPropertyType type;
+ gchar *name;
+
+ union {
+ TrackerProperty *property;
+ struct {
+ TrackerPathElement *child1;
+ TrackerPathElement *child2;
+ } composite;
+ } data;
+};
+
struct _TrackerContext {
GInitiallyUnowned parent_instance;
TrackerContext *parent;
@@ -190,6 +216,9 @@ struct _TrackerSelectContext {
/* Type to propagate upwards */
TrackerPropertyType type;
+
+ /* Property path elements */
+ GPtrArray *path_elements;
};
struct _TrackerSelectContextClass {
@@ -275,7 +304,9 @@ void tracker_token_literal_init (TrackerToken *token,
void tracker_token_variable_init (TrackerToken *token,
TrackerVariable *variable);
void tracker_token_parameter_init (TrackerToken *token,
- const gchar *pameter);
+ const gchar *parameter);
+void tracker_token_path_init (TrackerToken *token,
+ TrackerPathElement *path_elem);
void tracker_token_unset (TrackerToken *token);
gboolean tracker_token_is_empty (TrackerToken *token);
@@ -283,6 +314,7 @@ const gchar * tracker_token_get_literal (TrackerToken *token);
TrackerVariable * tracker_token_get_variable (TrackerToken *token);
const gchar * tracker_token_get_idstring (TrackerToken *token);
const gchar * tracker_token_get_parameter (TrackerToken *token);
+TrackerPathElement * tracker_token_get_path (TrackerToken *token);
/* Predicate variable */
TrackerPredicateVariable *tracker_predicate_variable_new (void);
@@ -306,6 +338,11 @@ void tracker_solution_add_value (TrackerSolution *solution,
const gchar *str);
GHashTable * tracker_solution_get_bindings (TrackerSolution *solution);
+/* Property path element */
+TrackerPathElement * tracker_path_element_property_new (TrackerProperty *prop);
+TrackerPathElement * tracker_path_element_operator_new (TrackerPathOperator op,
+ TrackerPathElement *child1,
+ TrackerPathElement *child2);
/* Context */
GType tracker_context_get_type (void) G_GNUC_CONST;
@@ -338,6 +375,11 @@ void tracker_select_context_add_literal_binding (TrackerSelectContext *context,
TrackerLiteralBinding *binding);
guint tracker_select_context_get_literal_binding_index (TrackerSelectContext *context,
TrackerLiteralBinding *binding);
+void tracker_select_context_add_path_element (TrackerSelectContext *context,
+ TrackerPathElement *path_elem);
+TrackerPathElement *
+ tracker_select_context_lookup_path_element_for_property (TrackerSelectContext *context,
+ TrackerProperty *property);
/* Triple context */
GType tracker_triple_context_get_type (void) G_GNUC_CONST;
diff --git a/src/libtracker-data/tracker-sparql.c b/src/libtracker-data/tracker-sparql.c
index db60aa822..d123c6330 100644
--- a/src/libtracker-data/tracker-sparql.c
+++ b/src/libtracker-data/tracker-sparql.c
@@ -126,9 +126,9 @@ struct _TrackerSparql
TrackerContext *context;
TrackerContext *select_context;
TrackerStringBuilder *sql;
+ TrackerStringBuilder *with_clauses;
TrackerParserNode *node;
TrackerParserNode *prev_node;
- TrackerParserNode *object_list;
TrackerToken graph;
TrackerToken subject;
@@ -137,6 +137,8 @@ struct _TrackerSparql
TrackerToken *token;
+ TrackerPathElement *path;
+
GHashTable *blank_node_map;
const gchar *expression_list_separator;
@@ -527,6 +529,104 @@ _append_variable_sql (TrackerSparql *sparql,
}
}
+static void
+_prepend_path_element (TrackerSparql *sparql,
+ TrackerPathElement *path_elem)
+{
+ TrackerStringBuilder *old;
+
+ old = tracker_sparql_swap_builder (sparql, sparql->current_state.with_clauses);
+
+ if (tracker_string_builder_is_empty (sparql->current_state.with_clauses))
+ _append_string (sparql, "WITH ");
+ else
+ _append_string (sparql, ", ");
+
+ switch (path_elem->op) {
+ case TRACKER_PATH_OPERATOR_NONE:
+ /* A simple property */
+ _append_string_printf (sparql,
+ "\"%s\" (ID, value, graph) AS "
+ "(SELECT ID, \"%s\", \"%s:graph\" FROM \"%s\") ",
+ path_elem->name,
+ tracker_property_get_name (path_elem->data.property),
+ tracker_property_get_name (path_elem->data.property),
+ tracker_property_get_table_name (path_elem->data.property));
+ break;
+ case TRACKER_PATH_OPERATOR_INVERSE:
+ _append_string_printf (sparql,
+ "\"%s\" (ID, value, graph) AS "
+ "(SELECT value, ID, graph FROM \"%s\" WHERE value IS NOT NULL) ",
+ path_elem->name,
+ path_elem->data.composite.child1->name);
+ break;
+ case TRACKER_PATH_OPERATOR_SEQUENCE:
+ _append_string_printf (sparql,
+ "\"%s\" (ID, value, graph) AS "
+ "(SELECT a.ID, b.value, b.graph "
+ "FROM \"%s\" AS a, \"%s\" AS b "
+ "WHERE a.value = b.ID) ",
+ path_elem->name,
+ path_elem->data.composite.child1->name,
+ path_elem->data.composite.child2->name);
+ break;
+ case TRACKER_PATH_OPERATOR_ALTERNATIVE:
+ _append_string_printf (sparql,
+ "\"%s\" (ID, value, graph) AS "
+ "(SELECT ID, value, graph "
+ "FROM \"%s\" "
+ "UNION ALL "
+ "SELECT ID, value, graph "
+ "FROM \"%s\") ",
+ path_elem->name,
+ path_elem->data.composite.child1->name,
+ path_elem->data.composite.child2->name);
+ break;
+ case TRACKER_PATH_OPERATOR_ZEROORMORE:
+ _append_string_printf (sparql,
+ "\"%s\" (ID, value, graph) AS "
+ "(SELECT ID, ID, graph "
+ "FROM \"%s\" "
+ "UNION "
+ "SELECT a.ID, b.value, b.graph "
+ "FROM \"%s\" AS a, \"%s\" AS b "
+ "WHERE b.ID = a.value) ",
+ path_elem->name,
+ path_elem->data.composite.child1->name,
+ path_elem->data.composite.child1->name,
+ path_elem->name);
+ break;
+ case TRACKER_PATH_OPERATOR_ONEORMORE:
+ _append_string_printf (sparql,
+ "\"%s\" (ID, value, graph) AS "
+ "(SELECT ID, value, graph "
+ "FROM \"%s\" "
+ "UNION "
+ "SELECT a.ID, b.value, b.graph "
+ "FROM \"%s\" AS a, \"%s\" AS b "
+ "WHERE b.ID = a.value) ",
+ path_elem->name,
+ path_elem->data.composite.child1->name,
+ path_elem->data.composite.child1->name,
+ path_elem->name);
+ break;
+ case TRACKER_PATH_OPERATOR_ZEROORONE:
+ _append_string_printf (sparql,
+ "\"%s\" (ID, value, graph) AS "
+ "(SELECT ID, ID, graph "
+ "FROM \"%s\" "
+ "UNION ALL "
+ "SELECT ID, value, graph "
+ "FROM \"%s\") ",
+ path_elem->name,
+ path_elem->data.composite.child1->name,
+ path_elem->data.composite.child1->name);
+ break;
+ }
+
+ tracker_sparql_swap_builder (sparql, old);
+}
+
static inline gchar *
_extract_node_string (TrackerParserNode *node,
TrackerSparql *sparql)
@@ -1082,6 +1182,11 @@ _add_quad (TrackerSparql *sparql,
if (!tracker_token_is_empty (graph))
pred_var->return_graph = TRUE;
+ } else if (tracker_token_get_path (predicate)) {
+ table = tracker_triple_context_add_table (triple_context,
+ "value",
+ tracker_token_get_idstring (predicate));
+ new_table = TRUE;
} else {
/* The parser disallows parameter predicates */
g_assert_not_reached ();
@@ -1122,6 +1227,13 @@ _add_quad (TrackerSparql *sparql,
tracker_binding_set_data_type (binding, TRACKER_PROPERTY_TYPE_STRING);
tracker_binding_set_db_column_name (binding, "object");
tracker_variable_binding_set_nullable (TRACKER_VARIABLE_BINDING (binding), TRUE);
+ } else if (tracker_token_get_path (predicate)) {
+ TrackerPathElement *path;
+
+ path = tracker_token_get_path (predicate);
+ tracker_binding_set_data_type (binding, path->type);
+ tracker_binding_set_db_column_name (binding, "value");
+ tracker_variable_binding_set_nullable (TRACKER_VARIABLE_BINDING (binding), TRUE);
} else {
g_assert (property != NULL);
tracker_binding_set_data_type (binding, tracker_property_get_data_type (property));
@@ -1221,6 +1333,12 @@ _add_quad (TrackerSparql *sparql,
if (tracker_token_get_variable (predicate)) {
tracker_binding_set_db_column_name (binding, "object");
+ } else if (tracker_token_get_path (predicate)) {
+ TrackerPathElement *path;
+
+ path = tracker_token_get_path (predicate);
+ tracker_binding_set_db_column_name (binding, "value");
+ tracker_binding_set_data_type (binding, path->type);
} else {
g_assert (property != NULL);
tracker_binding_set_data_type (binding, tracker_property_get_data_type (property));
@@ -1246,7 +1364,8 @@ _add_quad (TrackerSparql *sparql,
tracker_binding_set_data_type (binding, TRACKER_PROPERTY_TYPE_RESOURCE);
- if (tracker_token_get_variable (predicate)) {
+ if (tracker_token_get_variable (predicate) ||
+ tracker_token_get_path (predicate)) {
tracker_binding_set_db_column_name (binding, "graph");
} else {
gchar *column_name;
@@ -2730,6 +2849,7 @@ get_solution_for_pattern (TrackerSparql *sparql,
g_clear_pointer (&sparql->sql, tracker_string_builder_free);
sparql->sql = tracker_string_builder_new ();
tracker_sparql_swap_builder (sparql, sparql->sql);
+ sparql->current_state.with_clauses = _prepend_placeholder (sparql);
retval = prepare_solution_select (sparql, pattern, error);
tracker_sparql_pop_context (sparql, FALSE);
@@ -3967,7 +4087,6 @@ translate_PropertyListPathNotEmpty (TrackerSparql *sparql,
{
TrackerGrammarNamedRule rule;
TrackerToken old_predicate, *prev_token;
- TrackerParserNode *verb;
/* PropertyListPathNotEmpty ::= ( VerbPath | VerbSimple ) ObjectListPath ( ';' ( ( VerbPath | VerbSimple ) ObjectList )? )*
*/
@@ -3977,30 +4096,24 @@ translate_PropertyListPathNotEmpty (TrackerSparql *sparql,
sparql->current_state.token = &sparql->current_state.object;
if (rule == NAMED_RULE_VerbPath || rule == NAMED_RULE_VerbSimple) {
- verb = _skip_rule (sparql, rule);
+ _call_rule (sparql, rule, error);
} else {
g_assert_not_reached ();
}
- sparql->current_state.object_list = _skip_rule (sparql, NAMED_RULE_ObjectListPath);
- if (!_postprocess_rule (sparql, verb, NULL, error))
- return FALSE;
-
+ _call_rule (sparql, NAMED_RULE_ObjectListPath, error);
tracker_token_unset (&sparql->current_state.predicate);
while (_accept (sparql, RULE_TYPE_LITERAL, LITERAL_SEMICOLON)) {
rule = _current_rule (sparql);
if (rule == NAMED_RULE_VerbPath || rule == NAMED_RULE_VerbSimple) {
- verb = _skip_rule (sparql, rule);
+ _call_rule (sparql, rule, error);
} else {
break;
}
- sparql->current_state.object_list = _skip_rule (sparql, NAMED_RULE_ObjectList);
- if (!_postprocess_rule (sparql, verb, NULL, error))
- return FALSE;
-
+ _call_rule (sparql, NAMED_RULE_ObjectList, error);
tracker_token_unset (&sparql->current_state.predicate);
}
@@ -4016,7 +4129,27 @@ translate_VerbPath (TrackerSparql *sparql,
{
/* VerbPath ::= Path
*/
- _call_rule (sparql, NAMED_RULE_Path, error);
+
+ /* If this path consists of a single element, do not set
+ * up a property path. Just set the property token to
+ * be the only property literal and let _add_quad()
+ * apply its optimizations.
+ */
+ if (g_node_n_nodes ((GNode *) sparql->current_state.node,
+ G_TRAVERSE_LEAVES) == 1) {
+ TrackerParserNode *prop;
+ gchar *str;
+
+ prop = tracker_sparql_parser_tree_find_first (sparql->current_state.node, TRUE);
+ str = _extract_node_string (prop, sparql);
+ tracker_token_literal_init (&sparql->current_state.predicate, str);
+ g_free (str);
+
+ _skip_rule (sparql, NAMED_RULE_Path);
+ } else {
+ _call_rule (sparql, NAMED_RULE_Path, error);
+ sparql->current_state.path = NULL;
+ }
return TRUE;
}
@@ -4030,11 +4163,6 @@ translate_VerbSimple (TrackerSparql *sparql,
_call_rule (sparql, NAMED_RULE_Var, error);
_init_token (&sparql->current_state.predicate,
sparql->current_state.prev_node, sparql);
-
- if (!_postprocess_rule (sparql, sparql->current_state.object_list,
- NULL, error))
- return FALSE;
-
return TRUE;
}
@@ -4071,7 +4199,8 @@ translate_Path (TrackerSparql *sparql,
/* Path ::= PathAlternative
*/
_call_rule (sparql, NAMED_RULE_PathAlternative, error);
-
+ tracker_token_path_init (&sparql->current_state.predicate,
+ sparql->current_state.path);
return TRUE;
}
@@ -4079,14 +4208,47 @@ static gboolean
translate_PathAlternative (TrackerSparql *sparql,
GError **error)
{
+ GPtrArray *path_elems;
+
+ path_elems = g_ptr_array_new ();
+
/* PathAlternative ::= PathSequence ( '|' PathSequence )*
*/
_call_rule (sparql, NAMED_RULE_PathSequence, error);
+ g_ptr_array_add (path_elems, sparql->current_state.path);
- if (_accept (sparql, RULE_TYPE_LITERAL, LITERAL_PATH_ALTERNATIVE)) {
- _unimplemented ("Alternative property path");
+ while (_accept (sparql, RULE_TYPE_LITERAL, LITERAL_PATH_ALTERNATIVE)) {
+ _call_rule (sparql, NAMED_RULE_PathSequence, error);
+ g_ptr_array_add (path_elems, sparql->current_state.path);
}
+ if (path_elems->len > 1) {
+ TrackerPathElement *path_elem;
+ gint i;
+
+ path_elem = tracker_path_element_operator_new (TRACKER_PATH_OPERATOR_ALTERNATIVE,
+ 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),
+ 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_ALTERNATIVE,
+ 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;
+ }
+
+ g_ptr_array_unref (path_elems);
+
return TRUE;
}
@@ -4094,34 +4256,49 @@ static gboolean
translate_PathSequence (TrackerSparql *sparql,
GError **error)
{
- TrackerToken old_object, old_subject;
- TrackerVariable *var;
- TrackerParserNode *rule;
+ GPtrArray *path_elems;
+
+ path_elems = g_ptr_array_new ();
/* PathSequence ::= PathEltOrInverse ( '/' PathEltOrInverse )*
*/
- old_object = sparql->current_state.object;
- old_subject = sparql->current_state.subject;
-
- rule = _skip_rule (sparql, NAMED_RULE_PathEltOrInverse);
+ _call_rule (sparql, NAMED_RULE_PathEltOrInverse, error);
+ g_ptr_array_add (path_elems, sparql->current_state.path);
while (_accept (sparql, RULE_TYPE_LITERAL, LITERAL_PATH_SEQUENCE)) {
- var = tracker_select_context_add_generated_variable (TRACKER_SELECT_CONTEXT (sparql->context));
- tracker_token_variable_init (&sparql->current_state.object, var);
+ _call_rule (sparql, NAMED_RULE_PathEltOrInverse, error);
+ g_ptr_array_add (path_elems, sparql->current_state.path);
+ }
- if (!_postprocess_rule (sparql, rule, NULL, error))
- return FALSE;
+ if (path_elems->len > 1) {
+ TrackerPathElement *path_elem;
+ gint i;
- rule = _skip_rule (sparql, NAMED_RULE_PathEltOrInverse);
- sparql->current_state.subject = sparql->current_state.object;
- tracker_token_unset (&sparql->current_state.object);
- }
+ /* We must handle path elements in inverse order, paired to
+ * the path element created in the previous step.
+ */
+ path_elem = tracker_path_element_operator_new (TRACKER_PATH_OPERATOR_SEQUENCE,
+ g_ptr_array_index (path_elems, path_elems->len - 2),
+ g_ptr_array_index (path_elems, path_elems->len - 1));
+ tracker_select_context_add_path_element (TRACKER_SELECT_CONTEXT (sparql->context),
+ path_elem);
+ _prepend_path_element (sparql, path_elem);
+
+ for (i = ((gint) path_elems->len) - 3; i >= 0; i--) {
+ TrackerPathElement *child;
+
+ child = g_ptr_array_index (path_elems, i);
+ path_elem = tracker_path_element_operator_new (TRACKER_PATH_OPERATOR_SEQUENCE,
+ child, path_elem);
+ tracker_select_context_add_path_element (TRACKER_SELECT_CONTEXT (sparql->context),
+ path_elem);
+ _prepend_path_element (sparql, path_elem);
+ }
- if (!_postprocess_rule (sparql, rule, NULL, error))
- return FALSE;
+ sparql->current_state.path = path_elem;
+ }
- sparql->current_state.subject = old_subject;
- sparql->current_state.object = old_object;
+ g_ptr_array_unref (path_elems);
return TRUE;
}
@@ -4130,25 +4307,26 @@ static gboolean
translate_PathEltOrInverse (TrackerSparql *sparql,
GError **error)
{
- TrackerToken old_object, old_subject, *old_token;
+ gboolean inverse = FALSE;
/* PathEltOrInverse ::= PathElt | '^' PathElt
*/
- old_object = sparql->current_state.object;
- old_subject = sparql->current_state.subject;
- old_token = sparql->current_state.token;
-
- if (_accept (sparql, RULE_TYPE_LITERAL, LITERAL_PATH_INVERSE)) {
- sparql->current_state.object = old_subject;
- sparql->current_state.subject = old_object;
- sparql->current_state.token = &sparql->current_state.subject;
- }
+ if (_accept (sparql, RULE_TYPE_LITERAL, LITERAL_PATH_INVERSE))
+ inverse = TRUE;
_call_rule (sparql, NAMED_RULE_PathElt, error);
- sparql->current_state.subject = old_subject;
- sparql->current_state.object = old_object;
- sparql->current_state.token = old_token;
+ if (inverse) {
+ TrackerPathElement *path_elem;
+
+ path_elem = tracker_path_element_operator_new (TRACKER_PATH_OPERATOR_INVERSE,
+ 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;
}
@@ -4167,26 +4345,34 @@ translate_PathElt (TrackerSparql *sparql,
_call_rule (sparql, NAMED_RULE_PathMod, error);
}
- if (!tracker_token_is_empty (sparql->current_state.token)) {
- return _add_quad (sparql,
- &sparql->current_state.graph,
- &sparql->current_state.subject,
- &sparql->current_state.predicate,
- &sparql->current_state.object,
- error);
- } else {
- return _postprocess_rule (sparql, sparql->current_state.object_list,
- NULL, error);
- }
+ return TRUE;
}
static gboolean
translate_PathMod (TrackerSparql *sparql,
GError **error)
{
+ TrackerPathElement *path_elem;
+ TrackerPathOperator op;
+
/* PathMod ::= '?' | '*' | '+'
*/
- _unimplemented ("Path modifiers");
+ if (_accept (sparql, RULE_TYPE_LITERAL, LITERAL_PATH_STAR)) {
+ op = TRACKER_PATH_OPERATOR_ZEROORMORE;
+ } else if (_accept (sparql, RULE_TYPE_LITERAL, LITERAL_PATH_PLUS)) {
+ op = TRACKER_PATH_OPERATOR_ONEORMORE;
+ } else if (_accept (sparql, RULE_TYPE_LITERAL, LITERAL_PATH_OPTIONAL)) {
+ op = TRACKER_PATH_OPERATOR_ZEROORONE;
+ } else {
+ return TRUE;
+ }
+
+ path_elem = tracker_path_element_operator_new (op, 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;
}
static gboolean
@@ -4201,10 +4387,41 @@ translate_PathPrimary (TrackerSparql *sparql,
_call_rule (sparql, NAMED_RULE_Path, error);
_expect (sparql, RULE_TYPE_LITERAL, LITERAL_CLOSE_PARENS);
- } else if (_accept (sparql, RULE_TYPE_LITERAL, LITERAL_A)) {
+ } else if (_accept (sparql, RULE_TYPE_LITERAL, LITERAL_A) ||
+ _check_in_rule (sparql, NAMED_RULE_iri)) {
+ TrackerOntologies *ontologies;
+ TrackerProperty *prop;
+ TrackerPathElement *path_elem;
+ gchar *str;
- } else if (_check_in_rule (sparql, NAMED_RULE_iri)) {
- _call_rule (sparql, NAMED_RULE_iri, error);
+ if (_check_in_rule (sparql, NAMED_RULE_iri))
+ _call_rule (sparql, NAMED_RULE_iri, error);
+
+ str = _dup_last_string (sparql);
+ ontologies = tracker_data_manager_get_ontologies (sparql->data_manager);
+ prop = tracker_ontologies_get_property_by_uri (ontologies, str);
+
+ if (!prop) {
+ g_set_error (error, TRACKER_SPARQL_ERROR,
+ TRACKER_SPARQL_ERROR_UNKNOWN_PROPERTY,
+ "Unknown property '%s'", str);
+ g_free (str);
+ return FALSE;
+ }
+
+ path_elem =
+ tracker_select_context_lookup_path_element_for_property (TRACKER_SELECT_CONTEXT (sparql->context),
+ prop);
+
+ if (!path_elem) {
+ path_elem = tracker_path_element_property_new (prop);
+ 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;
+ g_free (str);
} else {
g_assert_not_reached ();
}
@@ -6520,6 +6737,7 @@ tracker_sparql_new (TrackerDataManager *manager,
sparql->current_state.node = tracker_node_tree_get_root (sparql->tree);
sparql->current_state.sql = sparql->sql;
+ sparql->current_state.with_clauses = _prepend_placeholder (sparql);
}
return sparql;
@@ -6697,6 +6915,7 @@ tracker_sparql_new_update (TrackerDataManager *manager,
sparql->current_state.node = tracker_node_tree_get_root (sparql->tree);
sparql->current_state.sql = sparql->sql;
+ sparql->current_state.with_clauses = _prepend_placeholder (sparql);
}
return sparql;
diff --git a/tests/libtracker-data/property-paths/alternative-path-1.out b/tests/libtracker-data/property-paths/alternative-path-1.out
new file mode 100644
index 000000000..d4ba27789
--- /dev/null
+++ b/tests/libtracker-data/property-paths/alternative-path-1.out
@@ -0,0 +1,5 @@
+"Alice" "Bob"
+"Alice" "Foo"
+"Bob" "Alice"
+"Bob" "Foo"
+"Eve" "Fred"
diff --git a/tests/libtracker-data/property-paths/alternative-path-1.rq b/tests/libtracker-data/property-paths/alternative-path-1.rq
new file mode 100644
index 000000000..ddd3a0732
--- /dev/null
+++ b/tests/libtracker-data/property-paths/alternative-path-1.rq
@@ -0,0 +1 @@
+select foaf:name(?u) foaf:name(?a) { ?u a foaf:Person . ?u foaf:knows|foaf:member ?a } order by foaf:name(?u) foaf:name(?a) \ No newline at end of file
diff --git a/tests/libtracker-data/property-paths/alternative-path-2.out b/tests/libtracker-data/property-paths/alternative-path-2.out
new file mode 100644
index 000000000..ef0350743
--- /dev/null
+++ b/tests/libtracker-data/property-paths/alternative-path-2.out
@@ -0,0 +1 @@
+"Alice"
diff --git a/tests/libtracker-data/property-paths/alternative-path-2.rq b/tests/libtracker-data/property-paths/alternative-path-2.rq
new file mode 100644
index 000000000..b90ecc092
--- /dev/null
+++ b/tests/libtracker-data/property-paths/alternative-path-2.rq
@@ -0,0 +1 @@
+select foaf:name(?u) { ?u a foaf:Person . ?u foaf:name|(foaf:member/foaf:name) "Alice" } order by foaf:name(?u) \ No newline at end of file
diff --git a/tests/libtracker-data/property-paths/inverse-path-1.out b/tests/libtracker-data/property-paths/inverse-path-1.out
index 0a9f74d4f..9f47bc3b5 100644
--- a/tests/libtracker-data/property-paths/inverse-path-1.out
+++ b/tests/libtracker-data/property-paths/inverse-path-1.out
@@ -1,3 +1,3 @@
-"Bob" "Alice"
"Alice" "Bob"
+"Bob" "Alice"
"Fred" "Eve"
diff --git a/tests/libtracker-data/property-paths/inverse-path-1.rq b/tests/libtracker-data/property-paths/inverse-path-1.rq
index 1aaf070ce..6b643dfd7 100644
--- a/tests/libtracker-data/property-paths/inverse-path-1.rq
+++ b/tests/libtracker-data/property-paths/inverse-path-1.rq
@@ -1 +1 @@
-select foaf:name(?a) foaf:name(?b) { ?a ^foaf:knows ?b } \ No newline at end of file
+select foaf:name(?a) foaf:name(?b) { ?a ^foaf:knows ?b } order by foaf:name(?a) foaf:name(?b) \ No newline at end of file
diff --git a/tests/libtracker-data/property-paths/mixed-inverse-and-sequence-3.out b/tests/libtracker-data/property-paths/mixed-inverse-and-sequence-3.out
new file mode 100644
index 000000000..d12a7b1c3
--- /dev/null
+++ b/tests/libtracker-data/property-paths/mixed-inverse-and-sequence-3.out
@@ -0,0 +1,2 @@
+"Alice" "Alice"
+"Bob" "Bob"
diff --git a/tests/libtracker-data/property-paths/mixed-inverse-and-sequence-3.rq b/tests/libtracker-data/property-paths/mixed-inverse-and-sequence-3.rq
new file mode 100644
index 000000000..3383f36b8
--- /dev/null
+++ b/tests/libtracker-data/property-paths/mixed-inverse-and-sequence-3.rq
@@ -0,0 +1 @@
+select foaf:name(?a) foaf:name(?b) { ?a ^(foaf:knows/foaf:knows) ?b } order by foaf:name(?a) foaf:name(?b) \ No newline at end of file
diff --git a/tests/libtracker-data/property-paths/mixed-recursive-and-alternative-1.out b/tests/libtracker-data/property-paths/mixed-recursive-and-alternative-1.out
new file mode 100644
index 000000000..878be5329
--- /dev/null
+++ b/tests/libtracker-data/property-paths/mixed-recursive-and-alternative-1.out
@@ -0,0 +1,7 @@
+"Alice" "Alice"
+"Alice" "Bob"
+"Alice" "Foo"
+"Bob" "Alice"
+"Bob" "Bob"
+"Bob" "Foo"
+"Eve" "Fred"
diff --git a/tests/libtracker-data/property-paths/mixed-recursive-and-alternative-1.rq b/tests/libtracker-data/property-paths/mixed-recursive-and-alternative-1.rq
new file mode 100644
index 000000000..44d2d7f88
--- /dev/null
+++ b/tests/libtracker-data/property-paths/mixed-recursive-and-alternative-1.rq
@@ -0,0 +1 @@
+select foaf:name(?u) foaf:name(?a) { ?u foaf:knows+|foaf:member ?a } order by foaf:name(?u) foaf:name(?a) \ No newline at end of file
diff --git a/tests/libtracker-data/property-paths/mixed-recursive-and-alternative-2.out b/tests/libtracker-data/property-paths/mixed-recursive-and-alternative-2.out
new file mode 100644
index 000000000..878be5329
--- /dev/null
+++ b/tests/libtracker-data/property-paths/mixed-recursive-and-alternative-2.out
@@ -0,0 +1,7 @@
+"Alice" "Alice"
+"Alice" "Bob"
+"Alice" "Foo"
+"Bob" "Alice"
+"Bob" "Bob"
+"Bob" "Foo"
+"Eve" "Fred"
diff --git a/tests/libtracker-data/property-paths/mixed-recursive-and-alternative-2.rq b/tests/libtracker-data/property-paths/mixed-recursive-and-alternative-2.rq
new file mode 100644
index 000000000..7f4c969c5
--- /dev/null
+++ b/tests/libtracker-data/property-paths/mixed-recursive-and-alternative-2.rq
@@ -0,0 +1 @@
+select foaf:name(?u) foaf:name(?a) { ?u (foaf:knows|foaf:member)+ ?a } order by foaf:name(?u) foaf:name(?a) \ No newline at end of file
diff --git a/tests/libtracker-data/property-paths/mixed-recursive-and-inverse-1.out b/tests/libtracker-data/property-paths/mixed-recursive-and-inverse-1.out
new file mode 100644
index 000000000..0c64aed0a
--- /dev/null
+++ b/tests/libtracker-data/property-paths/mixed-recursive-and-inverse-1.out
@@ -0,0 +1 @@
+"Fred" "Eve"
diff --git a/tests/libtracker-data/property-paths/mixed-recursive-and-inverse-1.rq b/tests/libtracker-data/property-paths/mixed-recursive-and-inverse-1.rq
new file mode 100644
index 000000000..a43469234
--- /dev/null
+++ b/tests/libtracker-data/property-paths/mixed-recursive-and-inverse-1.rq
@@ -0,0 +1 @@
+select foaf:name(?u) foaf:name(?a) { ?u ^foaf:knows+ ?a . ?u foaf:name 'Fred' } \ No newline at end of file
diff --git a/tests/libtracker-data/property-paths/mixed-recursive-and-inverse-2.out b/tests/libtracker-data/property-paths/mixed-recursive-and-inverse-2.out
new file mode 100644
index 000000000..0c64aed0a
--- /dev/null
+++ b/tests/libtracker-data/property-paths/mixed-recursive-and-inverse-2.out
@@ -0,0 +1 @@
+"Fred" "Eve"
diff --git a/tests/libtracker-data/property-paths/mixed-recursive-and-inverse-2.rq b/tests/libtracker-data/property-paths/mixed-recursive-and-inverse-2.rq
new file mode 100644
index 000000000..ebda97c36
--- /dev/null
+++ b/tests/libtracker-data/property-paths/mixed-recursive-and-inverse-2.rq
@@ -0,0 +1 @@
+select foaf:name(?u) foaf:name(?a) { ?u ^(foaf:knows+) ?a . ?u foaf:name 'Fred' } \ No newline at end of file
diff --git a/tests/libtracker-data/property-paths/mixed-recursive-and-inverse-3.out b/tests/libtracker-data/property-paths/mixed-recursive-and-inverse-3.out
new file mode 100644
index 000000000..0c64aed0a
--- /dev/null
+++ b/tests/libtracker-data/property-paths/mixed-recursive-and-inverse-3.out
@@ -0,0 +1 @@
+"Fred" "Eve"
diff --git a/tests/libtracker-data/property-paths/mixed-recursive-and-inverse-3.rq b/tests/libtracker-data/property-paths/mixed-recursive-and-inverse-3.rq
new file mode 100644
index 000000000..3b5416657
--- /dev/null
+++ b/tests/libtracker-data/property-paths/mixed-recursive-and-inverse-3.rq
@@ -0,0 +1 @@
+select foaf:name(?u) foaf:name(?a) { ?u (^foaf:knows)+ ?a . ?u foaf:name 'Fred' } \ No newline at end of file
diff --git a/tests/libtracker-data/property-paths/mixed-recursive-and-sequence-1.out b/tests/libtracker-data/property-paths/mixed-recursive-and-sequence-1.out
new file mode 100644
index 000000000..ac2dc970e
--- /dev/null
+++ b/tests/libtracker-data/property-paths/mixed-recursive-and-sequence-1.out
@@ -0,0 +1,2 @@
+"Alice"
+"Bob"
diff --git a/tests/libtracker-data/property-paths/mixed-recursive-and-sequence-1.rq b/tests/libtracker-data/property-paths/mixed-recursive-and-sequence-1.rq
new file mode 100644
index 000000000..1771d11d2
--- /dev/null
+++ b/tests/libtracker-data/property-paths/mixed-recursive-and-sequence-1.rq
@@ -0,0 +1 @@
+select foaf:name(?u) { ?u foaf:knows*/foaf:name 'Alice' } order by foaf:name(?u) \ No newline at end of file
diff --git a/tests/libtracker-data/property-paths/optional-path-1.out b/tests/libtracker-data/property-paths/optional-path-1.out
new file mode 100644
index 000000000..525aee442
--- /dev/null
+++ b/tests/libtracker-data/property-paths/optional-path-1.out
@@ -0,0 +1,2 @@
+"Alice" "Alice"
+"Alice" "Bob"
diff --git a/tests/libtracker-data/property-paths/optional-path-1.rq b/tests/libtracker-data/property-paths/optional-path-1.rq
new file mode 100644
index 000000000..d1da57abb
--- /dev/null
+++ b/tests/libtracker-data/property-paths/optional-path-1.rq
@@ -0,0 +1 @@
+select foaf:name(?u) foaf:name(?a) { ?u foaf:name 'Alice'; foaf:knows? ?a } order by foaf:name(?u) foaf:name(?a) \ No newline at end of file
diff --git a/tests/libtracker-data/property-paths/recursive-path-1.out b/tests/libtracker-data/property-paths/recursive-path-1.out
new file mode 100644
index 000000000..525aee442
--- /dev/null
+++ b/tests/libtracker-data/property-paths/recursive-path-1.out
@@ -0,0 +1,2 @@
+"Alice" "Alice"
+"Alice" "Bob"
diff --git a/tests/libtracker-data/property-paths/recursive-path-1.rq b/tests/libtracker-data/property-paths/recursive-path-1.rq
new file mode 100644
index 000000000..9bd80f372
--- /dev/null
+++ b/tests/libtracker-data/property-paths/recursive-path-1.rq
@@ -0,0 +1 @@
+select foaf:name(?u) foaf:name(?a) { ?u foaf:knows* ?a . FILTER (foaf:name(?u) = 'Alice') } \ No newline at end of file
diff --git a/tests/libtracker-data/property-paths/recursive-path-2.out b/tests/libtracker-data/property-paths/recursive-path-2.out
new file mode 100644
index 000000000..a02d506ff
--- /dev/null
+++ b/tests/libtracker-data/property-paths/recursive-path-2.out
@@ -0,0 +1 @@
+"Alice" "Bob"
diff --git a/tests/libtracker-data/property-paths/recursive-path-2.rq b/tests/libtracker-data/property-paths/recursive-path-2.rq
new file mode 100644
index 000000000..1ed508ee4
--- /dev/null
+++ b/tests/libtracker-data/property-paths/recursive-path-2.rq
@@ -0,0 +1 @@
+select foaf:name(?u) foaf:name(?a) { ?u foaf:knows+ ?a . FILTER (?u != ?a && foaf:name(?u) = 'Alice') } order by foaf:name(?u) foaf:name(?a) \ No newline at end of file
diff --git a/tests/libtracker-data/property-paths/sequence-path-1.rq b/tests/libtracker-data/property-paths/sequence-path-1.rq
index 8900f9d99..a703adf55 100644
--- a/tests/libtracker-data/property-paths/sequence-path-1.rq
+++ b/tests/libtracker-data/property-paths/sequence-path-1.rq
@@ -1 +1 @@
-select foaf:name(?a) foaf:name(?b) { ?a foaf:knows/foaf:knows ?b } \ No newline at end of file
+select foaf:name(?a) foaf:name(?b) { ?a foaf:knows/foaf:knows ?b } order by foaf:name(?a) foaf:name(?b) \ No newline at end of file
diff --git a/tests/libtracker-data/tracker-sparql-test.c b/tests/libtracker-data/tracker-sparql-test.c
index 3982fc125..2db5166ae 100644
--- a/tests/libtracker-data/tracker-sparql-test.c
+++ b/tests/libtracker-data/tracker-sparql-test.c
@@ -155,8 +155,20 @@ const TestInfo tests[] = {
{ "property-paths/sequence-path-1", "property-paths/data", FALSE },
{ "property-paths/sequence-path-2", "property-paths/data", FALSE },
{ "property-paths/sequence-path-3", "property-paths/data", FALSE },
+ { "property-paths/optional-path-1", "property-paths/data", FALSE },
+ { "property-paths/recursive-path-1", "property-paths/data", FALSE },
+ { "property-paths/recursive-path-2", "property-paths/data", FALSE },
+ { "property-paths/alternative-path-1", "property-paths/data", FALSE },
+ { "property-paths/alternative-path-2", "property-paths/data", FALSE },
{ "property-paths/mixed-inverse-and-sequence-1", "property-paths/data", FALSE },
{ "property-paths/mixed-inverse-and-sequence-2", "property-paths/data", FALSE },
+ { "property-paths/mixed-inverse-and-sequence-3", "property-paths/data", FALSE },
+ { "property-paths/mixed-recursive-and-sequence-1", "property-paths/data", FALSE },
+ { "property-paths/mixed-recursive-and-alternative-1", "property-paths/data", FALSE },
+ { "property-paths/mixed-recursive-and-alternative-2", "property-paths/data", FALSE },
+ { "property-paths/mixed-recursive-and-inverse-1", "property-paths/data", FALSE },
+ { "property-paths/mixed-recursive-and-inverse-2", "property-paths/data", FALSE },
+ { "property-paths/mixed-recursive-and-inverse-3", "property-paths/data", FALSE },
/* Update tests */
{ "update/insert-data-query-1", "update/insert-data-1", FALSE, FALSE },
{ "update/insert-data-query-2", "update/insert-data-2", FALSE, TRUE },
@@ -361,6 +373,8 @@ test_sparql_query (TestInfo *test_info,
g_free (results_filename);
g_object_unref (test_schemas);
g_object_unref (data_location);
+
+ tracker_data_manager_shutdown (manager);
g_object_unref (manager);
}