[tracker/wip/carlosg/sparql1.1: 58/145] libtracker-data: Support graphs as multiple databases
- From: Carlos Garnacho <carlosg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [tracker/wip/carlosg/sparql1.1: 58/145] libtracker-data: Support graphs as multiple databases
- Date: Thu, 18 Jul 2019 22:28:55 +0000 (UTC)
commit 4345c5bd2da147f987aa070170d4660dd6755b21
Author: Carlos Garnacho <carlosg gnome org>
Date: Thu May 30 13:57:48 2019 +0200
libtracker-data: Support graphs as multiple databases
src/libtracker-data/tracker-data-query.c | 6 +-
src/libtracker-data/tracker-data-query.h | 1 +
src/libtracker-data/tracker-data-update.c | 50 ++++---
src/libtracker-data/tracker-sparql-types.c | 10 +-
src/libtracker-data/tracker-sparql-types.h | 3 +
src/libtracker-data/tracker-sparql.c | 232 ++++++++++++++++++++++-------
6 files changed, 231 insertions(+), 71 deletions(-)
---
diff --git a/src/libtracker-data/tracker-data-query.c b/src/libtracker-data/tracker-data-query.c
index 2694d6d0b..ef4218679 100644
--- a/src/libtracker-data/tracker-data-query.c
+++ b/src/libtracker-data/tracker-data-query.c
@@ -35,6 +35,7 @@
GPtrArray*
tracker_data_query_rdf_type (TrackerDataManager *manager,
+ const gchar *graph,
gint id)
{
TrackerDBCursor *cursor = NULL;
@@ -49,8 +50,9 @@ tracker_data_query_rdf_type (TrackerDataManager *manager,
stmt = tracker_db_interface_create_statement (iface, TRACKER_DB_STATEMENT_CACHE_TYPE_SELECT, &error,
"SELECT (SELECT Uri FROM Resource WHERE ID =
\"rdf:type\") "
- "FROM \"rdfs:Resource_rdf:type\" "
- "WHERE ID = ?");
+ "FROM \"%s\".\"rdfs:Resource_rdf:type\" "
+ "WHERE ID = ?",
+ graph ? graph : "main");
if (stmt) {
tracker_db_statement_bind_int (stmt, 0, id);
diff --git a/src/libtracker-data/tracker-data-query.h b/src/libtracker-data/tracker-data-query.h
index 3b2df21fd..928483169 100644
--- a/src/libtracker-data/tracker-data-query.h
+++ b/src/libtracker-data/tracker-data-query.h
@@ -45,6 +45,7 @@ TrackerDBCursor *tracker_data_query_sparql_cursor (TrackerDataManager *mana
GError **error);
GPtrArray* tracker_data_query_rdf_type (TrackerDataManager *manager,
+ const gchar *graph,
gint id);
G_END_DECLS
diff --git a/src/libtracker-data/tracker-data-update.c b/src/libtracker-data/tracker-data-update.c
index 99495a3d0..8603b6763 100644
--- a/src/libtracker-data/tracker-data-update.c
+++ b/src/libtracker-data/tracker-data-update.c
@@ -1423,7 +1423,8 @@ static GArray *
get_property_values (TrackerData *data,
TrackerProperty *property)
{
- gboolean multiple_values;
+ gboolean multiple_values;
+ const gchar *database;
GArray *old_values;
multiple_values = tracker_property_get_multiple_values (property);
@@ -1432,6 +1433,9 @@ get_property_values (TrackerData *data,
g_array_set_clear_func (old_values, (GDestroyNotify) g_value_unset);
g_hash_table_insert (data->resource_buffer->predicates, g_object_ref (property), old_values);
+ database = data->resource_buffer->graph->graph ?
+ data->resource_buffer->graph->graph : "main";
+
if (!data->resource_buffer->create) {
TrackerDBInterface *iface;
TrackerDBStatement *stmt;
@@ -1446,8 +1450,8 @@ get_property_values (TrackerData *data,
iface = tracker_data_manager_get_writable_db_interface (data->manager);
stmt = tracker_db_interface_create_statement (iface, TRACKER_DB_STATEMENT_CACHE_TYPE_SELECT,
&error,
- "SELECT \"%s\" FROM \"%s\" WHERE ID = ?",
- field_name, table_name);
+ "SELECT \"%s\" FROM \"%s\".\"%s\" WHERE ID = ?",
+ field_name, database, table_name);
if (stmt) {
tracker_db_statement_bind_int (stmt, 0, data->resource_buffer->id);
@@ -2084,6 +2088,7 @@ delete_metadata_decomposed (TrackerData *data,
static void
db_delete_row (TrackerDBInterface *iface,
+ const gchar *database,
const gchar *table_name,
gint id)
{
@@ -2091,8 +2096,8 @@ db_delete_row (TrackerDBInterface *iface,
GError *error = NULL;
stmt = tracker_db_interface_create_statement (iface, TRACKER_DB_STATEMENT_CACHE_TYPE_UPDATE, &error,
- "DELETE FROM \"%s\" WHERE ID = ?",
- table_name);
+ "DELETE FROM \"%s\".\"%s\" WHERE ID = ?",
+ database, table_name);
if (stmt) {
tracker_db_statement_bind_int (stmt, 0, id);
@@ -2123,9 +2128,12 @@ cache_delete_resource_type_full (TrackerData *data,
guint p, n_props;
GError *error = NULL;
TrackerOntologies *ontologies;
+ const gchar *database;
iface = tracker_data_manager_get_writable_db_interface (data->manager);
ontologies = tracker_data_manager_get_ontologies (data->manager);
+ database = data->resource_buffer->graph->graph ?
+ data->resource_buffer->graph->graph : "main";
if (!single_type) {
if (strcmp (tracker_class_get_uri (class), TRACKER_PREFIX_RDFS "Resource") == 0 &&
@@ -2166,9 +2174,10 @@ cache_delete_resource_type_full (TrackerData *data,
/* retrieve all subclasses we need to remove from the subject
* before we can remove the class specified as object of the statement */
stmt = tracker_db_interface_create_statement (iface, TRACKER_DB_STATEMENT_CACHE_TYPE_SELECT,
&error,
- "SELECT (SELECT Uri FROM Resource WHERE ID =
\"rdfs:Class_rdfs:subClassOf\".ID) "
- "FROM \"rdfs:Resource_rdf:type\" INNER JOIN
\"rdfs:Class_rdfs:subClassOf\" ON (\"rdf:type\" = \"rdfs:Class_rdfs:subClassOf\".ID) "
- "WHERE \"rdfs:Resource_rdf:type\".ID = ? AND
\"rdfs:subClassOf\" = (SELECT ID FROM Resource WHERE Uri = ?)");
+ "SELECT (SELECT Uri FROM Resource WHERE ID =
subclass.ID) "
+ "FROM \"%s\".\"rdfs:Resource_rdf:type\" AS type
INNER JOIN \"%s\".\"rdfs:Class_rdfs:subClassOf\" AS subclass ON (type.\"rdf:type\" = subclass.ID) "
+ "WHERE type.ID = ? AND
subclass.\"rdfs:subClassOf\" = (SELECT ID FROM Resource WHERE Uri = ?)",
+ database, database);
if (stmt) {
tracker_db_statement_bind_int (stmt, 0, data->resource_buffer->id);
@@ -2222,7 +2231,7 @@ cache_delete_resource_type_full (TrackerData *data,
if (direct_delete) {
if (multiple_values) {
- db_delete_row (iface, table_name, data->resource_buffer->id);
+ db_delete_row (iface, database, table_name, data->resource_buffer->id);
}
/* single-valued property values are deleted right after the loop by deleting the row
in the class table */
continue;
@@ -2270,7 +2279,7 @@ cache_delete_resource_type_full (TrackerData *data,
if (direct_delete) {
/* delete row from class table */
- db_delete_row (iface, tracker_class_get_name (class), data->resource_buffer->id);
+ db_delete_row (iface, database, tracker_class_get_name (class), data->resource_buffer->id);
if (!single_type) {
/* delete row from rdfs:Resource_rdf:type table */
@@ -2402,7 +2411,7 @@ resource_buffer_switch (TrackerData *data,
if (resource_buffer->create) {
resource_buffer->types = g_ptr_array_new ();
} else {
- resource_buffer->types = tracker_data_query_rdf_type (data->manager,
resource_buffer->id);
+ resource_buffer->types = tracker_data_query_rdf_type (data->manager, graph,
resource_buffer->id);
}
resource_buffer->predicates = g_hash_table_new_full (g_direct_hash, g_direct_equal,
g_object_unref, (GDestroyNotify) g_array_unref);
resource_buffer->tables = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
(GDestroyNotify) cache_table_free);
@@ -2441,7 +2450,9 @@ tracker_data_delete_statement (TrackerData *data,
resource_buffer_switch (data, graph, subject, subject_id);
ontologies = tracker_data_manager_get_ontologies (data->manager);
- graph_id = tracker_data_manager_find_graph (data->manager, graph);
+
+ if (graph)
+ graph_id = tracker_data_manager_find_graph (data->manager, graph);
if (object && g_strcmp0 (predicate, TRACKER_PREFIX_RDF "type") == 0) {
class = tracker_ontologies_get_class_by_uri (ontologies, object);
@@ -2753,7 +2764,7 @@ tracker_data_insert_statement_with_uri (TrackerData *data,
change = TRUE;
} else {
/* add value to metadata database */
- change = cache_insert_metadata_decomposed (data, property, object, 0, graph, 0,
&actual_error);
+ change = cache_insert_metadata_decomposed (data, property, object, 0, graph, graph_id,
&actual_error);
if (actual_error) {
g_propagate_error (error, actual_error);
return;
@@ -2828,8 +2839,11 @@ tracker_data_insert_statement_with_string (TrackerData *data,
return;
}
+ if (graph)
+ graph_id = tracker_data_manager_find_graph (data->manager, graph);
+
/* add value to metadata database */
- change = cache_insert_metadata_decomposed (data, property, object, 0, graph, 0, &actual_error);
+ change = cache_insert_metadata_decomposed (data, property, object, 0, graph, graph_id, &actual_error);
if (actual_error) {
g_propagate_error (error, actual_error);
return;
@@ -2838,7 +2852,6 @@ tracker_data_insert_statement_with_string (TrackerData *data,
if (data->insert_callbacks && change) {
guint n;
- graph_id = (graph != NULL ? query_resource_id (data, graph) : 0);
pred_id = (pred_id != 0) ? pred_id : tracker_data_query_resource_id (data->manager, iface,
predicate);
for (n = 0; n < data->insert_callbacks->len; n++) {
@@ -2916,7 +2929,8 @@ tracker_data_update_statement_with_uri (TrackerData *data,
return;
}
- graph_id = tracker_data_manager_find_graph (data->manager, graph);
+ if (graph)
+ graph_id = tracker_data_manager_find_graph (data->manager, graph);
if (property == tracker_ontologies_get_rdf_type (ontologies)) {
/* handle rdf:type statements specially to
@@ -3128,8 +3142,10 @@ tracker_data_update_statement_with_string (TrackerData *data,
return;
}
+ if (graph)
+ graph_id = tracker_data_manager_find_graph (data->manager, graph);
+
if (((!multiple_values && data->delete_callbacks) || data->insert_callbacks) && change) {
- graph_id = (graph != NULL ? query_resource_id (data, graph) : 0);
pred_id = (pred_id != 0) ? pred_id : tracker_data_query_resource_id (data->manager, iface,
predicate);
}
diff --git a/src/libtracker-data/tracker-sparql-types.c b/src/libtracker-data/tracker-sparql-types.c
index c5f01b9f0..15f1df3e7 100644
--- a/src/libtracker-data/tracker-sparql-types.c
+++ b/src/libtracker-data/tracker-sparql-types.c
@@ -33,11 +33,13 @@ enum {
/* Helper structs */
static TrackerDataTable *
tracker_data_table_new (const gchar *tablename,
+ const gchar *graph,
gint idx)
{
TrackerDataTable *table;
table = g_new0 (TrackerDataTable, 1);
+ table->graph = g_strdup (graph);
table->sql_db_tablename = g_strdup (tablename);
table->sql_query_tablename = g_strdup_printf ("%s%d", tablename, idx);
@@ -47,6 +49,7 @@ tracker_data_table_new (const gchar *tablename,
static void
tracker_data_table_free (TrackerDataTable *table)
{
+ g_free (table->graph);
g_free (table->sql_db_tablename);
g_free (table->sql_query_tablename);
g_free (table);
@@ -874,6 +877,7 @@ tracker_triple_context_new (void)
TrackerDataTable *
tracker_triple_context_lookup_table (TrackerTripleContext *context,
+ const gchar *graph,
const gchar *tablename)
{
TrackerDataTable *table = NULL;
@@ -884,7 +888,8 @@ tracker_triple_context_lookup_table (TrackerTripleContext *context,
table = g_ptr_array_index (context->sql_tables, i);
- if (g_strcmp0 (table->sql_db_tablename, tablename) == 0)
+ if (g_strcmp0 (table->graph, graph) == 0 &&
+ g_strcmp0 (table->sql_db_tablename, tablename) == 0)
return table;
}
@@ -893,11 +898,12 @@ tracker_triple_context_lookup_table (TrackerTripleContext *context,
TrackerDataTable *
tracker_triple_context_add_table (TrackerTripleContext *context,
+ const gchar *graph,
const gchar *tablename)
{
TrackerDataTable *table;
- table = tracker_data_table_new (tablename, ++context->table_counter);
+ table = tracker_data_table_new (tablename, graph, ++context->table_counter);
g_ptr_array_add (context->sql_tables, table);
return table;
diff --git a/src/libtracker-data/tracker-sparql-types.h b/src/libtracker-data/tracker-sparql-types.h
index 24f373a8b..ac088d473 100644
--- a/src/libtracker-data/tracker-sparql-types.h
+++ b/src/libtracker-data/tracker-sparql-types.h
@@ -73,6 +73,7 @@ typedef struct _TrackerSolution TrackerSolution;
typedef struct _TrackerPathElement TrackerPathElement;
struct _TrackerDataTable {
+ gchar *graph; /* Graph for this table, if specified */
gchar *sql_db_tablename; /* as in db schema */
gchar *sql_query_tablename; /* temp. name, generated */
gboolean predicate_variable;
@@ -358,8 +359,10 @@ GType tracker_triple_context_get_type (void) G_GNUC_CONST;
TrackerContext * tracker_triple_context_new (void);
TrackerDataTable * tracker_triple_context_lookup_table (TrackerTripleContext *context,
+ const gchar *graph,
const gchar *table);
TrackerDataTable * tracker_triple_context_add_table (TrackerTripleContext *context,
+ const gchar *graph,
const gchar *table);
void tracker_triple_context_add_literal_binding (TrackerTripleContext *context,
TrackerLiteralBinding *binding);
diff --git a/src/libtracker-data/tracker-sparql.c b/src/libtracker-data/tracker-sparql.c
index 22bd29af2..a60e23fce 100644
--- a/src/libtracker-data/tracker-sparql.c
+++ b/src/libtracker-data/tracker-sparql.c
@@ -122,6 +122,9 @@ struct _TrackerSparql
GHashTable *parameters;
+ GPtrArray *anon_graphs;
+ GPtrArray *named_graphs;
+
struct {
TrackerContext *context;
TrackerContext *select_context;
@@ -173,6 +176,8 @@ tracker_sparql_finalize (GObject *object)
tracker_token_unset (&sparql->current_state.predicate);
tracker_token_unset (&sparql->current_state.object);
+ g_ptr_array_unref (sparql->named_graphs);
+ g_ptr_array_unref (sparql->anon_graphs);
g_ptr_array_unref (sparql->var_names);
g_array_unref (sparql->var_types);
@@ -1012,10 +1017,22 @@ _add_quad (TrackerSparql *sparql,
TrackerProperty *property = NULL;
TrackerClass *subject_type = NULL;
gboolean new_table = FALSE, is_fts = FALSE, is_rdf_type = FALSE;
+ const gchar *graph_db = NULL;
triple_context = TRACKER_TRIPLE_CONTEXT (sparql->current_state.context);
ontologies = tracker_data_manager_get_ontologies (sparql->data_manager);
+ if (tracker_token_get_literal (graph)) {
+ graph_db = tracker_token_get_idstring (graph);
+ if (tracker_data_manager_find_graph (sparql->data_manager, graph_db) == 0) {
+ g_set_error (error, TRACKER_SPARQL_ERROR,
+ TRACKER_SPARQL_ERROR_UNKNOWN_GRAPH,
+ "Unknown graph '%s'",
+ tracker_token_get_literal (graph));
+ return FALSE;
+ }
+ }
+
if (tracker_token_get_literal (predicate)) {
gboolean share_table = TRUE;
const gchar *db_table;
@@ -1023,8 +1040,7 @@ _add_quad (TrackerSparql *sparql,
property = tracker_ontologies_get_property_by_uri (ontologies,
tracker_token_get_literal (predicate));
- if (tracker_token_is_empty (graph) &&
- !tracker_token_get_variable (object) &&
+ if (!tracker_token_get_variable (object) &&
g_strcmp0 (tracker_token_get_literal (predicate), RDF_NS "type") == 0) {
/* rdf:type query */
subject_type = tracker_ontologies_get_class_by_uri (ontologies,
@@ -1039,6 +1055,7 @@ _add_quad (TrackerSparql *sparql,
is_rdf_type = TRUE;
db_table = tracker_class_get_name (subject_type);
+ share_table = !tracker_token_is_empty (graph);
} else if (g_strcmp0 (tracker_token_get_literal (predicate), FTS_NS "match") == 0) {
db_table = "fts5";
share_table = FALSE;
@@ -1082,8 +1099,11 @@ _add_quad (TrackerSparql *sparql,
/* We can never share the table with multiple triples for
* multi value properties as a property may consist of multiple rows.
+ * We can't either do that for graph unrestricted queries
+ * since we need the self-joins to query across all graphs.
*/
- share_table = !tracker_property_get_multiple_values (property);
+ share_table = (!tracker_property_get_multiple_values (property) &&
+ !tracker_token_is_empty (graph));
subject_type = tracker_property_get_domain (property);
} else if (property == NULL) {
@@ -1096,18 +1116,22 @@ _add_quad (TrackerSparql *sparql,
if (share_table) {
table = tracker_triple_context_lookup_table (triple_context,
+ graph_db,
db_table);
}
if (!table) {
table = tracker_triple_context_add_table (triple_context,
+ graph_db,
db_table);
new_table = TRUE;
}
} else if (tracker_token_get_variable (predicate)) {
/* Variable in predicate */
variable = tracker_token_get_variable (predicate);
- table = tracker_triple_context_add_table (triple_context, variable->name);
+ table = tracker_triple_context_add_table (triple_context,
+ graph_db,
+ variable->name);
tracker_data_table_set_predicate_variable (table, TRUE);
new_table = TRUE;
@@ -1119,6 +1143,7 @@ _add_quad (TrackerSparql *sparql,
g_object_unref (binding);
} else if (tracker_token_get_path (predicate)) {
table = tracker_triple_context_add_table (triple_context,
+ graph_db,
tracker_token_get_idstring (predicate));
new_table = TRUE;
} else {
@@ -1146,6 +1171,15 @@ _add_quad (TrackerSparql *sparql,
g_object_unref (binding);
}
+ if (tracker_token_get_variable (graph)) {
+ variable = tracker_token_get_variable (graph);
+ binding = tracker_variable_binding_new (variable, NULL, table);
+ tracker_binding_set_data_type (binding, TRACKER_PROPERTY_TYPE_RESOURCE);
+ tracker_binding_set_db_column_name (binding, "graph");
+ _add_binding (sparql, binding);
+ g_object_unref (binding);
+ }
+
if (is_rdf_type) {
/* The type binding is already implicit in the data table */
return TRUE;
@@ -1258,37 +1292,6 @@ _add_quad (TrackerSparql *sparql,
g_object_unref (binding);
}
- if (!tracker_token_is_empty (graph)) {
- if (tracker_token_get_variable (graph)) {
- variable = tracker_token_get_variable (graph);
- binding = tracker_variable_binding_new (variable, NULL, table);
- tracker_variable_binding_set_nullable (TRACKER_VARIABLE_BINDING (binding), TRUE);
- } else if (tracker_token_get_literal (graph)) {
- binding = tracker_literal_binding_new (tracker_token_get_literal (graph), table);
- } else if (tracker_token_get_parameter (graph)) {
- binding = tracker_parameter_binding_new (tracker_token_get_parameter (graph), table);
- } else {
- g_assert_not_reached ();
- }
-
- tracker_binding_set_data_type (binding, TRACKER_PROPERTY_TYPE_RESOURCE);
-
- if (tracker_token_get_variable (predicate) ||
- tracker_token_get_path (predicate)) {
- tracker_binding_set_db_column_name (binding, "graph");
- } else {
- gchar *column_name;
-
- g_assert (property != NULL);
- column_name = g_strdup_printf ("%s:graph", tracker_property_get_name (property));
- tracker_binding_set_db_column_name (binding, column_name);
- g_free (column_name);
- }
-
- _add_binding (sparql, binding);
- g_object_unref (binding);
- }
-
return TRUE;
}
@@ -1429,7 +1432,14 @@ _end_triples_block (TrackerSparql *sparql,
"(SELECT subject AS ID, predicate, "
"object, graph FROM tracker_triples) ");
} else {
- _append_string_printf (sparql, "\"%s\" ", table->sql_db_tablename);
+ if (table->graph) {
+ _append_string_printf (sparql, "\"%s\".\"%s\"",
+ table->graph,
+ table->sql_db_tablename);
+ } else {
+ _append_string_printf (sparql, "\"unionGraph_%s\" ",
+ table->sql_db_tablename);
+ }
}
_append_string_printf (sparql, "AS \"%s\" ", table->sql_query_tablename);
@@ -2006,11 +2016,15 @@ static gboolean
translate_DefaultGraphClause (TrackerSparql *sparql,
GError **error)
{
+ gchar *graph;
+
/* DefaultGraphClause ::= SourceSelector
*/
_call_rule (sparql, NAMED_RULE_SourceSelector, error);
- /* FIXME: FROM <graph> is unimplemented, and we never raised an error */
+ graph = g_strdup (tracker_token_get_idstring (&sparql->current_state.graph));
+ g_ptr_array_add (sparql->anon_graphs, graph);
+ tracker_token_unset (&sparql->current_state.graph);
return TRUE;
}
@@ -2019,12 +2033,16 @@ static gboolean
translate_NamedGraphClause (TrackerSparql *sparql,
GError **error)
{
+ gchar *graph;
+
/* NamedGraphClause ::= 'NAMED' SourceSelector
*/
_expect (sparql, RULE_TYPE_LITERAL, LITERAL_NAMED);
_call_rule (sparql, NAMED_RULE_SourceSelector, error);
- /* FIXME: FROM NAMED <graph> is unimplemented, and we never raised an error */
+ graph = g_strdup (tracker_token_get_idstring (&sparql->current_state.graph));
+ g_ptr_array_add (sparql->named_graphs, graph);
+ tracker_token_unset (&sparql->current_state.graph);
return TRUE;
}
@@ -2036,6 +2054,8 @@ translate_SourceSelector (TrackerSparql *sparql,
/* SourceSelector ::= iri
*/
_call_rule (sparql, NAMED_RULE_iri, error);
+ _init_token (&sparql->current_state.graph,
+ sparql->current_state.prev_node, sparql);
return TRUE;
}
@@ -2423,6 +2443,7 @@ translate_Create (TrackerSparql *sparql,
{
gboolean silent = FALSE;
GError *inner_error = NULL;
+ const gchar *graph_name;
_expect (sparql, RULE_TYPE_LITERAL, LITERAL_CREATE);
@@ -2916,8 +2937,6 @@ translate_GraphRefAll (TrackerSparql *sparql,
_unimplemented ("DROP/CLEAR ALL");
} else {
_call_rule (sparql, NAMED_RULE_GraphRef, error);
- _init_token (&sparql->current_state.graph,
- sparql->current_state.prev_node, sparql);
}
return TRUE;
@@ -2931,6 +2950,8 @@ translate_GraphRef (TrackerSparql *sparql,
*/
_expect (sparql, RULE_TYPE_LITERAL, LITERAL_GRAPH);
_call_rule (sparql, NAMED_RULE_iri, error);
+ _init_token (&sparql->current_state.graph,
+ sparql->current_state.prev_node, sparql);
return TRUE;
}
@@ -3235,6 +3256,27 @@ translate_GraphGraphPattern (TrackerSparql *sparql,
sparql->current_state.prev_node, sparql);
_call_rule (sparql, NAMED_RULE_GroupGraphPattern, error);
+ if (sparql->named_graphs->len > 0) {
+ gint i;
+
+ _append_string (sparql, "WHERE graph IN (");
+
+ for (i = 0; i < sparql->named_graphs->len; i++) {
+ const gchar *graph_name;
+ gint graph_id;
+
+ if (i > 0)
+ _append_string (sparql, ", ");
+
+ graph_name = g_ptr_array_index (sparql->named_graphs, i);
+ graph_id = tracker_data_manager_find_graph (sparql->data_manager,
+ graph_name);
+ _append_string_printf (sparql, "%d", graph_id);
+ }
+
+ _append_string (sparql, ") ");
+ }
+
tracker_token_unset (&sparql->current_state.graph);
sparql->current_state.graph = old_graph;
@@ -3248,9 +3290,86 @@ static gboolean
translate_ServiceGraphPattern (TrackerSparql *sparql,
GError **error)
{
+ gssize pattern_start, pattern_end;
+ TrackerParserNode *pattern, *node;
+ gchar *pattern_str, *escaped_str, *var_str;
+ TrackerContext *context;
+ GList *variables = NULL;
+ TrackerToken service;
+ GString *service_sparql;
+ gboolean silent;
+ gint i = 0;
+
/* ServiceGraphPattern ::= 'SERVICE' 'SILENT'? VarOrIri GroupGraphPattern
*/
- _unimplemented ("SERVICE");
+
+ context = tracker_triple_context_new ();
+ tracker_sparql_push_context (sparql, context);
+
+ _expect (sparql, RULE_TYPE_LITERAL, LITERAL_SERVICE);
+
+ if (_accept (sparql, RULE_TYPE_LITERAL, LITERAL_SILENT))
+ silent = TRUE;
+
+ _call_rule (sparql, NAMED_RULE_VarOrIri, error);
+ _init_token (&service, sparql->current_state.prev_node, sparql);
+
+ pattern = _skip_rule (sparql, NAMED_RULE_GroupGraphPattern);
+ _append_string (sparql, "SELECT ");
+ service_sparql = g_string_new ("SELECT ");
+
+ for (node = tracker_sparql_parser_tree_find_first (pattern, TRUE);
+ node;
+ node = tracker_sparql_parser_tree_find_next (node, TRUE)) {
+ const TrackerGrammarRule *rule;
+ TrackerBinding *binding;
+ TrackerVariable *var;
+
+ if (!g_node_is_ancestor ((GNode *) pattern, (GNode *) node))
+ break;
+
+ rule = tracker_parser_node_get_rule (node);
+
+ if (!tracker_grammar_rule_is_a (rule, RULE_TYPE_TERMINAL,
+ TERMINAL_TYPE_VAR1) &&
+ !tracker_grammar_rule_is_a (rule, RULE_TYPE_TERMINAL,
+ TERMINAL_TYPE_VAR2))
+ continue;
+
+ if (i > 0)
+ _append_string (sparql, ", ");
+
+ var_str = _extract_node_string (node, sparql);
+ var = _extract_node_variable (node, sparql);
+ variables = g_list_prepend (variables, var);
+ binding = tracker_variable_binding_new (var, NULL, NULL);
+ _add_binding (sparql, binding);
+
+
+ _append_string_printf (sparql, "col%d AS %s ",
+ i, tracker_variable_get_sql_expression (var));
+ g_string_append_printf (service_sparql, "?%s ", var_str);
+ g_free (var_str);
+ i++;
+ }
+
+ tracker_parser_node_get_extents (pattern, &pattern_start, &pattern_end);
+ pattern_str = g_strndup (&sparql->sparql[pattern_start], pattern_end - pattern_start);
+ escaped_str = _escape_sql_string (pattern_str);
+ g_string_append (service_sparql, escaped_str);
+ g_free (pattern_str);
+ g_free (escaped_str);
+
+ _append_string_printf (sparql, "FROM tracker_service WHERE service=\"%s\" AND query=\"%s\" AND
silent=%d ",
+ tracker_token_get_idstring (&service),
+ service_sparql->str,
+ silent);
+
+ tracker_token_unset (&service);
+ tracker_sparql_pop_context (sparql, TRUE);
+ g_string_free (service_sparql, TRUE);
+
+ return TRUE;
}
static gboolean
@@ -4957,6 +5076,8 @@ handle_property_function (TrackerSparql *sparql,
TrackerProperty *property,
GError **error)
{
+ TrackerPropertyType type;
+
if (tracker_property_get_multiple_values (property)) {
TrackerStringBuilder *str, *old;
@@ -4967,23 +5088,32 @@ handle_property_function (TrackerSparql *sparql,
convert_expression_to_string (sparql, tracker_property_get_data_type (property));
tracker_sparql_swap_builder (sparql, old);
- _append_string_printf (sparql, ", ',') FROM \"%s\" WHERE ID = ",
- tracker_property_get_table_name (property));
+ _append_string (sparql, ", ',') ");
- _call_rule (sparql, NAMED_RULE_ArgList, error);
- sparql->current_state.expression_type = TRACKER_PROPERTY_TYPE_STRING;
+ type = TRACKER_PROPERTY_TYPE_STRING;
} else {
_append_string_printf (sparql,
- "(SELECT \"%s\" FROM \"%s\" WHERE ID = ",
- tracker_property_get_name (property),
- tracker_property_get_table_name (property));
+ "(SELECT \"%s\" ",
+ tracker_property_get_name (property));
- _call_rule (sparql, NAMED_RULE_ArgList, error);
- sparql->current_state.expression_type = tracker_property_get_data_type (property);
+ type = tracker_property_get_data_type (property);
+ }
+
+ if (tracker_token_is_empty (&sparql->current_state.graph)) {
+ _append_string_printf (sparql, "FROM \"unionGraph_%s\" ",
+ tracker_property_get_table_name (property));
+ } else {
+ _append_string_printf (sparql, "FROM \"%s\".\"%s\" ",
+ tracker_token_get_idstring (&sparql->current_state.graph),
+ tracker_property_get_table_name (property));
}
+ _append_string (sparql, "WHERE ID = ");
+ _call_rule (sparql, NAMED_RULE_ArgList, error);
_append_string (sparql, ") ");
+ sparql->current_state.expression_type = type;
+
return TRUE;
}
@@ -6504,6 +6634,8 @@ tracker_sparql_init (TrackerSparql *sparql)
sparql->parameters = g_hash_table_new (g_str_hash, g_str_equal);
sparql->var_names = g_ptr_array_new_with_free_func (g_free);
sparql->var_types = g_array_new (FALSE, FALSE, sizeof (TrackerPropertyType));
+ sparql->anon_graphs = g_ptr_array_new_with_free_func (g_free);
+ sparql->named_graphs = g_ptr_array_new_with_free_func (g_free);
sparql->cacheable = TRUE;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]