[f-spot] Replace QueuedSqliteDatabase with HyenaSqliteConnection
- From: Ruben Vermeersch <rubenv src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [f-spot] Replace QueuedSqliteDatabase with HyenaSqliteConnection
- Date: Wed, 21 Jul 2010 14:44:41 +0000 (UTC)
commit c47fdca1e27dad051920f63b1f2443564dc1740a
Author: Mike Gemünde <mike gemuende de>
Date: Wed Jul 7 18:53:55 2010 +0200
Replace QueuedSqliteDatabase with HyenaSqliteConnection
This is the first commit for replacing the old database backend by
a more flexibel one based on Hyena. A new directory and namespace
(FSpot.Database) is created to create the new classes seperatetly
and start with better source code organization.
build/build.environment.mk | 10 +-
configure.ac | 1 +
extensions/Tools/HashJob/HashJob.cs | 9 +-
extensions/Tools/MergeDb/MergeDb.cs | 2 +-
.../Tools/RetroactiveRoll/RetroactiveRoll.cs | 8 +-
src/Db.cs | 36 +-
src/ExportStore.cs | 29 +-
src/FSpot.Database/FSpotDatabaseConnection.cs | 32 ++
src/FSpot.Database/Makefile.am | 14 +
src/JobStore.cs | 52 +-
src/Makefile.am | 2 +-
src/MetaStore.cs | 22 +-
src/PhotoStore.cs | 243 +++++-----
src/QueuedSqliteDatabase.cs | 501 --------------------
src/RollStore.cs | 23 +-
src/TagStore.cs | 54 ++-
src/Updater.cs | 131 +++---
src/Widgets/CellRendererTextProgress.cs | 2 -
src/Widgets/FolderTreeModel.cs | 6 +-
19 files changed, 369 insertions(+), 808 deletions(-)
---
diff --git a/build/build.environment.mk b/build/build.environment.mk
index 4b75af7..9c390d4 100644
--- a/build/build.environment.mk
+++ b/build/build.environment.mk
@@ -91,7 +91,7 @@ LINK_FSPOT_UTILS = -r:$(DIR_BIN)/FSpot.Utils.dll
LINK_FSPOT_UTILS_DEPS = $(REF_FSPOT_UTILS) $(LINK_FSPOT_UTILS)
# FSpot.Core
-REF_FSPOT_CORE = $(LINK_FSPOT_UTILS_DEPS) $(LINK_FSPOT_CMS_DEPS)
+REF_FSPOT_CORE = $(LINK_FSPOT_UTILS_DEPS) $(LINK_FSPOT_CMS_DEPS) $(LINK_HYENA_DATA_SQLITE_DEPS)
LINK_FSPOT_CORE = -r:$(DIR_BIN)/FSpot.Core.dll
LINK_FSPOT_CORE_DEPS = $(REF_FSPOT_CORE) $(LINK_FSPOT_CORE)
@@ -100,6 +100,11 @@ REF_FSPOT_QUERY = $(LINK_FSPOT_CORE_DEPS)
LINK_FSPOT_QUERY = -r:$(DIR_BIN)/FSpot.Query.dll
LINK_FSPOT_QUERY_DEPS = $(REF_FSPOT_QUERY) $(LINK_FSPOT_QUERY)
+# FSpot.Database
+REF_FSPOT_DATABASE = $(LINK_HYENA_DATA_SQLITE_DEPS) $(LINK_FSPOT_CORE_DEPS) $(LINK_SYSTEMDATA) $(LINK_FSPOT_QUERY_DEPS)
+LINK_FSPOT_DATABASE = -r:$(DIR_BIN)/FSpot.Database.dll
+LINK_FSPOT_DATABASE_DEPS = $(REF_FSPOT_DATABASE) $(LINK_FSPOT_DATABASE)
+
# FSpot.JobScheduler
REF_FSPOT_JOB_SCHEDULER = $(LINK_HYENA_DEPS)
LINK_FSPOT_JOB_SCHEDULER = -r:$(DIR_BIN)/FSpot.JobScheduler.dll
@@ -125,7 +130,8 @@ REF_FSPOT = $(LINK_FSPOT_WIDGETS_DEPS) $(LINK_FSPOT_PLATFORM_DEPS) $(LINK_FSPOT_
$(LINK_GLIB) $(LINK_MONO_ADDINS_DEPS) $(LINK_UNIQUE_DEPS) $(LINK_MONO_ADDINS_SETUP_DEPS) \
$(LINK_GLADE) $(LINK_MONODATA) $(LINK_MONO_DATA_SQLITECLIENT) \
$(LINK_MONO_ADDINS_GUI_DEPS) $(LINK_FSPOT_JOB_SCHEDULER_DEPS) $(LINK_ICSHARP_ZIP_LIB) \
- $(LINK_GNOME) $(LINK_HYENA_GUI_DEPS) $(LINK_TAGLIB)
+ $(LINK_GNOME) $(LINK_HYENA_GUI_DEPS) $(LINK_TAGLIB) $(LINK_FSPOT_DATABASE_DEPS)
+
# FIXME: do not link executables
LINK_FSPOT = -r:$(DIR_BIN)/f-spot.exe
LINK_FSPOT_DEPS = $(REF_FSPOT) $(LINK_FSPOT)
diff --git a/configure.ac b/configure.ac
index c610e4d..bf1d1cd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -363,6 +363,7 @@ src/Query/Makefile
src/Core/Defines.cs
src/Core/Makefile
src/Core/FSpot.Core.dll.config
+src/FSpot.Database/Makefile
src/Widgets/Makefile
src/Widgets/FSpot.Widgets.dll.config
src/Platform/Makefile
diff --git a/extensions/Tools/HashJob/HashJob.cs b/extensions/Tools/HashJob/HashJob.cs
index 2f36fe7..8f52631 100644
--- a/extensions/Tools/HashJob/HashJob.cs
+++ b/extensions/Tools/HashJob/HashJob.cs
@@ -9,8 +9,9 @@
using System;
using System.Collections.Generic;
+using System.Data;
+
using Mono.Unix;
-using Mono.Data.SqliteClient;
using Gtk;
@@ -35,7 +36,7 @@ namespace HashJobExtension {
public void ShowDialog ()
{
// This query is not very fast, but it's a 'one-time' so don't care much...
- SqliteDataReader reader = FSpot.App.Instance.Database.Database.Query (
+ IDataReader reader = FSpot.App.Instance.Database.Database.Query (
"SELECT COUNT(*) FROM photos p WHERE EXISTS " +
"(SELECT * FROM photo_versions pv WHERE p.id=pv.photo_id AND " +
"(pv.import_md5 IS NULL OR pv.import_md5 = ''))");
@@ -90,7 +91,7 @@ namespace HashJobExtension {
void HandleExecuteClicked (object o, EventArgs e)
{
- SqliteDataReader reader = FSpot.App.Instance.Database.Database.Query (
+ IDataReader reader = FSpot.App.Instance.Database.Database.Query (
"SELECT id FROM photos p WHERE EXISTS " +
"(SELECT * FROM photo_versions pv WHERE p.id=pv.photo_id AND " +
"(pv.import_md5 IS NULL OR pv.import_md5 = '') )");
@@ -104,7 +105,7 @@ namespace HashJobExtension {
void HandleStopClicked (object o, EventArgs e)
{
- FSpot.App.Instance.Database.Database.ExecuteNonQuery (String.Format ("DELETE FROM jobs WHERE job_type = '{0}'", typeof(FSpot.Jobs.CalculateHashJob).ToString ()));
+ FSpot.App.Instance.Database.Database.Execute (String.Format ("DELETE FROM jobs WHERE job_type = '{0}'", typeof(FSpot.Jobs.CalculateHashJob).ToString ()));
status_label.Text = Catalog.GetString ("Stopped");
}
diff --git a/extensions/Tools/MergeDb/MergeDb.cs b/extensions/Tools/MergeDb/MergeDb.cs
index 6e0dfbc..8786c1e 100644
--- a/extensions/Tools/MergeDb/MergeDb.cs
+++ b/extensions/Tools/MergeDb/MergeDb.cs
@@ -37,7 +37,7 @@ namespace MergeDbExtension
public void Run (object o, EventArgs e)
{
from_db = new Db ();
- from_db.ExceptionThrown += HandleDbException;
+// from_db.ExceptionThrown += HandleDbException;
to_db = App.Instance.Database;
//ShowDialog ();
diff --git a/extensions/Tools/RetroactiveRoll/RetroactiveRoll.cs b/extensions/Tools/RetroactiveRoll/RetroactiveRoll.cs
index 310277f..84be9e9 100644
--- a/extensions/Tools/RetroactiveRoll/RetroactiveRoll.cs
+++ b/extensions/Tools/RetroactiveRoll/RetroactiveRoll.cs
@@ -12,10 +12,10 @@ using FSpot;
using FSpot.Extensions;
using Mono.Unix;
using System;
-using Mono.Data.SqliteClient;
-using Banshee.Database;
using Hyena;
+using Hyena.Data.Sqlite;
+
namespace RetroactiveRoll
{
public class RetroactiveRoll: ICommand
@@ -37,11 +37,11 @@ namespace RetroactiveRoll
RollStore rolls = App.Instance.Database.Rolls;
Roll roll = rolls.Create(import_time);
foreach (Photo p in photos) {
- DbCommand cmd = new DbCommand ("UPDATE photos SET roll_id = :roll_id " +
+ HyenaSqliteCommand cmd = new HyenaSqliteCommand ("UPDATE photos SET roll_id = :roll_id " +
"WHERE id = :id ",
"roll_id", roll.Id,
"id", p.Id);
- App.Instance.Database.Database.ExecuteNonQuery (cmd);
+ App.Instance.Database.Database.Execute (cmd);
p.RollId = roll.Id;
}
Log.Debug ("RetroactiveRoll done: " + photos.Length + " photos in roll " + roll.Id);
diff --git a/src/Db.cs b/src/Db.cs
index e6097e4..599cb08 100644
--- a/src/Db.cs
+++ b/src/Db.cs
@@ -3,7 +3,6 @@ using System.Collections;
using System.Collections.Generic;
using System.IO;
using System;
-using Banshee.Database;
using System.Diagnostics;
using FSpot;
using Hyena;
@@ -106,8 +105,8 @@ public abstract class DbStore<T> where T : DbItem {
}
- QueuedSqliteDatabase database;
- protected QueuedSqliteDatabase Database {
+ FSpotDatabaseConnection database;
+ protected FSpotDatabaseConnection Database {
get {
return database;
}
@@ -116,7 +115,7 @@ public abstract class DbStore<T> where T : DbItem {
// Constructor.
- public DbStore (QueuedSqliteDatabase database,
+ public DbStore (FSpotDatabaseConnection database,
bool cache_is_immortal)
{
this.database = database;
@@ -149,10 +148,6 @@ public class Db : IDisposable {
bool empty;
string path;
- public delegate void ExceptionThrownHandler (Exception e);
- public event ExceptionThrownHandler ExceptionThrown;
-
-
public TagStore Tags {
get { return tag_store; }
}
@@ -182,12 +177,12 @@ public class Db : IDisposable {
public bool Sync {
set {
string query = "PRAGMA synchronous = " + (value ? "ON" : "OFF");
- Database.ExecuteNonQuery(query);
+ Database.Execute(query);
}
}
- QueuedSqliteDatabase database;
- public QueuedSqliteDatabase Database {
+ FSpotDatabaseConnection database;
+ public FSpotDatabaseConnection Database {
get { return database; }
}
@@ -220,11 +215,12 @@ public class Db : IDisposable {
if (new_db && ! create_if_missing)
throw new Exception (path + ": File not found");
- database = new QueuedSqliteDatabase(path);
- database.ExceptionThrown += HandleDbException;
+// database = new QueuedSqliteDatabase(path);
+// database.ExceptionThrown += HandleDbException;
- if (database.GetFileVersion(path) == 2)
- SqliteUpgrade ();
+// if (database.GetFileVersion(path) == 2)
+// SqliteUpgrade ();
+ database = new FSpotDatabaseConnection (path);
// Load or create the meta table
meta_store = new MetaStore (Database, new_db);
@@ -246,14 +242,6 @@ public class Db : IDisposable {
Log.DebugTimerPrint (timer, "Db Initialization took {0}");
}
- void HandleDbException (Exception e)
- {
- if (ExceptionThrown != null)
- ExceptionThrown (e);
- else
- throw e;
- }
-
public bool Empty {
get {
return empty;
@@ -333,7 +321,7 @@ public class Db : IDisposable {
throw new DbException("Failed to upgrade the f-spot sqlite2 database to sqlite3!\n" + stdError);
//Re-open the db
- database = new QueuedSqliteDatabase(path);
+ database = new FSpotDatabaseConnection (path);
}
}
diff --git a/src/ExportStore.cs b/src/ExportStore.cs
index c2b56db..74aab2b 100644
--- a/src/ExportStore.cs
+++ b/src/ExportStore.cs
@@ -1,11 +1,12 @@
using Gdk;
using Gtk;
-using Mono.Data.SqliteClient;
using System.Collections;
using System.IO;
+using System.Data;
using System;
-using Banshee.Database;
using FSpot;
+using FSpot.Database;
+using Hyena.Data.Sqlite;
public class ExportItem : DbItem {
@@ -53,7 +54,7 @@ public class ExportStore : DbStore<ExportItem> {
private void CreateTable ()
{
- Database.ExecuteNonQuery (
+ Database.Execute (
"CREATE TABLE exports (\n" +
" id INTEGER PRIMARY KEY NOT NULL, \n" +
" image_id INTEGER NOT NULL, \n" +
@@ -63,7 +64,7 @@ public class ExportStore : DbStore<ExportItem> {
")");
}
- private ExportItem LoadItem (SqliteDataReader reader)
+ private ExportItem LoadItem (IDataReader reader)
{
return new ExportItem (Convert.ToUInt32 (reader["id"]),
Convert.ToUInt32 (reader["image_id"]),
@@ -74,10 +75,10 @@ public class ExportStore : DbStore<ExportItem> {
private void LoadAllItems ()
{
- SqliteDataReader reader = Database.Query("SELECT id, image_id, image_version_id, export_type, export_token FROM exports");
+ IDataReader reader = Database.Query("SELECT id, image_id, image_version_id, export_type, export_token FROM exports");
while (reader.Read ()) {
- AddToCache (LoadItem (reader));
+ AddToCache (LoadItem (reader));
}
reader.Close ();
@@ -85,8 +86,8 @@ public class ExportStore : DbStore<ExportItem> {
public ExportItem Create (uint image_id, uint image_version_id, string export_type, string export_token)
{
- int id = Database.Execute(new DbCommand("INSERT INTO exports (image_id, image_version_id, export_type, export_token) VALUES (:image_id, :image_version_id, :export_type, :export_token)",
- "image_id", image_id, "image_version_id", image_version_id, "export_type", export_type, "export_token", export_token));
+ int id = Database.Execute(new HyenaSqliteCommand("INSERT INTO exports (image_id, image_version_id, export_type, export_token) VALUES (?, ?, ?, ?)",
+ "image_id", image_id, image_version_id, export_type, export_token));
ExportItem item = new ExportItem ((uint)id, image_id, image_version_id, export_type, export_token);
@@ -98,8 +99,8 @@ public class ExportStore : DbStore<ExportItem> {
public override void Commit (ExportItem item)
{
- Database.ExecuteNonQuery(new DbCommand("UPDATE exports SET image_id = :image_id, image_version_id = :image_version_id, export_type = :export_type SET export_token = :export_token WHERE id = :item_id",
- "item_id", item.Id, "image_id", item.ImageId, "image_version_id", item.ImageVersionId, "export_type", item.ExportType, "export_token", item.ExportToken));
+ Database.Execute(new HyenaSqliteCommand("UPDATE exports SET image_id = ?, image_version_id = ?, export_type = ? SET export_token = ? WHERE id = ?",
+ item.ImageId, item.ImageVersionId, item.ExportType, item.ExportToken, item.Id));
EmitChanged (item);
}
@@ -113,8 +114,8 @@ public class ExportStore : DbStore<ExportItem> {
public ArrayList GetByImageId (uint image_id, uint image_version_id)
{
- SqliteDataReader reader = Database.Query(new DbCommand("SELECT id, image_id, image_version_id, export_type, export_token FROM exports WHERE image_id = :image_id AND image_version_id = :image_version_id",
- "image_id", image_id, "image_version_id", image_version_id));
+ IDataReader reader = Database.Query(new HyenaSqliteCommand("SELECT id, image_id, image_version_id, export_type, export_token FROM exports WHERE image_id = ? AND image_version_id = ?",
+ image_id, image_version_id));
ArrayList list = new ArrayList ();
while (reader.Read ()) {
list.Add (LoadItem (reader));
@@ -128,14 +129,14 @@ public class ExportStore : DbStore<ExportItem> {
{
RemoveFromCache (item);
- Database.ExecuteNonQuery(new DbCommand("DELETE FROM exports WHERE id = :item_id", "item_id", item.Id));
+ Database.Execute(new HyenaSqliteCommand("DELETE FROM exports WHERE id = ?", item.Id));
EmitRemoved (item);
}
// Constructor
- public ExportStore (QueuedSqliteDatabase database, bool is_new)
+ public ExportStore (FSpotDatabaseConnection database, bool is_new)
: base (database, true)
{
if (is_new || !Database.TableExists ("exports"))
diff --git a/src/FSpot.Database/FSpotDatabaseConnection.cs b/src/FSpot.Database/FSpotDatabaseConnection.cs
new file mode 100644
index 0000000..17463a1
--- /dev/null
+++ b/src/FSpot.Database/FSpotDatabaseConnection.cs
@@ -0,0 +1,32 @@
+//
+// FSpotDatabaseConnection.cs
+//
+// Author:
+// Mike Gemuende <mike gemuende de>
+// Ruben Vermeersch <ruben savanne be>
+//
+// Copyright (c) 2010 Mike Gemuende <mike gemuende de>
+// Copyright (c) 2010 Ruben Vermeersch <ruben savanne be>
+//
+// This is free software. See COPYING for details.
+//
+
+using System;
+
+using Hyena.Data.Sqlite;
+
+namespace FSpot
+{
+
+
+ public class FSpotDatabaseConnection : HyenaSqliteConnection
+ {
+
+ public FSpotDatabaseConnection (string dbpath) : base(dbpath)
+ {
+ //Execute ("PRAGMA synchronous = OFF");
+ //Execute ("PRAGMA temp_store = MEMORY");
+ //Execute ("PRAGMA count_changes = OFF");
+ }
+ }
+}
diff --git a/src/FSpot.Database/Makefile.am b/src/FSpot.Database/Makefile.am
new file mode 100644
index 0000000..6740f90
--- /dev/null
+++ b/src/FSpot.Database/Makefile.am
@@ -0,0 +1,14 @@
+ASSEMBLY = FSpot.Database
+TARGET = library
+LINK = $(REF_FSPOT_DATABASE)
+
+SOURCES = \
+ FSpotDatabaseConnection.cs
+
+
+RESOURCES =
+
+include $(top_srcdir)/build/build.mk
+
+EXTRA_DIST +=
+module_SCRIPTS +=
diff --git a/src/JobStore.cs b/src/JobStore.cs
index e1dcd25..f36b60c 100644
--- a/src/JobStore.cs
+++ b/src/JobStore.cs
@@ -8,16 +8,17 @@
*
*/
-using Mono.Data.SqliteClient;
using System.Collections;
using System.IO;
+using System.Data;
using System;
-using Banshee.Database;
using Banshee.Kernel;
using FSpot.Jobs;
using FSpot;
using Hyena;
+using Hyena.Data.Sqlite;
+
public abstract class Job : DbItem, IJob
{
public Job (uint id, string job_options, JobPriority job_priority, DateTime run_at, bool persistent) : base (id)
@@ -86,13 +87,13 @@ public abstract class Job : DbItem, IJob
public class JobStore : DbStore<Job> {
- internal static void CreateTable (QueuedSqliteDatabase database)
+ internal static void CreateTable (FSpotDatabaseConnection database)
{
if (database.TableExists ("jobs")) {
return;
}
- database.ExecuteNonQuery (
+ database.Execute (
"CREATE TABLE jobs (\n" +
" id INTEGER PRIMARY KEY NOT NULL, \n" +
" job_type TEXT NOT NULL, \n" +
@@ -102,7 +103,7 @@ public class JobStore : DbStore<Job> {
")");
}
- private Job LoadItem (SqliteDataReader reader)
+ private Job LoadItem (IDataReader reader)
{
return (Job) Activator.CreateInstance (
Type.GetType (reader ["job_type"].ToString ()),
@@ -115,7 +116,7 @@ public class JobStore : DbStore<Job> {
private void LoadAllItems ()
{
- SqliteDataReader reader = Database.Query ("SELECT id, job_type, job_options, run_at, job_priority FROM jobs");
+ IDataReader reader = Database.Query ("SELECT id, job_type, job_options, run_at, job_priority FROM jobs");
Scheduler.Suspend ();
while (reader.Read ()) {
@@ -143,12 +144,12 @@ public class JobStore : DbStore<Job> {
{
int id = 0;
if (persistent)
- id = Database.Execute (new DbCommand ("INSERT INTO jobs (job_type, job_options, run_at, job_priority) VALUES (:job_type, :job_options, :run_at, :job_priority)",
- "job_type", job_type.ToString (),
- "job_options", job_options,
- "run_at", DateTimeUtil.FromDateTime (run_at),
- "job_priority", Convert.ToInt32 (job_priority)));
-
+ id = Database.Execute (new HyenaSqliteCommand ("INSERT INTO jobs (job_type, job_options, run_at, job_priority) VALUES (?, ?, ?, ?)",
+ job_type.ToString (),
+ job_options,
+ DateTimeUtil.FromDateTime (run_at),
+ Convert.ToInt32 (job_priority)));
+
Job job = (Job) Activator.CreateInstance (job_type, (uint)id, job_options, run_at, job_priority, true);
AddToCache (job);
@@ -163,17 +164,18 @@ public class JobStore : DbStore<Job> {
public override void Commit (Job item)
{
if (item.Persistent)
- Database.ExecuteNonQuery(new DbCommand("UPDATE jobs " +
- "SET job_type = :job_type " +
- "SET job_options = :job_options " +
- "SET run_at = :run_at " +
- "SET job_priority = :job_priority " +
- "WHERE id = :item_id",
- "job_type", "Empty", //FIXME
- "job_options", item.JobOptions,
- "run_at", DateTimeUtil.FromDateTime (item.RunAt),
- "job_priority", item.JobPriority));
-
+ Database.Execute(new HyenaSqliteCommand("UPDATE jobs " +
+ "SET job_type = ? " +
+ "SET job_options = ? " +
+ "SET run_at = ? " +
+ "SET job_priority = ? " +
+ "WHERE id = ?",
+ "Empty", //FIXME
+ item.JobOptions,
+ DateTimeUtil.FromDateTime (item.RunAt),
+ item.JobPriority,
+ item.Id));
+
EmitChanged (item);
}
@@ -188,7 +190,7 @@ public class JobStore : DbStore<Job> {
RemoveFromCache (item);
if ((item as Job).Persistent)
- Database.ExecuteNonQuery (new DbCommand ("DELETE FROM jobs WHERE id = :item_id", "item_id", item.Id));
+ Database.Execute (new HyenaSqliteCommand ("DELETE FROM jobs WHERE id = ?", item.Id));
EmitRemoved (item);
}
@@ -198,7 +200,7 @@ public class JobStore : DbStore<Job> {
Remove (o as Job);
}
- public JobStore (QueuedSqliteDatabase database, bool is_new) : base (database, true)
+ public JobStore (FSpotDatabaseConnection database, bool is_new) : base (database, true)
{
if (is_new || !Database.TableExists ("jobs")) {
CreateTable (database);
diff --git a/src/Makefile.am b/src/Makefile.am
index 92568a8..8540aa1 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -3,6 +3,7 @@ SUBDIRS = \
Utils \
Core \
Query \
+ FSpot.Database \
JobScheduler \
Bling \
Platform \
@@ -111,7 +112,6 @@ SOURCES = \
Preferences.cs \
PrintOperation.cs \
ProgressItem.cs \
- QueuedSqliteDatabase.cs \
RotateCommand.cs \
RollStore.cs \
SelectionDataExtensions.cs \
diff --git a/src/MetaStore.cs b/src/MetaStore.cs
index 13cc99c..fe381c9 100644
--- a/src/MetaStore.cs
+++ b/src/MetaStore.cs
@@ -1,11 +1,13 @@
using Gdk;
using Gtk;
-using Mono.Data.SqliteClient;
using System.Collections;
using System.IO;
+using System.Data;
using System;
-using Banshee.Database;
using FSpot;
+using FSpot.Database;
+using Hyena.Data.Sqlite;
+
public class MetaItem : DbItem {
private string name;
@@ -61,7 +63,7 @@ public class MetaStore : DbStore<MetaItem> {
private void CreateTable ()
{
- Database.ExecuteNonQuery (
+ Database.Execute (
"CREATE TABLE meta (\n" +
" id INTEGER PRIMARY KEY NOT NULL, \n" +
" name TEXT UNIQUE NOT NULL, \n" +
@@ -76,14 +78,14 @@ public class MetaStore : DbStore<MetaItem> {
// Get the hidden tag id, if it exists
try {
- string id = (string)Database.QuerySingle("SELECT id FROM tags WHERE name = 'Hidden'");
+ string id = Database.Query<string> ("SELECT id FROM tags WHERE name = 'Hidden'");
Create (hidden, id);
} catch (Exception) {}
}
private void LoadAllItems ()
{
- SqliteDataReader reader = Database.Query("SELECT id, name, data FROM meta");
+ IDataReader reader = Database.Query("SELECT id, name, data FROM meta");
while (reader.Read ()) {
uint id = Convert.ToUInt32 (reader ["id"]);
@@ -110,8 +112,8 @@ public class MetaStore : DbStore<MetaItem> {
private MetaItem Create (string name, string data)
{
- uint id = (uint)Database.Execute(new DbCommand("INSERT INTO meta (name, data) VALUES (:name, :data)",
- "name", name, "data", (data == null) ? "NULL" : data ));
+ uint id = (uint)Database.Execute(new HyenaSqliteCommand("INSERT INTO meta (name, data) VALUES (?, ?)",
+ name, (data == null) ? "NULL" : data ));
//FIXME This smells bad. This line used to be *before* the
//Command.executeNonQuery. It smells of a bug, but there might
@@ -128,7 +130,7 @@ public class MetaStore : DbStore<MetaItem> {
public override void Commit (MetaItem item)
{
- Database.ExecuteNonQuery(new DbCommand("UPDATE meta SET data = :data WHERE name = :name", "name", item.Name, "data", item.Value));
+ Database.Execute(new HyenaSqliteCommand("UPDATE meta SET data = ? WHERE name = ?", item.Value, item.Name));
EmitChanged (item);
}
@@ -142,14 +144,14 @@ public class MetaStore : DbStore<MetaItem> {
{
RemoveFromCache (item);
- Database.ExecuteNonQuery (new DbCommand ("DELETE FROM meta WHERE id = :id", "id", item.Id));
+ Database.Execute (new HyenaSqliteCommand ("DELETE FROM meta WHERE id = ?", item.Id));
EmitRemoved (item);
}
// Constructor
- public MetaStore (QueuedSqliteDatabase database, bool is_new)
+ public MetaStore (FSpotDatabaseConnection database, bool is_new)
: base (database, true)
{
if (is_new || !Database.TableExists ("meta")) {
diff --git a/src/PhotoStore.cs b/src/PhotoStore.cs
index d5c9eea..6916c9c 100644
--- a/src/PhotoStore.cs
+++ b/src/PhotoStore.cs
@@ -12,13 +12,13 @@
using Gdk;
using Gtk;
-using Mono.Data.SqliteClient;
using Mono.Unix;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
+using System.Data;
using System;
using FSpot;
@@ -28,13 +28,12 @@ using FSpot.Utils;
using FSpot.Platform;
using Hyena;
-using Banshee.Database;
-
+using Hyena.Data.Sqlite;
public class PhotoStore : DbStore<Photo> {
public int TotalPhotos {
get {
- SqliteDataReader reader = Database.Query("SELECT COUNT(*) AS photo_count FROM photos");
+ IDataReader reader = Database.Query("SELECT COUNT(*) AS photo_count FROM photos");
reader.Read ();
int total = Convert.ToInt32 (reader ["photo_count"]);
reader.Close ();
@@ -56,7 +55,7 @@ public class PhotoStore : DbStore<Photo> {
// Constructor
- public PhotoStore (QueuedSqliteDatabase database, bool is_new)
+ public PhotoStore (FSpotDatabaseConnection database, bool is_new)
: base (database, false)
{
EnsureThumbnailDirectory ();
@@ -64,7 +63,7 @@ public class PhotoStore : DbStore<Photo> {
if (! is_new)
return;
- Database.ExecuteNonQuery (
+ Database.Execute (
"CREATE TABLE photos (\n" +
" id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, \n" +
" time INTEGER NOT NULL, \n" +
@@ -76,14 +75,14 @@ public class PhotoStore : DbStore<Photo> {
" rating INTEGER NULL \n" +
")");
- Database.ExecuteNonQuery (
+ Database.Execute (
"CREATE TABLE photo_tags (\n" +
" photo_id INTEGER, \n" +
" tag_id INTEGER, \n" +
" UNIQUE (photo_id, tag_id)\n" +
")");
- Database.ExecuteNonQuery (
+ Database.Execute (
"CREATE TABLE photo_versions (\n"+
" photo_id INTEGER, \n" +
" version_id INTEGER, \n" +
@@ -95,9 +94,9 @@ public class PhotoStore : DbStore<Photo> {
" UNIQUE (photo_id, version_id)\n" +
")");
- Database.ExecuteNonQuery ("CREATE INDEX idx_photo_versions_id ON photo_versions(photo_id)");
- Database.ExecuteNonQuery ("CREATE INDEX idx_photo_versions_import_md5 ON photo_versions(import_md5)");
- Database.ExecuteNonQuery ("CREATE INDEX idx_photos_roll_id ON photos(roll_id)");
+ Database.Execute ("CREATE INDEX idx_photo_versions_id ON photo_versions(photo_id)");
+ Database.Execute ("CREATE INDEX idx_photo_versions_import_md5 ON photo_versions(import_md5)");
+ Database.Execute ("CREATE INDEX idx_photos_roll_id ON photos(roll_id)");
}
public bool HasDuplicate (IBrowsableItem item) {
@@ -118,7 +117,7 @@ public class PhotoStore : DbStore<Photo> {
DateTime? time = null;
// Look for a filename match.
- var reader = Database.Query (new DbCommand ("SELECT photos.id, photos.time, pv.filename FROM photos LEFT JOIN photo_versions AS pv ON pv.photo_id = photos.id WHERE pv.filename = :filename", "filename", name));
+ var reader = Database.Query (new HyenaSqliteCommand ("SELECT photos.id, photos.time, pv.filename FROM photos LEFT JOIN photo_versions AS pv ON pv.photo_id = photos.id WHERE pv.filename = ?", name));
while (reader.Read ()) {
Log.DebugFormat ("Found one possible duplicate for {0}", reader["filename"].ToString ());
if (!time.HasValue) {
@@ -149,16 +148,16 @@ public class PhotoStore : DbStore<Photo> {
string description = item.Description ?? String.Empty;
uint id = (uint) Database.Execute (
- new DbCommand (
+ new HyenaSqliteCommand (
"INSERT INTO photos (time, base_uri, filename, description, roll_id, default_version_id, rating) " +
- "VALUES (:time, :base_uri, :filename, :description, :roll_id, :default_version_id, :rating)",
- "time", unix_time,
- "base_uri", item.DefaultVersion.BaseUri.ToString (),
- "filename", item.DefaultVersion.Filename,
- "description", description,
- "roll_id", roll_id,
- "default_version_id", Photo.OriginalVersionId,
- "rating", "0"
+ "VALUES (?, ?, ?, ?, ?, ?, ?)",
+ unix_time,
+ item.DefaultVersion.BaseUri.ToString (),
+ item.DefaultVersion.Filename,
+ description,
+ roll_id,
+ Photo.OriginalVersionId,
+ "0"
)
);
@@ -173,26 +172,26 @@ public class PhotoStore : DbStore<Photo> {
private void InsertVersion (Photo photo, PhotoVersion version)
{
- Database.ExecuteNonQuery (new DbCommand (
+ Database.Execute (new HyenaSqliteCommand (
"INSERT OR IGNORE INTO photo_versions (photo_id, version_id, name, base_uri, filename, protected, import_md5) " +
- "VALUES (:photo_id, :version_id, :name, :base_uri, :filename, :is_protected, :import_md5)",
- "photo_id", photo.Id,
- "version_id", version.VersionId,
- "name", version.Name,
- "base_uri", version.BaseUri.ToString (),
- "filename", version.Filename,
- "is_protected", version.IsProtected,
- "import_md5", (version.ImportMD5 != String.Empty ? version.ImportMD5 : null)));
+ "VALUES (?, ?, ?, ?, ?, ?, ?)",
+ photo.Id,
+ version.VersionId,
+ version.Name,
+ version.BaseUri.ToString (),
+ version.Filename,
+ version.IsProtected,
+ (version.ImportMD5 != String.Empty ? version.ImportMD5 : null)));
}
private void GetVersions (Photo photo)
{
- SqliteDataReader reader = Database.Query(
- new DbCommand("SELECT version_id, name, base_uri, filename, import_md5, protected " +
- "FROM photo_versions " +
- "WHERE photo_id = :id",
- "id", photo.Id
+ IDataReader reader = Database.Query(
+ new HyenaSqliteCommand("SELECT version_id, name, base_uri, filename, import_md5, protected " +
+ "FROM photo_versions " +
+ "WHERE photo_id = ?",
+ photo.Id
)
);
@@ -211,7 +210,7 @@ public class PhotoStore : DbStore<Photo> {
private void GetTags (Photo photo)
{
- SqliteDataReader reader = Database.Query(new DbCommand("SELECT tag_id FROM photo_tags WHERE photo_id = :id", "id", photo.Id));
+ IDataReader reader = Database.Query(new HyenaSqliteCommand("SELECT tag_id FROM photo_tags WHERE photo_id = ?", photo.Id));
while (reader.Read ()) {
uint tag_id = Convert.ToUInt32 (reader ["tag_id"]);
@@ -222,7 +221,7 @@ public class PhotoStore : DbStore<Photo> {
}
private void GetAllVersions (string ids) {
- SqliteDataReader reader = Database.Query ("SELECT photo_id, version_id, name, base_uri, filename, import_md5, protected FROM photo_versions WHERE photo_id IN " + ids);
+ IDataReader reader = Database.Query ("SELECT photo_id, version_id, name, base_uri, filename, import_md5, protected FROM photo_versions WHERE photo_id IN " + ids);
while (reader.Read ()) {
uint id = Convert.ToUInt32 (reader ["photo_id"]);
@@ -260,7 +259,7 @@ public class PhotoStore : DbStore<Photo> {
}
private void GetAllTags (string ids) {
- SqliteDataReader reader = Database.Query ("SELECT photo_id, tag_id FROM photo_tags WHERE photo_id IN " + ids);
+ IDataReader reader = Database.Query ("SELECT photo_id, tag_id FROM photo_tags WHERE photo_id IN " + ids);
while (reader.Read ()) {
uint id = Convert.ToUInt32 (reader ["photo_id"]);
@@ -291,10 +290,10 @@ public class PhotoStore : DbStore<Photo> {
if (photo != null)
return photo;
- SqliteDataReader reader = Database.Query(
- new DbCommand("SELECT time, description, roll_id, default_version_id, rating " +
+ IDataReader reader = Database.Query(
+ new HyenaSqliteCommand("SELECT time, description, roll_id, default_version_id, rating " +
"FROM photos " +
- "WHERE id = :id", "id", id
+ "WHERE id = ?", id
)
);
@@ -324,14 +323,14 @@ public class PhotoStore : DbStore<Photo> {
var base_uri = uri.GetBaseUri ();
var filename = uri.GetFilename ();
- SqliteDataReader reader =
- Database.Query (new DbCommand ("SELECT id, time, description, roll_id, default_version_id, rating " +
+ IDataReader reader =
+ Database.Query (new HyenaSqliteCommand ("SELECT id, time, description, roll_id, default_version_id, rating " +
" FROM photos " +
" LEFT JOIN photo_versions AS pv ON photos.id = pv.photo_id" +
- " WHERE (photos.base_uri = :base_uri AND photos.filename = :filename)" +
- " OR (pv.base_uri = :base_uri AND pv.filename = :filename)",
- "base_uri", base_uri.ToString (),
- "filename", filename));
+ " WHERE (photos.base_uri = ? AND photos.filename = ?)" +
+ " OR (pv.base_uri = ? AND pv.filename = ?)",
+ base_uri.ToString (), filename,
+ base_uri.ToString (), filename));
if (reader.Read ()) {
photo = new Photo (Convert.ToUInt32 (reader ["id"]),
@@ -385,9 +384,9 @@ public class PhotoStore : DbStore<Photo> {
}
String id_list = String.Join ("','", ((string []) query_builder.ToArray (typeof (string))));
- Database.ExecuteNonQuery (String.Format ("DELETE FROM photos WHERE id IN ('{0}')", id_list));
- Database.ExecuteNonQuery (String.Format ("DELETE FROM photo_tags WHERE photo_id IN ('{0}')", id_list));
- Database.ExecuteNonQuery (String.Format ("DELETE FROM photo_versions WHERE photo_id IN ('{0}')", id_list));
+ Database.Execute (String.Format ("DELETE FROM photos WHERE id IN ('{0}')", id_list));
+ Database.Execute (String.Format ("DELETE FROM photo_tags WHERE photo_id IN ('{0}')", id_list));
+ Database.Execute (String.Format ("DELETE FROM photo_versions WHERE photo_id IN ('{0}')", id_list));
}
@@ -405,10 +404,20 @@ public class PhotoStore : DbStore<Photo> {
{
uint timer = Log.DebugTimerStart ();
// Only use a transaction for multiple saves. Avoids recursive transactions.
- bool use_transactions = !Database.InTransaction && items.Length > 1;
- if (use_transactions)
+ // TODO.
+ bool use_transactions = true; //!Database.InTransaction && items.Length > 1;
+
+ //if (use_transactions)
+ // Database.BeginTransaction ();
+
+ // FIXME: this hack is used, because HyenaSqliteConnection does not support
+ // the InTransaction propery
+ try {
Database.BeginTransaction ();
+ } catch {
+ use_transactions = false;
+ }
PhotosChanges changes = new PhotosChanges ();
foreach (DbItem item in items)
@@ -425,49 +434,50 @@ public class PhotoStore : DbStore<Photo> {
PhotoChanges changes = photo.Changes;
// Update photo.
if (changes.DescriptionChanged || changes.DefaultVersionIdChanged || changes.TimeChanged || changes.UriChanged || changes.RatingChanged || changes.MD5SumChanged )
- Database.ExecuteNonQuery (
- new DbCommand (
- "UPDATE photos " +
- "SET description = :description, " +
- " default_version_id = :default_version_id, " +
- " time = :time, " +
- " base_uri = :base_uri, " +
- " filename = :filename, " +
- " rating = :rating " +
- "WHERE id = :id ",
- "description", photo.Description,
- "default_version_id", photo.DefaultVersionId,
- "time", DateTimeUtil.FromDateTime (photo.Time),
- "base_uri", photo.VersionUri (Photo.OriginalVersionId).GetBaseUri ().ToString (),
- "filename", photo.VersionUri (Photo.OriginalVersionId).GetFilename (),
- "rating", String.Format ("{0}", photo.Rating),
- "id", photo.Id
+
+ Database.Execute (
+ new HyenaSqliteCommand (
+ "UPDATE photos " +
+ "SET description = ?, " +
+ " default_version_id = ?, " +
+ " time = ?, " +
+ " base_uri = ?, " +
+ " filename = ?, " +
+ " rating = ? " +
+ "WHERE id = ? ",
+ photo.Description,
+ photo.DefaultVersionId,
+ DateTimeUtil.FromDateTime (photo.Time),
+ photo.VersionUri (Photo.OriginalVersionId).GetBaseUri ().ToString (),
+ photo.VersionUri (Photo.OriginalVersionId).GetFilename (),
+ String.Format ("{0}", photo.Rating),
+ photo.Id
)
);
// Update tags.
if (changes.TagsRemoved != null)
foreach (Tag tag in changes.TagsRemoved)
- Database.ExecuteNonQuery (new DbCommand (
- "DELETE FROM photo_tags WHERE photo_id = :photo_id AND tag_id = :tag_id",
- "photo_id", photo.Id,
- "tag_id", tag.Id));
+ Database.Execute (new HyenaSqliteCommand (
+ "DELETE FROM photo_tags WHERE photo_id = ? AND tag_id = ?",
+ photo.Id,
+ tag.Id));
if (changes.TagsAdded != null)
foreach (Tag tag in changes.TagsAdded)
- Database.ExecuteNonQuery (new DbCommand (
+ Database.Execute (new HyenaSqliteCommand (
"INSERT OR IGNORE INTO photo_tags (photo_id, tag_id) " +
- "VALUES (:photo_id, :tag_id)",
- "photo_id", photo.Id,
- "tag_id", tag.Id));
+ "VALUES (?, ?)",
+ photo.Id,
+ tag.Id));
// Update versions.
if (changes.VersionsRemoved != null)
foreach (uint version_id in changes.VersionsRemoved)
- Database.ExecuteNonQuery (new DbCommand (
- "DELETE FROM photo_versions WHERE photo_id = :photo_id AND version_id = :version_id",
- "photo_id", photo.Id,
- "version_id", version_id));
+ Database.Execute (new HyenaSqliteCommand (
+ "DELETE FROM photo_versions WHERE photo_id = ? AND version_id = ?",
+ photo.Id,
+ version_id));
if (changes.VersionsAdded != null)
foreach (uint version_id in changes.VersionsAdded) {
@@ -477,17 +487,17 @@ public class PhotoStore : DbStore<Photo> {
if (changes.VersionsModified != null)
foreach (uint version_id in changes.VersionsModified) {
PhotoVersion version = photo.GetVersion (version_id) as PhotoVersion;
- Database.ExecuteNonQuery (new DbCommand (
- "UPDATE photo_versions SET name = :name, " +
- "base_uri = :base_uri, filename = :filename, protected = :protected, import_md5 = :import_md5 " +
- "WHERE photo_id = :photo_id AND version_id = :version_id",
- "name", version.Name,
- "base_uri", version.BaseUri.ToString (),
- "filename", version.Filename,
- "protected", version.IsProtected,
- "photo_id", photo.Id,
- "import_md5", (version.ImportMD5 != String.Empty ? version.ImportMD5 : null),
- "version_id", version_id));
+ Database.Execute (new HyenaSqliteCommand (
+ "UPDATE photo_versions SET name = ?, " +
+ "base_uri = ?, filename = ?, protected = ?, import_md5 = ? " +
+ "WHERE photo_id = ? AND version_id = ?",
+ version.Name,
+ version.BaseUri.ToString (),
+ version.Filename,
+ version.IsProtected,
+ photo.Id,
+ (version.ImportMD5 != String.Empty ? version.ImportMD5 : null),
+ version_id));
}
photo.Changes = null;
return changes;
@@ -523,7 +533,7 @@ public class PhotoStore : DbStore<Photo> {
where_added = true;
}
- SqliteDataReader reader = Database.Query (query_builder.ToString());
+ IDataReader reader = Database.Query (query_builder.ToString());
reader.Read ();
int count = Convert.ToInt32 (reader ["count"]);
reader.Close();
@@ -561,7 +571,7 @@ public class PhotoStore : DbStore<Photo> {
private int IndexOf (string query)
{
uint timer = Log.DebugTimerStart ();
- SqliteDataReader reader = Database.Query (query);
+ IDataReader reader = Database.Query (query);
int index = - 1;
if (reader.Read ())
index = Convert.ToInt32 (reader ["row_id"]);
@@ -574,7 +584,7 @@ public class PhotoStore : DbStore<Photo> {
{
uint timer = Log.DebugTimerStart ();
List<int> list = new List<int> ();
- SqliteDataReader reader = Database.Query (query);
+ IDataReader reader = Database.Query (query);
while (reader.Read ())
list.Add (Convert.ToInt32 (reader ["row_id"]) - 1);
reader.Close ();
@@ -588,7 +598,7 @@ public class PhotoStore : DbStore<Photo> {
Dictionary<int, int[]> val = new Dictionary<int, int[]> ();
//Sqlite is way more efficient querying to a temp then grouping than grouping at once
- Database.ExecuteNonQuery ("DROP TABLE IF EXISTS population");
+ Database.Execute ("DROP TABLE IF EXISTS population");
StringBuilder query_builder = new StringBuilder ("CREATE TEMPORARY TABLE population AS SELECT strftime('%Y%m', datetime(time, 'unixepoch')) AS month FROM photos");
bool where_added = false;
foreach (IQueryCondition condition in conditions) {
@@ -600,12 +610,12 @@ public class PhotoStore : DbStore<Photo> {
query_builder.Append (condition.SqlClause ());
where_added = true;
}
- Database.ExecuteNonQuery (query_builder.ToString ());
+ Database.Execute (query_builder.ToString ());
int minyear = Int32.MaxValue;
int maxyear = Int32.MinValue;
- SqliteDataReader reader = Database.Query ("SELECT COUNT (*) as count, month from population GROUP BY month");
+ IDataReader reader = Database.Query ("SELECT COUNT (*) as count, month from population GROUP BY month");
while (reader.Read ()) {
string yyyymm = reader ["month"].ToString ();
int count = Convert.ToInt32 (reader ["count"]);
@@ -705,9 +715,10 @@ public class PhotoStore : DbStore<Photo> {
uint timer = Log.DebugTimerStart ();
Log.DebugFormat ("Query Started : {0}", query);
Database.BeginTransaction ();
- Database.ExecuteNonQuery (String.Format ("DROP TABLE IF EXISTS {0}", temp_table));
- //Database.ExecuteNonQuery (String.Format ("CREATE TEMPORARY TABLE {0} AS {1}", temp_table, query));
- Database.Query (String.Format ("CREATE TEMPORARY TABLE {0} AS {1}", temp_table, query)).Close ();
+ Database.Execute (String.Format ("DROP TABLE IF EXISTS {0}", temp_table));
+ Database.Execute (String.Format ("CREATE TEMPORARY TABLE {0} AS {1}", temp_table, query));
+ // For Hyena.Data.Sqlite, we need to call Execute. Calling Query here does fail.
+ //Database.Query (String.Format ("CREATE TEMPORARY TABLE {0} AS {1}", temp_table, query)).Close ();
Database.CommitTransaction ();
Log.DebugTimerPrint (timer, "QueryToTemp took {0} : " + query);
}
@@ -724,13 +735,13 @@ public class PhotoStore : DbStore<Photo> {
public Photo [] Query (string query)
{
- return Query (new DbCommand (query));
+ return Query (new HyenaSqliteCommand (query));
}
- private Photo [] Query (DbCommand query)
+ private Photo [] Query (HyenaSqliteCommand query)
{
uint timer = Log.DebugTimerStart ();
- SqliteDataReader reader = Database.Query(query);
+ IDataReader reader = Database.Query(query);
List<Photo> new_photos = new List<Photo> ();
List<Photo> query_result = new List<Photo> ();
@@ -758,7 +769,7 @@ public class PhotoStore : DbStore<Photo> {
photo_ids = photo_ids + Convert.ToString(photo.Id) + ",";
need_load |= !photo.Loaded;
}
-
+
photo_ids = photo_ids + "-1)";
if (need_load) {
@@ -773,7 +784,7 @@ public class PhotoStore : DbStore<Photo> {
foreach (Photo photo in new_photos)
photo.Changes = null;
- Log.DebugTimerPrint (timer, "Query took {0} : " + query.CommandText);
+ Log.DebugTimerPrint (timer, "Query took {0} : " + query.Text);
return query_result.ToArray ();
}
@@ -783,7 +794,7 @@ public class PhotoStore : DbStore<Photo> {
/* query by file */
if ( ! String.IsNullOrEmpty (filename)) {
- return Query (new DbCommand (
+ return Query (new HyenaSqliteCommand (
"SELECT id, " +
"time, " +
"base_uri, " +
@@ -793,14 +804,14 @@ public class PhotoStore : DbStore<Photo> {
"default_version_id, " +
"rating " +
"FROM photos " +
- "WHERE base_uri LIKE :base_uri " +
- "AND filename LIKE :filename",
- "base_uri", uri.GetBaseUri ().ToString (),
- "filename", filename));
+ "WHERE base_uri LIKE ?" +
+ "AND filename LIKE ?",
+ uri.GetBaseUri ().ToString (),
+ filename));
}
/* query by directory */
- return Query (new DbCommand (
+ return Query (new HyenaSqliteCommand (
"SELECT id, " +
"time, " +
"base_uri, " +
@@ -810,10 +821,10 @@ public class PhotoStore : DbStore<Photo> {
"default_version_id, " +
"rating " +
"FROM photos " +
- "WHERE base_uri LIKE :base_uri " +
- "AND base_uri NOT LIKE :base_uri_",
- "base_uri", uri.ToString () + "%",
- "base_uri_", uri.ToString () + "/%/%"));
+ "WHERE base_uri LIKE ?" +
+ "AND base_uri NOT LIKE ?",
+ uri.ToString () + "%",
+ uri.ToString () + "/%/%"));
}
[Obsolete ("drop this, use IQueryCondition correctly instead")]
diff --git a/src/RollStore.cs b/src/RollStore.cs
index 25bc89d..1fd64da 100644
--- a/src/RollStore.cs
+++ b/src/RollStore.cs
@@ -9,22 +9,27 @@
* This is free software. See COPYING for details.
*/
-using Mono.Data.SqliteClient;
using System.Collections;
using System.IO;
+using System.Data;
using System;
-using Banshee.Database;
+
+using FSpot.Utils;
using FSpot;
+
using Hyena;
+using Hyena.Data.Sqlite;
+
+
public class RollStore : DbStore<Roll>
{
- public RollStore (QueuedSqliteDatabase database, bool is_new) : base (database, false)
+ public RollStore (FSpotDatabaseConnection database, bool is_new) : base (database, false)
{
if (!is_new && Database.TableExists("rolls"))
return;
- Database.ExecuteNonQuery (
+ Database.Execute (
"CREATE TABLE rolls (\n" +
" id INTEGER PRIMARY KEY NOT NULL, \n" +
" time INTEGER NOT NULL\n" +
@@ -34,7 +39,7 @@ public class RollStore : DbStore<Roll>
public Roll Create (DateTime time_in_utc)
{
long unix_time = DateTimeUtil.FromDateTime (time_in_utc);
- uint id = (uint) Database.Execute (new DbCommand ("INSERT INTO rolls (time) VALUES (:time)", "time", unix_time));
+ uint id = (uint) Database.Execute (new HyenaSqliteCommand ("INSERT INTO rolls (time) VALUES (?)", unix_time));
Roll roll = new Roll (id, unix_time);
AddToCache (roll);
@@ -53,7 +58,7 @@ public class RollStore : DbStore<Roll>
if (roll != null)
return roll;
- SqliteDataReader reader = Database.Query(new DbCommand ("SELECT time FROM rolls WHERE id = :id", "id", id));
+ IDataReader reader = Database.Query(new HyenaSqliteCommand ("SELECT time FROM rolls WHERE id = ?", id));
if (reader.Read ()) {
roll = new Roll (id, Convert.ToUInt32 (reader ["time"]));
@@ -66,7 +71,7 @@ public class RollStore : DbStore<Roll>
public override void Remove (Roll item)
{
RemoveFromCache (item);
- Database.ExecuteNonQuery (new DbCommand ("DELETE FROM rolls WHERE id = :id", "id", item.Id));
+ Database.Execute (new HyenaSqliteCommand ("DELETE FROM rolls WHERE id = ?", item.Id));
}
public override void Commit (Roll item)
@@ -77,7 +82,7 @@ public class RollStore : DbStore<Roll>
public uint PhotosInRoll (Roll roll)
{
uint number_of_photos = 0;
- using (SqliteDataReader reader = Database.Query (new DbCommand ("SELECT count(*) AS count FROM photos WHERE roll_id = :id", "id", roll.Id))) {
+ using (IDataReader reader = Database.Query (new HyenaSqliteCommand ("SELECT count(*) AS count FROM photos WHERE roll_id = ?", roll.Id))) {
if (reader.Read ())
number_of_photos = Convert.ToUInt32 (reader ["count"]);
@@ -99,7 +104,7 @@ public class RollStore : DbStore<Roll>
if (limit >= 0)
query += " LIMIT " + limit;
- using (SqliteDataReader reader = Database.Query(query)) {
+ using (IDataReader reader = Database.Query(query)) {
while (reader.Read ()) {
uint id = Convert.ToUInt32 (reader["roll_id"]);
diff --git a/src/TagStore.cs b/src/TagStore.cs
index fd9fa44..c6325ff 100644
--- a/src/TagStore.cs
+++ b/src/TagStore.cs
@@ -1,18 +1,19 @@
using Gdk;
using Gtk;
using Mono.Unix;
-using Mono.Data.SqliteClient;
using System.Collections.Generic;
using System.Collections;
using System.IO;
+using System.Data;
using System;
-using Banshee.Database;
using FSpot;
using FSpot.Jobs;
using FSpot.Query;
using FSpot.Utils;
using Hyena;
+using Hyena.Data.Sqlite;
+
public class InvalidTagOperationException : InvalidOperationException {
public Tag tag;
@@ -125,7 +126,7 @@ public class TagStore : DbStore<Tag> {
// Pass 1, get all the tags.
- SqliteDataReader reader = Database.Query ("SELECT id, name, is_category, sort_priority, icon FROM tags");
+ IDataReader reader = Database.Query ("SELECT id, name, is_category, sort_priority, icon FROM tags");
while (reader.Read ()) {
uint id = Convert.ToUInt32 (reader ["id"]);
@@ -188,7 +189,7 @@ public class TagStore : DbStore<Tag> {
private void CreateTable ()
{
- Database.ExecuteNonQuery (
+ Database.Execute (
"CREATE TABLE tags (\n" +
" id INTEGER PRIMARY KEY NOT NULL, \n" +
" name TEXT UNIQUE, \n" +
@@ -233,7 +234,7 @@ public class TagStore : DbStore<Tag> {
// Constructor
- public TagStore (QueuedSqliteDatabase database, bool is_new)
+ public TagStore (FSpotDatabaseConnection database, bool is_new)
: base (database, true)
{
// The label for the root category is used in new and edit tag dialogs
@@ -253,12 +254,12 @@ public class TagStore : DbStore<Tag> {
uint parent_category_id = parent_category.Id;
String default_tag_icon_value = autoicon ? null : String.Empty;
- int id = Database.Execute (new DbCommand ("INSERT INTO tags (name, category_id, is_category, sort_priority, icon)"
- + "VALUES (:name, :category_id, :is_category, 0, :icon)",
- "name", name,
- "category_id", parent_category_id,
- "is_category", is_category ? 1 : 0,
- "icon", default_tag_icon_value));
+ int id = Database.Execute (new HyenaSqliteCommand ("INSERT INTO tags (name, category_id, is_category, sort_priority, icon)"
+ + "VALUES (?, ?, ?, 0, ?)",
+ name,
+ parent_category_id,
+ is_category ? 1 : 0,
+ default_tag_icon_value));
return (uint) id;
@@ -316,7 +317,7 @@ public class TagStore : DbStore<Tag> {
tag.Category = null;
- Database.ExecuteNonQuery (new DbCommand ("DELETE FROM tags WHERE id = :id", "id", tag.Id));
+ Database.Execute (new HyenaSqliteCommand ("DELETE FROM tags WHERE id = ?", tag.Id));
EmitRemoved (tag);
}
@@ -349,20 +350,29 @@ public class TagStore : DbStore<Tag> {
public void Commit (Tag [] tags, bool update_xmp)
{
- bool use_transactions = !Database.InTransaction && update_xmp;
+ // TODO.
+ bool use_transactions = update_xmp;//!Database.InTransaction && update_xmp;
- if (use_transactions)
+ //if (use_transactions)
+ // Database.BeginTransaction ();
+
+ // FIXME: this hack is used, because HyenaSqliteConnection does not support
+ // the InTransaction propery
+ try {
Database.BeginTransaction ();
+ } catch {
+ use_transactions = false;
+ }
foreach (Tag tag in tags) {
- Database.ExecuteNonQuery (new DbCommand ("UPDATE tags SET name = :name, category_id = :category_id, "
- + "is_category = :is_category, sort_priority = :sort_priority, icon = :icon WHERE id = :id",
- "name", tag.Name,
- "category_id", tag.Category.Id,
- "is_category", tag is Category ? 1 : 0,
- "sort_priority", tag.SortPriority,
- "icon", GetIconString (tag),
- "id", tag.Id));
+ Database.Execute (new HyenaSqliteCommand ("UPDATE tags SET name = ?, category_id = ?, "
+ + "is_category = ?, sort_priority = ?, icon = ? WHERE id = ?",
+ tag.Name,
+ tag.Category.Id,
+ tag is Category ? 1 : 0,
+ tag.SortPriority,
+ GetIconString (tag),
+ tag.Id));
if (update_xmp && Preferences.Get<bool> (Preferences.METADATA_EMBED_IN_IMAGE)) {
Photo [] photos = App.Instance.Database.Photos.Query (new Tag [] { tag });
diff --git a/src/Updater.cs b/src/Updater.cs
index 26ce6e5..c52dd73 100644
--- a/src/Updater.cs
+++ b/src/Updater.cs
@@ -1,19 +1,22 @@
-using Mono.Data.SqliteClient;
using Mono.Unix;
using Gtk;
using System;
+using System.Data;
using System.Collections;
-using Banshee.Database;
+
using FSpot.Utils;
-using Hyena;
using FSpot.UI.Dialog;
+using Hyena;
+using Hyena.Data.Sqlite;
+
+
namespace FSpot.Database {
public static class Updater {
private static ProgressDialog dialog;
private static Hashtable updates = new Hashtable ();
private static Version db_version;
- private static QueuedSqliteDatabase db;
+ private static FSpotDatabaseConnection db;
public static bool silent = false;
@@ -51,7 +54,7 @@ namespace FSpot.Database {
return;
// Finally, we know that the Other tag exists and has no children, so remove it
- ExecuteNonQuery ("DELETE FROM tags WHERE name = 'Other'");
+ Execute ("DELETE FROM tags WHERE name = 'Other'");
});
// Update from version 1 to 2: Restore Other tags that were removed leaving dangling child tags
@@ -64,7 +67,7 @@ namespace FSpot.Database {
int id = ExecuteScalar ("INSERT INTO tags (name, category_id, is_category, icon) VALUES ('Other', 0, 1, 'stock_icon:f-spot-other.png')");
- ExecuteNonQuery (String.Format (
+ Execute (String.Format (
"UPDATE tags SET category_id = {0} WHERE id IN " +
"(SELECT id FROM tags WHERE category_id != 0 AND category_id " +
"NOT IN (SELECT id FROM tags))",
@@ -75,7 +78,7 @@ namespace FSpot.Database {
// Update from version 2 to 3: ensure that Hidden is the only tag left which is a real tag (not category)
AddUpdate (new Version ("3"), delegate () {
- ExecuteNonQuery ("UPDATE tags SET is_category = 1 WHERE name != 'Hidden'");
+ Execute ("UPDATE tags SET is_category = 1 WHERE name != 'Hidden'");
});
//Version 3.1, clean old (and unused) items in Export
@@ -93,7 +96,7 @@ namespace FSpot.Database {
AddUpdate (new Version (5, 0), delegate () {
Log.Debug ("Will add a roll_id field to photos!");
string tmp_photos = MoveTableToTemp ("photos");
- ExecuteNonQuery (
+ Execute (
"CREATE TABLE photos ( " +
" id INTEGER PRIMARY KEY NOT NULL, " +
" time INTEGER NOT NULL, " +
@@ -107,7 +110,7 @@ namespace FSpot.Database {
Log.Debug ("Will rename imports to rolls!");
string tmp_rolls = MoveTableToTemp ("imports");
- ExecuteNonQuery (
+ Execute (
"CREATE TABLE rolls ( " +
" id INTEGER PRIMARY KEY NOT NULL, " +
" time INTEGER NOT NULL " +
@@ -115,7 +118,7 @@ namespace FSpot.Database {
ExecuteScalar (String.Format("INSERT INTO rolls SELECT id, time FROM {0}", tmp_rolls));
Log.Debug ("Cleaning weird descriptions, fixes bug #324425.");
- ExecuteNonQuery ("UPDATE photos SET description = \"\" WHERE description LIKE \"Invalid size of entry%\"");
+ Execute ("UPDATE photos SET description = \"\" WHERE description LIKE \"Invalid size of entry%\"");
});
@@ -128,7 +131,7 @@ namespace FSpot.Database {
//Update to version 7.0, keep photo uri instead of path
AddUpdate (new Version (7,0), delegate () {
string tmp_photos = MoveTableToTemp ("photos");
- ExecuteNonQuery (
+ Execute (
"CREATE TABLE photos (" +
" id INTEGER PRIMARY KEY NOT NULL," +
" time INTEGER NOT NULL," +
@@ -137,7 +140,7 @@ namespace FSpot.Database {
" roll_id INTEGER NOT NULL," +
" default_version_id INTEGER NOT NULL" +
")");
- ExecuteNonQuery (String.Format (
+ Execute (String.Format (
"INSERT INTO photos (id, time, uri, description, roll_id, default_version_id) " +
"SELECT id, time, 'file://' || directory_path || '/' || name, " +
"description, roll_id, default_version_id FROM {0}", tmp_photos));
@@ -146,7 +149,7 @@ namespace FSpot.Database {
// Update to version 8.0, store full version uri
AddUpdate (new Version (8,0),delegate () {
string tmp_versions = MoveTableToTemp ("photo_versions");
- ExecuteNonQuery (
+ Execute (
"CREATE TABLE photo_versions ( " +
" photo_id INTEGER, " +
" version_id INTEGER, " +
@@ -154,7 +157,7 @@ namespace FSpot.Database {
" uri STRING NOT NULL " +
")");
- SqliteDataReader reader = ExecuteReader (String.Format (
+ IDataReader reader = ExecuteReader (String.Format (
"SELECT photo_id, version_id, name, uri " +
"FROM {0}, photos " +
"WHERE photo_id = id ", tmp_versions));
@@ -169,7 +172,7 @@ namespace FSpot.Database {
System.IO.Path.GetDirectoryName (photo_uri.AbsolutePath) + "/" +
name_without_extension + " (" + (reader [2]).ToString () + ")" + extension;
- ExecuteNonQuery (new DbCommand (
+ Execute (new HyenaSqliteCommand (
"INSERT INTO photo_versions (photo_id, version_id, name, uri) " +
"VALUES (:photo_id, :version_id, :name, :uri)",
"photo_id", Convert.ToUInt32 (reader [0]),
@@ -183,7 +186,7 @@ namespace FSpot.Database {
// Update to version 9.0
AddUpdate (new Version (9,0),delegate () {
string tmp_versions = MoveTableToTemp ("photo_versions");
- ExecuteNonQuery (
+ Execute (
"CREATE TABLE photo_versions ( " +
" photo_id INTEGER, " +
" version_id INTEGER, " +
@@ -191,7 +194,7 @@ namespace FSpot.Database {
" uri STRING NOT NULL," +
" protected BOOLEAN " +
")");
- ExecuteNonQuery (String.Format (
+ Execute (String.Format (
"INSERT INTO photo_versions (photo_id, version_id, name, uri, protected) " +
"SELECT photo_id, version_id, name, uri, 0 " +
"FROM {0} ", tmp_versions));
@@ -200,7 +203,7 @@ namespace FSpot.Database {
// Update to version 10.0, make id autoincrement
AddUpdate (new Version (10,0),delegate () {
string tmp_photos = MoveTableToTemp ("photos");
- ExecuteNonQuery (
+ Execute (
"CREATE TABLE photos ( " +
" id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, " +
" time INTEGER NOT NULL, " +
@@ -210,7 +213,7 @@ namespace FSpot.Database {
" default_version_id INTEGER NOT NULL " +
")");
- ExecuteNonQuery (String.Format (
+ Execute (String.Format (
"INSERT INTO photos (id, time, uri, description, roll_id, default_version_id) " +
"SELECT id, time, uri, description, roll_id, default_version_id " +
"FROM {0} ", tmp_photos));
@@ -523,7 +526,7 @@ namespace FSpot.Database {
" UNIQUE (photo_id, version_id)\n" +
")");
- SqliteDataReader reader = ExecuteReader (String.Format (
+ IDataReader reader = ExecuteReader (String.Format (
"SELECT id, time, uri, description, roll_id, default_version_id, rating, md5_sum " +
"FROM {0} ", tmp_photos));
@@ -535,7 +538,7 @@ namespace FSpot.Database {
string md5 = reader["md5_sum"] != null ? reader ["md5_sum"].ToString () : null;
- Execute (new DbCommand (
+ Execute (new HyenaSqliteCommand (
"INSERT INTO photos (id, time, base_uri, filename, description, roll_id, default_version_id, rating, md5_sum) " +
"VALUES (:id, :time, :base_uri, :filename, :description, :roll_id, :default_version_id, :rating, :md5_sum)",
"id", Convert.ToUInt32 (reader ["id"]),
@@ -563,7 +566,7 @@ namespace FSpot.Database {
string md5 = reader["md5_sum"] != null ? reader ["md5_sum"].ToString () : null;
- Execute (new DbCommand (
+ Execute (new HyenaSqliteCommand (
"INSERT INTO photo_versions (photo_id, version_id, name, base_uri, filename, protected, md5_sum) " +
"VALUES (:photo_id, :version_id, :name, :base_uri, :filename, :is_protected, :md5_sum)",
"photo_id", Convert.ToUInt32 (reader ["photo_id"]),
@@ -595,16 +598,16 @@ namespace FSpot.Database {
var reader = ExecuteReader (no_original_query);
while (reader.Read ()) {
- Execute (new DbCommand (
+ Execute (new HyenaSqliteCommand (
"INSERT INTO photo_versions (photo_id, version_id, name, base_uri, filename, protected, md5_sum) " +
- "VALUES (:photo_id, :version_id, :name, :base_uri, :filename, :is_protected, :md5_sum)",
- "photo_id", Convert.ToUInt32 (reader ["id"]),
- "version_id", 1,
- "name", "Original",
- "base_uri", reader["base_uri"].ToString (),
- "filename", reader["filename"].ToString (),
- "is_protected", 1,
- "md5_sum", ""));
+ "VALUES (?, ?, ?, ?, ?, ?, ?)",
+ Convert.ToUInt32 (reader ["id"]),
+ 1,
+ "Original",
+ reader["base_uri"].ToString (),
+ reader["filename"].ToString (),
+ 1,
+ ""));
}
}, true);
@@ -642,17 +645,17 @@ namespace FSpot.Database {
"FROM {0} ", tmp_photos));
while (reader.Read ()) {
- Execute (new DbCommand (
+ Execute (new HyenaSqliteCommand (
"INSERT INTO photos (id, time, base_uri, filename, description, roll_id, default_version_id, rating) " +
- "VALUES (:id, :time, :base_uri, :filename, :description, :roll_id, :default_version_id, :rating)",
- "id", Convert.ToUInt32 (reader ["id"]),
- "time", reader ["time"],
- "base_uri", reader ["base_uri"].ToString (),
- "filename", reader ["filename"].ToString (),
- "description", reader["description"].ToString (),
- "roll_id", Convert.ToUInt32 (reader ["roll_id"]),
- "default_version_id", Convert.ToUInt32 (reader ["default_version_id"]),
- "rating", Convert.ToUInt32 (reader ["rating"])));
+ "VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
+ Convert.ToUInt32 (reader ["id"]),
+ reader ["time"],
+ reader ["base_uri"].ToString (),
+ reader ["filename"].ToString (),
+ reader["description"].ToString (),
+ Convert.ToUInt32 (reader ["roll_id"]),
+ Convert.ToUInt32 (reader ["default_version_id"]),
+ Convert.ToUInt32 (reader ["rating"])));
}
reader.Close ();
@@ -662,16 +665,16 @@ namespace FSpot.Database {
"FROM {0} ", tmp_versions));
while (reader.Read ()) {
- Execute (new DbCommand (
+ Execute (new HyenaSqliteCommand (
"INSERT INTO photo_versions (photo_id, version_id, name, base_uri, filename, protected, import_md5) " +
- "VALUES (:photo_id, :version_id, :name, :base_uri, :filename, :is_protected, :import_md5)",
- "photo_id", Convert.ToUInt32 (reader ["photo_id"]),
- "version_id", Convert.ToUInt32 (reader ["version_id"]),
- "name", reader["name"].ToString (),
- "base_uri", reader["base_uri"].ToString (),
- "filename", reader["filename"].ToString (),
- "is_protected", Convert.ToBoolean (reader["protected"]),
- "import_md5", ""));
+ "VALUES (?, ?, ?, ?, ?, ?, ?)",
+ Convert.ToUInt32 (reader ["photo_id"]),
+ Convert.ToUInt32 (reader ["version_id"]),
+ reader["name"].ToString (),
+ reader["base_uri"].ToString (),
+ reader["filename"].ToString (),
+ Convert.ToBoolean (reader["protected"]),
+ ""));
}
Execute ("CREATE INDEX idx_photo_versions_import_md5 ON photo_versions(import_md5)");
@@ -691,7 +694,7 @@ namespace FSpot.Database {
return new Version (version_id);
}
- public static void Run (QueuedSqliteDatabase database)
+ public static void Run (FSpotDatabaseConnection database)
{
db = database;
db_version = GetDatabaseVersion ();
@@ -787,27 +790,17 @@ namespace FSpot.Database {
return db.Execute (statement);
}
- private static int Execute (DbCommand command)
+ private static int Execute (HyenaSqliteCommand command)
{
return db.Execute (command);
}
-
- private static void ExecuteNonQuery (string statement)
- {
- db.ExecuteNonQuery(statement);
- }
-
- private static void ExecuteNonQuery (DbCommand command)
- {
- db.ExecuteNonQuery(command);
- }
private static int ExecuteScalar (string statement)
{
return db.Execute(statement);
}
- private static SqliteDataReader ExecuteReader (string statement)
+ private static IDataReader ExecuteReader (string statement)
{
return db.Query (statement);
}
@@ -822,7 +815,7 @@ namespace FSpot.Database {
string result = null;
try {
- result = (string)db.QuerySingle(statement);
+ result = db.Query<string> (statement);
} catch (Exception) {}
return result;
@@ -836,16 +829,16 @@ namespace FSpot.Database {
string sql = SelectSingleString (String.Format ("SELECT sql FROM sqlite_master WHERE tbl_name = '{0}' AND type = 'table' ORDER BY type DESC", table_name));
// Drop temp table if already exists
- ExecuteNonQuery ("DROP TABLE IF EXISTS " + temp_name);
+ Execute ("DROP TABLE IF EXISTS " + temp_name);
// Change the SQL to create the temp table
- ExecuteNonQuery (sql.Replace ("CREATE TABLE " + table_name, "CREATE TEMPORARY TABLE " + temp_name));
+ Execute (sql.Replace ("CREATE TABLE " + table_name, "CREATE TEMPORARY TABLE " + temp_name));
// Copy the data
ExecuteScalar (String.Format ("INSERT INTO {0} SELECT * FROM {1}", temp_name, table_name));
// Delete the original table
- ExecuteNonQuery ("DROP TABLE " + table_name);
+ Execute ("DROP TABLE " + table_name);
return temp_name;
}
@@ -870,7 +863,7 @@ namespace FSpot.Database {
this.code = code;
}
- public void Execute (QueuedSqliteDatabase db, Version db_version)
+ public void Execute (HyenaSqliteConnection db, Version db_version)
{
code ();
@@ -880,7 +873,7 @@ namespace FSpot.Database {
Version.ToString ());
db_version = Version;
- db.ExecuteNonQuery(new DbCommand("UPDATE meta SET data = :data WHERE name = :name", "name", meta_db_version_string, "data", db_version.ToString ()));
+ db.Execute(new HyenaSqliteCommand("UPDATE meta SET data = ? WHERE name = ?", meta_db_version_string, db_version.ToString ()));
}
}
diff --git a/src/Widgets/CellRendererTextProgress.cs b/src/Widgets/CellRendererTextProgress.cs
index 24f6bbb..f79d86f 100644
--- a/src/Widgets/CellRendererTextProgress.cs
+++ b/src/Widgets/CellRendererTextProgress.cs
@@ -17,8 +17,6 @@ using GLib;
using FSpot;
using FSpot.Utils;
-using Banshee.Database;
-
using Mono.Unix;
using Mono.Data.SqliteClient;
diff --git a/src/Widgets/FolderTreeModel.cs b/src/Widgets/FolderTreeModel.cs
index 1afd1da..62a1b74 100644
--- a/src/Widgets/FolderTreeModel.cs
+++ b/src/Widgets/FolderTreeModel.cs
@@ -8,6 +8,7 @@
*/
using System;
+using System.Data;
using System.Collections.Generic;
using Gtk;
@@ -16,10 +17,7 @@ using GLib;
using FSpot;
using Hyena;
-using Banshee.Database;
-
using Mono.Unix;
-using Mono.Data.SqliteClient;
namespace FSpot.Widgets
{
@@ -104,7 +102,7 @@ namespace FSpot.Widgets
int last_count = 0;
- SqliteDataReader reader = database.Database.Query (query_string);
+ IDataReader reader = database.Database.Query (query_string);
while (reader.Read ()) {
var base_uri = new SafeUri (reader["base_uri"].ToString (), true);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]