[epiphany/history-rewrite: 1/45] Initial SQLite GObject wrapper implementation.



commit 6c2a974ea4029377d8526f97123f05c457f3b6a1
Author: Martin Robinson <mrobinson igalia com>
Date:   Thu Apr 14 18:08:31 2011 -0700

    Initial SQLite GObject wrapper implementation.

 .gitignore                             |    1 +
 configure.ac                           |    1 +
 embed/Makefile.am                      |    2 +
 embed/sqlite/ephy-sqlite-connection.c  |  211 ++++++++++++++++++++++++
 embed/sqlite/ephy-sqlite-connection.h  |   74 +++++++++
 embed/sqlite/ephy-sqlite-statement.c   |  274 ++++++++++++++++++++++++++++++++
 embed/sqlite/ephy-sqlite-statement.h   |   76 +++++++++
 embed/sqlite/ephy-sqlite-transaction.c |   70 ++++++++
 embed/sqlite/ephy-sqlite-transaction.h |   56 +++++++
 embed/sqlite/ephy-sqlite.h             |   36 ++++
 tests/Makefile.am                      |    5 +
 tests/ephy-sqlite.c                    |  215 +++++++++++++++++++++++++
 12 files changed, 1021 insertions(+), 0 deletions(-)
---
diff --git a/.gitignore b/.gitignore
index 634c1c1..58f13d1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -69,4 +69,5 @@ tests/test-ephy-embed-persist
 tests/test-ephy-embed-single
 tests/test-ephy-location-entry
 tests/test-ephy-search-entry
+tests/test-ephy-sqlite
 tests/test-ephy-zoom-control
diff --git a/configure.ac b/configure.ac
index cdf52a8..2297df4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -118,6 +118,7 @@ PKG_CHECK_MODULES([DEPENDENCIES], [
 		  libsoup-gnome-2.4 >= $LIBSOUP_GNOME_REQUIRED
 		  gnome-keyring-1 >= $GNOME_KEYRING_REQUIRED
 		  gsettings-desktop-schemas >= $GSETTINGS_DESKTOP_SCHEMAS_REQUIRED
+		  sqlite3
 		  ])
 
 # ******************
diff --git a/embed/Makefile.am b/embed/Makefile.am
index d517fb4..46905f7 100644
--- a/embed/Makefile.am
+++ b/embed/Makefile.am
@@ -49,6 +49,8 @@ libephyembed_la_SOURCES = \
 	ephy-permission-manager.c	\
 	ephy-embed-prefs.c		\
 	ephy-web-view.c			\
+	sqlite/ephy-sqlite-connection.c	\
+	sqlite/ephy-sqlite-statement.c	\
 	$(INST_H_FILES)			\
 	$(NOINST_H_FILES)
 
diff --git a/embed/sqlite/ephy-sqlite-connection.c b/embed/sqlite/ephy-sqlite-connection.c
new file mode 100644
index 0000000..a3bcdc7
--- /dev/null
+++ b/embed/sqlite/ephy-sqlite-connection.c
@@ -0,0 +1,211 @@
+/*
+ *  Copyright  2011 Igalia S.L.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU 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.
+ *
+ *  $Id$
+ */
+
+#include "config.h"
+
+#include <sqlite3.h>
+#include "ephy-sqlite-connection.h"
+#include "ephy-sqlite-statement.h"
+
+static void ephy_sqlite_connection_class_init (EphySQLiteConnectionClass *klass);
+static void ephy_sqlite_connection_init       (EphySQLiteConnection *self);
+static void ephy_sqlite_connection_finalize   (GObject *self);
+
+enum {
+  LAST_SIGNAL
+};
+
+struct _EphySQLiteConnectionPrivate {
+  sqlite3* database;
+};
+
+#define EPHY_SQLITE_CONNECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), EPHY_TYPE_SQLITE_CONNECTION, EphySQLiteConnectionPrivate))
+
+G_DEFINE_TYPE (EphySQLiteConnection, ephy_sqlite_connection, G_TYPE_OBJECT);
+
+static void
+ephy_sqlite_connection_class_init (EphySQLiteConnectionClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  object_class->finalize = ephy_sqlite_connection_finalize;
+  g_type_class_add_private (object_class, sizeof (EphySQLiteConnectionPrivate));
+}
+
+static void
+ephy_sqlite_connection_init (EphySQLiteConnection *self)
+{
+  self->priv = EPHY_SQLITE_CONNECTION_GET_PRIVATE (self);
+  self->priv->database = NULL;
+}
+
+static void
+ephy_sqlite_connection_finalize (GObject *self)
+{
+  ephy_sqlite_connection_close (EPHY_SQLITE_CONNECTION (self));
+  G_OBJECT_CLASS (ephy_sqlite_connection_parent_class)->dispose (self);
+}
+
+static GQuark get_ephy_sqlite_quark (void)
+{
+  return g_quark_from_static_string ("ephy-sqlite");
+}
+
+static void
+set_error_from_string (const char* string, GError **error)
+{
+  if (error)
+    *error = g_error_new (get_ephy_sqlite_quark (), 0, string, 0);
+}
+
+EphySQLiteConnection *
+ephy_sqlite_connection_new (void)
+{
+  return EPHY_SQLITE_CONNECTION (g_object_new (EPHY_TYPE_SQLITE_CONNECTION, NULL));
+}
+
+gboolean
+ephy_sqlite_connection_open (EphySQLiteConnection *self, const gchar *filename, GError **error)
+{
+  EphySQLiteConnectionPrivate *priv = self->priv;
+
+  if (priv->database) {
+    set_error_from_string ("Connection already open.", error);
+    return FALSE;
+  }
+  
+  if (SQLITE_OK != sqlite3_open (filename, &priv->database)) {
+    ephy_sqlite_connection_get_error (self, error);
+    priv->database = NULL;
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+void
+ephy_sqlite_connection_close (EphySQLiteConnection *self)
+{
+  EphySQLiteConnectionPrivate *priv = self->priv;
+  if (priv->database) {
+    sqlite3_close (priv->database);
+    priv->database = NULL;
+  }
+}
+
+void
+ephy_sqlite_connection_get_error(EphySQLiteConnection *self, GError **error)
+{
+  if (error)
+    *error = g_error_new (get_ephy_sqlite_quark (), 0, sqlite3_errmsg (self->priv->database), 0);
+}
+
+gboolean
+ephy_sqlite_connection_execute (EphySQLiteConnection *self, const char *sql, GError **error)
+{
+  EphySQLiteConnectionPrivate *priv = self->priv;
+  
+  if (!priv->database) {
+    set_error_from_string ("Connection not open.", error);
+    return FALSE;
+  }
+  
+  return sqlite3_exec (priv->database, sql, NULL, NULL, NULL) == SQLITE_OK;
+}
+
+EphySQLiteStatement *
+ephy_sqlite_connection_create_statement (EphySQLiteConnection *self, const char *sql, GError **error)
+{
+  EphySQLiteConnectionPrivate *priv = self->priv;
+  sqlite3_stmt *prepared_statement;
+
+  if (!priv->database) {
+    set_error_from_string ("Connection not open.", error);
+    return NULL;
+  }
+
+  if (sqlite3_prepare_v2 (priv->database, sql, -1, &prepared_statement, NULL) != SQLITE_OK) {
+    ephy_sqlite_connection_get_error (self, error);
+    return NULL;
+  }
+
+  return EPHY_SQLITE_STATEMENT (g_object_new (EPHY_TYPE_SQLITE_STATEMENT,
+                                              "prepared-statement", prepared_statement,
+                                              "connection", self,
+                                              NULL));
+}
+
+gint64
+ephy_sqlite_connection_get_last_insert_id (EphySQLiteConnection *self)
+{
+  return sqlite3_last_insert_rowid (self->priv->database);
+}
+
+gboolean
+ephy_sqlite_connection_begin_transaction (EphySQLiteConnection *self, GError **error)
+{
+  return ephy_sqlite_connection_execute (self, "BEGIN TRANSACTION", error);
+}
+
+gboolean
+ephy_sqlite_connection_rollback_transaction (EphySQLiteConnection *self, GError **error)
+{
+  return ephy_sqlite_connection_execute (self, "ROLLBACK", error);
+}
+
+gboolean
+ephy_sqlite_connection_commit_transaction (EphySQLiteConnection *self, GError **error)
+{
+  return ephy_sqlite_connection_execute (self, "COMMIT", error);
+}
+
+gboolean
+ephy_sqlite_connection_table_exists (EphySQLiteConnection *self, const char *table_name)
+{
+  GError *error = NULL;
+  gboolean table_exists = FALSE;
+
+  EphySQLiteStatement *statement = ephy_sqlite_connection_create_statement (self,
+    "SELECT COUNT(type) FROM sqlite_master WHERE type='table' and name=?", &error);
+  if (error) {
+    g_error ("Could not detect table existence: %s", error->message);
+    g_error_free (error);
+    return FALSE;
+  }
+
+  ephy_sqlite_statement_bind_string (statement, 0, table_name, &error);
+  if (error) {
+    g_object_unref (statement);
+    g_error ("Could not detect table existence: %s", error->message);
+    g_error_free (error);
+    return FALSE;
+  }
+
+  ephy_sqlite_statement_step (statement, &error);
+  if (error) {
+    g_object_unref (statement);
+    g_error ("Could not detect table existence: %s", error->message);
+    g_error_free (error);
+    return FALSE;
+  }
+
+  table_exists = ephy_sqlite_statement_get_column_as_int (statement, 0);
+  g_object_unref (statement);
+  return table_exists;
+}
diff --git a/embed/sqlite/ephy-sqlite-connection.h b/embed/sqlite/ephy-sqlite-connection.h
new file mode 100644
index 0000000..9f3f691
--- /dev/null
+++ b/embed/sqlite/ephy-sqlite-connection.h
@@ -0,0 +1,74 @@
+/*
+ *  Copyright  2011 Igalia S.L.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU 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.
+ *
+ *  $Id$
+ */
+
+#ifndef EPHY_SQLITE_CONNECTION_H
+#define EPHY_SQLITE_CONNECTION_H
+
+#include <glib-object.h>
+#include "ephy-sqlite-statement.h"
+
+G_BEGIN_DECLS
+
+/* convenience macros */
+#define EPHY_TYPE_SQLITE_CONNECTION             (ephy_sqlite_connection_get_type())
+#define EPHY_SQLITE_CONNECTION(obj)             (G_TYPE_CHECK_INSTANCE_CAST((obj),EPHY_TYPE_SQLITE_CONNECTION,EphySQLiteConnection))
+#define EPHY_SQLITE_CONNECTION_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST((klass),EPHY_TYPE_SQLITE_CONNECTION,EphySQLiteConnectionClass))
+#define EPHY_IS_SQLITE_CONNECTION(obj)          (G_TYPE_CHECK_INSTANCE_TYPE((obj),EPHY_TYPE_SQLITE_CONNECTION))
+#define EPHY_IS_SQLITE_CONNECTION_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE((klass),EPHY_TYPE_SQLITE_CONNECTION))
+#define EPHY_SQLITE_CONNECTION_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS((obj),EPHY_TYPE_SQLITE_CONNECTION,EphySQLiteConnectionClass))
+
+typedef struct _EphySQLiteConnection                EphySQLiteConnection;
+typedef struct _EphySQLiteConnectionClass           EphySQLiteConnectionClass;
+typedef struct _EphySQLiteConnectionPrivate         EphySQLiteConnectionPrivate;
+
+struct _EphySQLiteConnection {
+     GObject parent;
+
+    /* private */
+    EphySQLiteConnectionPrivate *priv;
+};
+
+struct _EphySQLiteConnectionClass {
+    GObjectClass parent_class;
+};
+
+GType                   ephy_sqlite_connection_get_type                (void);
+
+EphySQLiteConnection *  ephy_sqlite_connection_new                     (void);
+
+gboolean                ephy_sqlite_connection_open                    (EphySQLiteConnection *self, const gchar *filename, GError **error);
+void                    ephy_sqlite_connection_close                   (EphySQLiteConnection *self);
+
+void                    ephy_sqlite_connection_get_error               (EphySQLiteConnection *self, GError **error);
+
+gboolean                ephy_sqlite_connection_execute                 (EphySQLiteConnection *self, const char *sql, GError **error);
+EphySQLiteStatement *   ephy_sqlite_connection_create_statement        (EphySQLiteConnection *self, const char *sql, GError **error);
+gint64                  ephy_sqlite_connection_get_last_insert_id      (EphySQLiteConnection *self);
+
+gboolean                ephy_sqlite_connection_begin_transaction       (EphySQLiteConnection *self, GError **error);
+gboolean                ephy_sqlite_connection_rollback_transaction    (EphySQLiteConnection *self, GError **error);
+gboolean                ephy_sqlite_connection_commit_transaction      (EphySQLiteConnection *self, GError **error);
+
+gboolean                ephy_sqlite_connection_table_exists            (EphySQLiteConnection *self, const char *table_name);
+
+G_END_DECLS
+
+#endif /* __EPHY_SQLITE_CONNECTION_H__ */
+
diff --git a/embed/sqlite/ephy-sqlite-statement.c b/embed/sqlite/ephy-sqlite-statement.c
new file mode 100644
index 0000000..36ac76e
--- /dev/null
+++ b/embed/sqlite/ephy-sqlite-statement.c
@@ -0,0 +1,274 @@
+/*
+ *  Copyright  2011 Igalia S.L.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU 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.
+ *
+ *  $Id$
+ */
+
+#include "config.h"
+
+#include <sqlite3.h>
+#include "ephy-sqlite-connection.h"
+#include "ephy-sqlite-statement.h"
+
+static void ephy_sqlite_statement_class_init (EphySQLiteStatementClass *klass);
+static void ephy_sqlite_statement_init       (EphySQLiteStatement *self);
+static void ephy_sqlite_statement_finalize   (GObject *self);
+
+enum
+{
+  PROP_0,
+  PROP_PREPARED_STATEMENT,
+  PROP_CONNECTION
+};
+
+enum {
+    LAST_SIGNAL
+};
+
+struct _EphySQLiteStatementPrivate {
+  sqlite3_stmt *prepared_statement;
+  EphySQLiteConnection *connection;
+};
+
+#define EPHY_SQLITE_STATEMENT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), EPHY_TYPE_SQLITE_STATEMENT, EphySQLiteStatementPrivate))
+
+G_DEFINE_TYPE (EphySQLiteStatement, ephy_sqlite_statement, G_TYPE_OBJECT);
+
+static void
+ephy_sqlite_statement_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
+{
+  EphySQLiteStatement *self = EPHY_SQLITE_STATEMENT (object);
+
+  switch (property_id) {
+    case PROP_PREPARED_STATEMENT:
+      self->priv->prepared_statement = g_value_get_pointer (value);
+      break;
+    case PROP_CONNECTION:
+      self->priv->connection = EPHY_SQLITE_CONNECTION (g_object_ref (g_value_get_object (value)));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (self, property_id, pspec);
+      break;
+  }
+}
+
+static void
+ephy_sqlite_statement_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
+{
+  EphySQLiteStatement *self = EPHY_SQLITE_STATEMENT (object);
+
+  switch (property_id) {
+    case PROP_PREPARED_STATEMENT:
+      g_value_set_pointer (value, self->priv->prepared_statement);
+      break;
+    case PROP_CONNECTION:
+      g_value_set_object (value, self->priv->connection);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+  }
+}
+
+static void
+ephy_sqlite_statement_class_init (EphySQLiteStatementClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  gobject_class->finalize = ephy_sqlite_statement_finalize;
+  gobject_class->get_property = ephy_sqlite_statement_get_property;
+  gobject_class->set_property = ephy_sqlite_statement_set_property;
+  g_type_class_add_private (gobject_class, sizeof (EphySQLiteStatementPrivate));
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_PREPARED_STATEMENT,
+                                   g_param_spec_pointer ("prepared-statement",
+                                                        "Prepared statement",
+                                                        "The statement's backing SQLite prepared statement",
+                                                        G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_CONNECTION,
+                                   g_param_spec_object ("connection",
+                                                        "Connection",
+                                                        "The statement's backing SQLite connection",
+                                                        EPHY_TYPE_SQLITE_CONNECTION,
+                                                        G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
+}
+
+static void
+ephy_sqlite_statement_init (EphySQLiteStatement *self)
+{
+  self->priv = EPHY_SQLITE_STATEMENT_GET_PRIVATE (self);
+  self->priv->prepared_statement = NULL;
+  self->priv->connection = NULL;
+}
+
+static void
+ephy_sqlite_statement_finalize (GObject *self)
+{
+  EphySQLiteStatementPrivate *priv = EPHY_SQLITE_STATEMENT (self)->priv;
+
+  if (priv->prepared_statement) {
+    sqlite3_finalize (priv->prepared_statement);
+    priv->prepared_statement = NULL;
+  }
+
+  if (priv->connection) {
+    g_object_unref (priv->connection);
+    priv->connection = NULL;
+  }
+
+  G_OBJECT_CLASS (ephy_sqlite_statement_parent_class)->dispose (self);
+}
+
+gboolean
+ephy_sqlite_statement_bind_null (EphySQLiteStatement *self, int column, GError **error)
+{
+  if (SQLITE_OK != sqlite3_bind_null (self->priv->prepared_statement, column)) {
+    ephy_sqlite_connection_get_error (self->priv->connection, error);
+    return FALSE;
+  }
+  return TRUE;
+}
+
+gboolean
+ephy_sqlite_statement_bind_boolean (EphySQLiteStatement *self, int column, gboolean value, GError **error)
+{
+  if (SQLITE_OK != sqlite3_bind_int (self->priv->prepared_statement, column + 1, value ? 1 : 0)) {
+    ephy_sqlite_connection_get_error (self->priv->connection, error);
+    return FALSE;
+  }
+  return TRUE;
+}
+
+gboolean
+ephy_sqlite_statement_bind_int (EphySQLiteStatement *self, int column, int value, GError **error)
+{
+  if (SQLITE_OK != sqlite3_bind_int (self->priv->prepared_statement, column + 1, value)) {
+    ephy_sqlite_connection_get_error (self->priv->connection, error);
+    return FALSE;
+  }
+  return TRUE;
+}
+
+gboolean
+ephy_sqlite_statement_bind_double (EphySQLiteStatement *self, int column, double value, GError **error)
+{
+  if (SQLITE_OK != sqlite3_bind_double (self->priv->prepared_statement, column + 1, value)) {
+    ephy_sqlite_connection_get_error (self->priv->connection, error);
+    return FALSE;
+  }
+  return TRUE;
+}
+
+gboolean
+ephy_sqlite_statement_bind_string (EphySQLiteStatement *self, int column, const char *value, GError **error)
+{
+  if (SQLITE_OK != sqlite3_bind_text (self->priv->prepared_statement, column + 1, value, -1, SQLITE_TRANSIENT)) {
+    ephy_sqlite_connection_get_error (self->priv->connection, error);
+    return FALSE;
+  }
+  return TRUE;
+}
+
+gboolean
+ephy_sqlite_statement_bind_blob (EphySQLiteStatement *self, int column, const void *value, int length, GError **error)
+{
+  if (SQLITE_OK != sqlite3_bind_blob (self->priv->prepared_statement, column + 1, value, length, SQLITE_TRANSIENT)) {
+    ephy_sqlite_connection_get_error (self->priv->connection, error);
+    return FALSE;
+  }
+  return TRUE;
+}
+
+gboolean
+ephy_sqlite_statement_step (EphySQLiteStatement *self, GError **error)
+{
+  int error_code = sqlite3_step (self->priv->prepared_statement);
+  if (error_code != SQLITE_OK && error_code != SQLITE_ROW && error_code != SQLITE_DONE) {
+    ephy_sqlite_connection_get_error (self->priv->connection, error);
+  }
+
+  return error_code == SQLITE_ROW;
+}
+
+void
+ephy_sqlite_statement_reset (EphySQLiteStatement *self)
+{
+  sqlite3_reset (self->priv->prepared_statement);
+}
+
+int
+ephy_sqlite_statement_get_column_count (EphySQLiteStatement *self)
+{
+  return sqlite3_column_count (self->priv->prepared_statement);
+}
+
+EphySQLiteColumnType
+ephy_sqlite_statement_get_column_type (EphySQLiteStatement *self, int column)
+{
+  int column_type = sqlite3_column_type (self->priv->prepared_statement, column);
+  switch (column_type) {
+    case SQLITE_INTEGER:
+      return EPHY_SQLITE_COLUMN_TYPE_INT;
+    case SQLITE_FLOAT:
+      return EPHY_SQLITE_COLUMN_TYPE_FLOAT;
+    case SQLITE_TEXT:
+      return EPHY_SQLITE_COLUMN_TYPE_STRING;
+    case SQLITE_BLOB:
+      return EPHY_SQLITE_COLUMN_TYPE_BLOB;
+    case SQLITE_NULL:
+    default:
+      return EPHY_SQLITE_COLUMN_TYPE_NULL;
+  }
+}
+
+int
+ephy_sqlite_statement_get_column_size (EphySQLiteStatement *self, int column)
+{
+  return sqlite3_column_bytes (self->priv->prepared_statement, column);
+}
+
+int
+ephy_sqlite_statement_get_column_as_boolean (EphySQLiteStatement *self, int column)
+{
+  return ephy_sqlite_statement_get_column_as_int (self, column);
+}
+
+int
+ephy_sqlite_statement_get_column_as_int (EphySQLiteStatement *self, int column)
+{
+  return sqlite3_column_int (self->priv->prepared_statement, column);
+}
+
+double
+ephy_sqlite_statement_get_column_as_double (EphySQLiteStatement *self, int column)
+{
+  return sqlite3_column_double (self->priv->prepared_statement, column);
+}
+
+const char*
+ephy_sqlite_statement_get_column_as_string (EphySQLiteStatement *self, int column)
+{
+  return (const char*) sqlite3_column_text (self->priv->prepared_statement, column);
+}
+
+const void*
+ephy_sqlite_statement_get_column_as_blob (EphySQLiteStatement *self, int column)
+{
+  return sqlite3_column_blob (self->priv->prepared_statement, column);
+}
diff --git a/embed/sqlite/ephy-sqlite-statement.h b/embed/sqlite/ephy-sqlite-statement.h
new file mode 100644
index 0000000..98ea132
--- /dev/null
+++ b/embed/sqlite/ephy-sqlite-statement.h
@@ -0,0 +1,76 @@
+/*
+ *  Copyright  2011 Igalia S.L.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU 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.
+ *
+ *  $Id$
+ */
+
+#ifndef EPHY_SQLITE_STATEMENT_H
+#define EPHY_SQLITE_STATEMENT_H
+
+#include <glib-object.h>
+#include "ephy-sqlite.h"
+
+G_BEGIN_DECLS
+
+/* convenience macros */
+#define EPHY_TYPE_SQLITE_STATEMENT             (ephy_sqlite_statement_get_type())
+#define EPHY_SQLITE_STATEMENT(obj)             (G_TYPE_CHECK_INSTANCE_CAST((obj),EPHY_TYPE_SQLITE_STATEMENT,EphySQLiteStatement))
+#define EPHY_SQLITE_STATEMENT_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST((klass),EPHY_TYPE_SQLITE_STATEMENT,EphySQLiteStatementClass))
+#define EPHY_IS_SQLITE_STATEMENT(obj)          (G_TYPE_CHECK_INSTANCE_TYPE((obj),EPHY_TYPE_SQLITE_STATEMENT))
+#define EPHY_IS_SQLITE_STATEMENT_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE((klass),EPHY_TYPE_SQLITE_STATEMENT))
+#define EPHY_SQLITE_STATEMENT_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS((obj),EPHY_TYPE_SQLITE_STATEMENT,EphySQLiteStatementClass))
+
+typedef struct _EphySQLiteStatement                EphySQLiteStatement;
+typedef struct _EphySQLiteStatementClass           EphySQLiteStatementClass;
+typedef struct _EphySQLiteStatementPrivate         EphySQLiteStatementPrivate;
+
+struct _EphySQLiteStatement {
+     GObject parent;
+
+    /* private */
+    EphySQLiteStatementPrivate *priv;
+};
+
+struct _EphySQLiteStatementClass {
+    GObjectClass parent_class;
+};
+
+GType                    ephy_sqlite_statement_get_type              (void);
+
+gboolean                 ephy_sqlite_statement_bind_null             (EphySQLiteStatement *statement, int column, GError **error);
+gboolean                 ephy_sqlite_statement_bind_boolean          (EphySQLiteStatement *statement, int column, gboolean value, GError **error);
+gboolean                 ephy_sqlite_statement_bind_int              (EphySQLiteStatement *statement, int column, int value, GError **error);
+gboolean                 ephy_sqlite_statement_bind_double           (EphySQLiteStatement *statement, int column, double value, GError **error);
+gboolean                 ephy_sqlite_statement_bind_string           (EphySQLiteStatement *statement, int column, const char *value, GError **error);
+gboolean                 ephy_sqlite_statement_bind_blob             (EphySQLiteStatement *statement, int column, const void *value, int length, GError **error);
+
+gboolean                 ephy_sqlite_statement_step                  (EphySQLiteStatement *statement, GError **error);
+void                     ephy_sqlite_statement_reset                 (EphySQLiteStatement *statement);
+
+int                      ephy_sqlite_statement_get_column_count      (EphySQLiteStatement *statement);
+EphySQLiteColumnType     ephy_sqlite_statement_get_column_type       (EphySQLiteStatement *statement, int column);
+int                      ephy_sqlite_statement_get_column_size       (EphySQLiteStatement *statement, int column);
+int                      ephy_sqlite_statement_get_column_as_boolean (EphySQLiteStatement *statement, int column);
+int                      ephy_sqlite_statement_get_column_as_int     (EphySQLiteStatement *statement, int column);
+double                   ephy_sqlite_statement_get_column_as_double  (EphySQLiteStatement *statement, int column);
+const char*              ephy_sqlite_statement_get_column_as_string  (EphySQLiteStatement *statement, int column);
+const void*              ephy_sqlite_statement_get_column_as_blob    (EphySQLiteStatement *statement, int column);
+
+G_END_DECLS
+
+#endif /* EPHY_SQLITE_STATEMENT_H */
+
diff --git a/embed/sqlite/ephy-sqlite-transaction.c b/embed/sqlite/ephy-sqlite-transaction.c
new file mode 100644
index 0000000..fc1bb64
--- /dev/null
+++ b/embed/sqlite/ephy-sqlite-transaction.c
@@ -0,0 +1,70 @@
+/*
+ *  Copyright  2011 Igalia S.L.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU 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.
+ *
+ *  $Id$
+ */
+
+#include "config.h"
+
+#include "ephy-sqlite-statement.h"
+
+static void ephy_sqlite_statement_class_init (EphySQLiteStatementClass *klass);
+static void ephy_sqlite_statement_init       (EphySQLiteStatement *gobject);
+static void ephy_sqlite_statement_finalize   (GObject *gobject);
+
+enum {
+    LAST_SIGNAL
+};
+
+struct _EphySQLiteStatementPrivate {
+};
+
+#define EPHY_SQLITE_STATEMENT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), EPHY_TYPE_SQLITE_STATEMENT, EphySQLiteStatementPrivate))
+
+G_DEFINE_TYPE (EphySQLiteStatement, ephy_sqlite_statement, G_TYPE_OBJECT);
+
+static void
+ephy_sqlite_statement_class_init (EphySQLiteStatementClass *klass)
+{
+    GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
+
+    gobject_class->finalize = ephy_sqlite_statement_finalize;
+
+    g_type_class_add_private (gobject_class, sizeof (EphySQLiteStatementPrivate));
+
+}
+
+static void
+ephy_sqlite_statement_init (EphySQLiteStatement *gobject)
+{
+    gobject->_priv = EPHY_SQLITE_STATEMENT_GET_PRIVATE(gobject);
+
+/* to init any of the private data, do e.g: */
+/*     gobject->_priv->_frobnicate_mode = FALSE; */
+}
+
+static void
+ephy_sqlite_statement_finalize (GObject *gobject)
+{
+    G_OBJECT_CLASS (ephy_sqlite_statement_parent_class)->dispose (gobject);
+}
+
+EphySQLiteStatement *
+ephy_sqlite_statement_new (void)
+{
+    return EPHY_SQLITE_STATEMENT (g_object_new (EPHY_TYPE_SQLITE_STATEMENT, NULL));
+}
diff --git a/embed/sqlite/ephy-sqlite-transaction.h b/embed/sqlite/ephy-sqlite-transaction.h
new file mode 100644
index 0000000..8fc76e5
--- /dev/null
+++ b/embed/sqlite/ephy-sqlite-transaction.h
@@ -0,0 +1,56 @@
+/*
+ *  Copyright  2011 Igalia S.L.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU 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.
+ *
+ *  $Id$
+ */
+
+#ifndef EPHY_SQLITE_STATEMENT_H
+#define EPHY_SQLITE_STATEMENT_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+/* convenience macros */
+#define EPHY_TYPE_SQLITE_STATEMENT             (ephy_sqlite_connection_get_type())
+#define EPHY_SQLITE_STATEMENT(obj)             (G_TYPE_CHECK_INSTANCE_CAST((obj),EPHY_TYPE_SQLITE_STATEMENT,EphySQLiteStatement))
+#define EPHY_SQLITE_STATEMENT_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST((klass),EPHY_TYPE_SQLITE_STATEMENT,EphySQLiteStatementClass))
+#define EPHY_IS_SQLITE_STATEMENT(obj)          (G_TYPE_CHECK_INSTANCE_TYPE((obj),EPHY_TYPE_SQLITE_STATEMENT))
+#define EPHY_IS_SQLITE_STATEMENT_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE((klass),EPHY_TYPE_SQLITE_STATEMENT))
+#define EPHY_SQLITE_STATEMENT_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS((obj),EPHY_TYPE_SQLITE_STATEMENT,EphySQLiteStatementClass))
+
+typedef struct _EphySQLiteStatement                EphySQLiteStatement;
+typedef struct _EphySQLiteStatementClass           EphySQLiteStatementClass;
+typedef struct _EphySQLiteStatementPrivate         EphySQLiteStatementPrivate;
+
+struct _EphySQLiteStatement {
+     GObject parent;
+
+    /* private */
+    EphySQLiteStatementPrivate *priv;
+};
+
+struct _EphySQLiteStatementClass {
+    GObjectClass parent_class;
+};
+
+GType                    ephy_sqlite_connection_get_type            (void);
+
+G_END_DECLS
+
+#endif /* __EPHY_SQLITE_STATEMENT_H__ */
+
diff --git a/embed/sqlite/ephy-sqlite.h b/embed/sqlite/ephy-sqlite.h
new file mode 100644
index 0000000..a73794d
--- /dev/null
+++ b/embed/sqlite/ephy-sqlite.h
@@ -0,0 +1,36 @@
+/*
+ *  Copyright  2011 Igalia S.L.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU 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.
+ *
+ *  $Id$
+ */
+
+#ifndef EPHY_SQLITE_H
+#define EPHY_SQLITE_H
+
+G_BEGIN_DECLS
+
+typedef enum {
+  EPHY_SQLITE_COLUMN_TYPE_NULL,
+  EPHY_SQLITE_COLUMN_TYPE_INT,
+  EPHY_SQLITE_COLUMN_TYPE_FLOAT,
+  EPHY_SQLITE_COLUMN_TYPE_STRING,
+  EPHY_SQLITE_COLUMN_TYPE_BLOB
+} EphySQLiteColumnType;
+
+G_END_DECLS
+
+#endif /* EPHY_SQLITE_H */
diff --git a/tests/Makefile.am b/tests/Makefile.am
index bb538d8..3f693bd 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -3,10 +3,12 @@ noinst_PROGRAMS = \
 	test-ephy-embed-single \
 	test-ephy-location-entry \
 	test-ephy-search-entry \
+	test-ephy-sqlite \
 	test-ephy-zoom-control
 
 INCLUDES = \
 	-I$(top_srcdir)/embed    \
+	-I$(top_srcdir)/embed/sqlite \
 	-I$(top_srcdir)/lib      \
 	-I$(top_srcdir)/lib/widgets \
 	-I$(top_srcdir)/src      \
@@ -45,5 +47,8 @@ test_ephy_location_entry_SOURCES = \
 test_ephy_search_entry_SOURCES = \
 	ephy-search-entry.c
 
+test_ephy_sqlite_SOURCES = \
+	ephy-sqlite.c
+
 test_ephy_zoom_control_SOURCES = \
 	ephy-zoom-control.c
diff --git a/tests/ephy-sqlite.c b/tests/ephy-sqlite.c
new file mode 100644
index 0000000..560f923
--- /dev/null
+++ b/tests/ephy-sqlite.c
@@ -0,0 +1,215 @@
+/* vim: set sw=2 ts=2 sts=2 et: */
+/*
+ * ephy-sqlite-statement.c
+ * This file is part of Epiphany
+ *
+ * Copyright  2010 Igalia S.L.
+ *
+ * Epiphany is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Epiphany 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Epiphany; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA  02110-1301  USA
+ */
+
+#include "config.h"
+
+#include "ephy-sqlite-connection.h"
+#include "ephy-sqlite-statement.h"
+#include <glib.h>
+#include <glib/gstdio.h>
+#include <gtk/gtk.h>
+
+static EphySQLiteConnection *
+ensure_empty_database (const char* filename)
+{
+  EphySQLiteConnection *connection = ephy_sqlite_connection_new ();
+  GError *error = NULL;
+
+  if (g_file_test (filename, G_FILE_TEST_IS_REGULAR)) {
+    g_unlink (filename);
+  }
+
+  g_assert (ephy_sqlite_connection_open (connection, filename, &error));
+  g_assert (!error);
+  return connection;
+}
+
+static void
+test_create_connection (void)
+{
+  GError *error = NULL;
+  gchar *temporary_file = g_build_filename (g_get_tmp_dir (), "epiphany-sqlite-test.db", NULL);
+
+  EphySQLiteConnection *connection = ensure_empty_database (temporary_file);
+  ephy_sqlite_connection_close (connection);
+
+  g_assert ( g_file_test (temporary_file, G_FILE_TEST_IS_REGULAR));
+  g_unlink (temporary_file);
+  g_assert ( !g_file_test (temporary_file, G_FILE_TEST_IS_REGULAR));
+  g_free (temporary_file);
+
+  temporary_file = g_build_filename (g_get_tmp_dir (), "directory-that-does-not-exist", "epiphany_sqlite_test.db", NULL);
+  g_assert (!ephy_sqlite_connection_open (connection, temporary_file, &error));
+  g_assert (error);
+  g_assert (!g_file_test (temporary_file, G_FILE_TEST_IS_REGULAR));
+  g_object_unref (connection);
+}
+
+
+static void
+test_create_statement (void)
+{
+  gchar *temporary_file = g_build_filename (g_get_tmp_dir (), "epiphany-sqlite-test.db", NULL);
+  EphySQLiteConnection* connection = ensure_empty_database (temporary_file);
+  GError *error = NULL;
+  EphySQLiteStatement *statement = NULL;
+
+  statement = ephy_sqlite_connection_create_statement (connection, "CREATE TABLE TEST (id INTEGER)", &error);
+  g_assert (statement);
+  g_assert (!error);
+  g_object_unref (statement);
+
+  statement = ephy_sqlite_connection_create_statement (connection, "BLAHBLAHBLAHBA", &error);
+  g_assert (!statement);
+  g_assert (error);
+
+  ephy_sqlite_connection_close (connection);
+  g_unlink (temporary_file);
+  g_free (temporary_file);
+
+  g_object_unref (connection);
+}
+
+static void
+create_table_and_insert_row (EphySQLiteConnection *connection)
+{
+  GError *error = NULL;
+  EphySQLiteStatement *statement = ephy_sqlite_connection_create_statement (connection, "CREATE TABLE test (id INTEGER, text LONGVARCHAR)", &error);
+  g_assert (statement);
+  g_assert (!error);
+  ephy_sqlite_statement_step (statement, &error);
+  g_assert (!error);
+  g_object_unref (statement);
+
+  statement = ephy_sqlite_connection_create_statement (connection, "SELECT * FROM test", &error);
+  g_assert (statement);
+  g_assert (!error);
+  g_assert (!ephy_sqlite_statement_step (statement, &error));
+  g_assert (!error);
+  g_object_unref (statement);
+
+  statement = ephy_sqlite_connection_create_statement (connection, "INSERT INTO test (id, text) VALUES (3, \"test\")", &error);
+  g_assert (statement);
+  g_assert (!error);
+  ephy_sqlite_statement_step (statement, &error);
+  g_assert (!error);
+  g_object_unref (statement);
+
+  statement = ephy_sqlite_connection_create_statement (connection, "SELECT * FROM test", &error);
+  g_assert (statement);
+  g_assert (!error);
+
+  g_assert (ephy_sqlite_statement_step (statement, &error));
+  g_assert (!error);
+
+  g_assert_cmpint (ephy_sqlite_connection_get_last_insert_id (connection), ==, 1);
+  g_assert_cmpint (ephy_sqlite_statement_get_column_count (statement), ==, 2);
+  g_assert_cmpint (ephy_sqlite_statement_get_column_type (statement, 0), ==, EPHY_SQLITE_COLUMN_TYPE_INT);
+  g_assert_cmpint (ephy_sqlite_statement_get_column_type (statement, 1), ==, EPHY_SQLITE_COLUMN_TYPE_STRING);
+
+  /* Step will return false here since there is only one row. */
+  g_assert (!ephy_sqlite_statement_step (statement, &error));
+  g_object_unref (statement);
+}
+
+static void
+test_create_table_and_insert_row (void)
+{
+  gchar *temporary_file = g_build_filename (g_get_tmp_dir (), "epiphany-sqlite-test.db", NULL);
+  EphySQLiteConnection* connection = ensure_empty_database (temporary_file);
+
+  create_table_and_insert_row (connection);
+
+  g_object_unref (connection);
+  g_unlink (temporary_file);
+  g_free (temporary_file);
+}
+
+static void
+test_bind_data (void)
+{
+  gchar *temporary_file = g_build_filename (g_get_tmp_dir (), "epiphany-sqlite-test.db", NULL);
+  EphySQLiteConnection* connection = ensure_empty_database (temporary_file);
+  GError *error = NULL;
+  EphySQLiteStatement *statement = NULL;
+
+  ephy_sqlite_connection_execute (connection, "CREATE TABLE test (id INTEGER, text LONGVARCHAR)", &error);
+
+  statement = ephy_sqlite_connection_create_statement (connection, "INSERT INTO test (id, text) VALUES (?, ?)", &error);
+  g_assert (statement);
+  g_assert (!error);
+
+  g_assert (ephy_sqlite_statement_bind_int (statement, 0, 3, &error));
+  g_assert (!error);
+  g_assert (ephy_sqlite_statement_bind_string (statement, 1, "foo", &error));
+  g_assert (!error);
+
+  /* Will return false since there are no resulting rows. */
+  g_assert (!ephy_sqlite_statement_step (statement, &error));
+  g_assert (!error);
+  g_object_unref (statement);
+
+  statement = ephy_sqlite_connection_create_statement (connection, "SELECT * FROM test", &error);
+  g_assert (statement);
+  g_assert (!error);
+  g_assert (ephy_sqlite_statement_step (statement, &error));
+  g_assert (!error);
+  g_assert_cmpint (ephy_sqlite_statement_get_column_count (statement), ==, 2);
+  g_assert_cmpint (ephy_sqlite_statement_get_column_as_int (statement, 0), ==, 3);
+  g_assert_cmpstr (ephy_sqlite_statement_get_column_as_string (statement, 1), ==, "foo");
+
+  g_object_unref (connection);
+  g_unlink (temporary_file);
+  g_free (temporary_file);
+}
+
+static void
+test_table_exists (void)
+{
+  gchar *temporary_file = g_build_filename (g_get_tmp_dir (), "epiphany-sqlite-test.db", NULL);
+  EphySQLiteConnection* connection = ensure_empty_database (temporary_file);
+
+  g_assert (!ephy_sqlite_connection_table_exists (connection, "test"));
+  g_assert (!ephy_sqlite_connection_table_exists (connection, "something_fakey"));
+  create_table_and_insert_row (connection);
+  g_assert (ephy_sqlite_connection_table_exists (connection, "test"));
+  g_assert (!ephy_sqlite_connection_table_exists (connection, "something_fakey"));
+
+  g_object_unref (connection);
+  g_unlink (temporary_file);
+  g_free (temporary_file);
+}
+
+int
+main (int argc, char *argv[])
+{
+  gtk_test_init (&argc, &argv);
+
+  g_test_add_func ("/lib/sqlite/ephy-sqlite/create_connection", test_create_connection);
+  g_test_add_func ("/lib/sqlite/ephy-sqlite/create_statement", test_create_statement);
+  g_test_add_func ("/lib/sqlite/ephy-sqlite/create_table_and_insert_row", test_create_table_and_insert_row);
+  g_test_add_func ("/lib/sqlite/ephy-sqlite/bind_data", test_bind_data);
+  g_test_add_func ("/lib/sqlite/ephy-sqlite/table_exists", test_table_exists);
+
+  return g_test_run ();
+}



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]