summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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.c251
3 files changed, 364 insertions, 67 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..a1befd7f5 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,55 @@ _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;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ tracker_sparql_swap_builder (sparql, old);
+}
+
static inline gchar *
_extract_node_string (TrackerParserNode *node,
TrackerSparql *sparql)
@@ -1082,6 +1133,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 +1178,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 +1284,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 +1315,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 +2800,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 +4038,6 @@ translate_PropertyListPathNotEmpty (TrackerSparql *sparql,
{
TrackerGrammarNamedRule rule;
TrackerToken old_predicate, *prev_token;
- TrackerParserNode *verb;
/* PropertyListPathNotEmpty ::= ( VerbPath | VerbSimple ) ObjectListPath ( ';' ( ( VerbPath | VerbSimple ) ObjectList )? )*
*/
@@ -3977,30 +4047,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 +4080,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 +4114,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 +4150,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;
}
@@ -4094,34 +4174,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 +4225,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,17 +4263,7 @@ 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
@@ -4201,10 +4287,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 +6637,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 +6815,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;