From a2d6b0820d72c98ab045e4dc6843cef6d9575b2e Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Mon, 22 Jun 2020 16:02:57 +0200 Subject: Merge libtracker-sparql-backend with libtracker-sparql One more step towards the unification of libtracker-sparql. --- src/libtracker-sparql-backend/.gitignore | 1 - src/libtracker-sparql-backend/bus/.gitignore | 5 - src/libtracker-sparql-backend/bus/meson.build | 26 - .../bus/tracker-bus-fd-cursor.vala | 150 --- .../bus/tracker-bus-statement.vala | 91 -- src/libtracker-sparql-backend/bus/tracker-bus.vala | 295 ------ .../bus/tracker-namespace.vala | 29 - src/libtracker-sparql-backend/direct/meson.build | 15 - .../direct/tracker-direct-statement.c | 275 ----- .../direct/tracker-direct-statement.h | 52 - .../direct/tracker-direct.c | 1047 -------------------- .../direct/tracker-direct.h | 56 -- .../direct/tracker-direct.vapi | 10 - src/libtracker-sparql-backend/meson.build | 65 -- src/libtracker-sparql-backend/remote/meson.build | 30 - .../remote/tracker-json-cursor.vala | 140 --- .../remote/tracker-remote.vala | 97 -- .../remote/tracker-xml-cursor.vala | 204 ---- src/libtracker-sparql-backend/tracker-backend.vala | 51 - src/libtracker-sparql/bus/.gitignore | 5 + src/libtracker-sparql/bus/meson.build | 26 + .../bus/tracker-bus-fd-cursor.vala | 150 +++ .../bus/tracker-bus-statement.vala | 91 ++ src/libtracker-sparql/bus/tracker-bus.vala | 295 ++++++ src/libtracker-sparql/bus/tracker-namespace.vala | 29 + src/libtracker-sparql/direct/meson.build | 15 + .../direct/tracker-direct-statement.c | 275 +++++ .../direct/tracker-direct-statement.h | 52 + src/libtracker-sparql/direct/tracker-direct.c | 1047 ++++++++++++++++++++ src/libtracker-sparql/direct/tracker-direct.h | 56 ++ src/libtracker-sparql/direct/tracker-direct.vapi | 10 + src/libtracker-sparql/meson.build | 66 ++ src/libtracker-sparql/remote/meson.build | 30 + .../remote/tracker-json-cursor.vala | 140 +++ src/libtracker-sparql/remote/tracker-remote.vala | 97 ++ .../remote/tracker-xml-cursor.vala | 204 ++++ src/libtracker-sparql/tracker-backend.vala | 51 + src/meson.build | 11 +- 38 files changed, 2643 insertions(+), 2646 deletions(-) delete mode 100644 src/libtracker-sparql-backend/.gitignore delete mode 100644 src/libtracker-sparql-backend/bus/.gitignore delete mode 100644 src/libtracker-sparql-backend/bus/meson.build delete mode 100644 src/libtracker-sparql-backend/bus/tracker-bus-fd-cursor.vala delete mode 100644 src/libtracker-sparql-backend/bus/tracker-bus-statement.vala delete mode 100644 src/libtracker-sparql-backend/bus/tracker-bus.vala delete mode 100644 src/libtracker-sparql-backend/bus/tracker-namespace.vala delete mode 100644 src/libtracker-sparql-backend/direct/meson.build delete mode 100644 src/libtracker-sparql-backend/direct/tracker-direct-statement.c delete mode 100644 src/libtracker-sparql-backend/direct/tracker-direct-statement.h delete mode 100644 src/libtracker-sparql-backend/direct/tracker-direct.c delete mode 100644 src/libtracker-sparql-backend/direct/tracker-direct.h delete mode 100644 src/libtracker-sparql-backend/direct/tracker-direct.vapi delete mode 100644 src/libtracker-sparql-backend/meson.build delete mode 100644 src/libtracker-sparql-backend/remote/meson.build delete mode 100644 src/libtracker-sparql-backend/remote/tracker-json-cursor.vala delete mode 100644 src/libtracker-sparql-backend/remote/tracker-remote.vala delete mode 100644 src/libtracker-sparql-backend/remote/tracker-xml-cursor.vala delete mode 100644 src/libtracker-sparql-backend/tracker-backend.vala create mode 100644 src/libtracker-sparql/bus/.gitignore create mode 100644 src/libtracker-sparql/bus/meson.build create mode 100644 src/libtracker-sparql/bus/tracker-bus-fd-cursor.vala create mode 100644 src/libtracker-sparql/bus/tracker-bus-statement.vala create mode 100644 src/libtracker-sparql/bus/tracker-bus.vala create mode 100644 src/libtracker-sparql/bus/tracker-namespace.vala create mode 100644 src/libtracker-sparql/direct/meson.build create mode 100644 src/libtracker-sparql/direct/tracker-direct-statement.c create mode 100644 src/libtracker-sparql/direct/tracker-direct-statement.h create mode 100644 src/libtracker-sparql/direct/tracker-direct.c create mode 100644 src/libtracker-sparql/direct/tracker-direct.h create mode 100644 src/libtracker-sparql/direct/tracker-direct.vapi create mode 100644 src/libtracker-sparql/remote/meson.build create mode 100644 src/libtracker-sparql/remote/tracker-json-cursor.vala create mode 100644 src/libtracker-sparql/remote/tracker-remote.vala create mode 100644 src/libtracker-sparql/remote/tracker-xml-cursor.vala create mode 100644 src/libtracker-sparql/tracker-backend.vala diff --git a/src/libtracker-sparql-backend/.gitignore b/src/libtracker-sparql-backend/.gitignore deleted file mode 100644 index f8e59d4d9..000000000 --- a/src/libtracker-sparql-backend/.gitignore +++ /dev/null @@ -1 +0,0 @@ -tracker-backend.c diff --git a/src/libtracker-sparql-backend/bus/.gitignore b/src/libtracker-sparql-backend/bus/.gitignore deleted file mode 100644 index c34fe4c56..000000000 --- a/src/libtracker-sparql-backend/bus/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -tracker-namespace.c -tracker-bus.[ch] -tracker-bus*.vapi -tracker-array-cursor.c -tracker-bus-fd-cursor.c diff --git a/src/libtracker-sparql-backend/bus/meson.build b/src/libtracker-sparql-backend/bus/meson.build deleted file mode 100644 index 6d4edf2b1..000000000 --- a/src/libtracker-sparql-backend/bus/meson.build +++ /dev/null @@ -1,26 +0,0 @@ -libtracker_bus = static_library('tracker-bus', - 'tracker-bus.vala', - 'tracker-namespace.vala', - 'tracker-bus-fd-cursor.vala', - 'tracker-bus-statement.vala', - '../../libtracker-common/libtracker-common.vapi', - tracker_common_enum_header, - c_args: tracker_c_args + [ - '-include', 'libtracker-sparql/tracker-private.h', - ], - vala_args: [ - '--debug', - '--pkg', 'posix', - # FIXME: Meson has code to add --target-glib automatically, but it - # doesn't seem to work here. - '--target-glib', glib_required, - ], - dependencies: [tracker_common_dep, tracker_sparql_intermediate_dep], - include_directories: [commoninc, configinc, srcinc], - gnu_symbol_visibility: 'hidden', -) - -tracker_sparql_bus_dep = declare_dependency( - link_with: libtracker_bus, - include_directories: include_directories('.') -) diff --git a/src/libtracker-sparql-backend/bus/tracker-bus-fd-cursor.vala b/src/libtracker-sparql-backend/bus/tracker-bus-fd-cursor.vala deleted file mode 100644 index 954ad1ec7..000000000 --- a/src/libtracker-sparql-backend/bus/tracker-bus-fd-cursor.vala +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright (C) 2010, Nokia - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -class Tracker.Bus.FDCursor : Tracker.Sparql.Cursor { - internal char* buffer; - internal ulong buffer_index; - internal ulong buffer_size; - - internal int _n_columns; - internal int* offsets; - internal int* types; - internal char* data; - internal string[] variable_names; - internal bool cursor_finished; - - public FDCursor (char* buffer, ulong buffer_size, string[] variable_names) { - Object (); - this.buffer = buffer; - this.buffer_size = buffer_size; - this.variable_names = variable_names; - this.cursor_finished = true; - _n_columns = variable_names.length; - } - - ~FDCursor () { - free (buffer); - } - - inline int buffer_read_int () { - int v = *((int*) (buffer + buffer_index)); - - buffer_index += 4; - - return v; - } - - public override int n_columns { - get { return _n_columns; } - } - - public override Sparql.ValueType get_value_type (int column) - requires (types != null) { - if (column >= n_columns) { - return Sparql.ValueType.UNBOUND; - } - - /* Cast from int to enum */ - return (Sparql.ValueType) types[column]; - } - - public override unowned string? get_variable_name (int column) - requires (variable_names != null) { - return variable_names[column]; - } - - public override unowned string? get_string (int column, out long length = null) - requires (cursor_finished == false) { - unowned string str = null; - - if (column >= n_columns) { - length = 0; - return null; - } - - // return null instead of empty string for unbound values - if (types[column] == Sparql.ValueType.UNBOUND) { - length = 0; - return null; - } - - if (column == 0) { - str = (string) data; - } else { - str = (string) (data + offsets[column - 1] + 1); - } - - length = str.length; - - return str; - } - - public override bool next (Cancellable? cancellable = null) throws GLib.Error { - int last_offset; - - if (cancellable != null && cancellable.is_cancelled ()) { - throw new IOError.CANCELLED ("Operation was cancelled"); - } - - if (buffer_index >= buffer_size) { - cursor_finished = true; - data = null; - return false; - } - - /* So, the make up on each cursor segment is: - * - * iteration = [4 bytes for number of columns, - * columns x 4 bytes for types - * columns x 4 bytes for offsets] - */ - - _n_columns = buffer_read_int (); - - /* Storage of ints that will be cast to TrackerSparqlValueType enums, - * also see get_value_type */ - types = (int*) (buffer + buffer_index); - buffer_index += sizeof (int) * n_columns; - - offsets = (int*) (buffer + buffer_index); - buffer_index += sizeof (int) * (n_columns - 1); - last_offset = buffer_read_int (); - - data = buffer + buffer_index; - cursor_finished = false; - - buffer_index += last_offset + 1; - - return true; - } - - public override async bool next_async (Cancellable? cancellable = null) throws GLib.Error { - // next never blocks - return next (cancellable); - } - - public override void rewind () { - buffer_index = 0; - data = buffer; - cursor_finished = false; - } - - public override void close () { - } -} diff --git a/src/libtracker-sparql-backend/bus/tracker-bus-statement.vala b/src/libtracker-sparql-backend/bus/tracker-bus-statement.vala deleted file mode 100644 index b14143901..000000000 --- a/src/libtracker-sparql-backend/bus/tracker-bus-statement.vala +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (C) 2020, Red Hat Ltd. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * Author: Carlos Garnacho - */ - -public class Tracker.Bus.Statement : Tracker.Sparql.Statement { - private DBusConnection bus; - private string query; - private string dbus_name; - private string object_path; - private HashTable arguments; - - public Statement (DBusConnection bus, string dbus_name, string object_path, string query) { - Object (); - this.bus = bus; - this.dbus_name = dbus_name; - this.object_path = object_path; - this.query = query; - this.arguments = new HashTable (str_hash, str_equal); - } - - public override void bind_boolean (string name, bool value) { - this.arguments.insert (name, new GLib.Variant.boolean (value)); - } - - public override void bind_double (string name, double value) { - this.arguments.insert (name, new GLib.Variant.double (value)); - } - - public override void bind_int (string name, int64 value) { - this.arguments.insert (name, new GLib.Variant.int64 (value)); - } - - public override void bind_string (string name, string value) { - this.arguments.insert (name, new GLib.Variant.string (value)); - } - - public override void clear_bindings () { - this.arguments.remove_all (); - } - - private VariantBuilder? get_arguments () { - if (this.arguments.size () == 0) - return null; - - VariantBuilder builder = new VariantBuilder (new VariantType ("a{sv}")); - HashTableIter iter = HashTableIter (this.arguments); - unowned string arg; - unowned GLib.Variant value; - - while (iter.next (out arg, out value)) - builder.add ("{sv}", arg, value); - - return builder; - } - - public override Sparql.Cursor execute (GLib.Cancellable? cancellable) throws Sparql.Error, GLib.Error, GLib.IOError, GLib.DBusError { - // use separate main context for sync operation - var context = new MainContext (); - var loop = new MainLoop (context, false); - context.push_thread_default (); - AsyncResult async_res = null; - execute_async.begin (cancellable, (o, res) => { - async_res = res; - loop.quit (); - }); - loop.run (); - context.pop_thread_default (); - return execute_async.end (async_res); - } - - public async override Sparql.Cursor execute_async (GLib.Cancellable? cancellable) throws Sparql.Error, GLib.Error, GLib.IOError, GLib.DBusError { - return yield Tracker.Bus.Connection.perform_query_call (bus, dbus_name, object_path, query, get_arguments (), cancellable); - } -} diff --git a/src/libtracker-sparql-backend/bus/tracker-bus.vala b/src/libtracker-sparql-backend/bus/tracker-bus.vala deleted file mode 100644 index 72069873f..000000000 --- a/src/libtracker-sparql-backend/bus/tracker-bus.vala +++ /dev/null @@ -1,295 +0,0 @@ -/* - * Copyright (C) 2010, Nokia - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -public class Tracker.Bus.Connection : Tracker.Sparql.Connection { - DBusConnection bus; - string dbus_name; - string object_path; - - private const string ENDPOINT_IFACE = "org.freedesktop.Tracker3.Endpoint"; - - public string bus_name { - get { return dbus_name; } - } - - public string bus_object_path { - get { return object_path; } - } - - public Connection (string dbus_name, string object_path, DBusConnection? dbus_connection) throws Sparql.Error, IOError, DBusError, GLib.Error { - Object (); - this.dbus_name = dbus_name; - this.bus = dbus_connection; - this.object_path = object_path; - - // ensure that error domain is registered with GDBus - new Sparql.Error.INTERNAL (""); - } - - static void pipe (out UnixInputStream input, out UnixOutputStream output) throws IOError { - int pipefd[2]; - if (Posix.pipe (pipefd) < 0) { - throw new IOError.FAILED ("Pipe creation failed"); - } - input = new UnixInputStream (pipefd[0], true); - output = new UnixOutputStream (pipefd[1], true); - } - - static void handle_error_reply (DBusMessage message) throws Sparql.Error, IOError, DBusError { - try { - message.to_gerror (); - } catch (IOError e_io) { - throw e_io; - } catch (Sparql.Error e_sparql) { - throw e_sparql; - } catch (DBusError e_dbus) { - throw e_dbus; - } catch (Error e) { - throw new IOError.FAILED (e.message); - } - } - - static void send_query (DBusConnection bus, string dbus_name, string object_path, string sparql, VariantBuilder? arguments, UnixOutputStream output, Cancellable? cancellable, AsyncReadyCallback? callback) throws GLib.IOError, GLib.Error { - var message = new DBusMessage.method_call (dbus_name, object_path, ENDPOINT_IFACE, "Query"); - var fd_list = new UnixFDList (); - message.set_body (new Variant ("(sha{sv})", sparql, fd_list.append (output.fd), arguments)); - message.set_unix_fd_list (fd_list); - - bus.send_message_with_reply.begin (message, DBusSendMessageFlags.NONE, int.MAX, null, cancellable, callback); - } - - public static async Sparql.Cursor perform_query_call (DBusConnection bus, string dbus_name, string object_path, string sparql, VariantBuilder? arguments, Cancellable? cancellable) throws GLib.IOError, GLib.Error { - UnixInputStream input; - UnixOutputStream output; - pipe (out input, out output); - - // send D-Bus request - AsyncResult dbus_res = null; - bool received_result = false; - send_query (bus, dbus_name, object_path, sparql, arguments, output, cancellable, (o, res) => { - dbus_res = res; - if (received_result) { - perform_query_call.callback (); - } - }); - - output = null; - - // receive query results via FD - var mem_stream = new MemoryOutputStream (null, GLib.realloc, GLib.free); - - try { - yield mem_stream.splice_async (input, OutputStreamSpliceFlags.CLOSE_SOURCE | OutputStreamSpliceFlags.CLOSE_TARGET, Priority.DEFAULT, cancellable); - } finally { - // wait for D-Bus reply - received_result = true; - if (dbus_res == null) { - yield; - } - } - - var reply = bus.send_message_with_reply.end (dbus_res); - handle_error_reply (reply); - - string[] variable_names = (string[]) reply.get_body ().get_child_value (0); - mem_stream.close (); - return new FDCursor (mem_stream.steal_data (), mem_stream.data_size, variable_names); - } - - public override Sparql.Cursor query (string sparql, Cancellable? cancellable) throws Sparql.Error, GLib.Error, GLib.IOError, DBusError { - // use separate main context for sync operation - var context = new MainContext (); - var loop = new MainLoop (context, false); - context.push_thread_default (); - AsyncResult async_res = null; - query_async.begin (sparql, cancellable, (o, res) => { - async_res = res; - loop.quit (); - }); - loop.run (); - context.pop_thread_default (); - return query_async.end (async_res); - } - - public async override Sparql.Cursor query_async (string sparql, Cancellable? cancellable = null) throws Sparql.Error, GLib.Error, GLib.IOError, DBusError { - return yield perform_query_call (bus, dbus_name, object_path, sparql, null, cancellable); - } - - public override Sparql.Statement? query_statement (string sparql, GLib.Cancellable? cancellable = null) throws Sparql.Error { - return new Bus.Statement (bus, dbus_name, object_path, sparql); - } - - void send_update (string method, UnixInputStream input, Cancellable? cancellable, AsyncReadyCallback? callback) throws GLib.Error, GLib.IOError { - var message = new DBusMessage.method_call (dbus_name, object_path, ENDPOINT_IFACE, method); - var fd_list = new UnixFDList (); - message.set_body (new Variant ("(h)", fd_list.append (input.fd))); - message.set_unix_fd_list (fd_list); - - bus.send_message_with_reply.begin (message, DBusSendMessageFlags.NONE, int.MAX, null, cancellable, callback); - } - - public override void update (string sparql, Cancellable? cancellable = null) throws Sparql.Error, GLib.Error, GLib.IOError, DBusError { - // use separate main context for sync operation - var context = new MainContext (); - var loop = new MainLoop (context, false); - context.push_thread_default (); - AsyncResult async_res = null; - update_async.begin (sparql, cancellable, (o, res) => { - async_res = res; - loop.quit (); - }); - loop.run (); - context.pop_thread_default (); - update_async.end (async_res); - } - - public async override void update_async (string sparql, Cancellable? cancellable = null) throws Sparql.Error, GLib.Error, GLib.IOError, DBusError { - UnixInputStream input; - UnixOutputStream output; - pipe (out input, out output); - - // send D-Bus request - AsyncResult dbus_res = null; - bool sent_update = false; - send_update ("Update", input, cancellable, (o, res) => { - dbus_res = res; - if (sent_update) { - update_async.callback (); - } - }); - - // send sparql string via fd - var data_stream = new DataOutputStream (output); - data_stream.set_byte_order (DataStreamByteOrder.HOST_ENDIAN); - data_stream.put_int32 ((int32) sparql.length); - data_stream.put_string (sparql); - data_stream = null; - - // wait for D-Bus reply - sent_update = true; - if (dbus_res == null) { - yield; - } - - var reply = bus.send_message_with_reply.end (dbus_res); - handle_error_reply (reply); - } - - public async override bool update_array_async (string[] sparql, Cancellable? cancellable = null) throws Sparql.Error, GLib.Error, GLib.IOError, DBusError { - UnixInputStream input; - UnixOutputStream output; - pipe (out input, out output); - - // send D-Bus request - AsyncResult dbus_res = null; - bool sent_update = false; - send_update ("UpdateArray", input, cancellable, (o, res) => { - dbus_res = res; - if (sent_update) { - update_array_async.callback (); - } - }); - - // send sparql strings via fd - var data_stream = new DataOutputStream (output); - data_stream.set_byte_order (DataStreamByteOrder.HOST_ENDIAN); - data_stream.put_int32 ((int32) sparql.length); - for (int i = 0; i < sparql.length; i++) { - data_stream.put_int32 ((int32) sparql[i].length); - data_stream.put_string (sparql[i]); - } - data_stream = null; - - // wait for D-Bus reply - sent_update = true; - if (dbus_res == null) { - yield; - } - - var reply = bus.send_message_with_reply.end (dbus_res); - handle_error_reply (reply); - - return true; - } - - public override GLib.Variant? update_blank (string sparql, Cancellable? cancellable = null) throws Sparql.Error, GLib.Error, GLib.IOError, DBusError { - // use separate main context for sync operation - var context = new MainContext (); - var loop = new MainLoop (context, false); - context.push_thread_default (); - AsyncResult async_res = null; - update_blank_async.begin (sparql, cancellable, (o, res) => { - async_res = res; - loop.quit (); - }); - loop.run (); - context.pop_thread_default (); - return update_blank_async.end (async_res); - } - - public async override GLib.Variant? update_blank_async (string sparql, Cancellable? cancellable = null) throws Sparql.Error, GLib.Error, GLib.IOError, DBusError { - UnixInputStream input; - UnixOutputStream output; - pipe (out input, out output); - - // send D-Bus request - AsyncResult dbus_res = null; - bool sent_update = false; - send_update ("UpdateBlank", input, cancellable, (o, res) => { - dbus_res = res; - if (sent_update) { - update_blank_async.callback (); - } - }); - - // send sparql strings via fd - var data_stream = new DataOutputStream (output); - data_stream.set_byte_order (DataStreamByteOrder.HOST_ENDIAN); - data_stream.put_int32 ((int32) sparql.length); - data_stream.put_string (sparql); - data_stream = null; - - // wait for D-Bus reply - sent_update = true; - if (dbus_res == null) { - yield; - } - - var reply = bus.send_message_with_reply.end (dbus_res); - handle_error_reply (reply); - return reply.get_body ().get_child_value (0); - } - - public override Tracker.Notifier? create_notifier () { - var notifier = (Tracker.Notifier) Object.new (typeof (Tracker.Notifier), - "connection", this, - null); - - notifier.signal_subscribe (this.bus, this.dbus_name, null, null); - - return notifier; - } - - public override void close () { - } - - public async override bool close_async () throws GLib.IOError { - return true; - } -} diff --git a/src/libtracker-sparql-backend/bus/tracker-namespace.vala b/src/libtracker-sparql-backend/bus/tracker-namespace.vala deleted file mode 100644 index 9e0a404de..000000000 --- a/src/libtracker-sparql-backend/bus/tracker-namespace.vala +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright © 2015 Collabora Ltd. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -/* - * This file serves as the representation for the Tracker namespace, mostly - * so that we can set its namespace and version attributes for GIR. - */ - -[CCode (cprefix = "TrackerBus", gir_namespace = "TrackerBus", - gir_version = "2.0", lower_case_cprefix = "tracker_bus_")] -namespace Tracker -{ -} diff --git a/src/libtracker-sparql-backend/direct/meson.build b/src/libtracker-sparql-backend/direct/meson.build deleted file mode 100644 index c1ec244e9..000000000 --- a/src/libtracker-sparql-backend/direct/meson.build +++ /dev/null @@ -1,15 +0,0 @@ -libtracker_direct = static_library('tracker-direct', - 'tracker-direct.c', - 'tracker-direct-statement.c', - c_args: tracker_c_args + [ - '-include', 'libtracker-sparql/tracker-private.h', - ], - dependencies: [ glib, gio, tracker_data_dep, tracker_sparql_intermediate_dep ], - include_directories: [commoninc, configinc, srcinc], - gnu_symbol_visibility: 'hidden', -) - -tracker_sparql_direct_dep = declare_dependency( - link_with: libtracker_direct, - include_directories: include_directories('.') -) diff --git a/src/libtracker-sparql-backend/direct/tracker-direct-statement.c b/src/libtracker-sparql-backend/direct/tracker-direct-statement.c deleted file mode 100644 index 609dbb485..000000000 --- a/src/libtracker-sparql-backend/direct/tracker-direct-statement.c +++ /dev/null @@ -1,275 +0,0 @@ -/* - * Copyright (C) 2018, Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#include "config.h" -#include "tracker-direct-statement.h" -#include "tracker-data.h" - -typedef struct _TrackerDirectStatementPrivate TrackerDirectStatementPrivate; - -struct _TrackerDirectStatementPrivate -{ - TrackerSparql *sparql; - GHashTable *values; -}; - -G_DEFINE_TYPE_WITH_PRIVATE (TrackerDirectStatement, - tracker_direct_statement, - TRACKER_TYPE_SPARQL_STATEMENT) - -static void -tracker_direct_statement_finalize (GObject *object) -{ - TrackerDirectStatementPrivate *priv; - - priv = tracker_direct_statement_get_instance_private (TRACKER_DIRECT_STATEMENT (object)); - g_hash_table_destroy (priv->values); - g_clear_object (&priv->sparql); - - G_OBJECT_CLASS (tracker_direct_statement_parent_class)->finalize (object); -} - -static void -tracker_direct_statement_constructed (GObject *object) -{ - TrackerDirectStatementPrivate *priv; - TrackerSparqlConnection *conn; - gchar *sparql; - - priv = tracker_direct_statement_get_instance_private (TRACKER_DIRECT_STATEMENT (object)); - - g_object_get (object, - "sparql", &sparql, - "connection", &conn, - NULL); - - priv->sparql = tracker_sparql_new (tracker_direct_connection_get_data_manager (TRACKER_DIRECT_CONNECTION (conn)), - sparql); - g_object_unref (conn); - g_free (sparql); - - G_OBJECT_CLASS (tracker_direct_statement_parent_class)->constructed (object); -} - -static GValue * -insert_value (TrackerDirectStatement *stmt, - const gchar *name, - GType type) -{ - TrackerDirectStatementPrivate *priv; - GValue *value; - - priv = tracker_direct_statement_get_instance_private (stmt); - value = g_new0 (GValue, 1); - g_value_init (value, type); - - g_hash_table_insert (priv->values, g_strdup (name), value); - - return value; -} - -static void -tracker_direct_statement_bind_int (TrackerSparqlStatement *stmt, - const gchar *name, - gint64 value) -{ - GValue *gvalue; - - gvalue = insert_value (TRACKER_DIRECT_STATEMENT (stmt), name, G_TYPE_INT64); - g_value_set_int64 (gvalue, value); -} - -static void -tracker_direct_statement_bind_double (TrackerSparqlStatement *stmt, - const gchar *name, - double value) -{ - GValue *gvalue; - - gvalue = insert_value (TRACKER_DIRECT_STATEMENT (stmt), name, G_TYPE_DOUBLE); - g_value_set_double (gvalue, value); -} - -static void -tracker_direct_statement_bind_boolean (TrackerSparqlStatement *stmt, - const gchar *name, - gboolean value) -{ - GValue *gvalue; - - gvalue = insert_value (TRACKER_DIRECT_STATEMENT (stmt), name, G_TYPE_BOOLEAN); - g_value_set_boolean (gvalue, value); -} - -static void -tracker_direct_statement_bind_string (TrackerSparqlStatement *stmt, - const gchar *name, - const gchar *value) -{ - GValue *gvalue; - - gvalue = insert_value (TRACKER_DIRECT_STATEMENT (stmt), name, G_TYPE_STRING); - g_value_set_string (gvalue, value); -} - -static void -tracker_direct_statement_clear_bindings (TrackerSparqlStatement *stmt) -{ - TrackerDirectStatementPrivate *priv; - - priv = tracker_direct_statement_get_instance_private (TRACKER_DIRECT_STATEMENT (stmt)); - g_hash_table_remove_all (priv->values); -} - -static TrackerSparqlCursor * -tracker_direct_statement_execute (TrackerSparqlStatement *stmt, - GCancellable *cancellable, - GError **error) -{ - TrackerDirectStatementPrivate *priv; - - priv = tracker_direct_statement_get_instance_private (TRACKER_DIRECT_STATEMENT (stmt)); - - return tracker_sparql_execute_cursor (priv->sparql, priv->values, error); -} - -static void -execute_in_thread (GTask *task, - gpointer object, - gpointer task_data, - GCancellable *cancellable) -{ - TrackerDirectStatementPrivate *priv; - TrackerSparqlCursor *cursor; - GHashTable *values = task_data; - GError *error = NULL; - - priv = tracker_direct_statement_get_instance_private (object); - cursor = tracker_sparql_execute_cursor (priv->sparql, values, &error); - - if (error) - g_task_return_error (task, error); - else - g_task_return_pointer (task, cursor, g_object_unref); - - g_object_unref (task); -} - -static void -free_gvalue (gpointer data) -{ - g_value_unset (data); - g_free (data); -} - -static GHashTable * -create_values_ht (void) -{ - return g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, free_gvalue); -} - -static GHashTable * -copy_values_deep (GHashTable *values) -{ - GHashTable *copy; - GHashTableIter iter; - gpointer key, val; - - copy = create_values_ht (); - g_hash_table_iter_init (&iter, values); - - while (g_hash_table_iter_next (&iter, &key, &val)) { - GValue *copy_value; - - copy_value = g_new0 (GValue, 1); - g_value_init (copy_value, G_VALUE_TYPE (val)); - g_value_copy (val, copy_value); - - g_hash_table_insert (copy, g_strdup (key), copy_value); - } - - return copy; -} - -static void -tracker_direct_statement_execute_async (TrackerSparqlStatement *stmt, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - TrackerDirectStatementPrivate *priv; - GHashTable *values; - GTask *task; - - priv = tracker_direct_statement_get_instance_private (TRACKER_DIRECT_STATEMENT (stmt)); - - values = copy_values_deep (priv->values); - - task = g_task_new (stmt, cancellable, callback, user_data); - g_task_set_task_data (task, values, (GDestroyNotify) g_hash_table_unref); - g_task_run_in_thread (task, execute_in_thread); -} - -static TrackerSparqlCursor * -tracker_direct_statement_execute_finish (TrackerSparqlStatement *stmt, - GAsyncResult *res, - GError **error) -{ - return g_task_propagate_pointer (G_TASK (res), error); -} - -static void -tracker_direct_statement_class_init (TrackerDirectStatementClass *klass) -{ - TrackerSparqlStatementClass *stmt_class = (TrackerSparqlStatementClass *) klass; - GObjectClass *object_class = (GObjectClass *) klass; - - object_class->finalize = tracker_direct_statement_finalize; - object_class->constructed = tracker_direct_statement_constructed; - - stmt_class->bind_int = tracker_direct_statement_bind_int; - stmt_class->bind_boolean = tracker_direct_statement_bind_boolean; - stmt_class->bind_double = tracker_direct_statement_bind_double; - stmt_class->bind_string = tracker_direct_statement_bind_string; - stmt_class->clear_bindings = tracker_direct_statement_clear_bindings; - stmt_class->execute = tracker_direct_statement_execute; - stmt_class->execute_async = tracker_direct_statement_execute_async; - stmt_class->execute_finish = tracker_direct_statement_execute_finish; -} - -static void -tracker_direct_statement_init (TrackerDirectStatement *stmt) -{ - TrackerDirectStatementPrivate *priv; - - priv = tracker_direct_statement_get_instance_private (stmt); - priv->values = create_values_ht (); -} - -TrackerDirectStatement * -tracker_direct_statement_new (TrackerSparqlConnection *conn, - const gchar *sparql, - GError **error) -{ - return g_object_new (TRACKER_TYPE_DIRECT_STATEMENT, - "sparql", sparql, - "connection", conn, - NULL); -} diff --git a/src/libtracker-sparql-backend/direct/tracker-direct-statement.h b/src/libtracker-sparql-backend/direct/tracker-direct-statement.h deleted file mode 100644 index d68bb6bc8..000000000 --- a/src/libtracker-sparql-backend/direct/tracker-direct-statement.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2018, Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#ifndef __TRACKER_DIRECT_STATEMENT_H__ -#define __TRACKER_DIRECT_STATEMENT_H__ - -#include "tracker-direct.h" -#include - -#define TRACKER_TYPE_DIRECT_STATEMENT (tracker_direct_statement_get_type ()) -#define TRACKER_DIRECT_STATEMENT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), TRACKER_TYPE_DIRECT_STATEMENT, TrackerDirectStatement)) -#define TRACKER_DIRECT_STATEMENT_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), TRACKER_TYPE_DIRECT_STATEMENT, TrackerDirectStatementClass)) -#define TRACKER_IS_DIRECT_STATEMENT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), TRACKER_TYPE_DIRECT_STATEMENT)) -#define TRACKER_IS_DIRECT_STATEMENT_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), TRACKER_TYPE_DIRECT_STATEMENT)) -#define TRACKER_DIRECT_STATEMENT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), TRACKER_TYPE_DIRECT_STATEMENT, TrackerDirectStatementClass)) - -typedef struct _TrackerDirectStatement TrackerDirectStatement; -typedef struct _TrackerDirectStatementClass TrackerDirectStatementClass; - -struct _TrackerDirectStatementClass -{ - TrackerSparqlStatementClass parent_class; -}; - -struct _TrackerDirectStatement -{ - TrackerSparqlStatement parent_instance; -}; - -GType tracker_direct_statement_get_type (void) G_GNUC_CONST; - -TrackerDirectStatement * tracker_direct_statement_new (TrackerSparqlConnection *conn, - const gchar *sparql, - GError **error); - -#endif /* __TRACKER_DIRECT_STATEMENT_H__ */ diff --git a/src/libtracker-sparql-backend/direct/tracker-direct.c b/src/libtracker-sparql-backend/direct/tracker-direct.c deleted file mode 100644 index 355c5debf..000000000 --- a/src/libtracker-sparql-backend/direct/tracker-direct.c +++ /dev/null @@ -1,1047 +0,0 @@ -/* - * Copyright (C) 2010, Nokia - * Copyright (C) 2017, Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#include "config.h" - -#include "tracker-direct.h" -#include "tracker-direct-statement.h" -#include "libtracker-sparql/tracker-private.h" -#include -#include -#include - -typedef struct _TrackerDirectConnectionPrivate TrackerDirectConnectionPrivate; - -struct _TrackerDirectConnectionPrivate -{ - TrackerSparqlConnectionFlags flags; - GFile *store; - GFile *ontology; - - TrackerNamespaceManager *namespace_manager; - TrackerDataManager *data_manager; - GMutex mutex; - - GThreadPool *update_thread; /* Contains 1 exclusive thread */ - GThreadPool *select_pool; - - GList *notifiers; - - guint initialized : 1; - guint closing : 1; -}; - -enum { - PROP_0, - PROP_FLAGS, - PROP_STORE_LOCATION, - PROP_ONTOLOGY_LOCATION, - N_PROPS -}; - -static GParamSpec *props[N_PROPS] = { NULL }; - -typedef enum { - TASK_TYPE_QUERY, - TASK_TYPE_UPDATE, - TASK_TYPE_UPDATE_BLANK, -} TaskType; - -typedef struct { - TaskType type; - gchar *query; -} TaskData; - -static void tracker_direct_connection_initable_iface_init (GInitableIface *iface); -static void tracker_direct_connection_async_initable_iface_init (GAsyncInitableIface *iface); - -G_DEFINE_QUARK (TrackerDirectNotifier, tracker_direct_notifier) - -G_DEFINE_TYPE_WITH_CODE (TrackerDirectConnection, tracker_direct_connection, - TRACKER_TYPE_SPARQL_CONNECTION, - G_ADD_PRIVATE (TrackerDirectConnection) - G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, - tracker_direct_connection_initable_iface_init) - G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, - tracker_direct_connection_async_initable_iface_init)) - -static TaskData * -task_data_query_new (TaskType type, - const gchar *sparql) -{ - TaskData *data; - - data = g_new0 (TaskData, 1); - data->type = type; - data->query = g_strdup (sparql); - - return data; -} - -static void -task_data_free (TaskData *task) -{ - g_free (task->query); - g_free (task); -} - -static void -update_thread_func (gpointer data, - gpointer user_data) -{ - TrackerDirectConnectionPrivate *priv; - TrackerDirectConnection *conn; - GTask *task = data; - TaskData *task_data = g_task_get_task_data (task); - TrackerData *tracker_data; - GError *error = NULL; - gpointer retval = NULL; - GDestroyNotify destroy_notify = NULL; - - conn = user_data; - priv = tracker_direct_connection_get_instance_private (conn); - - g_mutex_lock (&priv->mutex); - tracker_data = tracker_data_manager_get_data (priv->data_manager); - - switch (task_data->type) { - case TASK_TYPE_QUERY: - g_warning ("Queries don't go through this thread"); - break; - case TASK_TYPE_UPDATE: - tracker_data_update_sparql (tracker_data, task_data->query, &error); - break; - case TASK_TYPE_UPDATE_BLANK: - retval = tracker_data_update_sparql_blank (tracker_data, task_data->query, &error); - destroy_notify = (GDestroyNotify) g_variant_unref; - break; - } - - if (error) - g_task_return_error (task, error); - else if (retval) - g_task_return_pointer (task, retval, destroy_notify); - else - g_task_return_boolean (task, TRUE); - - g_object_unref (task); - g_mutex_unlock (&priv->mutex); -} - -static void -query_thread_pool_func (gpointer data, - gpointer user_data) -{ - TrackerDirectConnection *conn = user_data; - TrackerDirectConnectionPrivate *priv; - TrackerSparqlCursor *cursor; - GTask *task = data; - TaskData *task_data = g_task_get_task_data (task); - GError *error = NULL; - - g_assert (task_data->type == TASK_TYPE_QUERY); - - priv = tracker_direct_connection_get_instance_private (conn); - - if (priv->closing) { - g_task_return_new_error (task, - G_IO_ERROR, - G_IO_ERROR_CONNECTION_CLOSED, - "Connection is closed"); - g_object_unref (task); - return; - } - - cursor = tracker_sparql_connection_query (TRACKER_SPARQL_CONNECTION (g_task_get_source_object (task)), - task_data->query, - g_task_get_cancellable (task), - &error); - if (cursor) - g_task_return_pointer (task, cursor, g_object_unref); - else - g_task_return_error (task, error); - - g_object_unref (task); -} - -static gint -task_compare_func (GTask *a, - GTask *b, - gpointer user_data) -{ - return g_task_get_priority (b) - g_task_get_priority (a); -} - -static gboolean -set_up_thread_pools (TrackerDirectConnection *conn, - GError **error) -{ - TrackerDirectConnectionPrivate *priv; - - priv = tracker_direct_connection_get_instance_private (conn); - - priv->select_pool = g_thread_pool_new (query_thread_pool_func, - conn, 16, FALSE, error); - if (!priv->select_pool) - return FALSE; - - priv->update_thread = g_thread_pool_new (update_thread_func, - conn, 1, TRUE, error); - if (!priv->update_thread) - return FALSE; - - g_thread_pool_set_sort_function (priv->select_pool, - (GCompareDataFunc) task_compare_func, - conn); - g_thread_pool_set_sort_function (priv->update_thread, - (GCompareDataFunc) task_compare_func, - conn); - return TRUE; -} - -static TrackerDBManagerFlags -translate_flags (TrackerSparqlConnectionFlags flags) -{ - TrackerDBManagerFlags db_flags = TRACKER_DB_MANAGER_ENABLE_MUTEXES; - - if ((flags & TRACKER_SPARQL_CONNECTION_FLAGS_READONLY) != 0) - db_flags |= TRACKER_DB_MANAGER_READONLY; - if ((flags & TRACKER_SPARQL_CONNECTION_FLAGS_FTS_ENABLE_STEMMER) != 0) - db_flags |= TRACKER_DB_MANAGER_FTS_ENABLE_STEMMER; - if ((flags & TRACKER_SPARQL_CONNECTION_FLAGS_FTS_ENABLE_UNACCENT) != 0) - db_flags |= TRACKER_DB_MANAGER_FTS_ENABLE_UNACCENT; - if ((flags & TRACKER_SPARQL_CONNECTION_FLAGS_FTS_ENABLE_STOP_WORDS) != 0) - db_flags |= TRACKER_DB_MANAGER_FTS_ENABLE_STOP_WORDS; - if ((flags & TRACKER_SPARQL_CONNECTION_FLAGS_FTS_IGNORE_NUMBERS) != 0) - db_flags |= TRACKER_DB_MANAGER_FTS_IGNORE_NUMBERS; - - return db_flags; -} - -static GError * -translate_error (GError *error) -{ - GError *new_error = NULL; - - if (error->domain == TRACKER_DATA_ONTOLOGY_ERROR) { - /* This is an internal error domain, so translate to a libtracker-sparql error code. */ - switch (error->code) { - case TRACKER_DATA_ONTOLOGY_NOT_FOUND: - new_error = g_error_new_literal (TRACKER_SPARQL_ERROR, - TRACKER_SPARQL_ERROR_ONTOLOGY_NOT_FOUND, - error->message); - break; - case TRACKER_DATA_UNSUPPORTED_LOCATION: - case TRACKER_DATA_UNSUPPORTED_ONTOLOGY_CHANGE: - new_error = g_error_new_literal (TRACKER_SPARQL_ERROR, - TRACKER_SPARQL_ERROR_UNSUPPORTED, - error->message); - break; - default: - new_error = g_error_new_literal (TRACKER_SPARQL_ERROR, - TRACKER_SPARQL_ERROR_INTERNAL, - error->message); - } - } - - if (new_error) { - g_error_free (error); - return new_error; - } else { - return error; - } -} - - -static gboolean -tracker_direct_connection_initable_init (GInitable *initable, - GCancellable *cancellable, - GError **error) -{ - TrackerDirectConnectionPrivate *priv; - TrackerDirectConnection *conn; - TrackerDBManagerFlags db_flags; - GHashTable *namespaces; - GHashTableIter iter; - gchar *prefix, *ns; - GError *inner_error = NULL; - - conn = TRACKER_DIRECT_CONNECTION (initable); - priv = tracker_direct_connection_get_instance_private (conn); - - tracker_locale_sanity_check (); - - if (!set_up_thread_pools (conn, error)) - return FALSE; - - db_flags = translate_flags (priv->flags); - - if (!priv->store) { - db_flags |= TRACKER_DB_MANAGER_IN_MEMORY; - } - - priv->data_manager = tracker_data_manager_new (db_flags, priv->store, - priv->ontology, - 100, 100); - if (!g_initable_init (G_INITABLE (priv->data_manager), cancellable, &inner_error)) { - g_propagate_error (error, translate_error (inner_error)); - g_clear_object (&priv->data_manager); - return FALSE; - } - - /* Initialize namespace manager */ - priv->namespace_manager = tracker_namespace_manager_new (); - namespaces = tracker_data_manager_get_namespaces (priv->data_manager); - g_hash_table_iter_init (&iter, namespaces); - - while (g_hash_table_iter_next (&iter, (gpointer*) &prefix, (gpointer*) &ns)) { - tracker_namespace_manager_add_prefix (priv->namespace_manager, - prefix, ns); - } - - g_hash_table_unref (namespaces); - - return TRUE; -} - -static void -tracker_direct_connection_initable_iface_init (GInitableIface *iface) -{ - iface->init = tracker_direct_connection_initable_init; -} - -static void -async_initable_thread_func (GTask *task, - gpointer source_object, - gpointer task_data, - GCancellable *cancellable) -{ - GError *error = NULL; - - if (!g_initable_init (G_INITABLE (source_object), cancellable, &error)) - g_task_return_error (task, error); - else - g_task_return_boolean (task, TRUE); - - g_object_unref (task); -} - -static void -tracker_direct_connection_async_initable_init_async (GAsyncInitable *async_initable, - gint priority, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GTask *task; - - task = g_task_new (async_initable, cancellable, callback, user_data); - g_task_set_priority (task, priority); - g_task_run_in_thread (task, async_initable_thread_func); -} - -static gboolean -tracker_direct_connection_async_initable_init_finish (GAsyncInitable *async_initable, - GAsyncResult *res, - GError **error) -{ - return g_task_propagate_boolean (G_TASK (res), error); -} - -static void -tracker_direct_connection_async_initable_iface_init (GAsyncInitableIface *iface) -{ - iface->init_async = tracker_direct_connection_async_initable_init_async; - iface->init_finish = tracker_direct_connection_async_initable_init_finish; -} - -static void -tracker_direct_connection_init (TrackerDirectConnection *conn) -{ -} - -static GHashTable * -get_event_cache_ht (TrackerNotifier *notifier) -{ - GHashTable *events; - - events = g_object_get_qdata (G_OBJECT (notifier), tracker_direct_notifier_quark ()); - if (!events) { - events = g_hash_table_new_full (NULL, NULL, NULL, - (GDestroyNotify) _tracker_notifier_event_cache_free); - g_object_set_qdata_full (G_OBJECT (notifier), tracker_direct_notifier_quark (), - events, (GDestroyNotify) g_hash_table_unref); - } - - return events; -} - -static TrackerNotifierEventCache * -lookup_event_cache (TrackerNotifier *notifier, - gint graph_id, - const gchar *graph) -{ - TrackerNotifierEventCache *cache; - GHashTable *events; - - events = get_event_cache_ht (notifier); - cache = g_hash_table_lookup (events, GINT_TO_POINTER (graph_id)); - - if (!cache) { - cache = _tracker_notifier_event_cache_new (notifier, graph); - g_hash_table_insert (events, GINT_TO_POINTER (graph_id), cache); - } - - return cache; -} - -/* These callbacks will be called from a different thread - * (always the same one though), handle with care. - */ -static void -insert_statement_cb (gint graph_id, - const gchar *graph, - gint subject_id, - const gchar *subject, - gint predicate_id, - gint object_id, - const gchar *object, - GPtrArray *rdf_types, - gpointer user_data) -{ - TrackerNotifier *notifier = user_data; - TrackerSparqlConnection *conn = _tracker_notifier_get_connection (notifier); - TrackerDirectConnection *direct = TRACKER_DIRECT_CONNECTION (conn); - TrackerDirectConnectionPrivate *priv = tracker_direct_connection_get_instance_private (direct); - TrackerOntologies *ontologies = tracker_data_manager_get_ontologies (priv->data_manager); - TrackerProperty *rdf_type = tracker_ontologies_get_rdf_type (ontologies); - TrackerNotifierEventCache *cache; - TrackerClass *new_class = NULL; - gint i; - - cache = lookup_event_cache (notifier, graph_id, graph); - - if (predicate_id == tracker_property_get_id (rdf_type)) { - const gchar *uri; - - uri = tracker_ontologies_get_uri_by_id (ontologies, object_id); - new_class = tracker_ontologies_get_class_by_uri (ontologies, uri); - } - - for (i = 0; i < rdf_types->len; i++) { - TrackerClass *class = g_ptr_array_index (rdf_types, i); - TrackerNotifierEventType event_type; - - if (!tracker_class_get_notify (class)) - continue; - - if (class == new_class) - event_type = TRACKER_NOTIFIER_EVENT_CREATE; - else - event_type = TRACKER_NOTIFIER_EVENT_UPDATE; - - _tracker_notifier_event_cache_push_event (cache, subject_id, event_type); - } -} - -static void -delete_statement_cb (gint graph_id, - const gchar *graph, - gint subject_id, - const gchar *subject, - gint predicate_id, - gint object_id, - const gchar *object, - GPtrArray *rdf_types, - gpointer user_data) -{ - TrackerNotifier *notifier = user_data; - TrackerSparqlConnection *conn = _tracker_notifier_get_connection (notifier); - TrackerDirectConnection *direct = TRACKER_DIRECT_CONNECTION (conn); - TrackerDirectConnectionPrivate *priv = tracker_direct_connection_get_instance_private (direct); - TrackerOntologies *ontologies = tracker_data_manager_get_ontologies (priv->data_manager); - TrackerProperty *rdf_type = tracker_ontologies_get_rdf_type (ontologies); - TrackerNotifierEventCache *cache; - TrackerClass *class_being_removed = NULL; - gint i; - - cache = lookup_event_cache (notifier, graph_id, graph); - - if (predicate_id == tracker_property_get_id (rdf_type)) { - class_being_removed = tracker_ontologies_get_class_by_uri (ontologies, object); - } - - for (i = 0; i < rdf_types->len; i++) { - TrackerClass *class = g_ptr_array_index (rdf_types, i); - TrackerNotifierEventType event_type; - - if (!tracker_class_get_notify (class)) - continue; - - if (class_being_removed && class == class_being_removed) { - event_type = TRACKER_NOTIFIER_EVENT_DELETE; - } else { - event_type = TRACKER_NOTIFIER_EVENT_UPDATE; - } - - _tracker_notifier_event_cache_push_event (cache, subject_id, event_type); - } -} - -static void -commit_statement_cb (gpointer user_data) -{ - TrackerNotifierEventCache *cache; - TrackerNotifier *notifier = user_data; - GHashTable *events; - GHashTableIter iter; - - events = get_event_cache_ht (notifier); - g_hash_table_iter_init (&iter, events); - - while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &cache)) { - g_hash_table_iter_steal (&iter); - _tracker_notifier_event_cache_flush_events (cache); - } -} - -static void -rollback_statement_cb (gpointer user_data) -{ - TrackerNotifier *notifier = user_data; - GHashTable *events; - - events = get_event_cache_ht (notifier); - g_hash_table_remove_all (events); -} - -static void -detach_notifier (TrackerDirectConnection *conn, - TrackerNotifier *notifier) -{ - TrackerDirectConnectionPrivate *priv; - TrackerData *tracker_data; - - priv = tracker_direct_connection_get_instance_private (conn); - - priv->notifiers = g_list_remove (priv->notifiers, notifier); - - tracker_data = tracker_data_manager_get_data (priv->data_manager); - tracker_data_remove_insert_statement_callback (tracker_data, - insert_statement_cb, - notifier); - tracker_data_remove_delete_statement_callback (tracker_data, - delete_statement_cb, - notifier); - tracker_data_remove_commit_statement_callback (tracker_data, - commit_statement_cb, - notifier); - tracker_data_remove_rollback_statement_callback (tracker_data, - rollback_statement_cb, - notifier); -} - -static void -weak_ref_notify (gpointer data, - GObject *prev_location) -{ - TrackerDirectConnection *conn = data; - - detach_notifier (conn, (TrackerNotifier *) prev_location); -} - -static void -tracker_direct_connection_finalize (GObject *object) -{ - TrackerDirectConnectionPrivate *priv; - TrackerDirectConnection *conn; - - conn = TRACKER_DIRECT_CONNECTION (object); - priv = tracker_direct_connection_get_instance_private (conn); - - g_clear_object (&priv->store); - g_clear_object (&priv->ontology); - g_clear_object (&priv->namespace_manager); - - G_OBJECT_CLASS (tracker_direct_connection_parent_class)->finalize (object); -} - -static void -tracker_direct_connection_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - TrackerDirectConnectionPrivate *priv; - TrackerDirectConnection *conn; - - conn = TRACKER_DIRECT_CONNECTION (object); - priv = tracker_direct_connection_get_instance_private (conn); - - switch (prop_id) { - case PROP_FLAGS: - priv->flags = g_value_get_flags (value); - break; - case PROP_STORE_LOCATION: - priv->store = g_value_dup_object (value); - break; - case PROP_ONTOLOGY_LOCATION: - priv->ontology = g_value_dup_object (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -tracker_direct_connection_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - TrackerDirectConnectionPrivate *priv; - TrackerDirectConnection *conn; - - conn = TRACKER_DIRECT_CONNECTION (object); - priv = tracker_direct_connection_get_instance_private (conn); - - switch (prop_id) { - case PROP_FLAGS: - g_value_set_flags (value, priv->flags); - break; - case PROP_STORE_LOCATION: - g_value_set_object (value, priv->store); - break; - case PROP_ONTOLOGY_LOCATION: - g_value_set_object (value, priv->ontology); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static TrackerSparqlCursor * -tracker_direct_connection_query (TrackerSparqlConnection *self, - const gchar *sparql, - GCancellable *cancellable, - GError **error) -{ - TrackerDirectConnectionPrivate *priv; - TrackerDirectConnection *conn; - TrackerSparql *query; - TrackerSparqlCursor *cursor; - - conn = TRACKER_DIRECT_CONNECTION (self); - priv = tracker_direct_connection_get_instance_private (conn); - - g_mutex_lock (&priv->mutex); - query = tracker_sparql_new (priv->data_manager, sparql); - cursor = tracker_sparql_execute_cursor (query, NULL, error); - g_object_unref (query); - - if (cursor) - tracker_sparql_cursor_set_connection (cursor, self); - g_mutex_unlock (&priv->mutex); - - return cursor; -} - -static void -tracker_direct_connection_query_async (TrackerSparqlConnection *self, - const gchar *sparql, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - TrackerDirectConnectionPrivate *priv; - TrackerDirectConnection *conn; - GError *error = NULL; - GTask *task; - - conn = TRACKER_DIRECT_CONNECTION (self); - priv = tracker_direct_connection_get_instance_private (conn); - - task = g_task_new (self, cancellable, callback, user_data); - g_task_set_task_data (task, - task_data_query_new (TASK_TYPE_QUERY, sparql), - (GDestroyNotify) task_data_free); - - if (!g_thread_pool_push (priv->select_pool, task, &error)) { - g_task_return_error (task, error); - g_object_unref (task); - } -} - -static TrackerSparqlCursor * -tracker_direct_connection_query_finish (TrackerSparqlConnection *self, - GAsyncResult *res, - GError **error) -{ - return g_task_propagate_pointer (G_TASK (res), error); -} - -static TrackerSparqlStatement * -tracker_direct_connection_query_statement (TrackerSparqlConnection *self, - const gchar *query, - GCancellable *cancellable, - GError **error) -{ - return TRACKER_SPARQL_STATEMENT (tracker_direct_statement_new (self, query, error)); -} - -static void -tracker_direct_connection_update (TrackerSparqlConnection *self, - const gchar *sparql, - GCancellable *cancellable, - GError **error) -{ - TrackerDirectConnectionPrivate *priv; - TrackerDirectConnection *conn; - TrackerData *data; - - conn = TRACKER_DIRECT_CONNECTION (self); - priv = tracker_direct_connection_get_instance_private (conn); - - g_mutex_lock (&priv->mutex); - data = tracker_data_manager_get_data (priv->data_manager); - tracker_data_update_sparql (data, sparql, error); - g_mutex_unlock (&priv->mutex); -} - -static void -tracker_direct_connection_update_async (TrackerSparqlConnection *self, - const gchar *sparql, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - TrackerDirectConnectionPrivate *priv; - TrackerDirectConnection *conn; - GTask *task; - - conn = TRACKER_DIRECT_CONNECTION (self); - priv = tracker_direct_connection_get_instance_private (conn); - - task = g_task_new (self, cancellable, callback, user_data); - g_task_set_task_data (task, - task_data_query_new (TASK_TYPE_UPDATE, sparql), - (GDestroyNotify) task_data_free); - - g_thread_pool_push (priv->update_thread, task, NULL); -} - -static void -tracker_direct_connection_update_finish (TrackerSparqlConnection *self, - GAsyncResult *res, - GError **error) -{ - g_task_propagate_boolean (G_TASK (res), error); -} - -static void -tracker_direct_connection_update_array_async (TrackerSparqlConnection *self, - gchar **updates, - gint n_updates, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - TrackerDirectConnectionPrivate *priv; - TrackerDirectConnection *conn; - TaskData *task_data; - GTask *task; - gchar *concatenated; - gchar **array_copy; - - conn = TRACKER_DIRECT_CONNECTION (self); - priv = tracker_direct_connection_get_instance_private (conn); - - /* Make a NULL-terminated array and concatenate it */ - array_copy = g_new0 (gchar *, n_updates + 1); - memcpy (array_copy, updates, n_updates * sizeof (gchar *)); - concatenated = g_strjoinv ("\n", array_copy); - g_free (array_copy); - - task_data = task_data_query_new (TASK_TYPE_UPDATE, NULL); - task_data->query = concatenated; - - task = g_task_new (self, cancellable, callback, user_data); - g_task_set_task_data (task, task_data, - (GDestroyNotify) task_data_free); - - g_thread_pool_push (priv->update_thread, task, NULL); -} - -static gboolean -tracker_direct_connection_update_array_finish (TrackerSparqlConnection *self, - GAsyncResult *res, - GError **error) -{ - return g_task_propagate_boolean (G_TASK (res), error); -} - -static GVariant * -tracker_direct_connection_update_blank (TrackerSparqlConnection *self, - const gchar *sparql, - GCancellable *cancellable, - GError **error) -{ - TrackerDirectConnectionPrivate *priv; - TrackerDirectConnection *conn; - TrackerData *data; - GVariant *blank_nodes; - - conn = TRACKER_DIRECT_CONNECTION (self); - priv = tracker_direct_connection_get_instance_private (conn); - - g_mutex_lock (&priv->mutex); - data = tracker_data_manager_get_data (priv->data_manager); - blank_nodes = tracker_data_update_sparql_blank (data, sparql, error); - g_mutex_unlock (&priv->mutex); - - return blank_nodes; -} - -static void -tracker_direct_connection_update_blank_async (TrackerSparqlConnection *self, - const gchar *sparql, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - TrackerDirectConnectionPrivate *priv; - TrackerDirectConnection *conn; - GTask *task; - - conn = TRACKER_DIRECT_CONNECTION (self); - priv = tracker_direct_connection_get_instance_private (conn); - - task = g_task_new (self, cancellable, callback, user_data); - g_task_set_task_data (task, - task_data_query_new (TASK_TYPE_UPDATE_BLANK, sparql), - (GDestroyNotify) task_data_free); - - g_thread_pool_push (priv->update_thread, task, NULL); -} - -static GVariant * -tracker_direct_connection_update_blank_finish (TrackerSparqlConnection *self, - GAsyncResult *res, - GError **error) -{ - return g_task_propagate_pointer (G_TASK (res), error); -} - -static TrackerNamespaceManager * -tracker_direct_connection_get_namespace_manager (TrackerSparqlConnection *self) -{ - TrackerDirectConnectionPrivate *priv; - - priv = tracker_direct_connection_get_instance_private (TRACKER_DIRECT_CONNECTION (self)); - - return priv->namespace_manager; -} - -static TrackerNotifier * -tracker_direct_connection_create_notifier (TrackerSparqlConnection *self) -{ - TrackerDirectConnectionPrivate *priv; - TrackerNotifier *notifier; - TrackerData *tracker_data; - - priv = tracker_direct_connection_get_instance_private (TRACKER_DIRECT_CONNECTION (self)); - - notifier = g_object_new (TRACKER_TYPE_NOTIFIER, - "connection", self, - NULL); - - tracker_data = tracker_data_manager_get_data (priv->data_manager); - tracker_data_add_insert_statement_callback (tracker_data, - insert_statement_cb, - notifier); - tracker_data_add_delete_statement_callback (tracker_data, - delete_statement_cb, - notifier); - tracker_data_add_commit_statement_callback (tracker_data, - commit_statement_cb, - notifier); - tracker_data_add_rollback_statement_callback (tracker_data, - rollback_statement_cb, - notifier); - - g_object_weak_ref (G_OBJECT (notifier), weak_ref_notify, self); - priv->notifiers = g_list_prepend (priv->notifiers, notifier); - - return notifier; -} - -static void -tracker_direct_connection_close (TrackerSparqlConnection *self) -{ - TrackerDirectConnectionPrivate *priv; - TrackerDirectConnection *conn; - - conn = TRACKER_DIRECT_CONNECTION (self); - priv = tracker_direct_connection_get_instance_private (conn); - priv->closing = TRUE; - - if (priv->update_thread) { - g_thread_pool_free (priv->update_thread, TRUE, TRUE); - priv->update_thread = NULL; - } - - if (priv->select_pool) { - g_thread_pool_free (priv->select_pool, TRUE, TRUE); - priv->select_pool = NULL; - } - - while (priv->notifiers) { - TrackerNotifier *notifier = priv->notifiers->data; - - g_object_weak_unref (G_OBJECT (notifier), - weak_ref_notify, - conn); - detach_notifier (conn, notifier); - } - - if (priv->data_manager) { - tracker_data_manager_shutdown (priv->data_manager); - g_clear_object (&priv->data_manager); - } -} - -void -async_close_thread_func (GTask *task, - gpointer source_object, - gpointer task_data, - GCancellable *cancellable) -{ - if (g_task_return_error_if_cancelled (task)) - return; - - tracker_sparql_connection_close (source_object); - g_task_return_boolean (task, TRUE); -} - -void -tracker_direct_connection_close_async (TrackerSparqlConnection *connection, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GTask *task; - - task = g_task_new (connection, cancellable, callback, user_data); - g_task_run_in_thread (task, async_close_thread_func); - g_object_unref (task); -} - -gboolean -tracker_direct_connection_close_finish (TrackerSparqlConnection *connection, - GAsyncResult *res, - GError **error) -{ - return g_task_propagate_boolean (G_TASK (res), error); -} - -static void -tracker_direct_connection_class_init (TrackerDirectConnectionClass *klass) -{ - TrackerSparqlConnectionClass *sparql_connection_class; - GObjectClass *object_class; - - object_class = G_OBJECT_CLASS (klass); - sparql_connection_class = TRACKER_SPARQL_CONNECTION_CLASS (klass); - - object_class->finalize = tracker_direct_connection_finalize; - object_class->set_property = tracker_direct_connection_set_property; - object_class->get_property = tracker_direct_connection_get_property; - - sparql_connection_class->query = tracker_direct_connection_query; - sparql_connection_class->query_async = tracker_direct_connection_query_async; - sparql_connection_class->query_finish = tracker_direct_connection_query_finish; - sparql_connection_class->query_statement = tracker_direct_connection_query_statement; - sparql_connection_class->update = tracker_direct_connection_update; - sparql_connection_class->update_async = tracker_direct_connection_update_async; - sparql_connection_class->update_finish = tracker_direct_connection_update_finish; - sparql_connection_class->update_array_async = tracker_direct_connection_update_array_async; - sparql_connection_class->update_array_finish = tracker_direct_connection_update_array_finish; - sparql_connection_class->update_blank = tracker_direct_connection_update_blank; - sparql_connection_class->update_blank_async = tracker_direct_connection_update_blank_async; - sparql_connection_class->update_blank_finish = tracker_direct_connection_update_blank_finish; - sparql_connection_class->get_namespace_manager = tracker_direct_connection_get_namespace_manager; - sparql_connection_class->create_notifier = tracker_direct_connection_create_notifier; - sparql_connection_class->close = tracker_direct_connection_close; - sparql_connection_class->close_async = tracker_direct_connection_close_async; - sparql_connection_class->close_finish = tracker_direct_connection_close_finish; - - props[PROP_FLAGS] = - g_param_spec_flags ("flags", - "Flags", - "Flags", - TRACKER_TYPE_SPARQL_CONNECTION_FLAGS, - TRACKER_SPARQL_CONNECTION_FLAGS_NONE, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY); - props[PROP_STORE_LOCATION] = - g_param_spec_object ("store-location", - "Store location", - "Store location", - G_TYPE_FILE, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY); - props[PROP_ONTOLOGY_LOCATION] = - g_param_spec_object ("ontology-location", - "Ontology location", - "Ontology location", - G_TYPE_FILE, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY); - - g_object_class_install_properties (object_class, N_PROPS, props); -} - -TrackerDirectConnection * -tracker_direct_connection_new (TrackerSparqlConnectionFlags flags, - GFile *store, - GFile *ontology, - GError **error) -{ - g_return_val_if_fail (!store || G_IS_FILE (store), NULL); - g_return_val_if_fail (!ontology || G_IS_FILE (ontology), NULL); - g_return_val_if_fail (!error || !*error, NULL); - - return g_object_new (TRACKER_TYPE_DIRECT_CONNECTION, - "flags", flags, - "store-location", store, - "ontology-location", ontology, - NULL); -} - -TrackerDataManager * -tracker_direct_connection_get_data_manager (TrackerDirectConnection *conn) -{ - TrackerDirectConnectionPrivate *priv; - - priv = tracker_direct_connection_get_instance_private (conn); - return priv->data_manager; -} diff --git a/src/libtracker-sparql-backend/direct/tracker-direct.h b/src/libtracker-sparql-backend/direct/tracker-direct.h deleted file mode 100644 index c47087dd5..000000000 --- a/src/libtracker-sparql-backend/direct/tracker-direct.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2010, Nokia - * Copyright (C) 2017, Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#ifndef __TRACKER_LOCAL_CONNECTION_H__ -#define __TRACKER_LOCAL_CONNECTION_H__ - -#include -#include - -#define TRACKER_TYPE_DIRECT_CONNECTION (tracker_direct_connection_get_type()) -#define TRACKER_DIRECT_CONNECTION(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), TRACKER_TYPE_DIRECT_CONNECTION, TrackerDirectConnection)) -#define TRACKER_DIRECT_CONNECTION_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), TRACKER_TYPE_DIRECT_CONNECTION, TrackerDirectConnectionClass)) -#define TRACKER_IS_DIRECT_CONNECTION(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), TRACKER_TYPE_DIRECT_CONNECTION)) -#define TRACKER_IS_DIRECT_CONNECTION_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), TRACKER_TYPE_DIRECT_CONNECTION)) -#define TRACKER_DIRECT_CONNECTION_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), TRACKER_TYPE_DIRECT_CONNECTION, TrackerDirectConnectionClass)) - -typedef struct _TrackerDirectConnection TrackerDirectConnection; -typedef struct _TrackerDirectConnectionClass TrackerDirectConnectionClass; - -struct _TrackerDirectConnectionClass -{ - TrackerSparqlConnectionClass parent_class; -}; - -struct _TrackerDirectConnection -{ - TrackerSparqlConnection parent_instance; -}; - -GType tracker_direct_connection_get_type (void) G_GNUC_CONST; - -TrackerDirectConnection *tracker_direct_connection_new (TrackerSparqlConnectionFlags flags, - GFile *store, - GFile *ontology, - GError **error); - -TrackerDataManager *tracker_direct_connection_get_data_manager (TrackerDirectConnection *conn); - -#endif /* __TRACKER_LOCAL_CONNECTION_H__ */ diff --git a/src/libtracker-sparql-backend/direct/tracker-direct.vapi b/src/libtracker-sparql-backend/direct/tracker-direct.vapi deleted file mode 100644 index 0b0e02815..000000000 --- a/src/libtracker-sparql-backend/direct/tracker-direct.vapi +++ /dev/null @@ -1,10 +0,0 @@ -[CCode (cprefix = "Tracker", gir_namespace = "Tracker", gir_version = "2.0", lower_case_cprefix = "tracker_")] -namespace Tracker { - namespace Direct { - [CCode (cheader_filename = "tracker-direct.h")] - public class Connection : Tracker.Sparql.Connection, GLib.Initable, GLib.AsyncInitable { - public Connection (Tracker.Sparql.ConnectionFlags connection_flags, GLib.File loc, GLib.File? ontology) throws Tracker.Sparql.Error, GLib.IOError, GLib.DBusError; - public unowned Tracker.Data.Manager get_data_manager (); - } - } -} diff --git a/src/libtracker-sparql-backend/meson.build b/src/libtracker-sparql-backend/meson.build deleted file mode 100644 index 86dcc04de..000000000 --- a/src/libtracker-sparql-backend/meson.build +++ /dev/null @@ -1,65 +0,0 @@ -subdir('bus') -subdir('direct') -subdir('remote') - -libtracker_sparql = library('tracker-sparql-' + tracker_api_version, - '../libtracker-common/libtracker-common.vapi', - '../libtracker-data/libtracker-data.vapi', - 'direct/tracker-direct.vapi', - 'tracker-backend.vala', - - gnu_symbol_visibility: 'hidden', - - soversion: soversion, - version: libversion, - - install: true, - install_rpath: tracker_internal_libs_dir, - - c_args: [ - '-include', 'libtracker-sparql/tracker-private.h', - ], - - link_whole: [libtracker_sparql_intermediate], - - dependencies: [tracker_common_dep, tracker_sparql_remote_dep, tracker_sparql_bus_dep, tracker_sparql_direct_dep, tracker_sparql_vapi_dep], -) - -tracker_sparql_dep = declare_dependency( - link_with: libtracker_sparql, - include_directories: srcinc, - dependencies: [tracker_common_dep], -) - -pkg.generate(libtracker_sparql, - description: 'Tracker : A SPARQL triple store library', - requires: [glib, gio, gobject, gmodule], - subdirs: [ - 'tracker-' + tracker_api_version, - 'tracker-' + tracker_api_version / 'libtracker-sparql', - ], - variables: [ - 'exec_prefix=${prefix}', - 'libexecdir=${prefix}' / get_option('libexecdir'), - 'datadir=${prefix}' / get_option('datadir'), - 'tracker_datadir=${datadir}' / tracker_versioned_name, - 'ontologies_dir=' + tracker_ontologies_dir, - ], -) - -tracker_sparql_gir = gnome.generate_gir(libtracker_sparql, - sources: libtracker_sparql_c_sources + libtracker_sparql_c_public_headers, - nsversion: tracker_api_version, - namespace: 'Tracker', - identifier_prefix: 'Tracker', - symbol_prefix: 'tracker', - includes : ['GLib-2.0', 'GObject-2.0', 'Gio-2.0' ], - link_with: libtracker_sparql, - install: true, - extra_args: [ - '--c-include', - 'libtracker-sparql/tracker-sparql.h', - '-DTRACKER_COMPILATION', - ]) - -tracker_sparql_uninstalled_dir = meson.current_build_dir() diff --git a/src/libtracker-sparql-backend/remote/meson.build b/src/libtracker-sparql-backend/remote/meson.build deleted file mode 100644 index f4d589d61..000000000 --- a/src/libtracker-sparql-backend/remote/meson.build +++ /dev/null @@ -1,30 +0,0 @@ -tracker_remote_dependencies = [json_glib, libsoup, libxml2] - -sources = [ - 'tracker-json-cursor.vala', - 'tracker-xml-cursor.vala', - 'tracker-remote.vala', - '../../libtracker-common/libtracker-common.vapi' -] - -libtracker_remote = static_library('tracker-remote', sources, - dependencies: tracker_remote_dependencies + [tracker_common_dep, tracker_sparql_intermediate_dep], - c_args: tracker_c_args + [ - '-include', 'config.h', - '-include', 'libtracker-sparql/tracker-private.h', - ], - vala_args: [ - '--debug', - '--pkg', 'posix', - # FIXME: Meson has code to add --target-glib automatically, but it - # doesn't seem to work here. - '--target-glib', glib_required, - ], - gnu_symbol_visibility: 'hidden', -) - -tracker_sparql_remote_dep = declare_dependency( - link_with: libtracker_remote, - include_directories: include_directories('.'), - dependencies: tracker_remote_dependencies, -) diff --git a/src/libtracker-sparql-backend/remote/tracker-json-cursor.vala b/src/libtracker-sparql-backend/remote/tracker-json-cursor.vala deleted file mode 100644 index 047d47278..000000000 --- a/src/libtracker-sparql-backend/remote/tracker-json-cursor.vala +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (C) 2016 Carlos Garnacho - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * Author: Carlos Garnacho - */ - -public class Tracker.Remote.JsonCursor : Tracker.Sparql.Cursor { - internal Json.Parser _parser; - internal Json.Array _vars; - internal Json.Array _results; - internal Json.Object _cur_row; - internal uint _cur_idx = 0; - internal bool _started_iterating = false; - - const string XSD_NS = "http://www.w3.org/2001/XMLSchema#"; - - public JsonCursor (string document, long length) throws GLib.Error { - Object (); - var parser = new Json.Parser (); - parser.load_from_data (document, length); - - var root = parser.get_root ().get_object (); - var head = root.get_object_member ("head"); - var results = root.get_object_member ("results"); - - _parser = parser; - _vars = head.get_array_member ("vars"); - _results = results.get_array_member ("bindings"); - _started_iterating = false; - } - - public override int n_columns { - get { return (int) _vars.get_length (); } - } - - public override Sparql.ValueType get_value_type (int column) requires (_cur_row != null) { - var col_node = _cur_row.get_member (get_variable_name (column)); - - if (col_node == null) - return Sparql.ValueType.UNBOUND; - - var object = col_node.get_object ();//_cur_row.get_object_member (get_variable_name (column)); - unowned string str = object.get_string_member ("type"); - - switch (str) { - case "uri": - return Sparql.ValueType.URI; - case "bnode": - return Sparql.ValueType.BLANK_NODE; - case "literal": { - var node = object.get_member ("datatype"); - - if (node == null) - return Sparql.ValueType.STRING; - - str = node.get_string (); - - switch (str) { - case XSD_NS + "byte": - case XSD_NS + "int": - case XSD_NS + "integer": - case XSD_NS + "long": - return Sparql.ValueType.INTEGER; - case XSD_NS + "decimal": - case XSD_NS + "double": - return Sparql.ValueType.DOUBLE; - case XSD_NS + "dateTime": - return Sparql.ValueType.DATETIME; - default: - return Sparql.ValueType.STRING; - } - } - - default: - return Sparql.ValueType.STRING; - } - } - - public override unowned string? get_variable_name (int column) { - return _vars.get_string_element (column); - } - - public override unowned string? get_string (int column, out long length = null) requires (_cur_row != null) { - var col_node = _cur_row.get_member (get_variable_name (column)); - length = 0; - - if (col_node == null) - return null; - - var object = col_node.get_object (); - - if (object == null) - return null; - - unowned string str = object.get_string_member ("value"); - length = str.length; - return str; - } - - public override bool next (Cancellable? cancellable = null) throws IOError, GLib.Error { - if (_started_iterating) - _cur_idx++; - - if (_cur_idx >= _results.get_length ()) - return false; - - if (cancellable != null && cancellable.is_cancelled ()) - throw new IOError.CANCELLED ("Operation was cancelled"); - - _started_iterating = true; - _cur_row = _results.get_object_element (_cur_idx); - return true; - } - - public async override bool next_async (Cancellable? cancellable = null) throws IOError, GLib.Error { - return next (cancellable); - } - - public override void rewind () { - _started_iterating = false; - } - - public override void close () { - } -} diff --git a/src/libtracker-sparql-backend/remote/tracker-remote.vala b/src/libtracker-sparql-backend/remote/tracker-remote.vala deleted file mode 100644 index 206c237fc..000000000 --- a/src/libtracker-sparql-backend/remote/tracker-remote.vala +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (C) 2016 Carlos Garnacho - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * Author: Carlos Garnacho - */ -[CCode (cname = "PACKAGE_VERSION")] -extern const string PACKAGE_VERSION; - -public class Tracker.Remote.Connection : Tracker.Sparql.Connection { - - internal Soup.Session _session; - internal string _base_uri; - - const string XML_TYPE = "application/sparql-results+xml"; - const string JSON_TYPE = "application/sparql-results+json"; - const string USER_AGENT = "Tracker/" + PACKAGE_VERSION + " (https://gitlab.gnome.org/GNOME/tracker/issues/; tracker-list@lists.gnome.org) Tracker/" + PACKAGE_VERSION; - - public Connection (string base_uri) { - Object (); - _base_uri = base_uri; - _session = new Soup.Session (); - } - - private Soup.Message create_request (string sparql) { - var uri = _base_uri + "?query=" + sparql; - var message = new Soup.Message ("GET", uri); - var headers = message.request_headers; - - headers.append ("User-Agent", USER_AGENT); - headers.append ("Accept", JSON_TYPE); - headers.append ("Accept", XML_TYPE); - - return message; - } - - private Sparql.Cursor create_cursor (Soup.Message message) throws GLib.Error, Sparql.Error { - string document = (string) message.response_body.flatten ().data; - - if (message.status_code != Soup.Status.OK) { - throw new Sparql.Error.UNSUPPORTED ("Unhandled status code %u, document is: %s", - message.status_code, document); - } - - var headers = message.response_headers; - var content_type = headers.get_content_type (null); - long length = document.length; - - if (content_type == JSON_TYPE) { - return new Tracker.Remote.JsonCursor (document, length); - } else if (content_type == XML_TYPE) { - return new Tracker.Remote.XmlCursor (document, length); - } else { - throw new Sparql.Error.UNSUPPORTED ("Unknown content type '%s', document is: %s", content_type, document); - } - } - - public override Sparql.Cursor query (string sparql, Cancellable? cancellable) throws GLib.Error, Sparql.Error, IOError { - var message = create_request (sparql); - - _session.send_message (message); - - if (cancellable != null && cancellable.is_cancelled ()) - throw new IOError.CANCELLED ("Operation was cancelled"); - - return create_cursor (message); - } - - public async override Sparql.Cursor query_async (string sparql, Cancellable? cancellable) throws GLib.Error, Sparql.Error, IOError { - var message = create_request (sparql); - - yield _session.send_async (message, cancellable); - - return create_cursor (message); - } - - public override void close () { - } - - public async override bool close_async () throws GLib.IOError { - return true; - } -} diff --git a/src/libtracker-sparql-backend/remote/tracker-xml-cursor.vala b/src/libtracker-sparql-backend/remote/tracker-xml-cursor.vala deleted file mode 100644 index a7a710041..000000000 --- a/src/libtracker-sparql-backend/remote/tracker-xml-cursor.vala +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Copyright (C) 2016 Carlos Garnacho - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * Author: Carlos Garnacho - */ - -public class Tracker.Remote.XmlCursor : Tracker.Sparql.Cursor { - Xml.Node *_results; - Xml.Node *_cur_row; - HashTable _cur_row_map; - string [] _vars; - - const string XSD_NS = "http://www.w3.org/2001/XMLSchema#"; - - private Xml.Node * find_first_child_node (Xml.Node *node) { - for (Xml.Node* iter = node->children; iter != null; iter = iter->next) { - if (iter->type != Xml.ElementType.ELEMENT_NODE) - continue; - return iter; - } - - return null; - } - - private Xml.Node * find_next_node (Xml.Node *node) { - for (Xml.Node* iter = node->next; iter != null; iter = iter->next) { - if (iter->type != Xml.ElementType.ELEMENT_NODE) - continue; - return iter; - } - - return null; - } - - private Xml.Node * lookup_child_node (Xml.Node *node, string name) { - for (Xml.Node* iter = node->children; iter != null; iter = iter->next) { - if (iter->type != Xml.ElementType.ELEMENT_NODE) - continue; - if (iter->name == name) - return iter; - } - - return null; - } - - private Xml.Attr * lookup_attribute (Xml.Node *node, string name) { - for (Xml.Attr* iter = node->properties; iter != null; iter = iter->next) { - if (iter->name == name) - return iter; - } - - return null; - } - - private void parse_vars (Xml.Node *vars) { - for (Xml.Node* iter = vars->children; iter != null; iter = iter->next) { - if (iter->name != "variable" || - iter->type != Xml.ElementType.ELEMENT_NODE) - continue; - - var attr = lookup_attribute (iter, "name"); - if (attr == null) - continue; - - _vars += attr->children->content; - } - } - - public XmlCursor (string document, long length) throws Sparql.Error { - Object (); - Xml.Parser.init (); - var doc = Xml.Parser.parse_memory (document, (int) length); - - if (doc == null) - throw new Sparql.Error.INTERNAL ("Could not parse XML document"); - - var root = doc->get_root_element (); - _results = lookup_child_node (root, "results"); - - var vars = lookup_child_node (root, "head"); - parse_vars (vars); - Xml.Parser.cleanup (); - - _cur_row_map = new HashTable (str_hash, str_equal); - } - - public override int n_columns { - get { return (int) _vars.length; } - } - - public override Sparql.ValueType get_value_type (int column) requires (_cur_row != null) { - var variable = _vars[column]; - Xml.Node* node = (Xml.Node*) _cur_row_map.get (variable); - if (node == null) - return Sparql.ValueType.UNBOUND; - - switch (node->children->name) { - case "uri": - return Sparql.ValueType.URI; - case "bnode": - return Sparql.ValueType.BLANK_NODE; - case "literal": - var attr = lookup_attribute (node, "datatype"); - if (attr == null) - return Sparql.ValueType.STRING; - - switch (attr->children->content) { - case XSD_NS + "byte": - case XSD_NS + "int": - case XSD_NS + "integer": - case XSD_NS + "long": - return Sparql.ValueType.INTEGER; - case XSD_NS + "decimal": - case XSD_NS + "double": - return Sparql.ValueType.DOUBLE; - case XSD_NS + "dateTime": - return Sparql.ValueType.DATETIME; - default: - return Sparql.ValueType.STRING; - } - default: - return Sparql.ValueType.STRING; - } - } - - public override unowned string? get_variable_name (int column) { - if (column < 0 || column > _vars.length) - return null; - return _vars[column]; - } - - public override unowned string? get_string (int column, out long length = null) requires (_cur_row != null) { - length = 0; - - var variable = _vars[column]; - Xml.Node* node = (Xml.Node*) _cur_row_map.get (variable); - if (node == null) - return null; - - var child = find_first_child_node (node); - if (child == null) - return null; - - var text = child->children; - if (text == null || - text->type != Xml.ElementType.TEXT_NODE) - return null; - - length = text->content.length; - return text->content; - } - - public override bool next (Cancellable? cancellable = null) throws IOError, GLib.Error { - if (_cur_row == null) - _cur_row = find_first_child_node (_results); - else - _cur_row = find_next_node (_cur_row); - - _cur_row_map.remove_all (); - - if (_cur_row == null) - return false; - - for (Xml.Node* iter = _cur_row->children; iter != null; iter = iter->next) { - if (iter->name != "binding") - continue; - - var attr = lookup_attribute (iter, "name"); - if (attr == null) - continue; - - var binding_name = attr->children->content; - _cur_row_map.insert (binding_name, iter); - } - - return true; - } - - public async override bool next_async (Cancellable? cancellable = null) throws IOError, GLib.Error { - return next (cancellable); - } - - public override void rewind () { - _cur_row = null; - } - - public override void close () { - } -} diff --git a/src/libtracker-sparql-backend/tracker-backend.vala b/src/libtracker-sparql-backend/tracker-backend.vala deleted file mode 100644 index fc3682872..000000000 --- a/src/libtracker-sparql-backend/tracker-backend.vala +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2010, Nokia - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -public static Tracker.Sparql.Connection tracker_sparql_connection_remote_new (string url_base) { - return new Tracker.Remote.Connection (url_base); -} - -public static Tracker.Sparql.Connection tracker_sparql_connection_bus_new (string service, string? object_path, DBusConnection? conn) throws Tracker.Sparql.Error, IOError, DBusError, GLib.Error { - GLib.DBusConnection dbus_conn; - string path; - - if (conn != null) - dbus_conn = conn; - else - dbus_conn = GLib.Bus.get_sync (GLib.BusType.SESSION, null); - - if (object_path != null) - path = object_path; - else - path = "/org/freedesktop/Tracker3/Endpoint"; - - return new Tracker.Bus.Connection (service, path, dbus_conn); -} - -public static Tracker.Sparql.Connection tracker_sparql_connection_new (Tracker.Sparql.ConnectionFlags flags, File? store, File? ontology, Cancellable? cancellable = null) throws GLib.Error, Tracker.Sparql.Error, IOError { - var conn = new Tracker.Direct.Connection (flags, store, ontology); - conn.init (cancellable); - return conn; -} - -public static async Tracker.Sparql.Connection tracker_sparql_connection_new_async (Tracker.Sparql.ConnectionFlags flags, File store, File ontology, Cancellable? cancellable = null) throws GLib.Error, Tracker.Sparql.Error, IOError { - var conn = new Tracker.Direct.Connection (flags, store, ontology); - yield conn.init_async (Priority.DEFAULT, cancellable); - return conn; -} diff --git a/src/libtracker-sparql/bus/.gitignore b/src/libtracker-sparql/bus/.gitignore new file mode 100644 index 000000000..c34fe4c56 --- /dev/null +++ b/src/libtracker-sparql/bus/.gitignore @@ -0,0 +1,5 @@ +tracker-namespace.c +tracker-bus.[ch] +tracker-bus*.vapi +tracker-array-cursor.c +tracker-bus-fd-cursor.c diff --git a/src/libtracker-sparql/bus/meson.build b/src/libtracker-sparql/bus/meson.build new file mode 100644 index 000000000..6d4edf2b1 --- /dev/null +++ b/src/libtracker-sparql/bus/meson.build @@ -0,0 +1,26 @@ +libtracker_bus = static_library('tracker-bus', + 'tracker-bus.vala', + 'tracker-namespace.vala', + 'tracker-bus-fd-cursor.vala', + 'tracker-bus-statement.vala', + '../../libtracker-common/libtracker-common.vapi', + tracker_common_enum_header, + c_args: tracker_c_args + [ + '-include', 'libtracker-sparql/tracker-private.h', + ], + vala_args: [ + '--debug', + '--pkg', 'posix', + # FIXME: Meson has code to add --target-glib automatically, but it + # doesn't seem to work here. + '--target-glib', glib_required, + ], + dependencies: [tracker_common_dep, tracker_sparql_intermediate_dep], + include_directories: [commoninc, configinc, srcinc], + gnu_symbol_visibility: 'hidden', +) + +tracker_sparql_bus_dep = declare_dependency( + link_with: libtracker_bus, + include_directories: include_directories('.') +) diff --git a/src/libtracker-sparql/bus/tracker-bus-fd-cursor.vala b/src/libtracker-sparql/bus/tracker-bus-fd-cursor.vala new file mode 100644 index 000000000..954ad1ec7 --- /dev/null +++ b/src/libtracker-sparql/bus/tracker-bus-fd-cursor.vala @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2010, Nokia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +class Tracker.Bus.FDCursor : Tracker.Sparql.Cursor { + internal char* buffer; + internal ulong buffer_index; + internal ulong buffer_size; + + internal int _n_columns; + internal int* offsets; + internal int* types; + internal char* data; + internal string[] variable_names; + internal bool cursor_finished; + + public FDCursor (char* buffer, ulong buffer_size, string[] variable_names) { + Object (); + this.buffer = buffer; + this.buffer_size = buffer_size; + this.variable_names = variable_names; + this.cursor_finished = true; + _n_columns = variable_names.length; + } + + ~FDCursor () { + free (buffer); + } + + inline int buffer_read_int () { + int v = *((int*) (buffer + buffer_index)); + + buffer_index += 4; + + return v; + } + + public override int n_columns { + get { return _n_columns; } + } + + public override Sparql.ValueType get_value_type (int column) + requires (types != null) { + if (column >= n_columns) { + return Sparql.ValueType.UNBOUND; + } + + /* Cast from int to enum */ + return (Sparql.ValueType) types[column]; + } + + public override unowned string? get_variable_name (int column) + requires (variable_names != null) { + return variable_names[column]; + } + + public override unowned string? get_string (int column, out long length = null) + requires (cursor_finished == false) { + unowned string str = null; + + if (column >= n_columns) { + length = 0; + return null; + } + + // return null instead of empty string for unbound values + if (types[column] == Sparql.ValueType.UNBOUND) { + length = 0; + return null; + } + + if (column == 0) { + str = (string) data; + } else { + str = (string) (data + offsets[column - 1] + 1); + } + + length = str.length; + + return str; + } + + public override bool next (Cancellable? cancellable = null) throws GLib.Error { + int last_offset; + + if (cancellable != null && cancellable.is_cancelled ()) { + throw new IOError.CANCELLED ("Operation was cancelled"); + } + + if (buffer_index >= buffer_size) { + cursor_finished = true; + data = null; + return false; + } + + /* So, the make up on each cursor segment is: + * + * iteration = [4 bytes for number of columns, + * columns x 4 bytes for types + * columns x 4 bytes for offsets] + */ + + _n_columns = buffer_read_int (); + + /* Storage of ints that will be cast to TrackerSparqlValueType enums, + * also see get_value_type */ + types = (int*) (buffer + buffer_index); + buffer_index += sizeof (int) * n_columns; + + offsets = (int*) (buffer + buffer_index); + buffer_index += sizeof (int) * (n_columns - 1); + last_offset = buffer_read_int (); + + data = buffer + buffer_index; + cursor_finished = false; + + buffer_index += last_offset + 1; + + return true; + } + + public override async bool next_async (Cancellable? cancellable = null) throws GLib.Error { + // next never blocks + return next (cancellable); + } + + public override void rewind () { + buffer_index = 0; + data = buffer; + cursor_finished = false; + } + + public override void close () { + } +} diff --git a/src/libtracker-sparql/bus/tracker-bus-statement.vala b/src/libtracker-sparql/bus/tracker-bus-statement.vala new file mode 100644 index 000000000..b14143901 --- /dev/null +++ b/src/libtracker-sparql/bus/tracker-bus-statement.vala @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2020, Red Hat Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + * Author: Carlos Garnacho + */ + +public class Tracker.Bus.Statement : Tracker.Sparql.Statement { + private DBusConnection bus; + private string query; + private string dbus_name; + private string object_path; + private HashTable arguments; + + public Statement (DBusConnection bus, string dbus_name, string object_path, string query) { + Object (); + this.bus = bus; + this.dbus_name = dbus_name; + this.object_path = object_path; + this.query = query; + this.arguments = new HashTable (str_hash, str_equal); + } + + public override void bind_boolean (string name, bool value) { + this.arguments.insert (name, new GLib.Variant.boolean (value)); + } + + public override void bind_double (string name, double value) { + this.arguments.insert (name, new GLib.Variant.double (value)); + } + + public override void bind_int (string name, int64 value) { + this.arguments.insert (name, new GLib.Variant.int64 (value)); + } + + public override void bind_string (string name, string value) { + this.arguments.insert (name, new GLib.Variant.string (value)); + } + + public override void clear_bindings () { + this.arguments.remove_all (); + } + + private VariantBuilder? get_arguments () { + if (this.arguments.size () == 0) + return null; + + VariantBuilder builder = new VariantBuilder (new VariantType ("a{sv}")); + HashTableIter iter = HashTableIter (this.arguments); + unowned string arg; + unowned GLib.Variant value; + + while (iter.next (out arg, out value)) + builder.add ("{sv}", arg, value); + + return builder; + } + + public override Sparql.Cursor execute (GLib.Cancellable? cancellable) throws Sparql.Error, GLib.Error, GLib.IOError, GLib.DBusError { + // use separate main context for sync operation + var context = new MainContext (); + var loop = new MainLoop (context, false); + context.push_thread_default (); + AsyncResult async_res = null; + execute_async.begin (cancellable, (o, res) => { + async_res = res; + loop.quit (); + }); + loop.run (); + context.pop_thread_default (); + return execute_async.end (async_res); + } + + public async override Sparql.Cursor execute_async (GLib.Cancellable? cancellable) throws Sparql.Error, GLib.Error, GLib.IOError, GLib.DBusError { + return yield Tracker.Bus.Connection.perform_query_call (bus, dbus_name, object_path, query, get_arguments (), cancellable); + } +} diff --git a/src/libtracker-sparql/bus/tracker-bus.vala b/src/libtracker-sparql/bus/tracker-bus.vala new file mode 100644 index 000000000..72069873f --- /dev/null +++ b/src/libtracker-sparql/bus/tracker-bus.vala @@ -0,0 +1,295 @@ +/* + * Copyright (C) 2010, Nokia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +public class Tracker.Bus.Connection : Tracker.Sparql.Connection { + DBusConnection bus; + string dbus_name; + string object_path; + + private const string ENDPOINT_IFACE = "org.freedesktop.Tracker3.Endpoint"; + + public string bus_name { + get { return dbus_name; } + } + + public string bus_object_path { + get { return object_path; } + } + + public Connection (string dbus_name, string object_path, DBusConnection? dbus_connection) throws Sparql.Error, IOError, DBusError, GLib.Error { + Object (); + this.dbus_name = dbus_name; + this.bus = dbus_connection; + this.object_path = object_path; + + // ensure that error domain is registered with GDBus + new Sparql.Error.INTERNAL (""); + } + + static void pipe (out UnixInputStream input, out UnixOutputStream output) throws IOError { + int pipefd[2]; + if (Posix.pipe (pipefd) < 0) { + throw new IOError.FAILED ("Pipe creation failed"); + } + input = new UnixInputStream (pipefd[0], true); + output = new UnixOutputStream (pipefd[1], true); + } + + static void handle_error_reply (DBusMessage message) throws Sparql.Error, IOError, DBusError { + try { + message.to_gerror (); + } catch (IOError e_io) { + throw e_io; + } catch (Sparql.Error e_sparql) { + throw e_sparql; + } catch (DBusError e_dbus) { + throw e_dbus; + } catch (Error e) { + throw new IOError.FAILED (e.message); + } + } + + static void send_query (DBusConnection bus, string dbus_name, string object_path, string sparql, VariantBuilder? arguments, UnixOutputStream output, Cancellable? cancellable, AsyncReadyCallback? callback) throws GLib.IOError, GLib.Error { + var message = new DBusMessage.method_call (dbus_name, object_path, ENDPOINT_IFACE, "Query"); + var fd_list = new UnixFDList (); + message.set_body (new Variant ("(sha{sv})", sparql, fd_list.append (output.fd), arguments)); + message.set_unix_fd_list (fd_list); + + bus.send_message_with_reply.begin (message, DBusSendMessageFlags.NONE, int.MAX, null, cancellable, callback); + } + + public static async Sparql.Cursor perform_query_call (DBusConnection bus, string dbus_name, string object_path, string sparql, VariantBuilder? arguments, Cancellable? cancellable) throws GLib.IOError, GLib.Error { + UnixInputStream input; + UnixOutputStream output; + pipe (out input, out output); + + // send D-Bus request + AsyncResult dbus_res = null; + bool received_result = false; + send_query (bus, dbus_name, object_path, sparql, arguments, output, cancellable, (o, res) => { + dbus_res = res; + if (received_result) { + perform_query_call.callback (); + } + }); + + output = null; + + // receive query results via FD + var mem_stream = new MemoryOutputStream (null, GLib.realloc, GLib.free); + + try { + yield mem_stream.splice_async (input, OutputStreamSpliceFlags.CLOSE_SOURCE | OutputStreamSpliceFlags.CLOSE_TARGET, Priority.DEFAULT, cancellable); + } finally { + // wait for D-Bus reply + received_result = true; + if (dbus_res == null) { + yield; + } + } + + var reply = bus.send_message_with_reply.end (dbus_res); + handle_error_reply (reply); + + string[] variable_names = (string[]) reply.get_body ().get_child_value (0); + mem_stream.close (); + return new FDCursor (mem_stream.steal_data (), mem_stream.data_size, variable_names); + } + + public override Sparql.Cursor query (string sparql, Cancellable? cancellable) throws Sparql.Error, GLib.Error, GLib.IOError, DBusError { + // use separate main context for sync operation + var context = new MainContext (); + var loop = new MainLoop (context, false); + context.push_thread_default (); + AsyncResult async_res = null; + query_async.begin (sparql, cancellable, (o, res) => { + async_res = res; + loop.quit (); + }); + loop.run (); + context.pop_thread_default (); + return query_async.end (async_res); + } + + public async override Sparql.Cursor query_async (string sparql, Cancellable? cancellable = null) throws Sparql.Error, GLib.Error, GLib.IOError, DBusError { + return yield perform_query_call (bus, dbus_name, object_path, sparql, null, cancellable); + } + + public override Sparql.Statement? query_statement (string sparql, GLib.Cancellable? cancellable = null) throws Sparql.Error { + return new Bus.Statement (bus, dbus_name, object_path, sparql); + } + + void send_update (string method, UnixInputStream input, Cancellable? cancellable, AsyncReadyCallback? callback) throws GLib.Error, GLib.IOError { + var message = new DBusMessage.method_call (dbus_name, object_path, ENDPOINT_IFACE, method); + var fd_list = new UnixFDList (); + message.set_body (new Variant ("(h)", fd_list.append (input.fd))); + message.set_unix_fd_list (fd_list); + + bus.send_message_with_reply.begin (message, DBusSendMessageFlags.NONE, int.MAX, null, cancellable, callback); + } + + public override void update (string sparql, Cancellable? cancellable = null) throws Sparql.Error, GLib.Error, GLib.IOError, DBusError { + // use separate main context for sync operation + var context = new MainContext (); + var loop = new MainLoop (context, false); + context.push_thread_default (); + AsyncResult async_res = null; + update_async.begin (sparql, cancellable, (o, res) => { + async_res = res; + loop.quit (); + }); + loop.run (); + context.pop_thread_default (); + update_async.end (async_res); + } + + public async override void update_async (string sparql, Cancellable? cancellable = null) throws Sparql.Error, GLib.Error, GLib.IOError, DBusError { + UnixInputStream input; + UnixOutputStream output; + pipe (out input, out output); + + // send D-Bus request + AsyncResult dbus_res = null; + bool sent_update = false; + send_update ("Update", input, cancellable, (o, res) => { + dbus_res = res; + if (sent_update) { + update_async.callback (); + } + }); + + // send sparql string via fd + var data_stream = new DataOutputStream (output); + data_stream.set_byte_order (DataStreamByteOrder.HOST_ENDIAN); + data_stream.put_int32 ((int32) sparql.length); + data_stream.put_string (sparql); + data_stream = null; + + // wait for D-Bus reply + sent_update = true; + if (dbus_res == null) { + yield; + } + + var reply = bus.send_message_with_reply.end (dbus_res); + handle_error_reply (reply); + } + + public async override bool update_array_async (string[] sparql, Cancellable? cancellable = null) throws Sparql.Error, GLib.Error, GLib.IOError, DBusError { + UnixInputStream input; + UnixOutputStream output; + pipe (out input, out output); + + // send D-Bus request + AsyncResult dbus_res = null; + bool sent_update = false; + send_update ("UpdateArray", input, cancellable, (o, res) => { + dbus_res = res; + if (sent_update) { + update_array_async.callback (); + } + }); + + // send sparql strings via fd + var data_stream = new DataOutputStream (output); + data_stream.set_byte_order (DataStreamByteOrder.HOST_ENDIAN); + data_stream.put_int32 ((int32) sparql.length); + for (int i = 0; i < sparql.length; i++) { + data_stream.put_int32 ((int32) sparql[i].length); + data_stream.put_string (sparql[i]); + } + data_stream = null; + + // wait for D-Bus reply + sent_update = true; + if (dbus_res == null) { + yield; + } + + var reply = bus.send_message_with_reply.end (dbus_res); + handle_error_reply (reply); + + return true; + } + + public override GLib.Variant? update_blank (string sparql, Cancellable? cancellable = null) throws Sparql.Error, GLib.Error, GLib.IOError, DBusError { + // use separate main context for sync operation + var context = new MainContext (); + var loop = new MainLoop (context, false); + context.push_thread_default (); + AsyncResult async_res = null; + update_blank_async.begin (sparql, cancellable, (o, res) => { + async_res = res; + loop.quit (); + }); + loop.run (); + context.pop_thread_default (); + return update_blank_async.end (async_res); + } + + public async override GLib.Variant? update_blank_async (string sparql, Cancellable? cancellable = null) throws Sparql.Error, GLib.Error, GLib.IOError, DBusError { + UnixInputStream input; + UnixOutputStream output; + pipe (out input, out output); + + // send D-Bus request + AsyncResult dbus_res = null; + bool sent_update = false; + send_update ("UpdateBlank", input, cancellable, (o, res) => { + dbus_res = res; + if (sent_update) { + update_blank_async.callback (); + } + }); + + // send sparql strings via fd + var data_stream = new DataOutputStream (output); + data_stream.set_byte_order (DataStreamByteOrder.HOST_ENDIAN); + data_stream.put_int32 ((int32) sparql.length); + data_stream.put_string (sparql); + data_stream = null; + + // wait for D-Bus reply + sent_update = true; + if (dbus_res == null) { + yield; + } + + var reply = bus.send_message_with_reply.end (dbus_res); + handle_error_reply (reply); + return reply.get_body ().get_child_value (0); + } + + public override Tracker.Notifier? create_notifier () { + var notifier = (Tracker.Notifier) Object.new (typeof (Tracker.Notifier), + "connection", this, + null); + + notifier.signal_subscribe (this.bus, this.dbus_name, null, null); + + return notifier; + } + + public override void close () { + } + + public async override bool close_async () throws GLib.IOError { + return true; + } +} diff --git a/src/libtracker-sparql/bus/tracker-namespace.vala b/src/libtracker-sparql/bus/tracker-namespace.vala new file mode 100644 index 000000000..9e0a404de --- /dev/null +++ b/src/libtracker-sparql/bus/tracker-namespace.vala @@ -0,0 +1,29 @@ +/* + * Copyright © 2015 Collabora Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +/* + * This file serves as the representation for the Tracker namespace, mostly + * so that we can set its namespace and version attributes for GIR. + */ + +[CCode (cprefix = "TrackerBus", gir_namespace = "TrackerBus", + gir_version = "2.0", lower_case_cprefix = "tracker_bus_")] +namespace Tracker +{ +} diff --git a/src/libtracker-sparql/direct/meson.build b/src/libtracker-sparql/direct/meson.build new file mode 100644 index 000000000..c1ec244e9 --- /dev/null +++ b/src/libtracker-sparql/direct/meson.build @@ -0,0 +1,15 @@ +libtracker_direct = static_library('tracker-direct', + 'tracker-direct.c', + 'tracker-direct-statement.c', + c_args: tracker_c_args + [ + '-include', 'libtracker-sparql/tracker-private.h', + ], + dependencies: [ glib, gio, tracker_data_dep, tracker_sparql_intermediate_dep ], + include_directories: [commoninc, configinc, srcinc], + gnu_symbol_visibility: 'hidden', +) + +tracker_sparql_direct_dep = declare_dependency( + link_with: libtracker_direct, + include_directories: include_directories('.') +) diff --git a/src/libtracker-sparql/direct/tracker-direct-statement.c b/src/libtracker-sparql/direct/tracker-direct-statement.c new file mode 100644 index 000000000..609dbb485 --- /dev/null +++ b/src/libtracker-sparql/direct/tracker-direct-statement.c @@ -0,0 +1,275 @@ +/* + * Copyright (C) 2018, Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "tracker-direct-statement.h" +#include "tracker-data.h" + +typedef struct _TrackerDirectStatementPrivate TrackerDirectStatementPrivate; + +struct _TrackerDirectStatementPrivate +{ + TrackerSparql *sparql; + GHashTable *values; +}; + +G_DEFINE_TYPE_WITH_PRIVATE (TrackerDirectStatement, + tracker_direct_statement, + TRACKER_TYPE_SPARQL_STATEMENT) + +static void +tracker_direct_statement_finalize (GObject *object) +{ + TrackerDirectStatementPrivate *priv; + + priv = tracker_direct_statement_get_instance_private (TRACKER_DIRECT_STATEMENT (object)); + g_hash_table_destroy (priv->values); + g_clear_object (&priv->sparql); + + G_OBJECT_CLASS (tracker_direct_statement_parent_class)->finalize (object); +} + +static void +tracker_direct_statement_constructed (GObject *object) +{ + TrackerDirectStatementPrivate *priv; + TrackerSparqlConnection *conn; + gchar *sparql; + + priv = tracker_direct_statement_get_instance_private (TRACKER_DIRECT_STATEMENT (object)); + + g_object_get (object, + "sparql", &sparql, + "connection", &conn, + NULL); + + priv->sparql = tracker_sparql_new (tracker_direct_connection_get_data_manager (TRACKER_DIRECT_CONNECTION (conn)), + sparql); + g_object_unref (conn); + g_free (sparql); + + G_OBJECT_CLASS (tracker_direct_statement_parent_class)->constructed (object); +} + +static GValue * +insert_value (TrackerDirectStatement *stmt, + const gchar *name, + GType type) +{ + TrackerDirectStatementPrivate *priv; + GValue *value; + + priv = tracker_direct_statement_get_instance_private (stmt); + value = g_new0 (GValue, 1); + g_value_init (value, type); + + g_hash_table_insert (priv->values, g_strdup (name), value); + + return value; +} + +static void +tracker_direct_statement_bind_int (TrackerSparqlStatement *stmt, + const gchar *name, + gint64 value) +{ + GValue *gvalue; + + gvalue = insert_value (TRACKER_DIRECT_STATEMENT (stmt), name, G_TYPE_INT64); + g_value_set_int64 (gvalue, value); +} + +static void +tracker_direct_statement_bind_double (TrackerSparqlStatement *stmt, + const gchar *name, + double value) +{ + GValue *gvalue; + + gvalue = insert_value (TRACKER_DIRECT_STATEMENT (stmt), name, G_TYPE_DOUBLE); + g_value_set_double (gvalue, value); +} + +static void +tracker_direct_statement_bind_boolean (TrackerSparqlStatement *stmt, + const gchar *name, + gboolean value) +{ + GValue *gvalue; + + gvalue = insert_value (TRACKER_DIRECT_STATEMENT (stmt), name, G_TYPE_BOOLEAN); + g_value_set_boolean (gvalue, value); +} + +static void +tracker_direct_statement_bind_string (TrackerSparqlStatement *stmt, + const gchar *name, + const gchar *value) +{ + GValue *gvalue; + + gvalue = insert_value (TRACKER_DIRECT_STATEMENT (stmt), name, G_TYPE_STRING); + g_value_set_string (gvalue, value); +} + +static void +tracker_direct_statement_clear_bindings (TrackerSparqlStatement *stmt) +{ + TrackerDirectStatementPrivate *priv; + + priv = tracker_direct_statement_get_instance_private (TRACKER_DIRECT_STATEMENT (stmt)); + g_hash_table_remove_all (priv->values); +} + +static TrackerSparqlCursor * +tracker_direct_statement_execute (TrackerSparqlStatement *stmt, + GCancellable *cancellable, + GError **error) +{ + TrackerDirectStatementPrivate *priv; + + priv = tracker_direct_statement_get_instance_private (TRACKER_DIRECT_STATEMENT (stmt)); + + return tracker_sparql_execute_cursor (priv->sparql, priv->values, error); +} + +static void +execute_in_thread (GTask *task, + gpointer object, + gpointer task_data, + GCancellable *cancellable) +{ + TrackerDirectStatementPrivate *priv; + TrackerSparqlCursor *cursor; + GHashTable *values = task_data; + GError *error = NULL; + + priv = tracker_direct_statement_get_instance_private (object); + cursor = tracker_sparql_execute_cursor (priv->sparql, values, &error); + + if (error) + g_task_return_error (task, error); + else + g_task_return_pointer (task, cursor, g_object_unref); + + g_object_unref (task); +} + +static void +free_gvalue (gpointer data) +{ + g_value_unset (data); + g_free (data); +} + +static GHashTable * +create_values_ht (void) +{ + return g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, free_gvalue); +} + +static GHashTable * +copy_values_deep (GHashTable *values) +{ + GHashTable *copy; + GHashTableIter iter; + gpointer key, val; + + copy = create_values_ht (); + g_hash_table_iter_init (&iter, values); + + while (g_hash_table_iter_next (&iter, &key, &val)) { + GValue *copy_value; + + copy_value = g_new0 (GValue, 1); + g_value_init (copy_value, G_VALUE_TYPE (val)); + g_value_copy (val, copy_value); + + g_hash_table_insert (copy, g_strdup (key), copy_value); + } + + return copy; +} + +static void +tracker_direct_statement_execute_async (TrackerSparqlStatement *stmt, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + TrackerDirectStatementPrivate *priv; + GHashTable *values; + GTask *task; + + priv = tracker_direct_statement_get_instance_private (TRACKER_DIRECT_STATEMENT (stmt)); + + values = copy_values_deep (priv->values); + + task = g_task_new (stmt, cancellable, callback, user_data); + g_task_set_task_data (task, values, (GDestroyNotify) g_hash_table_unref); + g_task_run_in_thread (task, execute_in_thread); +} + +static TrackerSparqlCursor * +tracker_direct_statement_execute_finish (TrackerSparqlStatement *stmt, + GAsyncResult *res, + GError **error) +{ + return g_task_propagate_pointer (G_TASK (res), error); +} + +static void +tracker_direct_statement_class_init (TrackerDirectStatementClass *klass) +{ + TrackerSparqlStatementClass *stmt_class = (TrackerSparqlStatementClass *) klass; + GObjectClass *object_class = (GObjectClass *) klass; + + object_class->finalize = tracker_direct_statement_finalize; + object_class->constructed = tracker_direct_statement_constructed; + + stmt_class->bind_int = tracker_direct_statement_bind_int; + stmt_class->bind_boolean = tracker_direct_statement_bind_boolean; + stmt_class->bind_double = tracker_direct_statement_bind_double; + stmt_class->bind_string = tracker_direct_statement_bind_string; + stmt_class->clear_bindings = tracker_direct_statement_clear_bindings; + stmt_class->execute = tracker_direct_statement_execute; + stmt_class->execute_async = tracker_direct_statement_execute_async; + stmt_class->execute_finish = tracker_direct_statement_execute_finish; +} + +static void +tracker_direct_statement_init (TrackerDirectStatement *stmt) +{ + TrackerDirectStatementPrivate *priv; + + priv = tracker_direct_statement_get_instance_private (stmt); + priv->values = create_values_ht (); +} + +TrackerDirectStatement * +tracker_direct_statement_new (TrackerSparqlConnection *conn, + const gchar *sparql, + GError **error) +{ + return g_object_new (TRACKER_TYPE_DIRECT_STATEMENT, + "sparql", sparql, + "connection", conn, + NULL); +} diff --git a/src/libtracker-sparql/direct/tracker-direct-statement.h b/src/libtracker-sparql/direct/tracker-direct-statement.h new file mode 100644 index 000000000..d68bb6bc8 --- /dev/null +++ b/src/libtracker-sparql/direct/tracker-direct-statement.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2018, Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __TRACKER_DIRECT_STATEMENT_H__ +#define __TRACKER_DIRECT_STATEMENT_H__ + +#include "tracker-direct.h" +#include + +#define TRACKER_TYPE_DIRECT_STATEMENT (tracker_direct_statement_get_type ()) +#define TRACKER_DIRECT_STATEMENT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), TRACKER_TYPE_DIRECT_STATEMENT, TrackerDirectStatement)) +#define TRACKER_DIRECT_STATEMENT_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), TRACKER_TYPE_DIRECT_STATEMENT, TrackerDirectStatementClass)) +#define TRACKER_IS_DIRECT_STATEMENT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), TRACKER_TYPE_DIRECT_STATEMENT)) +#define TRACKER_IS_DIRECT_STATEMENT_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), TRACKER_TYPE_DIRECT_STATEMENT)) +#define TRACKER_DIRECT_STATEMENT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), TRACKER_TYPE_DIRECT_STATEMENT, TrackerDirectStatementClass)) + +typedef struct _TrackerDirectStatement TrackerDirectStatement; +typedef struct _TrackerDirectStatementClass TrackerDirectStatementClass; + +struct _TrackerDirectStatementClass +{ + TrackerSparqlStatementClass parent_class; +}; + +struct _TrackerDirectStatement +{ + TrackerSparqlStatement parent_instance; +}; + +GType tracker_direct_statement_get_type (void) G_GNUC_CONST; + +TrackerDirectStatement * tracker_direct_statement_new (TrackerSparqlConnection *conn, + const gchar *sparql, + GError **error); + +#endif /* __TRACKER_DIRECT_STATEMENT_H__ */ diff --git a/src/libtracker-sparql/direct/tracker-direct.c b/src/libtracker-sparql/direct/tracker-direct.c new file mode 100644 index 000000000..355c5debf --- /dev/null +++ b/src/libtracker-sparql/direct/tracker-direct.c @@ -0,0 +1,1047 @@ +/* + * Copyright (C) 2010, Nokia + * Copyright (C) 2017, Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#include "tracker-direct.h" +#include "tracker-direct-statement.h" +#include "libtracker-sparql/tracker-private.h" +#include +#include +#include + +typedef struct _TrackerDirectConnectionPrivate TrackerDirectConnectionPrivate; + +struct _TrackerDirectConnectionPrivate +{ + TrackerSparqlConnectionFlags flags; + GFile *store; + GFile *ontology; + + TrackerNamespaceManager *namespace_manager; + TrackerDataManager *data_manager; + GMutex mutex; + + GThreadPool *update_thread; /* Contains 1 exclusive thread */ + GThreadPool *select_pool; + + GList *notifiers; + + guint initialized : 1; + guint closing : 1; +}; + +enum { + PROP_0, + PROP_FLAGS, + PROP_STORE_LOCATION, + PROP_ONTOLOGY_LOCATION, + N_PROPS +}; + +static GParamSpec *props[N_PROPS] = { NULL }; + +typedef enum { + TASK_TYPE_QUERY, + TASK_TYPE_UPDATE, + TASK_TYPE_UPDATE_BLANK, +} TaskType; + +typedef struct { + TaskType type; + gchar *query; +} TaskData; + +static void tracker_direct_connection_initable_iface_init (GInitableIface *iface); +static void tracker_direct_connection_async_initable_iface_init (GAsyncInitableIface *iface); + +G_DEFINE_QUARK (TrackerDirectNotifier, tracker_direct_notifier) + +G_DEFINE_TYPE_WITH_CODE (TrackerDirectConnection, tracker_direct_connection, + TRACKER_TYPE_SPARQL_CONNECTION, + G_ADD_PRIVATE (TrackerDirectConnection) + G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, + tracker_direct_connection_initable_iface_init) + G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, + tracker_direct_connection_async_initable_iface_init)) + +static TaskData * +task_data_query_new (TaskType type, + const gchar *sparql) +{ + TaskData *data; + + data = g_new0 (TaskData, 1); + data->type = type; + data->query = g_strdup (sparql); + + return data; +} + +static void +task_data_free (TaskData *task) +{ + g_free (task->query); + g_free (task); +} + +static void +update_thread_func (gpointer data, + gpointer user_data) +{ + TrackerDirectConnectionPrivate *priv; + TrackerDirectConnection *conn; + GTask *task = data; + TaskData *task_data = g_task_get_task_data (task); + TrackerData *tracker_data; + GError *error = NULL; + gpointer retval = NULL; + GDestroyNotify destroy_notify = NULL; + + conn = user_data; + priv = tracker_direct_connection_get_instance_private (conn); + + g_mutex_lock (&priv->mutex); + tracker_data = tracker_data_manager_get_data (priv->data_manager); + + switch (task_data->type) { + case TASK_TYPE_QUERY: + g_warning ("Queries don't go through this thread"); + break; + case TASK_TYPE_UPDATE: + tracker_data_update_sparql (tracker_data, task_data->query, &error); + break; + case TASK_TYPE_UPDATE_BLANK: + retval = tracker_data_update_sparql_blank (tracker_data, task_data->query, &error); + destroy_notify = (GDestroyNotify) g_variant_unref; + break; + } + + if (error) + g_task_return_error (task, error); + else if (retval) + g_task_return_pointer (task, retval, destroy_notify); + else + g_task_return_boolean (task, TRUE); + + g_object_unref (task); + g_mutex_unlock (&priv->mutex); +} + +static void +query_thread_pool_func (gpointer data, + gpointer user_data) +{ + TrackerDirectConnection *conn = user_data; + TrackerDirectConnectionPrivate *priv; + TrackerSparqlCursor *cursor; + GTask *task = data; + TaskData *task_data = g_task_get_task_data (task); + GError *error = NULL; + + g_assert (task_data->type == TASK_TYPE_QUERY); + + priv = tracker_direct_connection_get_instance_private (conn); + + if (priv->closing) { + g_task_return_new_error (task, + G_IO_ERROR, + G_IO_ERROR_CONNECTION_CLOSED, + "Connection is closed"); + g_object_unref (task); + return; + } + + cursor = tracker_sparql_connection_query (TRACKER_SPARQL_CONNECTION (g_task_get_source_object (task)), + task_data->query, + g_task_get_cancellable (task), + &error); + if (cursor) + g_task_return_pointer (task, cursor, g_object_unref); + else + g_task_return_error (task, error); + + g_object_unref (task); +} + +static gint +task_compare_func (GTask *a, + GTask *b, + gpointer user_data) +{ + return g_task_get_priority (b) - g_task_get_priority (a); +} + +static gboolean +set_up_thread_pools (TrackerDirectConnection *conn, + GError **error) +{ + TrackerDirectConnectionPrivate *priv; + + priv = tracker_direct_connection_get_instance_private (conn); + + priv->select_pool = g_thread_pool_new (query_thread_pool_func, + conn, 16, FALSE, error); + if (!priv->select_pool) + return FALSE; + + priv->update_thread = g_thread_pool_new (update_thread_func, + conn, 1, TRUE, error); + if (!priv->update_thread) + return FALSE; + + g_thread_pool_set_sort_function (priv->select_pool, + (GCompareDataFunc) task_compare_func, + conn); + g_thread_pool_set_sort_function (priv->update_thread, + (GCompareDataFunc) task_compare_func, + conn); + return TRUE; +} + +static TrackerDBManagerFlags +translate_flags (TrackerSparqlConnectionFlags flags) +{ + TrackerDBManagerFlags db_flags = TRACKER_DB_MANAGER_ENABLE_MUTEXES; + + if ((flags & TRACKER_SPARQL_CONNECTION_FLAGS_READONLY) != 0) + db_flags |= TRACKER_DB_MANAGER_READONLY; + if ((flags & TRACKER_SPARQL_CONNECTION_FLAGS_FTS_ENABLE_STEMMER) != 0) + db_flags |= TRACKER_DB_MANAGER_FTS_ENABLE_STEMMER; + if ((flags & TRACKER_SPARQL_CONNECTION_FLAGS_FTS_ENABLE_UNACCENT) != 0) + db_flags |= TRACKER_DB_MANAGER_FTS_ENABLE_UNACCENT; + if ((flags & TRACKER_SPARQL_CONNECTION_FLAGS_FTS_ENABLE_STOP_WORDS) != 0) + db_flags |= TRACKER_DB_MANAGER_FTS_ENABLE_STOP_WORDS; + if ((flags & TRACKER_SPARQL_CONNECTION_FLAGS_FTS_IGNORE_NUMBERS) != 0) + db_flags |= TRACKER_DB_MANAGER_FTS_IGNORE_NUMBERS; + + return db_flags; +} + +static GError * +translate_error (GError *error) +{ + GError *new_error = NULL; + + if (error->domain == TRACKER_DATA_ONTOLOGY_ERROR) { + /* This is an internal error domain, so translate to a libtracker-sparql error code. */ + switch (error->code) { + case TRACKER_DATA_ONTOLOGY_NOT_FOUND: + new_error = g_error_new_literal (TRACKER_SPARQL_ERROR, + TRACKER_SPARQL_ERROR_ONTOLOGY_NOT_FOUND, + error->message); + break; + case TRACKER_DATA_UNSUPPORTED_LOCATION: + case TRACKER_DATA_UNSUPPORTED_ONTOLOGY_CHANGE: + new_error = g_error_new_literal (TRACKER_SPARQL_ERROR, + TRACKER_SPARQL_ERROR_UNSUPPORTED, + error->message); + break; + default: + new_error = g_error_new_literal (TRACKER_SPARQL_ERROR, + TRACKER_SPARQL_ERROR_INTERNAL, + error->message); + } + } + + if (new_error) { + g_error_free (error); + return new_error; + } else { + return error; + } +} + + +static gboolean +tracker_direct_connection_initable_init (GInitable *initable, + GCancellable *cancellable, + GError **error) +{ + TrackerDirectConnectionPrivate *priv; + TrackerDirectConnection *conn; + TrackerDBManagerFlags db_flags; + GHashTable *namespaces; + GHashTableIter iter; + gchar *prefix, *ns; + GError *inner_error = NULL; + + conn = TRACKER_DIRECT_CONNECTION (initable); + priv = tracker_direct_connection_get_instance_private (conn); + + tracker_locale_sanity_check (); + + if (!set_up_thread_pools (conn, error)) + return FALSE; + + db_flags = translate_flags (priv->flags); + + if (!priv->store) { + db_flags |= TRACKER_DB_MANAGER_IN_MEMORY; + } + + priv->data_manager = tracker_data_manager_new (db_flags, priv->store, + priv->ontology, + 100, 100); + if (!g_initable_init (G_INITABLE (priv->data_manager), cancellable, &inner_error)) { + g_propagate_error (error, translate_error (inner_error)); + g_clear_object (&priv->data_manager); + return FALSE; + } + + /* Initialize namespace manager */ + priv->namespace_manager = tracker_namespace_manager_new (); + namespaces = tracker_data_manager_get_namespaces (priv->data_manager); + g_hash_table_iter_init (&iter, namespaces); + + while (g_hash_table_iter_next (&iter, (gpointer*) &prefix, (gpointer*) &ns)) { + tracker_namespace_manager_add_prefix (priv->namespace_manager, + prefix, ns); + } + + g_hash_table_unref (namespaces); + + return TRUE; +} + +static void +tracker_direct_connection_initable_iface_init (GInitableIface *iface) +{ + iface->init = tracker_direct_connection_initable_init; +} + +static void +async_initable_thread_func (GTask *task, + gpointer source_object, + gpointer task_data, + GCancellable *cancellable) +{ + GError *error = NULL; + + if (!g_initable_init (G_INITABLE (source_object), cancellable, &error)) + g_task_return_error (task, error); + else + g_task_return_boolean (task, TRUE); + + g_object_unref (task); +} + +static void +tracker_direct_connection_async_initable_init_async (GAsyncInitable *async_initable, + gint priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GTask *task; + + task = g_task_new (async_initable, cancellable, callback, user_data); + g_task_set_priority (task, priority); + g_task_run_in_thread (task, async_initable_thread_func); +} + +static gboolean +tracker_direct_connection_async_initable_init_finish (GAsyncInitable *async_initable, + GAsyncResult *res, + GError **error) +{ + return g_task_propagate_boolean (G_TASK (res), error); +} + +static void +tracker_direct_connection_async_initable_iface_init (GAsyncInitableIface *iface) +{ + iface->init_async = tracker_direct_connection_async_initable_init_async; + iface->init_finish = tracker_direct_connection_async_initable_init_finish; +} + +static void +tracker_direct_connection_init (TrackerDirectConnection *conn) +{ +} + +static GHashTable * +get_event_cache_ht (TrackerNotifier *notifier) +{ + GHashTable *events; + + events = g_object_get_qdata (G_OBJECT (notifier), tracker_direct_notifier_quark ()); + if (!events) { + events = g_hash_table_new_full (NULL, NULL, NULL, + (GDestroyNotify) _tracker_notifier_event_cache_free); + g_object_set_qdata_full (G_OBJECT (notifier), tracker_direct_notifier_quark (), + events, (GDestroyNotify) g_hash_table_unref); + } + + return events; +} + +static TrackerNotifierEventCache * +lookup_event_cache (TrackerNotifier *notifier, + gint graph_id, + const gchar *graph) +{ + TrackerNotifierEventCache *cache; + GHashTable *events; + + events = get_event_cache_ht (notifier); + cache = g_hash_table_lookup (events, GINT_TO_POINTER (graph_id)); + + if (!cache) { + cache = _tracker_notifier_event_cache_new (notifier, graph); + g_hash_table_insert (events, GINT_TO_POINTER (graph_id), cache); + } + + return cache; +} + +/* These callbacks will be called from a different thread + * (always the same one though), handle with care. + */ +static void +insert_statement_cb (gint graph_id, + const gchar *graph, + gint subject_id, + const gchar *subject, + gint predicate_id, + gint object_id, + const gchar *object, + GPtrArray *rdf_types, + gpointer user_data) +{ + TrackerNotifier *notifier = user_data; + TrackerSparqlConnection *conn = _tracker_notifier_get_connection (notifier); + TrackerDirectConnection *direct = TRACKER_DIRECT_CONNECTION (conn); + TrackerDirectConnectionPrivate *priv = tracker_direct_connection_get_instance_private (direct); + TrackerOntologies *ontologies = tracker_data_manager_get_ontologies (priv->data_manager); + TrackerProperty *rdf_type = tracker_ontologies_get_rdf_type (ontologies); + TrackerNotifierEventCache *cache; + TrackerClass *new_class = NULL; + gint i; + + cache = lookup_event_cache (notifier, graph_id, graph); + + if (predicate_id == tracker_property_get_id (rdf_type)) { + const gchar *uri; + + uri = tracker_ontologies_get_uri_by_id (ontologies, object_id); + new_class = tracker_ontologies_get_class_by_uri (ontologies, uri); + } + + for (i = 0; i < rdf_types->len; i++) { + TrackerClass *class = g_ptr_array_index (rdf_types, i); + TrackerNotifierEventType event_type; + + if (!tracker_class_get_notify (class)) + continue; + + if (class == new_class) + event_type = TRACKER_NOTIFIER_EVENT_CREATE; + else + event_type = TRACKER_NOTIFIER_EVENT_UPDATE; + + _tracker_notifier_event_cache_push_event (cache, subject_id, event_type); + } +} + +static void +delete_statement_cb (gint graph_id, + const gchar *graph, + gint subject_id, + const gchar *subject, + gint predicate_id, + gint object_id, + const gchar *object, + GPtrArray *rdf_types, + gpointer user_data) +{ + TrackerNotifier *notifier = user_data; + TrackerSparqlConnection *conn = _tracker_notifier_get_connection (notifier); + TrackerDirectConnection *direct = TRACKER_DIRECT_CONNECTION (conn); + TrackerDirectConnectionPrivate *priv = tracker_direct_connection_get_instance_private (direct); + TrackerOntologies *ontologies = tracker_data_manager_get_ontologies (priv->data_manager); + TrackerProperty *rdf_type = tracker_ontologies_get_rdf_type (ontologies); + TrackerNotifierEventCache *cache; + TrackerClass *class_being_removed = NULL; + gint i; + + cache = lookup_event_cache (notifier, graph_id, graph); + + if (predicate_id == tracker_property_get_id (rdf_type)) { + class_being_removed = tracker_ontologies_get_class_by_uri (ontologies, object); + } + + for (i = 0; i < rdf_types->len; i++) { + TrackerClass *class = g_ptr_array_index (rdf_types, i); + TrackerNotifierEventType event_type; + + if (!tracker_class_get_notify (class)) + continue; + + if (class_being_removed && class == class_being_removed) { + event_type = TRACKER_NOTIFIER_EVENT_DELETE; + } else { + event_type = TRACKER_NOTIFIER_EVENT_UPDATE; + } + + _tracker_notifier_event_cache_push_event (cache, subject_id, event_type); + } +} + +static void +commit_statement_cb (gpointer user_data) +{ + TrackerNotifierEventCache *cache; + TrackerNotifier *notifier = user_data; + GHashTable *events; + GHashTableIter iter; + + events = get_event_cache_ht (notifier); + g_hash_table_iter_init (&iter, events); + + while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &cache)) { + g_hash_table_iter_steal (&iter); + _tracker_notifier_event_cache_flush_events (cache); + } +} + +static void +rollback_statement_cb (gpointer user_data) +{ + TrackerNotifier *notifier = user_data; + GHashTable *events; + + events = get_event_cache_ht (notifier); + g_hash_table_remove_all (events); +} + +static void +detach_notifier (TrackerDirectConnection *conn, + TrackerNotifier *notifier) +{ + TrackerDirectConnectionPrivate *priv; + TrackerData *tracker_data; + + priv = tracker_direct_connection_get_instance_private (conn); + + priv->notifiers = g_list_remove (priv->notifiers, notifier); + + tracker_data = tracker_data_manager_get_data (priv->data_manager); + tracker_data_remove_insert_statement_callback (tracker_data, + insert_statement_cb, + notifier); + tracker_data_remove_delete_statement_callback (tracker_data, + delete_statement_cb, + notifier); + tracker_data_remove_commit_statement_callback (tracker_data, + commit_statement_cb, + notifier); + tracker_data_remove_rollback_statement_callback (tracker_data, + rollback_statement_cb, + notifier); +} + +static void +weak_ref_notify (gpointer data, + GObject *prev_location) +{ + TrackerDirectConnection *conn = data; + + detach_notifier (conn, (TrackerNotifier *) prev_location); +} + +static void +tracker_direct_connection_finalize (GObject *object) +{ + TrackerDirectConnectionPrivate *priv; + TrackerDirectConnection *conn; + + conn = TRACKER_DIRECT_CONNECTION (object); + priv = tracker_direct_connection_get_instance_private (conn); + + g_clear_object (&priv->store); + g_clear_object (&priv->ontology); + g_clear_object (&priv->namespace_manager); + + G_OBJECT_CLASS (tracker_direct_connection_parent_class)->finalize (object); +} + +static void +tracker_direct_connection_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + TrackerDirectConnectionPrivate *priv; + TrackerDirectConnection *conn; + + conn = TRACKER_DIRECT_CONNECTION (object); + priv = tracker_direct_connection_get_instance_private (conn); + + switch (prop_id) { + case PROP_FLAGS: + priv->flags = g_value_get_flags (value); + break; + case PROP_STORE_LOCATION: + priv->store = g_value_dup_object (value); + break; + case PROP_ONTOLOGY_LOCATION: + priv->ontology = g_value_dup_object (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +tracker_direct_connection_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + TrackerDirectConnectionPrivate *priv; + TrackerDirectConnection *conn; + + conn = TRACKER_DIRECT_CONNECTION (object); + priv = tracker_direct_connection_get_instance_private (conn); + + switch (prop_id) { + case PROP_FLAGS: + g_value_set_flags (value, priv->flags); + break; + case PROP_STORE_LOCATION: + g_value_set_object (value, priv->store); + break; + case PROP_ONTOLOGY_LOCATION: + g_value_set_object (value, priv->ontology); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static TrackerSparqlCursor * +tracker_direct_connection_query (TrackerSparqlConnection *self, + const gchar *sparql, + GCancellable *cancellable, + GError **error) +{ + TrackerDirectConnectionPrivate *priv; + TrackerDirectConnection *conn; + TrackerSparql *query; + TrackerSparqlCursor *cursor; + + conn = TRACKER_DIRECT_CONNECTION (self); + priv = tracker_direct_connection_get_instance_private (conn); + + g_mutex_lock (&priv->mutex); + query = tracker_sparql_new (priv->data_manager, sparql); + cursor = tracker_sparql_execute_cursor (query, NULL, error); + g_object_unref (query); + + if (cursor) + tracker_sparql_cursor_set_connection (cursor, self); + g_mutex_unlock (&priv->mutex); + + return cursor; +} + +static void +tracker_direct_connection_query_async (TrackerSparqlConnection *self, + const gchar *sparql, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + TrackerDirectConnectionPrivate *priv; + TrackerDirectConnection *conn; + GError *error = NULL; + GTask *task; + + conn = TRACKER_DIRECT_CONNECTION (self); + priv = tracker_direct_connection_get_instance_private (conn); + + task = g_task_new (self, cancellable, callback, user_data); + g_task_set_task_data (task, + task_data_query_new (TASK_TYPE_QUERY, sparql), + (GDestroyNotify) task_data_free); + + if (!g_thread_pool_push (priv->select_pool, task, &error)) { + g_task_return_error (task, error); + g_object_unref (task); + } +} + +static TrackerSparqlCursor * +tracker_direct_connection_query_finish (TrackerSparqlConnection *self, + GAsyncResult *res, + GError **error) +{ + return g_task_propagate_pointer (G_TASK (res), error); +} + +static TrackerSparqlStatement * +tracker_direct_connection_query_statement (TrackerSparqlConnection *self, + const gchar *query, + GCancellable *cancellable, + GError **error) +{ + return TRACKER_SPARQL_STATEMENT (tracker_direct_statement_new (self, query, error)); +} + +static void +tracker_direct_connection_update (TrackerSparqlConnection *self, + const gchar *sparql, + GCancellable *cancellable, + GError **error) +{ + TrackerDirectConnectionPrivate *priv; + TrackerDirectConnection *conn; + TrackerData *data; + + conn = TRACKER_DIRECT_CONNECTION (self); + priv = tracker_direct_connection_get_instance_private (conn); + + g_mutex_lock (&priv->mutex); + data = tracker_data_manager_get_data (priv->data_manager); + tracker_data_update_sparql (data, sparql, error); + g_mutex_unlock (&priv->mutex); +} + +static void +tracker_direct_connection_update_async (TrackerSparqlConnection *self, + const gchar *sparql, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + TrackerDirectConnectionPrivate *priv; + TrackerDirectConnection *conn; + GTask *task; + + conn = TRACKER_DIRECT_CONNECTION (self); + priv = tracker_direct_connection_get_instance_private (conn); + + task = g_task_new (self, cancellable, callback, user_data); + g_task_set_task_data (task, + task_data_query_new (TASK_TYPE_UPDATE, sparql), + (GDestroyNotify) task_data_free); + + g_thread_pool_push (priv->update_thread, task, NULL); +} + +static void +tracker_direct_connection_update_finish (TrackerSparqlConnection *self, + GAsyncResult *res, + GError **error) +{ + g_task_propagate_boolean (G_TASK (res), error); +} + +static void +tracker_direct_connection_update_array_async (TrackerSparqlConnection *self, + gchar **updates, + gint n_updates, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + TrackerDirectConnectionPrivate *priv; + TrackerDirectConnection *conn; + TaskData *task_data; + GTask *task; + gchar *concatenated; + gchar **array_copy; + + conn = TRACKER_DIRECT_CONNECTION (self); + priv = tracker_direct_connection_get_instance_private (conn); + + /* Make a NULL-terminated array and concatenate it */ + array_copy = g_new0 (gchar *, n_updates + 1); + memcpy (array_copy, updates, n_updates * sizeof (gchar *)); + concatenated = g_strjoinv ("\n", array_copy); + g_free (array_copy); + + task_data = task_data_query_new (TASK_TYPE_UPDATE, NULL); + task_data->query = concatenated; + + task = g_task_new (self, cancellable, callback, user_data); + g_task_set_task_data (task, task_data, + (GDestroyNotify) task_data_free); + + g_thread_pool_push (priv->update_thread, task, NULL); +} + +static gboolean +tracker_direct_connection_update_array_finish (TrackerSparqlConnection *self, + GAsyncResult *res, + GError **error) +{ + return g_task_propagate_boolean (G_TASK (res), error); +} + +static GVariant * +tracker_direct_connection_update_blank (TrackerSparqlConnection *self, + const gchar *sparql, + GCancellable *cancellable, + GError **error) +{ + TrackerDirectConnectionPrivate *priv; + TrackerDirectConnection *conn; + TrackerData *data; + GVariant *blank_nodes; + + conn = TRACKER_DIRECT_CONNECTION (self); + priv = tracker_direct_connection_get_instance_private (conn); + + g_mutex_lock (&priv->mutex); + data = tracker_data_manager_get_data (priv->data_manager); + blank_nodes = tracker_data_update_sparql_blank (data, sparql, error); + g_mutex_unlock (&priv->mutex); + + return blank_nodes; +} + +static void +tracker_direct_connection_update_blank_async (TrackerSparqlConnection *self, + const gchar *sparql, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + TrackerDirectConnectionPrivate *priv; + TrackerDirectConnection *conn; + GTask *task; + + conn = TRACKER_DIRECT_CONNECTION (self); + priv = tracker_direct_connection_get_instance_private (conn); + + task = g_task_new (self, cancellable, callback, user_data); + g_task_set_task_data (task, + task_data_query_new (TASK_TYPE_UPDATE_BLANK, sparql), + (GDestroyNotify) task_data_free); + + g_thread_pool_push (priv->update_thread, task, NULL); +} + +static GVariant * +tracker_direct_connection_update_blank_finish (TrackerSparqlConnection *self, + GAsyncResult *res, + GError **error) +{ + return g_task_propagate_pointer (G_TASK (res), error); +} + +static TrackerNamespaceManager * +tracker_direct_connection_get_namespace_manager (TrackerSparqlConnection *self) +{ + TrackerDirectConnectionPrivate *priv; + + priv = tracker_direct_connection_get_instance_private (TRACKER_DIRECT_CONNECTION (self)); + + return priv->namespace_manager; +} + +static TrackerNotifier * +tracker_direct_connection_create_notifier (TrackerSparqlConnection *self) +{ + TrackerDirectConnectionPrivate *priv; + TrackerNotifier *notifier; + TrackerData *tracker_data; + + priv = tracker_direct_connection_get_instance_private (TRACKER_DIRECT_CONNECTION (self)); + + notifier = g_object_new (TRACKER_TYPE_NOTIFIER, + "connection", self, + NULL); + + tracker_data = tracker_data_manager_get_data (priv->data_manager); + tracker_data_add_insert_statement_callback (tracker_data, + insert_statement_cb, + notifier); + tracker_data_add_delete_statement_callback (tracker_data, + delete_statement_cb, + notifier); + tracker_data_add_commit_statement_callback (tracker_data, + commit_statement_cb, + notifier); + tracker_data_add_rollback_statement_callback (tracker_data, + rollback_statement_cb, + notifier); + + g_object_weak_ref (G_OBJECT (notifier), weak_ref_notify, self); + priv->notifiers = g_list_prepend (priv->notifiers, notifier); + + return notifier; +} + +static void +tracker_direct_connection_close (TrackerSparqlConnection *self) +{ + TrackerDirectConnectionPrivate *priv; + TrackerDirectConnection *conn; + + conn = TRACKER_DIRECT_CONNECTION (self); + priv = tracker_direct_connection_get_instance_private (conn); + priv->closing = TRUE; + + if (priv->update_thread) { + g_thread_pool_free (priv->update_thread, TRUE, TRUE); + priv->update_thread = NULL; + } + + if (priv->select_pool) { + g_thread_pool_free (priv->select_pool, TRUE, TRUE); + priv->select_pool = NULL; + } + + while (priv->notifiers) { + TrackerNotifier *notifier = priv->notifiers->data; + + g_object_weak_unref (G_OBJECT (notifier), + weak_ref_notify, + conn); + detach_notifier (conn, notifier); + } + + if (priv->data_manager) { + tracker_data_manager_shutdown (priv->data_manager); + g_clear_object (&priv->data_manager); + } +} + +void +async_close_thread_func (GTask *task, + gpointer source_object, + gpointer task_data, + GCancellable *cancellable) +{ + if (g_task_return_error_if_cancelled (task)) + return; + + tracker_sparql_connection_close (source_object); + g_task_return_boolean (task, TRUE); +} + +void +tracker_direct_connection_close_async (TrackerSparqlConnection *connection, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GTask *task; + + task = g_task_new (connection, cancellable, callback, user_data); + g_task_run_in_thread (task, async_close_thread_func); + g_object_unref (task); +} + +gboolean +tracker_direct_connection_close_finish (TrackerSparqlConnection *connection, + GAsyncResult *res, + GError **error) +{ + return g_task_propagate_boolean (G_TASK (res), error); +} + +static void +tracker_direct_connection_class_init (TrackerDirectConnectionClass *klass) +{ + TrackerSparqlConnectionClass *sparql_connection_class; + GObjectClass *object_class; + + object_class = G_OBJECT_CLASS (klass); + sparql_connection_class = TRACKER_SPARQL_CONNECTION_CLASS (klass); + + object_class->finalize = tracker_direct_connection_finalize; + object_class->set_property = tracker_direct_connection_set_property; + object_class->get_property = tracker_direct_connection_get_property; + + sparql_connection_class->query = tracker_direct_connection_query; + sparql_connection_class->query_async = tracker_direct_connection_query_async; + sparql_connection_class->query_finish = tracker_direct_connection_query_finish; + sparql_connection_class->query_statement = tracker_direct_connection_query_statement; + sparql_connection_class->update = tracker_direct_connection_update; + sparql_connection_class->update_async = tracker_direct_connection_update_async; + sparql_connection_class->update_finish = tracker_direct_connection_update_finish; + sparql_connection_class->update_array_async = tracker_direct_connection_update_array_async; + sparql_connection_class->update_array_finish = tracker_direct_connection_update_array_finish; + sparql_connection_class->update_blank = tracker_direct_connection_update_blank; + sparql_connection_class->update_blank_async = tracker_direct_connection_update_blank_async; + sparql_connection_class->update_blank_finish = tracker_direct_connection_update_blank_finish; + sparql_connection_class->get_namespace_manager = tracker_direct_connection_get_namespace_manager; + sparql_connection_class->create_notifier = tracker_direct_connection_create_notifier; + sparql_connection_class->close = tracker_direct_connection_close; + sparql_connection_class->close_async = tracker_direct_connection_close_async; + sparql_connection_class->close_finish = tracker_direct_connection_close_finish; + + props[PROP_FLAGS] = + g_param_spec_flags ("flags", + "Flags", + "Flags", + TRACKER_TYPE_SPARQL_CONNECTION_FLAGS, + TRACKER_SPARQL_CONNECTION_FLAGS_NONE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY); + props[PROP_STORE_LOCATION] = + g_param_spec_object ("store-location", + "Store location", + "Store location", + G_TYPE_FILE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY); + props[PROP_ONTOLOGY_LOCATION] = + g_param_spec_object ("ontology-location", + "Ontology location", + "Ontology location", + G_TYPE_FILE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY); + + g_object_class_install_properties (object_class, N_PROPS, props); +} + +TrackerDirectConnection * +tracker_direct_connection_new (TrackerSparqlConnectionFlags flags, + GFile *store, + GFile *ontology, + GError **error) +{ + g_return_val_if_fail (!store || G_IS_FILE (store), NULL); + g_return_val_if_fail (!ontology || G_IS_FILE (ontology), NULL); + g_return_val_if_fail (!error || !*error, NULL); + + return g_object_new (TRACKER_TYPE_DIRECT_CONNECTION, + "flags", flags, + "store-location", store, + "ontology-location", ontology, + NULL); +} + +TrackerDataManager * +tracker_direct_connection_get_data_manager (TrackerDirectConnection *conn) +{ + TrackerDirectConnectionPrivate *priv; + + priv = tracker_direct_connection_get_instance_private (conn); + return priv->data_manager; +} diff --git a/src/libtracker-sparql/direct/tracker-direct.h b/src/libtracker-sparql/direct/tracker-direct.h new file mode 100644 index 000000000..c47087dd5 --- /dev/null +++ b/src/libtracker-sparql/direct/tracker-direct.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2010, Nokia + * Copyright (C) 2017, Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __TRACKER_LOCAL_CONNECTION_H__ +#define __TRACKER_LOCAL_CONNECTION_H__ + +#include +#include + +#define TRACKER_TYPE_DIRECT_CONNECTION (tracker_direct_connection_get_type()) +#define TRACKER_DIRECT_CONNECTION(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), TRACKER_TYPE_DIRECT_CONNECTION, TrackerDirectConnection)) +#define TRACKER_DIRECT_CONNECTION_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), TRACKER_TYPE_DIRECT_CONNECTION, TrackerDirectConnectionClass)) +#define TRACKER_IS_DIRECT_CONNECTION(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), TRACKER_TYPE_DIRECT_CONNECTION)) +#define TRACKER_IS_DIRECT_CONNECTION_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), TRACKER_TYPE_DIRECT_CONNECTION)) +#define TRACKER_DIRECT_CONNECTION_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), TRACKER_TYPE_DIRECT_CONNECTION, TrackerDirectConnectionClass)) + +typedef struct _TrackerDirectConnection TrackerDirectConnection; +typedef struct _TrackerDirectConnectionClass TrackerDirectConnectionClass; + +struct _TrackerDirectConnectionClass +{ + TrackerSparqlConnectionClass parent_class; +}; + +struct _TrackerDirectConnection +{ + TrackerSparqlConnection parent_instance; +}; + +GType tracker_direct_connection_get_type (void) G_GNUC_CONST; + +TrackerDirectConnection *tracker_direct_connection_new (TrackerSparqlConnectionFlags flags, + GFile *store, + GFile *ontology, + GError **error); + +TrackerDataManager *tracker_direct_connection_get_data_manager (TrackerDirectConnection *conn); + +#endif /* __TRACKER_LOCAL_CONNECTION_H__ */ diff --git a/src/libtracker-sparql/direct/tracker-direct.vapi b/src/libtracker-sparql/direct/tracker-direct.vapi new file mode 100644 index 000000000..0b0e02815 --- /dev/null +++ b/src/libtracker-sparql/direct/tracker-direct.vapi @@ -0,0 +1,10 @@ +[CCode (cprefix = "Tracker", gir_namespace = "Tracker", gir_version = "2.0", lower_case_cprefix = "tracker_")] +namespace Tracker { + namespace Direct { + [CCode (cheader_filename = "tracker-direct.h")] + public class Connection : Tracker.Sparql.Connection, GLib.Initable, GLib.AsyncInitable { + public Connection (Tracker.Sparql.ConnectionFlags connection_flags, GLib.File loc, GLib.File? ontology) throws Tracker.Sparql.Error, GLib.IOError, GLib.DBusError; + public unowned Tracker.Data.Manager get_data_manager (); + } + } +} diff --git a/src/libtracker-sparql/meson.build b/src/libtracker-sparql/meson.build index f50bae559..4e37a0a25 100644 --- a/src/libtracker-sparql/meson.build +++ b/src/libtracker-sparql/meson.build @@ -69,3 +69,69 @@ install_data( rename: ['tracker-sparql-' + tracker_api_version + '.deps'], install_dir: vapi_dir, ) + +subdir('bus') +subdir('direct') +subdir('remote') + +libtracker_sparql = library('tracker-sparql-' + tracker_api_version, + '../libtracker-common/libtracker-common.vapi', + '../libtracker-data/libtracker-data.vapi', + 'direct/tracker-direct.vapi', + 'tracker-backend.vala', + + gnu_symbol_visibility: 'hidden', + + soversion: soversion, + version: libversion, + + install: true, + install_rpath: tracker_internal_libs_dir, + + c_args: [ + '-include', 'libtracker-sparql/tracker-private.h', + ], + + link_whole: [libtracker_sparql_intermediate], + + dependencies: [tracker_common_dep, tracker_sparql_remote_dep, tracker_sparql_bus_dep, tracker_sparql_direct_dep, tracker_sparql_vapi_dep], +) + +tracker_sparql_dep = declare_dependency( + link_with: libtracker_sparql, + include_directories: srcinc, + dependencies: [tracker_common_dep], +) + +pkg.generate(libtracker_sparql, + description: 'Tracker : A SPARQL triple store library', + requires: [glib, gio, gobject, gmodule], + subdirs: [ + 'tracker-' + tracker_api_version, + 'tracker-' + tracker_api_version / 'libtracker-sparql', + ], + variables: [ + 'exec_prefix=${prefix}', + 'libexecdir=${prefix}' / get_option('libexecdir'), + 'datadir=${prefix}' / get_option('datadir'), + 'tracker_datadir=${datadir}' / tracker_versioned_name, + 'ontologies_dir=' + tracker_ontologies_dir, + ], +) + +tracker_sparql_gir = gnome.generate_gir(libtracker_sparql, + sources: libtracker_sparql_c_sources + libtracker_sparql_c_public_headers, + nsversion: tracker_api_version, + namespace: 'Tracker', + identifier_prefix: 'Tracker', + symbol_prefix: 'tracker', + includes : ['GLib-2.0', 'GObject-2.0', 'Gio-2.0' ], + link_with: libtracker_sparql, + install: true, + extra_args: [ + '--c-include', + 'libtracker-sparql/tracker-sparql.h', + '-DTRACKER_COMPILATION', + ]) + +tracker_sparql_uninstalled_dir = meson.current_build_dir() diff --git a/src/libtracker-sparql/remote/meson.build b/src/libtracker-sparql/remote/meson.build new file mode 100644 index 000000000..f4d589d61 --- /dev/null +++ b/src/libtracker-sparql/remote/meson.build @@ -0,0 +1,30 @@ +tracker_remote_dependencies = [json_glib, libsoup, libxml2] + +sources = [ + 'tracker-json-cursor.vala', + 'tracker-xml-cursor.vala', + 'tracker-remote.vala', + '../../libtracker-common/libtracker-common.vapi' +] + +libtracker_remote = static_library('tracker-remote', sources, + dependencies: tracker_remote_dependencies + [tracker_common_dep, tracker_sparql_intermediate_dep], + c_args: tracker_c_args + [ + '-include', 'config.h', + '-include', 'libtracker-sparql/tracker-private.h', + ], + vala_args: [ + '--debug', + '--pkg', 'posix', + # FIXME: Meson has code to add --target-glib automatically, but it + # doesn't seem to work here. + '--target-glib', glib_required, + ], + gnu_symbol_visibility: 'hidden', +) + +tracker_sparql_remote_dep = declare_dependency( + link_with: libtracker_remote, + include_directories: include_directories('.'), + dependencies: tracker_remote_dependencies, +) diff --git a/src/libtracker-sparql/remote/tracker-json-cursor.vala b/src/libtracker-sparql/remote/tracker-json-cursor.vala new file mode 100644 index 000000000..047d47278 --- /dev/null +++ b/src/libtracker-sparql/remote/tracker-json-cursor.vala @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2016 Carlos Garnacho + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + * Author: Carlos Garnacho + */ + +public class Tracker.Remote.JsonCursor : Tracker.Sparql.Cursor { + internal Json.Parser _parser; + internal Json.Array _vars; + internal Json.Array _results; + internal Json.Object _cur_row; + internal uint _cur_idx = 0; + internal bool _started_iterating = false; + + const string XSD_NS = "http://www.w3.org/2001/XMLSchema#"; + + public JsonCursor (string document, long length) throws GLib.Error { + Object (); + var parser = new Json.Parser (); + parser.load_from_data (document, length); + + var root = parser.get_root ().get_object (); + var head = root.get_object_member ("head"); + var results = root.get_object_member ("results"); + + _parser = parser; + _vars = head.get_array_member ("vars"); + _results = results.get_array_member ("bindings"); + _started_iterating = false; + } + + public override int n_columns { + get { return (int) _vars.get_length (); } + } + + public override Sparql.ValueType get_value_type (int column) requires (_cur_row != null) { + var col_node = _cur_row.get_member (get_variable_name (column)); + + if (col_node == null) + return Sparql.ValueType.UNBOUND; + + var object = col_node.get_object ();//_cur_row.get_object_member (get_variable_name (column)); + unowned string str = object.get_string_member ("type"); + + switch (str) { + case "uri": + return Sparql.ValueType.URI; + case "bnode": + return Sparql.ValueType.BLANK_NODE; + case "literal": { + var node = object.get_member ("datatype"); + + if (node == null) + return Sparql.ValueType.STRING; + + str = node.get_string (); + + switch (str) { + case XSD_NS + "byte": + case XSD_NS + "int": + case XSD_NS + "integer": + case XSD_NS + "long": + return Sparql.ValueType.INTEGER; + case XSD_NS + "decimal": + case XSD_NS + "double": + return Sparql.ValueType.DOUBLE; + case XSD_NS + "dateTime": + return Sparql.ValueType.DATETIME; + default: + return Sparql.ValueType.STRING; + } + } + + default: + return Sparql.ValueType.STRING; + } + } + + public override unowned string? get_variable_name (int column) { + return _vars.get_string_element (column); + } + + public override unowned string? get_string (int column, out long length = null) requires (_cur_row != null) { + var col_node = _cur_row.get_member (get_variable_name (column)); + length = 0; + + if (col_node == null) + return null; + + var object = col_node.get_object (); + + if (object == null) + return null; + + unowned string str = object.get_string_member ("value"); + length = str.length; + return str; + } + + public override bool next (Cancellable? cancellable = null) throws IOError, GLib.Error { + if (_started_iterating) + _cur_idx++; + + if (_cur_idx >= _results.get_length ()) + return false; + + if (cancellable != null && cancellable.is_cancelled ()) + throw new IOError.CANCELLED ("Operation was cancelled"); + + _started_iterating = true; + _cur_row = _results.get_object_element (_cur_idx); + return true; + } + + public async override bool next_async (Cancellable? cancellable = null) throws IOError, GLib.Error { + return next (cancellable); + } + + public override void rewind () { + _started_iterating = false; + } + + public override void close () { + } +} diff --git a/src/libtracker-sparql/remote/tracker-remote.vala b/src/libtracker-sparql/remote/tracker-remote.vala new file mode 100644 index 000000000..206c237fc --- /dev/null +++ b/src/libtracker-sparql/remote/tracker-remote.vala @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2016 Carlos Garnacho + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + * Author: Carlos Garnacho + */ +[CCode (cname = "PACKAGE_VERSION")] +extern const string PACKAGE_VERSION; + +public class Tracker.Remote.Connection : Tracker.Sparql.Connection { + + internal Soup.Session _session; + internal string _base_uri; + + const string XML_TYPE = "application/sparql-results+xml"; + const string JSON_TYPE = "application/sparql-results+json"; + const string USER_AGENT = "Tracker/" + PACKAGE_VERSION + " (https://gitlab.gnome.org/GNOME/tracker/issues/; tracker-list@lists.gnome.org) Tracker/" + PACKAGE_VERSION; + + public Connection (string base_uri) { + Object (); + _base_uri = base_uri; + _session = new Soup.Session (); + } + + private Soup.Message create_request (string sparql) { + var uri = _base_uri + "?query=" + sparql; + var message = new Soup.Message ("GET", uri); + var headers = message.request_headers; + + headers.append ("User-Agent", USER_AGENT); + headers.append ("Accept", JSON_TYPE); + headers.append ("Accept", XML_TYPE); + + return message; + } + + private Sparql.Cursor create_cursor (Soup.Message message) throws GLib.Error, Sparql.Error { + string document = (string) message.response_body.flatten ().data; + + if (message.status_code != Soup.Status.OK) { + throw new Sparql.Error.UNSUPPORTED ("Unhandled status code %u, document is: %s", + message.status_code, document); + } + + var headers = message.response_headers; + var content_type = headers.get_content_type (null); + long length = document.length; + + if (content_type == JSON_TYPE) { + return new Tracker.Remote.JsonCursor (document, length); + } else if (content_type == XML_TYPE) { + return new Tracker.Remote.XmlCursor (document, length); + } else { + throw new Sparql.Error.UNSUPPORTED ("Unknown content type '%s', document is: %s", content_type, document); + } + } + + public override Sparql.Cursor query (string sparql, Cancellable? cancellable) throws GLib.Error, Sparql.Error, IOError { + var message = create_request (sparql); + + _session.send_message (message); + + if (cancellable != null && cancellable.is_cancelled ()) + throw new IOError.CANCELLED ("Operation was cancelled"); + + return create_cursor (message); + } + + public async override Sparql.Cursor query_async (string sparql, Cancellable? cancellable) throws GLib.Error, Sparql.Error, IOError { + var message = create_request (sparql); + + yield _session.send_async (message, cancellable); + + return create_cursor (message); + } + + public override void close () { + } + + public async override bool close_async () throws GLib.IOError { + return true; + } +} diff --git a/src/libtracker-sparql/remote/tracker-xml-cursor.vala b/src/libtracker-sparql/remote/tracker-xml-cursor.vala new file mode 100644 index 000000000..a7a710041 --- /dev/null +++ b/src/libtracker-sparql/remote/tracker-xml-cursor.vala @@ -0,0 +1,204 @@ +/* + * Copyright (C) 2016 Carlos Garnacho + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + * Author: Carlos Garnacho + */ + +public class Tracker.Remote.XmlCursor : Tracker.Sparql.Cursor { + Xml.Node *_results; + Xml.Node *_cur_row; + HashTable _cur_row_map; + string [] _vars; + + const string XSD_NS = "http://www.w3.org/2001/XMLSchema#"; + + private Xml.Node * find_first_child_node (Xml.Node *node) { + for (Xml.Node* iter = node->children; iter != null; iter = iter->next) { + if (iter->type != Xml.ElementType.ELEMENT_NODE) + continue; + return iter; + } + + return null; + } + + private Xml.Node * find_next_node (Xml.Node *node) { + for (Xml.Node* iter = node->next; iter != null; iter = iter->next) { + if (iter->type != Xml.ElementType.ELEMENT_NODE) + continue; + return iter; + } + + return null; + } + + private Xml.Node * lookup_child_node (Xml.Node *node, string name) { + for (Xml.Node* iter = node->children; iter != null; iter = iter->next) { + if (iter->type != Xml.ElementType.ELEMENT_NODE) + continue; + if (iter->name == name) + return iter; + } + + return null; + } + + private Xml.Attr * lookup_attribute (Xml.Node *node, string name) { + for (Xml.Attr* iter = node->properties; iter != null; iter = iter->next) { + if (iter->name == name) + return iter; + } + + return null; + } + + private void parse_vars (Xml.Node *vars) { + for (Xml.Node* iter = vars->children; iter != null; iter = iter->next) { + if (iter->name != "variable" || + iter->type != Xml.ElementType.ELEMENT_NODE) + continue; + + var attr = lookup_attribute (iter, "name"); + if (attr == null) + continue; + + _vars += attr->children->content; + } + } + + public XmlCursor (string document, long length) throws Sparql.Error { + Object (); + Xml.Parser.init (); + var doc = Xml.Parser.parse_memory (document, (int) length); + + if (doc == null) + throw new Sparql.Error.INTERNAL ("Could not parse XML document"); + + var root = doc->get_root_element (); + _results = lookup_child_node (root, "results"); + + var vars = lookup_child_node (root, "head"); + parse_vars (vars); + Xml.Parser.cleanup (); + + _cur_row_map = new HashTable (str_hash, str_equal); + } + + public override int n_columns { + get { return (int) _vars.length; } + } + + public override Sparql.ValueType get_value_type (int column) requires (_cur_row != null) { + var variable = _vars[column]; + Xml.Node* node = (Xml.Node*) _cur_row_map.get (variable); + if (node == null) + return Sparql.ValueType.UNBOUND; + + switch (node->children->name) { + case "uri": + return Sparql.ValueType.URI; + case "bnode": + return Sparql.ValueType.BLANK_NODE; + case "literal": + var attr = lookup_attribute (node, "datatype"); + if (attr == null) + return Sparql.ValueType.STRING; + + switch (attr->children->content) { + case XSD_NS + "byte": + case XSD_NS + "int": + case XSD_NS + "integer": + case XSD_NS + "long": + return Sparql.ValueType.INTEGER; + case XSD_NS + "decimal": + case XSD_NS + "double": + return Sparql.ValueType.DOUBLE; + case XSD_NS + "dateTime": + return Sparql.ValueType.DATETIME; + default: + return Sparql.ValueType.STRING; + } + default: + return Sparql.ValueType.STRING; + } + } + + public override unowned string? get_variable_name (int column) { + if (column < 0 || column > _vars.length) + return null; + return _vars[column]; + } + + public override unowned string? get_string (int column, out long length = null) requires (_cur_row != null) { + length = 0; + + var variable = _vars[column]; + Xml.Node* node = (Xml.Node*) _cur_row_map.get (variable); + if (node == null) + return null; + + var child = find_first_child_node (node); + if (child == null) + return null; + + var text = child->children; + if (text == null || + text->type != Xml.ElementType.TEXT_NODE) + return null; + + length = text->content.length; + return text->content; + } + + public override bool next (Cancellable? cancellable = null) throws IOError, GLib.Error { + if (_cur_row == null) + _cur_row = find_first_child_node (_results); + else + _cur_row = find_next_node (_cur_row); + + _cur_row_map.remove_all (); + + if (_cur_row == null) + return false; + + for (Xml.Node* iter = _cur_row->children; iter != null; iter = iter->next) { + if (iter->name != "binding") + continue; + + var attr = lookup_attribute (iter, "name"); + if (attr == null) + continue; + + var binding_name = attr->children->content; + _cur_row_map.insert (binding_name, iter); + } + + return true; + } + + public async override bool next_async (Cancellable? cancellable = null) throws IOError, GLib.Error { + return next (cancellable); + } + + public override void rewind () { + _cur_row = null; + } + + public override void close () { + } +} diff --git a/src/libtracker-sparql/tracker-backend.vala b/src/libtracker-sparql/tracker-backend.vala new file mode 100644 index 000000000..fc3682872 --- /dev/null +++ b/src/libtracker-sparql/tracker-backend.vala @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2010, Nokia + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +public static Tracker.Sparql.Connection tracker_sparql_connection_remote_new (string url_base) { + return new Tracker.Remote.Connection (url_base); +} + +public static Tracker.Sparql.Connection tracker_sparql_connection_bus_new (string service, string? object_path, DBusConnection? conn) throws Tracker.Sparql.Error, IOError, DBusError, GLib.Error { + GLib.DBusConnection dbus_conn; + string path; + + if (conn != null) + dbus_conn = conn; + else + dbus_conn = GLib.Bus.get_sync (GLib.BusType.SESSION, null); + + if (object_path != null) + path = object_path; + else + path = "/org/freedesktop/Tracker3/Endpoint"; + + return new Tracker.Bus.Connection (service, path, dbus_conn); +} + +public static Tracker.Sparql.Connection tracker_sparql_connection_new (Tracker.Sparql.ConnectionFlags flags, File? store, File? ontology, Cancellable? cancellable = null) throws GLib.Error, Tracker.Sparql.Error, IOError { + var conn = new Tracker.Direct.Connection (flags, store, ontology); + conn.init (cancellable); + return conn; +} + +public static async Tracker.Sparql.Connection tracker_sparql_connection_new_async (Tracker.Sparql.ConnectionFlags flags, File store, File ontology, Cancellable? cancellable = null) throws GLib.Error, Tracker.Sparql.Error, IOError { + var conn = new Tracker.Direct.Connection (flags, store, ontology); + yield conn.init_async (Priority.DEFAULT, cancellable); + return conn; +} diff --git a/src/meson.build b/src/meson.build index 87d41623f..2f9817ece 100644 --- a/src/meson.build +++ b/src/meson.build @@ -1,11 +1,6 @@ # Shared common code subdir('libtracker-common') -# Intermediate library of RDF & SPARQL helper functions. -# This gets used internally and also becomes part of the -# public libtracker-sparql library. -subdir('libtracker-sparql') - # Public ontologies subdir('ontologies') @@ -14,8 +9,10 @@ subdir('gvdb') subdir('libtracker-fts') subdir('libtracker-data') -# Public libtracker-sparql library -subdir('libtracker-sparql-backend') +# Intermediate library of RDF & SPARQL helper functions. +# This gets used internally and also becomes part of the +# public libtracker-sparql library. +subdir('libtracker-sparql') # Public commandline control tool subdir('tracker') -- cgit v1.2.1