Commit 0b80cc61 authored by Carlos Garnacho's avatar Carlos Garnacho

libtracker-data: Handle current path operators through WITH clause

Using the WITH clause is already a pre-requisite for * and + operators
(as those queries need to be recursive). It then struck me that using
it for all path operators is simpler and easier to read both in code and
SQL, for starters:
  - We were going long ways to invert the processing order of VerbPath and
    ObjectList, so the latter would be handled within the former. This was
    necessary so we could eg. invert subject and object in ^.
  - Each property path element results in a rather simple SELECT in the
    WITH clause, and nesting those comes off naturally. This is handy as
    a property path is actually an expression tree, which we weren't
    handling that well.

As a first step, add this infrastructure for property paths using the WITH
clause and use it for the currently supported operators.

We still fall through the usual code paths (no subqueries in WITH clause)
if the property path is formed of a single literal with no operators
(i.e. the good old "?s foo:bar ?o" case). This is still necessary for
fts:match (which is not really a property, thus can't be used in property
paths) and rdfs:domain special casing (which just applies if the predicate
is a variable, not the case with property paths).
parent 98f36a5a
......@@ -27,6 +27,7 @@ enum {
TOKEN_TYPE_LITERAL,
TOKEN_TYPE_VARIABLE,
TOKEN_TYPE_PARAMETER,
TOKEN_TYPE_PATH,
};
/* Helper structs */
......@@ -197,6 +198,14 @@ tracker_token_parameter_init (TrackerToken *token,
token->content.parameter = g_strdup (parameter);
}
void
tracker_token_path_init (TrackerToken *token,
TrackerPathElement *path)
{
token->type = TOKEN_TYPE_PATH;
token->content.path = path;
}
void
tracker_token_unset (TrackerToken *token)
{
......@@ -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)
......
......@@ -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;
......
......@@ -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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment