[rygel] media-export: Get rid of callbacks in database
- From: Jens Georg <jensgeorg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [rygel] media-export: Get rid of callbacks in database
- Date: Thu, 21 Jul 2011 22:25:31 +0000 (UTC)
commit 592bee9125faf9ba0b5b1449857c6554435c8f29
Author: Jens Georg <mail jensge org>
Date: Fri Feb 25 00:55:30 2011 +0100
media-export: Get rid of callbacks in database
Actually most of the code using the callback approach was more like a
loop body. Now we have a database cursor that can be used with vala's
foreach syntax, removing some indirection.
Note: This also drops SQL debugging which will be re-introduced later.
configure.ac | 7 -
src/plugins/media-export/Makefile.am | 2 +
.../rygel-media-export-database-cursor.vala | 143 +++++++++++++++
.../media-export/rygel-media-export-database.vala | 190 +++++++-------------
.../rygel-media-export-media-cache-upgrader.vala | 59 +++----
.../rygel-media-export-media-cache.vala | 163 ++++++-----------
.../rygel-media-export-sqlite-wrapper.vala | 80 ++++++++
7 files changed, 365 insertions(+), 279 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 0d371c5..80a620d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -74,12 +74,6 @@ dnl glib-genmarshal
GLIB_GENMARSHAL=`pkg-config --variable=glib_genmarshal glib-2.0`
AC_SUBST(GLIB_GENMARSHAL)
-AC_ARG_ENABLE(sql-debugging,
- AS_HELP_STRING([--enable-sql-debugging],[enable SQL statement debugging]),,
- enable_sql_debugging=no)
-AS_IF([test x$enable_sql_debugging = xyes],
- [RYGEL_ADD_VALAFLAGS([-D RYGEL_DEBUG_SQL])])
-
dnl Add plugins
RYGEL_ADD_PLUGIN([test],[Test],[no])
RYGEL_ADD_PLUGIN([tracker],[Tracker],[yes])
@@ -231,7 +225,6 @@ echo "
VALAFLAGS: ${VALAFLAGS}
uninstalled: ${enable_uninstalled}
preferences ui: ${BUILD_UI}
- SQL debugging: ${enable_sql_debugging}
Plugins:
test: ${enable_test_plugin}
tracker: ${enable_tracker_plugin}
diff --git a/src/plugins/media-export/Makefile.am b/src/plugins/media-export/Makefile.am
index c5ec8c8..70e9fb9 100644
--- a/src/plugins/media-export/Makefile.am
+++ b/src/plugins/media-export/Makefile.am
@@ -12,6 +12,8 @@ AM_CFLAGS += \
librygel_media_export_la_SOURCES = \
rygel-media-export-plugin.vala \
rygel-media-export-database.vala \
+ rygel-media-export-database-cursor.vala \
+ rygel-media-export-sqlite-wrapper.vala \
rygel-media-export-db-container.vala \
rygel-media-export-sql-factory.vala \
rygel-media-export-media-cache.vala \
diff --git a/src/plugins/media-export/rygel-media-export-database-cursor.vala b/src/plugins/media-export/rygel-media-export-database-cursor.vala
new file mode 100644
index 0000000..6c3f0dc
--- /dev/null
+++ b/src/plugins/media-export/rygel-media-export-database-cursor.vala
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2011 Jens Georg <mail jensge org>.
+ *
+ * Author: Jens Georg <mail jensge org>
+ *
+ * This file is part of Rygel.
+ *
+ * Rygel 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 of the License, or
+ * (at your option) any later version.
+ *
+ * Rygel 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 program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+using Sqlite;
+
+internal class Rygel.MediaExport.DatabaseCursor : SqliteWrapper {
+ private Statement statement;
+ private int current_state = -1;
+ private bool dirty = true;
+
+ /**
+ * Prepare a SQLite statement from a SQL string
+ *
+ * This function uses the type of the GValue passed in values to determine
+ * which _bind function to use.
+ *
+ * Supported types are: int, long, int64, uint64, string and pointer.
+ * @note the only pointer supported is the null pointer as provided by
+ * Database null This is a special value to bind a column to NULL
+ *
+ * @param db SQLite database this cursor belongs to
+ * @param sql statement to execute
+ * @param values array of values to bind to the SQL statement or null if
+ * none
+ */
+ public DatabaseCursor (Sqlite.Database db,
+ string sql,
+ GLib.Value[]? arguments) throws DatabaseError {
+ base.wrap (db);
+
+ this.throw_if_code_is_error (db.prepare_v2 (sql,
+ -1,
+ out this.statement,
+ null));
+ if (arguments == null) {
+ return;
+ }
+
+ for (var i = 1; i <= arguments.length; ++i) {
+ unowned GLib.Value current_value = arguments[i - 1];
+
+ if (current_value.holds (typeof (int))) {
+ statement.bind_int (i, current_value.get_int ());
+ } else if (current_value.holds (typeof (int64))) {
+ statement.bind_int64 (i, current_value.get_int64 ());
+ } else if (current_value.holds (typeof (uint64))) {
+ statement.bind_int64 (i, (int64) current_value.get_uint64 ());
+ } else if (current_value.holds (typeof (long))) {
+ statement.bind_int64 (i, current_value.get_long ());
+ } else if (current_value.holds (typeof (string))) {
+ statement.bind_text (i, current_value.get_string ());
+ } else if (current_value.holds (typeof (void *))) {
+ if (current_value.peek_pointer () == null) {
+ statement.bind_null (i);
+ } else {
+ assert_not_reached ();
+ }
+ } else {
+ var type = current_value.type ();
+ warning (_("Unsupported type %s"), type.name ());
+ assert_not_reached ();
+ }
+
+ this.throw_if_db_has_error ();
+ }
+ }
+
+ /**
+ * Check if the cursor has more rows left
+ *
+ * @return true if more rows left, false otherwise
+ */
+ public bool has_next () {
+ if (this.dirty) {
+ this.current_state = this.statement.step ();
+ this.dirty = false;
+ }
+
+ return this.current_state == Sqlite.ROW || this.current_state == -1;
+ }
+
+ /**
+ * Get the next row of this cursor.
+ *
+ * This function uses pointers instead of unowned because var doesn't work
+ * with unowned.
+ *
+ * @return a pointer to the current row
+ */
+ public Statement* next () throws DatabaseError {
+ this.has_next ();
+ this.throw_if_code_is_error (this.current_state);
+ this.dirty = true;
+
+ return this.statement;
+ }
+
+ // convenience functions for "foreach"
+
+ /**
+ * Return a iterator to the cursor to use with foreach
+ *
+ * @return an iterator wrapping the cursor
+ */
+ public Iterator iterator () {
+ return new Iterator (this);
+ }
+
+ public class Iterator {
+ public DatabaseCursor cursor;
+
+ public Iterator (DatabaseCursor cursor) {
+ this.cursor = cursor;
+ }
+
+ public bool next () {
+ return this.cursor.has_next ();
+ }
+
+ public unowned Statement @get () throws DatabaseError {
+ return this.cursor.next ();
+ }
+ }
+}
diff --git a/src/plugins/media-export/rygel-media-export-database.vala b/src/plugins/media-export/rygel-media-export-database.vala
index e45b312..e35cf85 100644
--- a/src/plugins/media-export/rygel-media-export-database.vala
+++ b/src/plugins/media-export/rygel-media-export-database.vala
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 Jens Georg <mail jensge org>.
+ * Copyright (C) 2009,2011 Jens Georg <mail jensge org>.
*
* Author: Jens Georg <mail jensge org>
*
@@ -33,16 +33,11 @@ public errordomain Rygel.MediaExport.DatabaseError {
* It adds statement preparation based on GValue and a cancellable exec
* function.
*/
-internal class Rygel.MediaExport.Database : Object {
- private Sqlite.Database db;
+internal class Rygel.MediaExport.Database : SqliteWrapper {
/**
- * Callback to pass to exec
- *
- * @return true, if you want the query to continue, false otherwise
+ * Function to implement the custom SQL function 'contains'
*/
- public delegate bool RowCallback (Sqlite.Statement stmt);
-
private static void utf8_contains (Sqlite.Context context,
Sqlite.Value[] args)
requires (args.length == 2) {
@@ -62,6 +57,11 @@ internal class Rygel.MediaExport.Database : Object {
}
}
+ /**
+ * Function to implement the custom SQLite collation 'CASEFOLD'.
+ *
+ * Uses utf8 case-fold to compare the strings.
+ */
private static int utf8_collate (int alen, void* a, int blen, void* b) {
// unowned to prevent array copy
unowned uint8[] _a = (uint8[]) a;
@@ -87,18 +87,14 @@ internal class Rygel.MediaExport.Database : Object {
"rygel");
DirUtils.create_with_parents (dirname, 0750);
var db_file = Path.build_filename (dirname, "%s.db".printf (name));
+
+ base (db_file);
+
debug ("Using database file %s", db_file);
- var rc = Sqlite.Database.open (db_file, out this.db);
- if (rc != Sqlite.OK) {
- throw new DatabaseError.IO_ERROR
- (_("Failed to open database: %d (%s)"),
- rc,
- db.errmsg ());
- }
- this.db.exec ("PRAGMA synchronous = OFF");
- this.db.exec ("PRAGMA temp_store = MEMORY");
- this.db.exec ("PRAGMA count_changes = OFF");
+ this.exec ("PRAGMA synchronous = OFF");
+ this.exec ("PRAGMA temp_store = MEMORY");
+ this.exec ("PRAGMA count_changes = OFF");
this.db.create_function ("contains",
2,
@@ -114,55 +110,58 @@ internal class Rygel.MediaExport.Database : Object {
}
/**
- * Execute a cancellable SQL statement.
+ * SQL query function.
*
- * The supplied values are bound to the SQL statement and the RowCallback
- * is called on every row of the resultset.
+ * Use for all queries that return a result set.
*
- * @param sql statement to execute
- * @param values array of values to bind to the SQL statement or null if
- * none
- * @param callback to call on each row of the result set or null if none
- * necessary
- * @param cancellable to cancel the running query or null if none
- * necessary
+ * @param sql The SQL query to run.
+ * @param args Values to bind in the SQL query or null.
+ * @throws DatabaseError if the underlying SQLite operation fails.
*/
- public int exec (string sql,
- GLib.Value[]? values = null,
- RowCallback? callback = null,
- Cancellable? cancellable = null) throws DatabaseError {
- #if RYGEL_DEBUG_SQL
- var t = new Timer ();
- #endif
- int rc;
-
- if (values == null && callback == null && cancellable == null) {
- rc = this.db.exec (sql);
- } else {
- var statement = prepare_statement (sql, values);
- while ((rc = statement.step ()) == Sqlite.ROW) {
- if (cancellable != null && cancellable.is_cancelled ()) {
- break;
- }
+ public DatabaseCursor exec_cursor (string sql,
+ GLib.Value[]? arguments = null)
+ throws DatabaseError {
+ return new DatabaseCursor (this.db, sql, arguments);
+ }
- if (callback != null) {
- if (!callback (statement)) {
- rc = Sqlite.DONE;
+ /**
+ * Simple SQL query execution function.
+ *
+ * Use for all queries that don't return anything.
+ *
+ * @param sql The SQL query to run.
+ * @param args Values to bind in the SQL query or null.
+ * @throws DatabaseError if the underlying SQLite operation fails.
+ */
+ public void exec (string sql,
+ GLib.Value[]? arguments = null)
+ throws DatabaseError {
+ if (arguments == null) {
+ this.throw_if_code_is_error (this.db.exec (sql));
- break;
- }
- }
- }
+ return;
}
- if (rc != Sqlite.DONE && rc != Sqlite.OK) {
- throw new DatabaseError.SQLITE_ERROR (db.errmsg ());
+ var cursor = this.exec_cursor (sql, arguments);
+ while (cursor.has_next ()) {
+ cursor.next ();
}
- #if RYGEL_DEBUG_SQL
- debug ("Query: %s, Time: %f", sql, t.elapsed ());
- #endif
+ }
- return rc;
+ /**
+ * Execute a SQL query that returns a single number.
+ *
+ * @param sql The SQL query to run.
+ * @param args Values to bind in the SQL query or null.
+ * @return The contents of the first row's column as an int.
+ * @throws DatabaseError if the underlying SQLite operation fails.
+ */
+ public int query_value (string sql,
+ GLib.Value[]? args = null)
+ throws DatabaseError {
+ var cursor = this.exec_cursor (sql, args);
+ var statement = cursor.next ();
+ return statement->column_int (0);
}
/**
@@ -173,7 +172,7 @@ internal class Rygel.MediaExport.Database : Object {
}
/**
- * Special GValue to pass to exec or prepare_statement to bind a column to
+ * Special GValue to pass to exec or exec_cursor to bind a column to
* NULL
*/
public static GLib.Value @null () {
@@ -187,14 +186,14 @@ internal class Rygel.MediaExport.Database : Object {
* Start a transaction
*/
public void begin () throws DatabaseError {
- this.single_statement ("BEGIN");
+ this.exec ("BEGIN");
}
/**
* Commit a transaction
*/
public void commit () throws DatabaseError {
- this.single_statement ("COMMIT");
+ this.exec ("COMMIT");
}
/**
@@ -202,77 +201,10 @@ internal class Rygel.MediaExport.Database : Object {
*/
public void rollback () {
try {
- this.single_statement ("ROLLBACK");
+ this.exec ("ROLLBACK");
} catch (DatabaseError error) {
critical (_("Failed to roll back transaction: %s"),
error.message);
}
}
-
- /**
- * Execute a single SQL statement and throw an exception on error
- *
- * @param sql SQL statement to execute
- * @throws DatabaseError if SQL statement fails
- */
- private void single_statement (string sql) throws DatabaseError {
- if (this.db.exec (sql) != Sqlite.OK) {
- throw new DatabaseError.SQLITE_ERROR (db.errmsg ());
- }
- }
-
- /**
- * Prepare a SQLite statement from a SQL string
- *
- * This function uses the type of the GValue passed in values to determine
- * which _bind function to use.
- *
- * Supported types are: int, long, int64, uint64, string and pointer.
- * @note the only pointer supported is the null pointer as provided by
- * Database null This is a special value to bind a column to NULL
- *
- * @param sql statement to execute
- * @param values array of values to bind to the SQL statement or null if
- * none
- */
- private Statement prepare_statement (string sql,
- GLib.Value[]? values = null)
- throws DatabaseError {
- Statement statement;
- var rc = db.prepare_v2 (sql, -1, out statement, null);
- if (rc != Sqlite.OK) {
- throw new DatabaseError.SQLITE_ERROR (db.errmsg ());
- }
-
- if (values != null) {
- for (int i = 0; i < values.length; i++) {
- if (values[i].holds (typeof (int))) {
- rc = statement.bind_int (i + 1, values[i].get_int ());
- } else if (values[i].holds (typeof (int64))) {
- rc = statement.bind_int64 (i + 1, values[i].get_int64 ());
- } else if (values[i].holds (typeof (uint64))) {
- rc = statement.bind_int64 (i + 1, (int64) values[i].get_uint64 ());
- } else if (values[i].holds (typeof (long))) {
- rc = statement.bind_int64 (i + 1, values[i].get_long ());
- } else if (values[i].holds (typeof (string))) {
- rc = statement.bind_text (i + 1, values[i].get_string ());
- } else if (values[i].holds (typeof (void *))) {
- if (values[i].peek_pointer () == null) {
- rc = statement.bind_null (i + 1);
- } else {
- assert_not_reached ();
- }
- } else {
- var t = values[i].type ();
- warning (_("Unsupported type %s"), t.name ());
- assert_not_reached ();
- }
- if (rc != Sqlite.OK) {
- throw new DatabaseError.SQLITE_ERROR (db.errmsg ());
- }
- }
- }
-
- return statement;
- }
}
diff --git a/src/plugins/media-export/rygel-media-export-media-cache-upgrader.vala b/src/plugins/media-export/rygel-media-export-media-cache-upgrader.vala
index c997230..192d159 100644
--- a/src/plugins/media-export/rygel-media-export-media-cache-upgrader.vala
+++ b/src/plugins/media-export/rygel-media-export-media-cache-upgrader.vala
@@ -41,34 +41,19 @@ internal class Rygel.MediaExport.MediaCacheUpgrader {
}
public bool needs_upgrade (out int current_version) throws Error {
- // cannot capture out parameters in closure
- int current_version_temp = 0;
-
- this.database.exec ("SELECT version FROM schema_info",
- null,
- (statement) => {
- current_version_temp = statement.column_int (0);
-
- return false;
- });
- current_version = current_version_temp;
+ current_version = this.database.query_value (
+ "SELECT version FROM schema_info");
return current_version < int.parse (SQLFactory.schema_version);
}
public void fix_schema () throws Error {
- bool schema_ok = true;
-
- database.exec ("SELECT count(*) FROM sqlite_master WHERE sql " +
- "LIKE 'CREATE TABLE Meta_Data%object_fk TEXT " +
- "UNIQUE%'",
- null,
- (statement) => {
- schema_ok = statement.column_int (0) == 1;
-
- return false;
- });
- if (!schema_ok) {
+ var matching_schema_count = this.database.query_value (
+ "SELECT count(*) FROM " +
+ "sqlite_master WHERE sql " +
+ "LIKE 'CREATE TABLE Meta_Data" +
+ "%object_fk TEXT UNIQUE%'");
+ if (matching_schema_count == 0) {
try {
message ("Found faulty schema, forcing full reindex");
database.begin ();
@@ -182,13 +167,13 @@ internal class Rygel.MediaExport.MediaCacheUpgrader {
queue.offer ("0");
while (!queue.is_empty) {
GLib.Value[] args = { queue.poll () };
- database.exec ("SELECT upnp_id FROM _Object WHERE parent = ?",
- args,
- (statement) => {
- queue.offer (statement.column_text (0));
-
- return true;
- });
+ var cursor = this.database.exec_cursor (
+ "SELECT upnp_id FROM _Object WHERE " +
+ "parent = ?",
+ args);
+ foreach (var statement in cursor) {
+ queue.offer (statement.column_text (0));
+ }
database.exec ("INSERT INTO Object SELECT * FROM _OBJECT " +
"WHERE parent = ?",
@@ -329,13 +314,13 @@ internal class Rygel.MediaExport.MediaCacheUpgrader {
queue.offer ("0");
while (!queue.is_empty) {
GLib.Value[] args = { queue.poll () };
- database.exec ("SELECT upnp_id FROM _Object WHERE parent = ?",
- args,
- (statement) => {
- queue.offer (statement.column_text (0));
-
- return true;
- });
+ var cursor = this.database.exec_cursor (
+ "SELECT upnp_id FROM _Object WHERE " +
+ "parent = ?",
+ args);
+ foreach (var statement in cursor) {
+ queue.offer (statement.column_text (0));
+ }
database.exec ("INSERT INTO Object SELECT * FROM _Object " +
"WHERE parent = ?",
diff --git a/src/plugins/media-export/rygel-media-export-media-cache.vala b/src/plugins/media-export/rygel-media-export-media-cache.vala
index f0572c6..4004a51 100644
--- a/src/plugins/media-export/rygel-media-export-media-cache.vala
+++ b/src/plugins/media-export/rygel-media-export-media-cache.vala
@@ -102,7 +102,9 @@ public class Rygel.MediaExport.MediaCache : Object {
GLib.Value[] values = { object_id };
MediaObject parent = null;
- Database.RowCallback cb = (statement) => {
+ var cursor = this.exec_cursor (SQLString.GET_OBJECT, values);
+
+ foreach (var statement in cursor) {
var parent_container = parent as MediaContainer;
var id = statement.column_text (DetailColumn.ID);
var object = get_object_from_statement
@@ -111,11 +113,7 @@ public class Rygel.MediaExport.MediaCache : Object {
statement);
object.parent_ref = parent_container;
parent = object;
-
- return true;
- };
-
- this.db.exec (this.sql.make (SQLString.GET_OBJECT), values, cb);
+ }
return parent;
}
@@ -146,44 +144,28 @@ public class Rygel.MediaExport.MediaCache : Object {
}
public int get_child_count (string container_id) throws DatabaseError {
- int count = 0;
GLib.Value[] values = { container_id };
- this.db.exec (this.sql.make (SQLString.CHILD_COUNT),
- values,
- (statement) => {
- count = statement.column_int (0);
-
- return false;
- });
-
- return count;
+ return this.query_value (SQLString.CHILD_COUNT, values);
}
private void get_exists_cache () throws DatabaseError {
this.exists_cache = new HashMap<string, ExistsCacheEntry?> ();
- this.db.exec (this.sql.make (SQLString.EXISTS_CACHE),
- null,
- (statement) => {
- var entry = ExistsCacheEntry ();
- entry.mtime = statement.column_int64 (1);
- entry.size = statement.column_int64 (0);
- this.exists_cache.set (statement.column_text (2),
- entry);
-
- return true;
- });
+ var cursor = this.exec_cursor (SQLString.EXISTS_CACHE);
+ foreach (var statement in cursor) {
+ var entry = ExistsCacheEntry ();
+ entry.mtime = statement.column_int64 (1);
+ entry.size = statement.column_int64 (0);
+ this.exists_cache.set (statement.column_text (2), entry);
+ }
}
public bool exists (File file,
out int64 timestamp,
out int64 size) throws DatabaseError {
- var exists = false;
var uri = file.get_uri ();
GLib.Value[] values = { uri };
- int64 tmp_timestamp = 0;
- int64 tmp_size = 0;
if (this.exists_cache.has_key (uri)) {
var entry = this.exists_cache.get (uri);
@@ -194,21 +176,12 @@ public class Rygel.MediaExport.MediaCache : Object {
return true;
}
- this.db.exec (this.sql.make (SQLString.EXISTS),
- values,
- (statement) => {
- exists = statement.column_int (0) == 1;
- tmp_timestamp = statement.column_int64 (1);
- tmp_size = statement.column_int64 (2);
-
- return false;
- });
+ var cursor = this.exec_cursor (SQLString.EXISTS, values);
+ var statement = cursor.next ();
+ timestamp = statement->column_int64 (1);
+ size = statement->column_int64 (2);
- // out parameters are not allowed to be captured
- timestamp = tmp_timestamp;
- size = tmp_size;
-
- return exists;
+ return statement->column_int (0) == 1;
}
public MediaObjects get_children (MediaContainer container,
@@ -220,19 +193,16 @@ public class Rygel.MediaExport.MediaCache : Object {
GLib.Value[] values = { container.id,
(int64) offset,
(int64) max_count };
- Database.RowCallback callback = (statement) => {
+
+ var cursor = this.exec_cursor (SQLString.GET_CHILDREN, values);
+
+ foreach (var statement in cursor) {
var child_id = statement.column_text (DetailColumn.ID);
children.add (get_object_from_statement (container,
child_id,
statement));
children.last ().parent_ref = container;
-
- return true;
- };
-
- this.db.exec (this.sql.make (SQLString.GET_CHILDREN),
- values,
- callback);
+ }
return children;
}
@@ -304,24 +274,12 @@ public class Rygel.MediaExport.MediaCache : Object {
throws Error {
GLib.Value v = container_id;
args.prepend (v);
- long count = 0;
debug ("Parameters to bind: %u", args.n_values);
-
- Database.RowCallback callback = (statement) => {
- count = statement.column_int (0);
-
- return false;
- };
-
- unowned string sql = this.sql.make
+ unowned string pattern = this.sql.make
(SQLString.GET_OBJECT_COUNT_BY_FILTER);
- this.db.exec (sql.printf (filter),
- args.values,
- callback);
-
- return count;
+ return this.db.query_value (pattern.printf (filter), args.values);
}
@@ -340,7 +298,9 @@ public class Rygel.MediaExport.MediaCache : Object {
debug ("Parameters to bind: %u", args.n_values);
- Database.RowCallback callback = (statement) => {
+ unowned string sql = this.sql.make (SQLString.GET_OBJECTS_BY_FILTER);
+ var cursor = this.db.exec_cursor (sql.printf (filter), args.values);
+ foreach (var statement in cursor) {
var child_id = statement.column_text (DetailColumn.ID);
var parent_id = statement.column_text (DetailColumn.PARENT);
@@ -360,14 +320,7 @@ public class Rygel.MediaExport.MediaCache : Object {
child_id,
parent_id);
}
-
- return true;
- };
-
- var sql = this.sql.make (SQLString.GET_OBJECTS_BY_FILTER);
- this.db.exec (sql.printf (filter),
- args.values,
- callback);
+ }
return children;
}
@@ -413,15 +366,8 @@ public class Rygel.MediaExport.MediaCache : Object {
debug ("Could not find schema version;" +
" checking for empty database...");
try {
- int rows = -1;
- this.db.exec ("SELECT count(type) FROM sqlite_master " +
- "WHERE rowid=1",
- null,
- (statement) => {
- rows = statement.column_int (0);
-
- return false;
- });
+ var rows = this.db.query_value ("SELECT count(type) FROM " +
+ "sqlite_master WHERE rowid=1");
if (rows == 0) {
debug ("Empty database, creating new schema version %s",
SQLFactory.schema_version);
@@ -639,13 +585,10 @@ public class Rygel.MediaExport.MediaCache : Object {
ArrayList<string> children = new ArrayList<string> (str_equal);
GLib.Value[] values = { container_id };
- this.db.exec (this.sql.make (SQLString.CHILD_IDS),
- values,
- (statement) => {
- children.add (statement.column_text (0));
-
- return true;
- });
+ var cursor = this.exec_cursor (SQLString.CHILD_IDS, values);
+ foreach (var statement in cursor) {
+ children.add (statement.column_text (0));
+ }
return children;
}
@@ -827,16 +770,13 @@ public class Rygel.MediaExport.MediaCache : Object {
args.append (v);
var data = new ArrayList<string> ();
- Database.RowCallback callback = (statement) => {
- data.add (statement.column_text (0));
- return true;
- };
-
- var sql = this.sql.make (SQLString.GET_META_DATA_COLUMN);
- this.db.exec (sql.printf (column, filter),
- args.values,
- callback);
+ unowned string sql = this.sql.make (SQLString.GET_META_DATA_COLUMN);
+ var cursor = this.db.exec_cursor (sql.printf (column, filter),
+ args.values);
+ foreach (var statement in cursor) {
+ data.add (statement.column_text (0));
+ }
return data;
}
@@ -871,15 +811,26 @@ public class Rygel.MediaExport.MediaCache : Object {
public Gee.List<string> get_flagged_uris (string flag) throws Error {
var uris = new ArrayList<string> ();
+ const string query = "SELECT uri FROM object WHERE flags = ?";
+
GLib.Value[] args = { flag };
- this.db.exec ("SELECT uri FROM object WHERE flags = ?",
- args,
- (statement) => {
- uris.add (statement.column_text (0));
- return true;
- });
+ var cursor = this.db.exec_cursor (query, args);
+ foreach (var statement in cursor) {
+ uris.add (statement.column_text (0));
+ }
return uris;
}
+ private DatabaseCursor exec_cursor (SQLString id,
+ GLib.Value[]? values = null)
+ throws DatabaseError {
+ return this.db.exec_cursor (this.sql.make (id), values);
+ }
+
+ private int query_value (SQLString id,
+ GLib.Value[]? values = null)
+ throws DatabaseError {
+ return this.db.query_value (this.sql.make (id), values);
+ }
}
diff --git a/src/plugins/media-export/rygel-media-export-sqlite-wrapper.vala b/src/plugins/media-export/rygel-media-export-sqlite-wrapper.vala
new file mode 100644
index 0000000..84a288b
--- /dev/null
+++ b/src/plugins/media-export/rygel-media-export-sqlite-wrapper.vala
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2011 Jens Georg <mail jensge org>.
+ *
+ * Author: Jens Georg <mail jensge org>
+ *
+ * This file is part of Rygel.
+ *
+ * Rygel 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 of the License, or
+ * (at your option) any later version.
+ *
+ * Rygel 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 program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+using Sqlite;
+
+internal class Rygel.MediaExport.SqliteWrapper : Object {
+ private Sqlite.Database database = null;
+ private Sqlite.Database *reference = null;
+
+ /**
+ * Property to access the wrapped database
+ */
+ protected unowned Sqlite.Database db {
+ get { return reference; }
+ }
+
+ /**
+ * Wrap an existing SQLite Database object.
+ *
+ * The SqliteWrapper doesn't take ownership of the passed db
+ */
+ public SqliteWrapper.wrap (Sqlite.Database db) {
+ this.reference = db;
+ }
+
+ /**
+ * Create or open a new SQLite database in path.
+ *
+ * @note: Path may also be ":memory:" for temporary databases
+ */
+ public SqliteWrapper (string path) throws DatabaseError {
+ Sqlite.Database.open (path, out this.database);
+ this.reference = this.database;
+ this.throw_if_db_has_error ();
+ }
+
+ /**
+ * Convert a SQLite return code to a DatabaseError
+ */
+ protected void throw_if_code_is_error (int sqlite_error)
+ throws DatabaseError {
+ switch (sqlite_error) {
+ case Sqlite.OK:
+ case Sqlite.DONE:
+ case Sqlite.ROW:
+ return;
+ default:
+ throw new DatabaseError.SQLITE_ERROR
+ ("SQLite error %d: %s",
+ sqlite_error,
+ this.reference->errmsg ());
+ }
+ }
+
+ /**
+ * Check if the last operation on the database was an error
+ */
+ protected void throw_if_db_has_error () throws DatabaseError {
+ this.throw_if_code_is_error (this.reference->errcode ());
+ }
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]