diff options
-rw-r--r-- | src/libtracker-data/tracker-sparql-types.c | 136 | ||||
-rw-r--r-- | src/libtracker-data/tracker-sparql-types.h | 44 | ||||
-rw-r--r-- | src/libtracker-data/tracker-sparql.c | 251 |
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; |