[tracker] libtracker-db: Support dynamic statement preparation
- From: Jürg Billeter <juergbi src gnome org>
- To: svn-commits-list gnome org
- Subject: [tracker] libtracker-db: Support dynamic statement preparation
- Date: Thu, 16 Apr 2009 05:28:43 -0400 (EDT)
commit 67a4c236cbe27c359fe1968d0d10e8a88aba4cd1
Author: Jürg Billeter <j bitron ch>
Date: Thu Apr 9 18:56:39 2009 +0200
libtracker-db: Support dynamic statement preparation
---
src/libtracker-db/tracker-db-interface-sqlite.c | 182 +++++++++++++++++++++++
src/libtracker-db/tracker-db-interface-sqlite.h | 18 +++
src/libtracker-db/tracker-db-interface.c | 92 ++++++++++++
src/libtracker-db/tracker-db-interface.h | 46 ++++++
4 files changed, 338 insertions(+), 0 deletions(-)
diff --git a/src/libtracker-db/tracker-db-interface-sqlite.c b/src/libtracker-db/tracker-db-interface-sqlite.c
index 112d69b..30a6d74 100644
--- a/src/libtracker-db/tracker-db-interface-sqlite.c
+++ b/src/libtracker-db/tracker-db-interface-sqlite.c
@@ -25,7 +25,10 @@
#define TRACKER_DB_INTERFACE_SQLITE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), TRACKER_TYPE_DB_INTERFACE_SQLITE, TrackerDBInterfaceSqlitePrivate))
+#define TRACKER_DB_STATEMENT_SQLITE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), TRACKER_TYPE_DB_STATEMENT_SQLITE, TrackerDBStatementSqlitePrivate))
+
typedef struct TrackerDBInterfaceSqlitePrivate TrackerDBInterfaceSqlitePrivate;
+typedef struct TrackerDBStatementSqlitePrivate TrackerDBStatementSqlitePrivate;
typedef struct SqliteFunctionData SqliteFunctionData;
typedef struct SqliteAggregateData SqliteAggregateData;
@@ -33,6 +36,7 @@ struct TrackerDBInterfaceSqlitePrivate {
gchar *filename;
sqlite3 *db;
+ GHashTable *dynamic_statements;
GHashTable *statements;
GHashTable *procedures;
@@ -43,6 +47,11 @@ struct TrackerDBInterfaceSqlitePrivate {
guint ro : 1;
};
+struct TrackerDBStatementSqlitePrivate {
+ TrackerDBInterfaceSqlite *db_interface;
+ sqlite3_stmt *stmt;
+};
+
struct SqliteFunctionData {
TrackerDBInterface *interface;
TrackerDBFunc func;
@@ -57,6 +66,11 @@ struct SqliteAggregateData {
};
static void tracker_db_interface_sqlite_iface_init (TrackerDBInterfaceIface *iface);
+static void tracker_db_statement_sqlite_iface_init (TrackerDBStatementIface *iface);
+
+static TrackerDBStatementSqlite * tracker_db_statement_sqlite_new (TrackerDBInterfaceSqlite *db_interface,
+ sqlite3_stmt *sqlite_stmt);
+static void tracker_db_statement_sqlite_reset (TrackerDBStatementSqlite *stmt);
enum {
PROP_0,
@@ -69,6 +83,10 @@ G_DEFINE_TYPE_WITH_CODE (TrackerDBInterfaceSqlite, tracker_db_interface_sqlite,
G_IMPLEMENT_INTERFACE (TRACKER_TYPE_DB_INTERFACE,
tracker_db_interface_sqlite_iface_init))
+G_DEFINE_TYPE_WITH_CODE (TrackerDBStatementSqlite, tracker_db_statement_sqlite, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (TRACKER_TYPE_DB_STATEMENT,
+ tracker_db_statement_sqlite_iface_init))
+
void
tracker_db_interface_sqlite_enable_shared_cache (void)
{
@@ -166,6 +184,8 @@ tracker_db_interface_sqlite_finalize (GObject *object)
priv = TRACKER_DB_INTERFACE_SQLITE_GET_PRIVATE (object);
+ g_hash_table_destroy (priv->dynamic_statements);
+
g_hash_table_destroy (priv->statements);
if (priv->procedures) {
@@ -228,6 +248,9 @@ tracker_db_interface_sqlite_init (TrackerDBInterfaceSqlite *db_interface)
priv = TRACKER_DB_INTERFACE_SQLITE_GET_PRIVATE (db_interface);
priv->ro = FALSE;
+ priv->dynamic_statements = g_hash_table_new_full (g_str_hash, g_str_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify) g_object_unref);
priv->statements = g_hash_table_new_full (g_str_hash, g_str_equal,
(GDestroyNotify) g_free,
(GDestroyNotify) sqlite3_finalize);
@@ -362,6 +385,36 @@ internal_sqlite3_function (sqlite3_context *context,
g_free (values);
}
+static TrackerDBStatement *
+tracker_db_interface_sqlite_create_statement (TrackerDBInterface *db_interface,
+ const gchar *query)
+{
+ TrackerDBInterfaceSqlitePrivate *priv;
+ TrackerDBStatementSqlite *stmt;
+
+ priv = TRACKER_DB_INTERFACE_SQLITE_GET_PRIVATE (db_interface);
+
+ stmt = g_hash_table_lookup (priv->dynamic_statements, query);
+
+ if (!stmt) {
+ sqlite3_stmt *sqlite_stmt;
+
+ g_debug ("Preparing query: '%s'", query);
+
+ if (sqlite3_prepare_v2 (priv->db, query, -1, &sqlite_stmt, NULL) != SQLITE_OK) {
+ g_critical ("Unable to prepare query '%s': %s", query, sqlite3_errmsg (priv->db));
+ return NULL;
+ }
+
+ stmt = tracker_db_statement_sqlite_new (TRACKER_DB_INTERFACE_SQLITE (db_interface), sqlite_stmt);
+ g_hash_table_insert (priv->dynamic_statements, g_strdup (query), stmt);
+ } else {
+ tracker_db_statement_sqlite_reset (stmt);
+ }
+
+ return g_object_ref (stmt);
+}
+
static void
internal_sqlite3_aggregate_step (sqlite3_context *context,
int argc,
@@ -721,6 +774,7 @@ tracker_db_interface_sqlite_iface_init (TrackerDBInterfaceIface *iface)
iface->set_procedure_table = tracker_db_interface_sqlite_set_procedure_table;
iface->execute_procedure = tracker_db_interface_sqlite_execute_procedure;
iface->execute_procedure_len = tracker_db_interface_sqlite_execute_procedure_len;
+ iface->create_statement = tracker_db_interface_sqlite_create_statement;
iface->execute_query = tracker_db_interface_sqlite_execute_query;
}
@@ -829,3 +883,131 @@ tracker_db_interface_sqlite_get_last_insert_id (TrackerDBInterfaceSqlite *interf
return (gint64) sqlite3_last_insert_rowid (priv->db);
}
+
+static void
+tracker_db_statement_sqlite_finalize (GObject *object)
+{
+ TrackerDBStatementSqlitePrivate *priv;
+
+ priv = TRACKER_DB_STATEMENT_SQLITE_GET_PRIVATE (object);
+
+ sqlite3_finalize (priv->stmt);
+
+ G_OBJECT_CLASS (tracker_db_statement_sqlite_parent_class)->finalize (object);
+}
+
+static void
+tracker_db_statement_sqlite_class_init (TrackerDBStatementSqliteClass *class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+ object_class->finalize = tracker_db_statement_sqlite_finalize;
+
+ g_type_class_add_private (object_class,
+ sizeof (TrackerDBStatementSqlitePrivate));
+}
+
+static TrackerDBStatementSqlite *
+tracker_db_statement_sqlite_new (TrackerDBInterfaceSqlite *db_interface,
+ sqlite3_stmt *sqlite_stmt)
+{
+ TrackerDBStatementSqlite *stmt;
+ TrackerDBStatementSqlitePrivate *priv;
+
+ stmt = g_object_new (TRACKER_TYPE_DB_STATEMENT_SQLITE, NULL);
+
+ priv = TRACKER_DB_STATEMENT_SQLITE_GET_PRIVATE (stmt);
+
+ priv->db_interface = db_interface;
+ priv->stmt = sqlite_stmt;
+
+ return stmt;
+}
+
+static void
+tracker_db_statement_sqlite_bind_double (TrackerDBStatement *stmt,
+ int index,
+ double value)
+{
+ TrackerDBStatementSqlitePrivate *priv;
+
+ priv = TRACKER_DB_STATEMENT_SQLITE_GET_PRIVATE (stmt);
+
+ sqlite3_bind_double (priv->stmt, index + 1, value);
+}
+
+static void
+tracker_db_statement_sqlite_bind_int (TrackerDBStatement *stmt,
+ int index,
+ int value)
+{
+ TrackerDBStatementSqlitePrivate *priv;
+
+ priv = TRACKER_DB_STATEMENT_SQLITE_GET_PRIVATE (stmt);
+
+ sqlite3_bind_int (priv->stmt, index + 1, value);
+}
+
+
+
+static void
+tracker_db_statement_sqlite_bind_int64 (TrackerDBStatement *stmt,
+ int index,
+ gint64 value)
+{
+ TrackerDBStatementSqlitePrivate *priv;
+
+ priv = TRACKER_DB_STATEMENT_SQLITE_GET_PRIVATE (stmt);
+
+ sqlite3_bind_int64 (priv->stmt, index + 1, value);
+}
+
+static void
+tracker_db_statement_sqlite_bind_text (TrackerDBStatement *stmt,
+ int index,
+ const gchar *value)
+{
+ TrackerDBStatementSqlitePrivate *priv;
+
+ priv = TRACKER_DB_STATEMENT_SQLITE_GET_PRIVATE (stmt);
+
+ sqlite3_bind_text (priv->stmt, index + 1, value, -1, SQLITE_TRANSIENT);
+}
+
+static TrackerDBResultSet *
+tracker_db_statement_sqlite_execute (TrackerDBStatement *stmt,
+ GError **error)
+{
+ TrackerDBStatementSqlitePrivate *priv;
+
+ priv = TRACKER_DB_STATEMENT_SQLITE_GET_PRIVATE (stmt);
+
+ return create_result_set_from_stmt (priv->db_interface, priv->stmt, error);
+}
+
+static void
+tracker_db_statement_sqlite_iface_init (TrackerDBStatementIface *iface)
+{
+ iface->bind_double = tracker_db_statement_sqlite_bind_double;
+ iface->bind_int = tracker_db_statement_sqlite_bind_int;
+ iface->bind_int64 = tracker_db_statement_sqlite_bind_int64;
+ iface->bind_text = tracker_db_statement_sqlite_bind_text;
+ iface->execute = tracker_db_statement_sqlite_execute;
+}
+
+static void
+tracker_db_statement_sqlite_init (TrackerDBStatementSqlite *stmt)
+{
+}
+
+static void
+tracker_db_statement_sqlite_reset (TrackerDBStatementSqlite *stmt)
+{
+ TrackerDBStatementSqlitePrivate *priv;
+
+ priv = TRACKER_DB_STATEMENT_SQLITE_GET_PRIVATE (stmt);
+
+ sqlite3_reset (priv->stmt);
+ sqlite3_clear_bindings (priv->stmt);
+}
+
diff --git a/src/libtracker-db/tracker-db-interface-sqlite.h b/src/libtracker-db/tracker-db-interface-sqlite.h
index a1c9cae..8ef3ace 100644
--- a/src/libtracker-db/tracker-db-interface-sqlite.h
+++ b/src/libtracker-db/tracker-db-interface-sqlite.h
@@ -31,8 +31,17 @@ G_BEGIN_DECLS
#define TRACKER_IS_DB_INTERFACE_SQLITE_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((o), TRACKER_TYPE_DB_INTERFACE_SQLITE))
#define TRACKER_DB_INTERFACE_SQLITE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), TRACKER_TYPE_DB_INTERFACE_SQLITE, TrackerDBInterfaceSqliteClass))
+#define TRACKER_TYPE_DB_STATEMENT_SQLITE (tracker_db_statement_sqlite_get_type ())
+#define TRACKER_DB_STATEMENT_SQLITE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), TRACKER_TYPE_DB_STATEMENT_SQLITE, TrackerDBStatementSqlite))
+#define TRACKER_DB_STATEMENT_SQLITE_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), TRACKER_TYPE_DB_STATEMENT_SQLITE, TrackerDBStatementSqliteClass))
+#define TRACKER_IS_DB_STATEMENT_SQLITE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), TRACKER_TYPE_DB_STATEMENT_SQLITE))
+#define TRACKER_IS_DB_STATEMENT_SQLITE_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((o), TRACKER_TYPE_DB_STATEMENT_SQLITE))
+#define TRACKER_DB_STATEMENT_SQLITE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), TRACKER_TYPE_DB_STATEMENT_SQLITE, TrackerDBStatementSqliteClass))
+
typedef struct TrackerDBInterfaceSqlite TrackerDBInterfaceSqlite;
typedef struct TrackerDBInterfaceSqliteClass TrackerDBInterfaceSqliteClass;
+typedef struct TrackerDBStatementSqlite TrackerDBStatementSqlite;
+typedef struct TrackerDBStatementSqliteClass TrackerDBStatementSqliteClass;
typedef gint (* TrackerDBCollationFunc) (gchar *str1,
gint len1,
@@ -58,7 +67,16 @@ struct TrackerDBInterfaceSqliteClass {
GObjectClass parent_class;
};
+struct TrackerDBStatementSqlite {
+ GObject parent_instance;
+};
+
+struct TrackerDBStatementSqliteClass {
+ GObjectClass parent_class;
+};
+
GType tracker_db_interface_sqlite_get_type (void);
+GType tracker_db_statement_sqlite_get_type (void);
TrackerDBInterface * tracker_db_interface_sqlite_new (const gchar *filename);
TrackerDBInterface * tracker_db_interface_sqlite_new_ro (const gchar *filename);
diff --git a/src/libtracker-db/tracker-db-interface.c b/src/libtracker-db/tracker-db-interface.c
index 344bf12..26d46d7 100644
--- a/src/libtracker-db/tracker-db-interface.c
+++ b/src/libtracker-db/tracker-db-interface.c
@@ -77,6 +77,24 @@ tracker_db_interface_get_type (void)
return type;
}
+GType
+tracker_db_statement_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ type = g_type_register_static_simple (G_TYPE_INTERFACE,
+ "TrackerDBStatement",
+ sizeof (TrackerDBStatementIface),
+ NULL,
+ 0, NULL, 0);
+
+ g_type_interface_add_prerequisite (type, G_TYPE_OBJECT);
+ }
+
+ return type;
+}
+
/* Boxed type for blobs */
static gpointer
blob_copy (gpointer boxed)
@@ -233,6 +251,26 @@ ensure_result_set_state (TrackerDBResultSet *result_set)
return result_set;
}
+TrackerDBStatement *
+tracker_db_interface_create_statement (TrackerDBInterface *interface,
+ const gchar *query,
+ ...)
+{
+ va_list args;
+ gchar *str;
+
+ g_return_val_if_fail (TRACKER_IS_DB_INTERFACE (interface), NULL);
+ g_return_val_if_fail (query != NULL, NULL);
+
+ va_start (args, query);
+ str = g_strdup_vprintf (query, args);
+ va_end (args);
+
+ return TRACKER_DB_INTERFACE_GET_IFACE (interface)->create_statement (interface,
+ str);
+}
+
+
TrackerDBResultSet *
tracker_db_interface_execute_vquery (TrackerDBInterface *interface,
GError **error,
@@ -439,6 +477,60 @@ tracker_db_interface_end_transaction (TrackerDBInterface *interface)
return TRUE;
}
+void
+tracker_db_statement_bind_double (TrackerDBStatement *stmt,
+ int index,
+ double value)
+{
+ g_return_if_fail (TRACKER_IS_DB_STATEMENT (stmt));
+
+ TRACKER_DB_STATEMENT_GET_IFACE (stmt)->bind_double (stmt, index, value);
+}
+
+void
+tracker_db_statement_bind_int (TrackerDBStatement *stmt,
+ int index,
+ int value)
+{
+ g_return_if_fail (TRACKER_IS_DB_STATEMENT (stmt));
+
+ TRACKER_DB_STATEMENT_GET_IFACE (stmt)->bind_int (stmt, index, value);
+}
+
+
+void
+tracker_db_statement_bind_int64 (TrackerDBStatement *stmt,
+ int index,
+ gint64 value)
+{
+ g_return_if_fail (TRACKER_IS_DB_STATEMENT (stmt));
+
+ TRACKER_DB_STATEMENT_GET_IFACE (stmt)->bind_int64 (stmt, index, value);
+}
+
+void
+tracker_db_statement_bind_text (TrackerDBStatement *stmt,
+ int index,
+ const gchar *value)
+{
+ g_return_if_fail (TRACKER_IS_DB_STATEMENT (stmt));
+
+ TRACKER_DB_STATEMENT_GET_IFACE (stmt)->bind_text (stmt, index, value);
+}
+
+TrackerDBResultSet *
+tracker_db_statement_execute (TrackerDBStatement *stmt,
+ GError **error)
+{
+ TrackerDBResultSet *result_set;
+
+ g_return_val_if_fail (TRACKER_IS_DB_STATEMENT (stmt), NULL);
+
+ result_set = TRACKER_DB_STATEMENT_GET_IFACE (stmt)->execute (stmt, error);
+
+ return ensure_result_set_state (result_set);
+}
+
/* TrackerDBResultSet semiprivate API */
TrackerDBResultSet *
_tracker_db_result_set_new (guint columns)
diff --git a/src/libtracker-db/tracker-db-interface.h b/src/libtracker-db/tracker-db-interface.h
index 14964ba..230c3ba 100644
--- a/src/libtracker-db/tracker-db-interface.h
+++ b/src/libtracker-db/tracker-db-interface.h
@@ -30,6 +30,11 @@ G_BEGIN_DECLS
#define TRACKER_IS_DB_INTERFACE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TRACKER_TYPE_DB_INTERFACE))
#define TRACKER_DB_INTERFACE_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), TRACKER_TYPE_DB_INTERFACE, TrackerDBInterfaceIface))
+#define TRACKER_TYPE_DB_STATEMENT (tracker_db_statement_get_type ())
+#define TRACKER_DB_STATEMENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TRACKER_TYPE_DB_STATEMENT, TrackerDBStatement))
+#define TRACKER_IS_DB_STATEMENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TRACKER_TYPE_DB_STATEMENT))
+#define TRACKER_DB_STATEMENT_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), TRACKER_TYPE_DB_STATEMENT, TrackerDBStatementIface))
+
#define TRACKER_TYPE_DB_RESULT_SET (tracker_db_result_set_get_type ())
#define TRACKER_DB_RESULT_SET(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), TRACKER_TYPE_DB_RESULT_SET, TrackerDbResultSet))
#define TRACKER_DB_RESULT_SET_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), TRACKER_TYPE_DB_RESULT_SET, TrackerDbResultSetClass))
@@ -48,6 +53,8 @@ typedef enum {
typedef struct TrackerDBInterface TrackerDBInterface;
typedef struct TrackerDBInterfaceIface TrackerDBInterfaceIface;
+typedef struct TrackerDBStatement TrackerDBStatement;
+typedef struct TrackerDBStatementIface TrackerDBStatementIface;
typedef struct TrackerDBResultSet TrackerDBResultSet;
typedef struct TrackerDBResultSetClass TrackerDBResultSetClass;
@@ -64,12 +71,33 @@ struct TrackerDBInterfaceIface {
GError **error,
const gchar *procedure,
va_list args);
+ TrackerDBStatement * (* create_statement) (TrackerDBInterface *interface,
+ const gchar *query);
TrackerDBResultSet * (* execute_query) (TrackerDBInterface *interface,
GError **error,
const gchar *query);
};
+struct TrackerDBStatementIface {
+ GTypeInterface iface;
+
+ void (* bind_double) (TrackerDBStatement *stmt,
+ int index,
+ double value);
+ void (* bind_int) (TrackerDBStatement *stmt,
+ int index,
+ int value);
+ void (* bind_text) (TrackerDBStatement *stmt,
+ int index,
+ const gchar *value);
+ TrackerDBResultSet * (* execute) (TrackerDBStatement *stmt,
+ GError **error);
+ void (* bind_int64) (TrackerDBStatement *stmt,
+ int index,
+ gint64 value);
+};
+
struct TrackerDBResultSet {
GObject parent_class;
};
@@ -82,11 +110,15 @@ struct TrackerDBResultSetClass {
GQuark tracker_db_interface_error_quark (void);
GType tracker_db_interface_get_type (void);
+GType tracker_db_statement_get_type (void);
GType tracker_db_result_set_get_type (void);
GType tracker_db_blob_get_type (void);
/* Functions to create queries/procedures */
+TrackerDBStatement * tracker_db_interface_create_statement (TrackerDBInterface *interface,
+ const gchar *query,
+ ...) G_GNUC_PRINTF (2, 3);
TrackerDBResultSet * tracker_db_interface_execute_vquery (TrackerDBInterface *interface,
GError **error,
const gchar *query,
@@ -118,6 +150,20 @@ TrackerDBResultSet * tracker_db_interface_execute_procedure_len (TrackerDBInter
gboolean tracker_db_interface_start_transaction (TrackerDBInterface *interface);
gboolean tracker_db_interface_end_transaction (TrackerDBInterface *interface);
+void tracker_db_statement_bind_double (TrackerDBStatement *stmt,
+ int index,
+ double value);
+void tracker_db_statement_bind_int (TrackerDBStatement *stmt,
+ int index,
+ int value);
+void tracker_db_statement_bind_int64 (TrackerDBStatement *stmt,
+ int index,
+ gint64 value);
+void tracker_db_statement_bind_text (TrackerDBStatement *stmt,
+ int index,
+ const gchar *value);
+TrackerDBResultSet * tracker_db_statement_execute (TrackerDBStatement *stmt,
+ GError **error);
/* Semi private TrackerDBResultSet functions */
TrackerDBResultSet * _tracker_db_result_set_new (guint cols);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]