diff options
author | Carlos Garnacho <carlosg@gnome.org> | 2023-01-10 15:19:01 +0000 |
---|---|---|
committer | Carlos Garnacho <carlosg@gnome.org> | 2023-01-10 15:19:01 +0000 |
commit | 84a01b7f0481e71cd9cd0b930c51b8a12a5c531c (patch) | |
tree | 037c609ce40c95a86e913f4e20c7b405d20707c5 | |
parent | 8dbf74386f28871385f784d9873c5aeaecf5222e (diff) | |
parent | 857d8a4711f436fa207ffad638c83c4fcc31d90e (diff) | |
download | tracker-84a01b7f0481e71cd9cd0b930c51b8a12a5c531c.tar.gz |
Merge branch 'wip/carlosg/triples-table-perf' into 'master'
Performance improvements to tracker_triples virtual table
See merge request https://gitlab.gnome.org/GNOME/tracker/-/merge_requests/562
11 files changed, 393 insertions, 219 deletions
diff --git a/src/libtracker-sparql/core/tracker-db-interface-sqlite.c b/src/libtracker-sparql/core/tracker-db-interface-sqlite.c index c8e221c0c..4696319ec 100644 --- a/src/libtracker-sparql/core/tracker-db-interface-sqlite.c +++ b/src/libtracker-sparql/core/tracker-db-interface-sqlite.c @@ -1890,27 +1890,27 @@ function_sparql_print_value (sqlite3_context *context, case TRACKER_PROPERTY_TYPE_DATE: case TRACKER_PROPERTY_TYPE_DATETIME: if (sqlite3_value_numeric_type (argv[0]) == SQLITE_INTEGER) { - GDateTime *datetime; + struct tm tm; gint64 timestamp; + gchar buf[100]; + int retval; timestamp = sqlite3_value_int64 (argv[0]); - datetime = g_date_time_new_from_unix_utc (timestamp); - if (datetime) { - gchar *str; + if (gmtime_r ((time_t *) ×tamp, &tm) == NULL) + result_context_function_error (context, fn, "Invalid unix timestamp"); - if (prop_type == TRACKER_PROPERTY_TYPE_DATETIME) - str = tracker_date_format_iso8601 (datetime); - else if (prop_type == TRACKER_PROPERTY_TYPE_DATE) - str = g_date_time_format (datetime, "%Y-%m-%d"); - else - g_assert_not_reached (); + if (prop_type == TRACKER_PROPERTY_TYPE_DATETIME) + retval = strftime ((gchar *) &buf, sizeof (buf), "%2C%y-%m-%dT%TZ", &tm); + else if (prop_type == TRACKER_PROPERTY_TYPE_DATE) + retval = strftime ((gchar *) &buf, sizeof (buf), "%2C%y-%m-%d", &tm); + else + g_assert_not_reached (); - sqlite3_result_text (context, str, -1, g_free); - g_date_time_unref (datetime); - } else { - sqlite3_result_null (context); - } + if (retval != 0) + sqlite3_result_text (context, g_strdup (buf), -1, g_free); + else + result_context_function_error (context, fn, "Invalid unix timestamp"); } else if (sqlite3_value_type (argv[0]) == SQLITE_TEXT) { if (prop_type == TRACKER_PROPERTY_TYPE_DATETIME) { sqlite3_result_value (context, argv[0]); @@ -3489,26 +3489,20 @@ tracker_db_cursor_get_boolean (TrackerSparqlCursor *sparql_cursor, static gboolean tracker_db_cursor_get_annotated_value_type (TrackerDBCursor *cursor, guint column, + int column_type, TrackerSparqlValueType *value_type) { - TrackerDBInterface *iface; TrackerPropertyType property_type; gboolean is_null; if (cursor->n_columns == 0) return FALSE; - iface = cursor->ref_stmt->db_interface; - - tracker_db_interface_lock (iface); - /* The value type may be annotated in extra columns, one per * user-visible column. */ property_type = sqlite3_column_int64 (cursor->stmt, column + cursor->n_columns); - is_null = sqlite3_column_type (cursor->stmt, column) == SQLITE_NULL; - - tracker_db_interface_unlock (iface); + is_null = column_type == SQLITE_NULL; if (is_null) { *value_type = TRACKER_SPARQL_VALUE_TYPE_UNBOUND; @@ -3536,7 +3530,7 @@ tracker_db_cursor_get_annotated_value_type (TrackerDBCursor *cursor, *value_type = TRACKER_SPARQL_VALUE_TYPE_DATETIME; return TRUE; case TRACKER_PROPERTY_TYPE_RESOURCE: - if (g_str_has_prefix (tracker_db_cursor_get_string (cursor, column, NULL), + if (g_str_has_prefix ((const gchar *) sqlite3_column_text (cursor->stmt, column), "urn:bnode:")) *value_type = TRACKER_SPARQL_VALUE_TYPE_BLANK_NODE; else @@ -3554,34 +3548,35 @@ tracker_db_cursor_get_value_type (TrackerDBCursor *cursor, { TrackerDBInterface *iface; gint column_type; - guint n_columns = tracker_db_cursor_get_n_columns (cursor); TrackerSparqlValueType value_type; - g_return_val_if_fail (column < n_columns, TRACKER_SPARQL_VALUE_TYPE_UNBOUND); - - if (tracker_db_cursor_get_annotated_value_type (cursor, column, &value_type)) - return value_type; - iface = cursor->ref_stmt->db_interface; tracker_db_interface_lock (iface); column_type = sqlite3_column_type (cursor->stmt, column); - tracker_db_interface_unlock (iface); - - if (column_type == SQLITE_NULL) { - return TRACKER_SPARQL_VALUE_TYPE_UNBOUND; - } + if (!tracker_db_cursor_get_annotated_value_type (cursor, column, column_type, &value_type)) { + if (column_type == SQLITE_NULL) { + value_type = TRACKER_SPARQL_VALUE_TYPE_UNBOUND; + } - switch (column_type) { - case SQLITE_INTEGER: - return TRACKER_SPARQL_VALUE_TYPE_INTEGER; - case SQLITE_FLOAT: - return TRACKER_SPARQL_VALUE_TYPE_DOUBLE; - default: - return TRACKER_SPARQL_VALUE_TYPE_STRING; + switch (column_type) { + case SQLITE_INTEGER: + value_type = TRACKER_SPARQL_VALUE_TYPE_INTEGER; + break; + case SQLITE_FLOAT: + value_type = TRACKER_SPARQL_VALUE_TYPE_DOUBLE; + break; + default: + value_type = TRACKER_SPARQL_VALUE_TYPE_STRING; + break; + } } + + tracker_db_interface_unlock (iface); + + return value_type; } const gchar* diff --git a/src/libtracker-sparql/core/tracker-vtab-triples.c b/src/libtracker-sparql/core/tracker-vtab-triples.c index 4d18f84f6..f3fe7aea1 100644 --- a/src/libtracker-sparql/core/tracker-vtab-triples.c +++ b/src/libtracker-sparql/core/tracker-vtab-triples.c @@ -37,8 +37,10 @@ #define SQLITE_INDEX_CONSTRAINT_ISNULL 71 #endif +/* Properties are additional columns after graph and rowid */ +#define FIRST_PROPERTY_COLUMN 2 + enum { - COL_ROWID, COL_GRAPH, COL_SUBJECT, COL_PREDICATE, @@ -77,6 +79,8 @@ typedef struct { struct sqlite3_vtab_cursor parent; TrackerTriplesVTab *vtab; struct sqlite3_stmt *stmt; + TrackerProperty **column_properties; + guint n_alloc_column_properties; struct { sqlite3_value *graph; @@ -88,8 +92,14 @@ typedef struct { GHashTable *query_graphs; GList *properties; + GList *classes; GList *graphs; + const GList *cur_property; + const GList *cur_class; + const GList *cur_graph; + gint column; + guint64 rowid; guint finished : 1; } TrackerTriplesCursor; @@ -120,6 +130,7 @@ tracker_triples_cursor_reset (TrackerTriplesCursor *cursor) g_clear_pointer (&cursor->match.subject, sqlite3_value_free); g_clear_pointer (&cursor->match.predicate, sqlite3_value_free); g_clear_pointer (&cursor->properties, g_list_free); + g_clear_pointer (&cursor->classes, g_list_free); g_clear_pointer (&cursor->graphs, g_list_free); g_clear_pointer (&cursor->query_graphs, g_hash_table_unref); cursor->match.idxFlags = 0; @@ -133,6 +144,7 @@ tracker_triples_cursor_free (gpointer data) TrackerTriplesCursor *cursor = data; tracker_triples_cursor_reset (cursor); + g_clear_pointer (&cursor->column_properties, g_free); g_free (cursor); } @@ -153,7 +165,6 @@ triples_connect (sqlite3 *db, rc = sqlite3_declare_vtab (module->db, "CREATE TABLE x(" - " ID INTEGER," " graph INTEGER," " subject INTEGER, " " predicate INTEGER, " @@ -203,11 +214,6 @@ triples_best_index (sqlite3_vtab *vtab, info->aConstraint[i].iColumn == COL_OBJECT_TYPE) continue; - if (info->aConstraint[i].iColumn == COL_ROWID) { - sqlite3_free (idx_str); - return SQLITE_ERROR; - } - /* We can only check for (in)equality */ if (info->aConstraint[i].op != SQLITE_INDEX_CONSTRAINT_EQ && info->aConstraint[i].op != SQLITE_INDEX_CONSTRAINT_NE && @@ -218,11 +224,11 @@ triples_best_index (sqlite3_vtab *vtab, } /* idxNum encodes the used columns and their operators */ - idx |= masks[info->aConstraint[i].iColumn - 1].mask; + idx |= masks[info->aConstraint[i].iColumn].mask; if (info->aConstraint[i].op == SQLITE_INDEX_CONSTRAINT_NE || info->aConstraint[i].op == SQLITE_INDEX_CONSTRAINT_ISNOTNULL) - idx |= masks[info->aConstraint[i].iColumn - 1].negated_mask; + idx |= masks[info->aConstraint[i].iColumn].negated_mask; /* idxStr stores the mapping between columns and filter arguments */ idx_str[info->aConstraint[i].iColumn] = argv_idx - 1; @@ -281,26 +287,48 @@ triples_close (sqlite3_vtab_cursor *vtab_cursor) } static void -collect_properties (TrackerTriplesCursor *cursor) +collect_tables (TrackerTriplesCursor *cursor) { - TrackerProperty **properties; - guint n_properties, i; - - properties = tracker_ontologies_get_properties (cursor->vtab->module->ontologies, - &n_properties); - for (i = 0; i < n_properties; i++) { - if (cursor->match.predicate) { - gboolean negated = !!(cursor->match.idxFlags & IDX_MATCH_PREDICATE_NEG); - gboolean equals = - (sqlite3_value_int64 (cursor->match.predicate) == - tracker_property_get_id (properties[i])); + TrackerProperty *property = NULL; + const gchar *uri = NULL; + gboolean pred_negated; - if (equals == negated) - continue; - } + pred_negated = !!(cursor->match.idxFlags & IDX_MATCH_PREDICATE_NEG); - cursor->properties = g_list_prepend (cursor->properties, - properties[i]); + if (cursor->match.predicate) { + uri = tracker_ontologies_get_uri_by_id (cursor->vtab->module->ontologies, + sqlite3_value_int64 (cursor->match.predicate)); + } + + if (uri) { + property = tracker_ontologies_get_property_by_uri (cursor->vtab->module->ontologies, + uri); + } + + if (property && !pred_negated) { + cursor->properties = g_list_prepend (cursor->properties, property); + } else { + TrackerProperty **properties; + guint n_properties, i; + + properties = tracker_ontologies_get_properties (cursor->vtab->module->ontologies, + &n_properties); + for (i = 0; i < n_properties; i++) { + if (tracker_property_get_multiple_values (properties[i])) { + if (pred_negated && property == properties[i]) + continue; + + cursor->properties = g_list_prepend (cursor->properties, + properties[i]); + } else { + TrackerClass *class; + + class = tracker_property_get_domain (properties[i]); + + if (!g_list_find (cursor->classes, class)) + cursor->classes = g_list_prepend (cursor->classes, class); + } + } } } @@ -389,31 +417,75 @@ bind_arg (sqlite3_stmt *stmt, sqlite3_bind_value (stmt, idx, value); } +static TrackerProperty * +get_column_property (TrackerTriplesCursor *cursor, + int n_col) +{ + TrackerProperty *property; + const gchar *col_name; + int n_cols; + + n_cols = sqlite3_column_count (cursor->stmt); + g_assert ((guint) n_cols <= cursor->n_alloc_column_properties); + + if (n_col < 0 || n_col >= n_cols) + return NULL; + + property = cursor->column_properties[n_col]; + + if (!property) { + col_name = sqlite3_column_name (cursor->stmt, n_col); + property = tracker_ontologies_get_property_by_uri (cursor->vtab->module->ontologies, + col_name); + cursor->column_properties[n_col] = property; + } + + return property; +} + static gboolean iterate_next_stmt (TrackerTriplesCursor *cursor, const gchar **graph, TrackerRowid *graph_id, + TrackerClass **class, TrackerProperty **property) { TrackerRowid *id; - while (cursor->properties && !cursor->graphs) { - /* Iterate to next property, and redo graph list */ - cursor->properties = g_list_remove (cursor->properties, - cursor->properties->data); - cursor->graphs = g_hash_table_get_keys (cursor->query_graphs); - } + *graph_id = 0; + *graph = NULL; + *class = NULL; + *property = NULL; - if (!cursor->properties) + if (cursor->finished) return FALSE; - *property = cursor->properties->data; + if (cursor->cur_class) + cursor->cur_class = cursor->cur_class->next; + else if (cursor->cur_property) + cursor->cur_property = cursor->cur_property->next; + + if (!cursor->cur_class && !cursor->cur_property) { + if (cursor->cur_graph) + cursor->cur_graph = cursor->cur_graph->next; + else + cursor->cur_graph = cursor->graphs; + + cursor->cur_class = cursor->classes; + cursor->cur_property = cursor->properties; + } + + if (!cursor->cur_graph) + return FALSE; - id = cursor->graphs->data; + id = cursor->cur_graph->data; *graph_id = *id; *graph = g_hash_table_lookup (cursor->query_graphs, id); - cursor->graphs = g_list_remove (cursor->graphs, cursor->graphs->data); + if (cursor->cur_class) + *class = cursor->cur_class->data; + else if (cursor->cur_property) + *property = cursor->cur_property->data; return TRUE; } @@ -422,41 +494,72 @@ static int init_stmt (TrackerTriplesCursor *cursor) { TrackerProperty *property; + TrackerClass *class; const gchar *graph; TrackerRowid graph_id; - GString *sql; - int rc; + int rc = SQLITE_DONE; + + while (iterate_next_stmt (cursor, &graph, &graph_id, &class, &property)) { + GString *sql; - while (iterate_next_stmt (cursor, &graph, &graph_id, &property)) { sql = g_string_new (NULL); - g_string_append_printf (sql, - "SELECT %" G_GINT64_FORMAT ", t.ID, " - " (SELECT ID From Resource WHERE Uri = \"%s\"), " - " t.\"%s\", " - " %d " - "FROM \"%s\".\"%s\" AS t " - "WHERE 1 ", - graph_id, - tracker_property_get_uri (property), - tracker_property_get_name (property), - tracker_property_get_data_type (property), - graph, - tracker_property_get_table_name (property)); + + if (class) { + TrackerProperty **properties; + guint n_properties, i; + + g_string_append_printf (sql, + "SELECT %" G_GINT64_FORMAT ", ROWID ", + graph_id); + + + properties = tracker_ontologies_get_properties (cursor->vtab->module->ontologies, + &n_properties); + for (i = 0; i < n_properties; i++) { + if (!tracker_property_get_multiple_values (properties[i]) && + tracker_property_get_domain (properties[i]) == class) { + g_string_append_printf (sql, ", \"%s\" ", + tracker_property_get_name (properties[i])); + } + } + + g_string_append_printf (sql, + "FROM \"%s\".\"%s\" AS t ", + graph, + tracker_class_get_name (class)); + } else if (property) { + sql = g_string_new (NULL); + + if (tracker_property_get_multiple_values (property)) { + g_string_append_printf (sql, + "SELECT %" G_GINT64_FORMAT ", * " + "FROM \"%s\".\"%s\" AS t ", + graph_id, + graph, + tracker_property_get_table_name (property)); + } else { + g_string_append_printf (sql, + "SELECT %" G_GINT64_FORMAT ", ROWID, \"%s\" " + "FROM \"%s\".\"%s\" AS t ", + graph_id, + tracker_property_get_name (property), + graph, + tracker_property_get_table_name (property)); + } + } if (cursor->match.subject) { - g_string_append (sql, "AND t.ID "); + g_string_append (sql, "WHERE t.ID "); add_arg_check (sql, cursor->match.subject, !!(cursor->match.idxFlags & IDX_MATCH_SUBJECT_NEG), "@s"); } rc = sqlite3_prepare_v2 (cursor->vtab->module->db, - sql->str, -1, &cursor->stmt, 0); + sql->str, -1, &cursor->stmt, 0); g_string_free (sql, TRUE); if (rc == SQLITE_OK) { - if (cursor->match.graph) - bind_arg (cursor->stmt, cursor->match.graph, "@g"); if (cursor->match.subject) bind_arg (cursor->stmt, cursor->match.subject, "@s"); @@ -464,12 +567,29 @@ init_stmt (TrackerTriplesCursor *cursor) } if (rc != SQLITE_DONE) - return rc; + break; g_clear_pointer (&cursor->stmt, sqlite3_finalize); } - return SQLITE_DONE; + if (rc == SQLITE_ROW) { + int columns; + + columns = sqlite3_column_count (cursor->stmt); + + if ((guint) columns > cursor->n_alloc_column_properties) { + g_free (cursor->column_properties); + cursor->column_properties = + g_new0 (TrackerProperty*, columns); + cursor->n_alloc_column_properties = columns; + } else { + bzero (cursor->column_properties, + sizeof (TrackerProperty*) * + cursor->n_alloc_column_properties); + } + } + + return rc; } static int @@ -504,8 +624,14 @@ triples_filter (sqlite3_vtab_cursor *vtab_cursor, if ((rc = collect_graphs (cursor)) != SQLITE_DONE) return rc; - collect_properties (cursor); + collect_tables (cursor); + + cursor->cur_graph = NULL; + cursor->cur_class = NULL; + cursor->cur_property = NULL; + rc = init_stmt (cursor); + cursor->column = FIRST_PROPERTY_COLUMN; if (rc == SQLITE_DONE) cursor->finished = TRUE; @@ -520,21 +646,43 @@ static int triples_next (sqlite3_vtab_cursor *vtab_cursor) { TrackerTriplesCursor *cursor = (TrackerTriplesCursor *) vtab_cursor; - int rc; + int rc, column_count; + + cursor->rowid++; + column_count = sqlite3_column_count (cursor->stmt); + + while (cursor->column < column_count) { + cursor->column++; + + if ((cursor->match.idxFlags & IDX_MATCH_PREDICATE_NEG) != 0) { + TrackerProperty *property; + + /* Single valued properties skip the "predicate != ..." here */ + property = get_column_property (cursor, cursor->column); + + if (property && + sqlite3_value_int64 (cursor->match.predicate) == + tracker_property_get_id (property)) + cursor->column++; + } + + if (sqlite3_column_type (cursor->stmt, cursor->column) != SQLITE_NULL) + break; + } + + if (cursor->column < column_count) + return SQLITE_OK; rc = sqlite3_step (cursor->stmt); + cursor->column = FIRST_PROPERTY_COLUMN; if (rc == SQLITE_DONE) { g_clear_pointer (&cursor->stmt, sqlite3_finalize); rc = init_stmt (cursor); } - if (rc == SQLITE_ROW) { - cursor->rowid++; - } else { + if (rc != SQLITE_ROW) cursor->finished = TRUE; - } - if (rc != SQLITE_ROW && rc != SQLITE_DONE) return rc; @@ -556,12 +704,34 @@ triples_column (sqlite3_vtab_cursor *vtab_cursor, { TrackerTriplesCursor *cursor = (TrackerTriplesCursor *) vtab_cursor; sqlite3_value *value; + TrackerProperty *property; - if (n_col == COL_ROWID) { - sqlite3_result_int64 (context, cursor->rowid); - } else { - value = sqlite3_column_value (cursor->stmt, n_col - 1); + switch (n_col) { + case COL_GRAPH: + value = sqlite3_column_value (cursor->stmt, 0); + sqlite3_result_value (context, value); + break; + case COL_SUBJECT: + value = sqlite3_column_value (cursor->stmt, 1); sqlite3_result_value (context, value); + break; + case COL_OBJECT: + value = sqlite3_column_value (cursor->stmt, cursor->column); + sqlite3_result_value (context, value); + break; + case COL_PREDICATE: + case COL_OBJECT_TYPE: + property = get_column_property (cursor, cursor->column); + if (!property) { + sqlite3_result_error_code (context, SQLITE_CORRUPT); + break; + } + + if (n_col == COL_PREDICATE) + sqlite3_result_int64 (context, tracker_property_get_id (property)); + else + sqlite3_result_int64 (context, tracker_property_get_data_type (property)); + break; } return SQLITE_OK; diff --git a/src/libtracker-sparql/tracker-namespace-manager.c b/src/libtracker-sparql/tracker-namespace-manager.c index 377feab81..f2eabdf00 100644 --- a/src/libtracker-sparql/tracker-namespace-manager.c +++ b/src/libtracker-sparql/tracker-namespace-manager.c @@ -31,8 +31,15 @@ #define MAX_PREFIX_LENGTH 100 typedef struct { + const gchar *prefix; + const gchar *uri; + int uri_len; +} PrefixMap; + +typedef struct { GHashTable *prefix_to_namespace; GHashTable *namespace_to_prefix; + GArray *prefix_map; gboolean sealed; } TrackerNamespaceManagerPrivate; @@ -74,6 +81,7 @@ tracker_namespace_manager_init (TrackerNamespaceManager *self) priv->prefix_to_namespace = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); priv->namespace_to_prefix = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + priv->prefix_map = g_array_new (FALSE, FALSE, sizeof (PrefixMap)); } static void @@ -85,6 +93,7 @@ finalize (GObject *object) g_hash_table_unref (priv->prefix_to_namespace); g_hash_table_unref (priv->namespace_to_prefix); + g_array_unref (priv->prefix_map); (G_OBJECT_CLASS (tracker_namespace_manager_parent_class)->finalize)(object); } @@ -220,6 +229,8 @@ tracker_namespace_manager_add_prefix (TrackerNamespaceManager *self, { TrackerNamespaceManagerPrivate *priv; const char *str; + gchar *prefix_copy, *ns_copy; + PrefixMap map; g_return_if_fail (TRACKER_IS_NAMESPACE_MANAGER (self)); g_return_if_fail (prefix != NULL); @@ -245,8 +256,16 @@ tracker_namespace_manager_add_prefix (TrackerNamespaceManager *self, return; } - g_hash_table_insert (priv->prefix_to_namespace, g_strdup (prefix), g_strdup (ns)); + prefix_copy = g_strdup (prefix); + ns_copy = g_strdup (ns); + + g_hash_table_insert (priv->prefix_to_namespace, prefix_copy, ns_copy); g_hash_table_insert (priv->namespace_to_prefix, g_strdup (ns), g_strdup (prefix)); + + map.prefix = prefix_copy; + map.uri = ns_copy; + map.uri_len = strlen (map.uri); + g_array_append_val (priv->prefix_map, map); } /** @@ -311,20 +330,28 @@ tracker_namespace_manager_compress_uri (TrackerNamespaceManager *self, const char *uri) { TrackerNamespaceManagerPrivate *priv; - GHashTableIter iter; - const char *prefix, *namespace, *suffix; + guint i; + int len; g_return_val_if_fail (TRACKER_IS_NAMESPACE_MANAGER (self), NULL); g_return_val_if_fail (uri != NULL, NULL); priv = GET_PRIVATE (self); - g_hash_table_iter_init (&iter, priv->prefix_to_namespace); + len = strlen (uri); + + for (i = 0; i < priv->prefix_map->len; i++) { + PrefixMap *map; + const char *suffix; + + map = &g_array_index (priv->prefix_map, PrefixMap, i); - while (g_hash_table_iter_next (&iter, (gpointer *) &prefix, (gpointer *) &namespace)) { - if (g_str_has_prefix (uri, namespace)) { - suffix = &uri[strlen(namespace)]; - return g_strdup_printf ("%s:%s", prefix, suffix); + if (map->uri_len <= len && + map->uri[0] == uri[0] && + map->uri[map->uri_len - 1] == uri[map->uri_len - 1] && + strncmp (uri, map->uri, map->uri_len) == 0) { + suffix = &uri[map->uri_len]; + return g_strconcat (map->prefix, ":", suffix, NULL); } } diff --git a/src/libtracker-sparql/tracker-serializer-trig.c b/src/libtracker-sparql/tracker-serializer-trig.c index 307bfb78c..2af6d557f 100644 --- a/src/libtracker-sparql/tracker-serializer-trig.c +++ b/src/libtracker-sparql/tracker-serializer-trig.c @@ -42,7 +42,7 @@ struct _TrackerQuad struct _TrackerSerializerTrig { TrackerSerializer parent_instance; - TrackerQuad *last_quad; + TrackerQuad last_quad; GString *data; guint stream_closed : 1; guint cursor_started : 1; @@ -63,15 +63,10 @@ typedef enum TRACKER_QUAD_BREAK_OBJECT, } TrackerQuadBreak; -static TrackerQuad * -tracker_quad_new_from_cursor (TrackerSparqlCursor *cursor) +static void +tracker_quad_init_from_cursor (TrackerQuad *quad, + TrackerSparqlCursor *cursor) { - TrackerQuad *quad; - - if (tracker_sparql_cursor_get_n_columns (cursor) < 3) - return NULL; - - quad = g_new0 (TrackerQuad, 1); quad->subject_type = tracker_sparql_cursor_get_value_type (cursor, 0); quad->object_type = tracker_sparql_cursor_get_value_type (cursor, 2); quad->subject = g_strdup (tracker_sparql_cursor_get_string (cursor, 0, NULL)); @@ -80,6 +75,8 @@ tracker_quad_new_from_cursor (TrackerSparqlCursor *cursor) if (tracker_sparql_cursor_get_n_columns (cursor) >= 4) quad->graph = g_strdup (tracker_sparql_cursor_get_string (cursor, 3, NULL)); + else + quad->graph = NULL; if (quad->subject_type == TRACKER_SPARQL_VALUE_TYPE_STRING) { if (g_str_has_prefix (quad->subject, "urn:bnode:")) { @@ -94,25 +91,22 @@ tracker_quad_new_from_cursor (TrackerSparqlCursor *cursor) quad->object_type = TRACKER_SPARQL_VALUE_TYPE_BLANK_NODE; } } - - return quad; } static void -tracker_quad_free (TrackerQuad *quad) +tracker_quad_clear (TrackerQuad *quad) { - g_free (quad->subject); - g_free (quad->predicate); - g_free (quad->object); - g_free (quad->graph); - g_free (quad); + g_clear_pointer (&quad->subject, g_free); + g_clear_pointer (&quad->predicate, g_free); + g_clear_pointer (&quad->object, g_free); + g_clear_pointer (&quad->graph, g_free); } static TrackerQuadBreak tracker_quad_get_break (TrackerQuad *last, TrackerQuad *cur) { - if (!last) + if (!last->subject) return TRACKER_QUAD_BREAK_NONE; if (g_strcmp0 (last->graph, cur->graph) != 0) @@ -148,9 +142,11 @@ print_value (GString *str, shortname = tracker_namespace_manager_compress_uri (namespaces, value); if (shortname) { - g_string_append_printf (str, "%s", shortname); + g_string_append (str, shortname); } else { - g_string_append_printf (str, "<%s>", value); + g_string_append_c (str, '<'); + g_string_append (str, value); + g_string_append_c (str, '>'); } g_free (shortname); @@ -160,7 +156,8 @@ print_value (GString *str, gchar *bnode_label; bnode_label = g_strdelimit (g_strdup (value), ":", '_'); - g_string_append_printf (str, "_:%s", bnode_label); + g_string_append (str, "_:"); + g_string_append (str, bnode_label); g_free (bnode_label); break; } @@ -169,8 +166,9 @@ print_value (GString *str, gchar *escaped; escaped = tracker_sparql_escape_string (value); - g_string_append_printf (str, "\"%s\"", - escaped); + g_string_append_c (str, '"'); + g_string_append (str, escaped); + g_string_append_c (str, '"'); g_free (escaped); break; } @@ -190,14 +188,14 @@ print_value (GString *str, static gboolean serialize_up_to_size (TrackerSerializerTrig *serializer_trig, - gsize size, - GCancellable *cancellable, - GError **error) + gsize size, + GCancellable *cancellable, + GError **error) { TrackerSparqlCursor *cursor; TrackerNamespaceManager *namespaces; GError *inner_error = NULL; - TrackerQuad *cur; + TrackerQuad cur; if (!serializer_trig->data) serializer_trig->data = g_string_new (NULL); @@ -210,7 +208,8 @@ serialize_up_to_size (TrackerSerializerTrig *serializer_trig, str = tracker_namespace_manager_print_turtle (namespaces); - g_string_append_printf (serializer_trig->data, "%s\n", str); + g_string_append (serializer_trig->data, str); + g_string_append_c (serializer_trig->data, '\n'); g_free (str); serializer_trig->head_printed = TRUE; } @@ -231,9 +230,9 @@ serialize_up_to_size (TrackerSerializerTrig *serializer_trig, serializer_trig->cursor_started = TRUE; } - cur = tracker_quad_new_from_cursor (cursor); + tracker_quad_init_from_cursor (&cur, cursor); - if (!cur) { + if (!cur.subject && cur.predicate && cur.object) { g_set_error (error, TRACKER_SPARQL_ERROR, TRACKER_SPARQL_ERROR_INTERNAL, @@ -241,15 +240,15 @@ serialize_up_to_size (TrackerSerializerTrig *serializer_trig, return FALSE; } - br = tracker_quad_get_break (serializer_trig->last_quad, cur); + br = tracker_quad_get_break (&serializer_trig->last_quad, &cur); if (br <= TRACKER_QUAD_BREAK_GRAPH) { if (br == TRACKER_QUAD_BREAK_GRAPH) g_string_append (serializer_trig->data, " .\n}\n\n"); - if (cur->graph) { + if (cur.graph) { g_string_append (serializer_trig->data, "GRAPH "); - print_value (serializer_trig->data, cur->graph, + print_value (serializer_trig->data, cur.graph, TRACKER_SPARQL_VALUE_TYPE_URI, namespaces); g_string_append_c (serializer_trig->data, ' '); } @@ -260,7 +259,7 @@ serialize_up_to_size (TrackerSerializerTrig *serializer_trig, if (br <= TRACKER_QUAD_BREAK_SUBJECT) { if (br == TRACKER_QUAD_BREAK_SUBJECT) g_string_append (serializer_trig->data, " .\n\n "); - print_value (serializer_trig->data, cur->subject, cur->subject_type, namespaces); + print_value (serializer_trig->data, cur.subject, cur.subject_type, namespaces); } if (br <= TRACKER_QUAD_BREAK_PREDICATE) { @@ -269,7 +268,7 @@ serialize_up_to_size (TrackerSerializerTrig *serializer_trig, else g_string_append_c (serializer_trig->data, ' '); - print_value (serializer_trig->data, cur->predicate, + print_value (serializer_trig->data, cur.predicate, TRACKER_SPARQL_VALUE_TYPE_URI, namespaces); } @@ -278,12 +277,12 @@ serialize_up_to_size (TrackerSerializerTrig *serializer_trig, g_string_append (serializer_trig->data, ","); g_string_append_c (serializer_trig->data, ' '); - print_value (serializer_trig->data, cur->object, cur->object_type, namespaces); + print_value (serializer_trig->data, cur.object, cur.object_type, namespaces); } serializer_trig->has_quads = TRUE; - g_clear_pointer (&serializer_trig->last_quad, tracker_quad_free); - serializer_trig->last_quad = cur; + tracker_quad_clear (&serializer_trig->last_quad); + memcpy (&serializer_trig->last_quad, &cur, sizeof (TrackerQuad)); } /* Close the last quad */ @@ -332,7 +331,7 @@ tracker_serializer_trig_close (GInputStream *istream, { TrackerSerializerTrig *serializer_trig = TRACKER_SERIALIZER_TRIG (istream); - g_clear_pointer (&serializer_trig->last_quad, tracker_quad_free); + tracker_quad_clear (&serializer_trig->last_quad); if (serializer_trig->data) { g_string_free (serializer_trig->data, TRUE); diff --git a/src/libtracker-sparql/tracker-serializer-turtle.c b/src/libtracker-sparql/tracker-serializer-turtle.c index fc60f2325..2202c9c1b 100644 --- a/src/libtracker-sparql/tracker-serializer-turtle.c +++ b/src/libtracker-sparql/tracker-serializer-turtle.c @@ -41,7 +41,7 @@ struct _TrackerTriple struct _TrackerSerializerTurtle { TrackerSerializer parent_instance; - TrackerTriple *last_triple; + TrackerTriple last_triple; GString *data; guint stream_closed : 1; guint cursor_started : 1; @@ -61,15 +61,10 @@ typedef enum TRACKER_TRIPLE_BREAK_OBJECT, } TrackerTripleBreak; -static TrackerTriple * -tracker_triple_new_from_cursor (TrackerSparqlCursor *cursor) +static void +tracker_triple_init_from_cursor (TrackerTriple *triple, + TrackerSparqlCursor *cursor) { - TrackerTriple *triple; - - if (tracker_sparql_cursor_get_n_columns (cursor) < 3) - return NULL; - - triple = g_new0 (TrackerTriple, 1); triple->subject_type = tracker_sparql_cursor_get_value_type (cursor, 0); triple->object_type = tracker_sparql_cursor_get_value_type (cursor, 2); triple->subject = g_strdup (tracker_sparql_cursor_get_string (cursor, 0, NULL)); @@ -89,24 +84,21 @@ tracker_triple_new_from_cursor (TrackerSparqlCursor *cursor) triple->object_type = TRACKER_SPARQL_VALUE_TYPE_BLANK_NODE; } } - - return triple; } static void -tracker_triple_free (TrackerTriple *triple) +tracker_triple_clear (TrackerTriple *triple) { - g_free (triple->subject); - g_free (triple->predicate); - g_free (triple->object); - g_free (triple); + g_clear_pointer (&triple->subject, g_free); + g_clear_pointer (&triple->predicate, g_free); + g_clear_pointer (&triple->object, g_free); } static TrackerTripleBreak tracker_triple_get_break (TrackerTriple *last, TrackerTriple *cur) { - if (!last) + if (!last->subject) return TRACKER_TRIPLE_BREAK_NONE; if (g_strcmp0 (last->subject, cur->subject) != 0) @@ -139,9 +131,11 @@ print_value (GString *str, shortname = tracker_namespace_manager_compress_uri (namespaces, value); if (shortname) { - g_string_append_printf (str, "%s", shortname); + g_string_append (str, shortname); } else { - g_string_append_printf (str, "<%s>", value); + g_string_append_c (str, '<'); + g_string_append (str, value); + g_string_append_c (str, '>'); } g_free (shortname); @@ -151,7 +145,8 @@ print_value (GString *str, gchar *bnode_label; bnode_label = g_strdelimit (g_strdup (value), ":", '_'); - g_string_append_printf (str, "_:%s", bnode_label); + g_string_append (str, "_:"); + g_string_append (str, bnode_label); g_free (bnode_label); break; } @@ -160,8 +155,9 @@ print_value (GString *str, gchar *escaped; escaped = tracker_sparql_escape_string (value); - g_string_append_printf (str, "\"%s\"", - escaped); + g_string_append_c (str, '"'); + g_string_append (str, escaped); + g_string_append_c (str, '"'); g_free (escaped); break; } @@ -181,14 +177,14 @@ print_value (GString *str, static gboolean serialize_up_to_size (TrackerSerializerTurtle *serializer_ttl, - gsize size, - GCancellable *cancellable, - GError **error) + gsize size, + GCancellable *cancellable, + GError **error) { TrackerSparqlCursor *cursor; TrackerNamespaceManager *namespaces; GError *inner_error = NULL; - TrackerTriple *cur; + TrackerTriple cur; if (!serializer_ttl->data) serializer_ttl->data = g_string_new (NULL); @@ -201,7 +197,8 @@ serialize_up_to_size (TrackerSerializerTurtle *serializer_ttl, str = tracker_namespace_manager_print_turtle (namespaces); - g_string_append_printf (serializer_ttl->data, "%s\n", str); + g_string_append (serializer_ttl->data, str); + g_string_append_c (serializer_ttl->data, '\n'); g_free (str); serializer_ttl->head_printed = TRUE; } @@ -222,9 +219,9 @@ serialize_up_to_size (TrackerSerializerTurtle *serializer_ttl, serializer_ttl->cursor_started = TRUE; } - cur = tracker_triple_new_from_cursor (cursor); + tracker_triple_init_from_cursor (&cur, cursor); - if (!cur) { + if (!cur.subject || !cur.predicate || !cur.object) { g_set_error (error, TRACKER_SPARQL_ERROR, TRACKER_SPARQL_ERROR_INTERNAL, @@ -232,12 +229,12 @@ serialize_up_to_size (TrackerSerializerTurtle *serializer_ttl, return FALSE; } - br = tracker_triple_get_break (serializer_ttl->last_triple, cur); + br = tracker_triple_get_break (&serializer_ttl->last_triple, &cur); if (br <= TRACKER_TRIPLE_BREAK_SUBJECT) { if (br == TRACKER_TRIPLE_BREAK_SUBJECT) g_string_append (serializer_ttl->data, " .\n\n"); - print_value (serializer_ttl->data, cur->subject, cur->subject_type, namespaces); + print_value (serializer_ttl->data, cur.subject, cur.subject_type, namespaces); } if (br <= TRACKER_TRIPLE_BREAK_PREDICATE) { @@ -246,7 +243,7 @@ serialize_up_to_size (TrackerSerializerTurtle *serializer_ttl, else g_string_append_c (serializer_ttl->data, ' '); - print_value (serializer_ttl->data, cur->predicate, + print_value (serializer_ttl->data, cur.predicate, TRACKER_SPARQL_VALUE_TYPE_URI, namespaces); } @@ -255,12 +252,12 @@ serialize_up_to_size (TrackerSerializerTurtle *serializer_ttl, g_string_append (serializer_ttl->data, ","); g_string_append_c (serializer_ttl->data, ' '); - print_value (serializer_ttl->data, cur->object, cur->object_type, namespaces); + print_value (serializer_ttl->data, cur.object, cur.object_type, namespaces); } serializer_ttl->has_triples = TRUE; - g_clear_pointer (&serializer_ttl->last_triple, tracker_triple_free); - serializer_ttl->last_triple = cur; + tracker_triple_clear (&serializer_ttl->last_triple); + memcpy (&serializer_ttl->last_triple, &cur, sizeof (TrackerTriple)); } /* Print dot for the last triple */ @@ -309,7 +306,7 @@ tracker_serializer_turtle_close (GInputStream *istream, { TrackerSerializerTurtle *serializer_ttl = TRACKER_SERIALIZER_TURTLE (istream); - g_clear_pointer (&serializer_ttl->last_triple, tracker_triple_free); + tracker_triple_clear (&serializer_ttl->last_triple); if (serializer_ttl->data) { g_string_free (serializer_ttl->data, TRUE); diff --git a/tests/libtracker-sparql/serialize/describe-graph-trig.out b/tests/libtracker-sparql/serialize/describe-graph-trig.out index 323a1e0d5..0c03de073 100644 --- a/tests/libtracker-sparql/serialize/describe-graph-trig.out +++ b/tests/libtracker-sparql/serialize/describe-graph-trig.out @@ -14,32 +14,19 @@ @prefix xsd: <http://www.w3.org/2001/XMLSchema#> . @prefix mfo: <http://tracker.api.gnome.org/ontology/v3/mfo#> . -GRAPH <http://example/B> { - <http://example/a> nmm:trackNumber 1 . - - <http://example/b> nmm:beatsPerMinute 120 . -} - GRAPH <http://example/A> { <http://example/a> nie:title "Aaa" ; dc:title "Aaa" ; + rdf:type rdfs:Resource, nie:InformationElement, nfo:Media, nmm:MusicPiece . } GRAPH <http://example/B> { + <http://example/a> nmm:trackNumber 1 . -} - -GRAPH <http://example/A> { -} + <http://example/b> nmm:beatsPerMinute 120 . -GRAPH <http://example/B> { -} -GRAPH <http://example/A> { - <http://example/a> rdf:type rdfs:Resource, nie:InformationElement, nfo:Media, nmm:MusicPiece . -} -GRAPH <http://example/B> { <http://example/a> rdf:type rdfs:Resource, nie:InformationElement, nfo:Media, nmm:MusicPiece . <http://example/b> rdf:type rdfs:Resource, nie:InformationElement, nfo:Media, nmm:MusicPiece . diff --git a/tests/libtracker-sparql/serialize/describe-graph-ttl.out b/tests/libtracker-sparql/serialize/describe-graph-ttl.out index 196f83d8e..6204d080d 100644 --- a/tests/libtracker-sparql/serialize/describe-graph-ttl.out +++ b/tests/libtracker-sparql/serialize/describe-graph-ttl.out @@ -14,16 +14,15 @@ @prefix xsd: <http://www.w3.org/2001/XMLSchema#> . @prefix mfo: <http://tracker.api.gnome.org/ontology/v3/mfo#> . -<http://example/a> nmm:trackNumber 1 . - -<http://example/b> nmm:beatsPerMinute 120 . - <http://example/a> nie:title "Aaa" ; dc:title "Aaa" ; + rdf:type rdfs:Resource, nie:InformationElement, nfo:Media, nmm:MusicPiece ; + nmm:trackNumber 1 . +<http://example/b> nmm:beatsPerMinute 120 . -<http://example/a> rdf:type rdfs:Resource, nie:InformationElement, nfo:Media, nmm:MusicPiece, rdfs:Resource, nie:InformationElement, nfo:Media, nmm:MusicPiece . +<http://example/a> rdf:type rdfs:Resource, nie:InformationElement, nfo:Media, nmm:MusicPiece . <http://example/b> rdf:type rdfs:Resource, nie:InformationElement, nfo:Media, nmm:MusicPiece . diff --git a/tests/libtracker-sparql/serialize/describe-single-trig.out b/tests/libtracker-sparql/serialize/describe-single-trig.out index ec5667d31..77649d1cf 100644 --- a/tests/libtracker-sparql/serialize/describe-single-trig.out +++ b/tests/libtracker-sparql/serialize/describe-single-trig.out @@ -16,7 +16,7 @@ { rdfs:Resource nrl:classSpecification "https://www.w3.org/TR/rdf-schema/#ch_resource" ; - rdfs:label "All Resources" ; rdfs:comment "All resources" ; + rdfs:label "All Resources" ; rdf:type rdfs:Resource, rdfs:Class . } diff --git a/tests/libtracker-sparql/serialize/describe-single-ttl.out b/tests/libtracker-sparql/serialize/describe-single-ttl.out index 78b8ce55a..3b76470f6 100644 --- a/tests/libtracker-sparql/serialize/describe-single-ttl.out +++ b/tests/libtracker-sparql/serialize/describe-single-ttl.out @@ -15,6 +15,6 @@ @prefix mfo: <http://tracker.api.gnome.org/ontology/v3/mfo#> . rdfs:Resource nrl:classSpecification "https://www.w3.org/TR/rdf-schema/#ch_resource" ; - rdfs:label "All Resources" ; rdfs:comment "All resources" ; + rdfs:label "All Resources" ; rdf:type rdfs:Resource, rdfs:Class . diff --git a/tests/libtracker-sparql/serialize/describe-var-trig.out b/tests/libtracker-sparql/serialize/describe-var-trig.out index eb1ceda36..ddcbc81d4 100644 --- a/tests/libtracker-sparql/serialize/describe-var-trig.out +++ b/tests/libtracker-sparql/serialize/describe-var-trig.out @@ -16,8 +16,8 @@ { rdfs:Class nrl:classSpecification "https://www.w3.org/TR/rdf-schema/#ch_class" ; - rdfs:label "Class" ; rdfs:comment "The class of classes" ; + rdfs:label "Class" ; rdfs:subClassOf rdfs:Resource ; rdf:type rdfs:Resource, rdfs:Class . } diff --git a/tests/libtracker-sparql/serialize/describe-var-ttl.out b/tests/libtracker-sparql/serialize/describe-var-ttl.out index 8cd80c5d4..26a905ba8 100644 --- a/tests/libtracker-sparql/serialize/describe-var-ttl.out +++ b/tests/libtracker-sparql/serialize/describe-var-ttl.out @@ -15,7 +15,7 @@ @prefix mfo: <http://tracker.api.gnome.org/ontology/v3/mfo#> . rdfs:Class nrl:classSpecification "https://www.w3.org/TR/rdf-schema/#ch_class" ; - rdfs:label "Class" ; rdfs:comment "The class of classes" ; + rdfs:label "Class" ; rdfs:subClassOf rdfs:Resource ; rdf:type rdfs:Resource, rdfs:Class . |