[epiphany/history-rewrite: 45/45] ephy-history-service: add the hosts table and plug it



commit 6f826c4a20d379ae16f93ef0036efa41318f71fb
Author: Claudio Saavedra <csaavedra igalia com>
Date:   Wed Aug 3 18:39:43 2011 +0300

    ephy-history-service: add the hosts table and plug it
    
    Add the methods needed to work with hosts and ensure the hosts are
    up-to-date upon addition of visits to the history.
    
    One thing that is missing: on removal of urls from the history the
    hosts remain in the database. Ideally, we need to remove a host once
    all the urls referring to it are gone.
    
    Also, it is probably a bad idea to store the visit count in this
    table, since removing urls from the database would make the count
    inconsistent. We need to either update it or to just remove it and
    make the client-code calculate it on demand through sql.

 lib/history/ephy-history-service-hosts-table.c |  318 ++++++++++++++++++++++++
 lib/history/ephy-history-service-private.h     |    7 +
 lib/history/ephy-history-service-urls-table.c  |    8 +-
 lib/history/ephy-history-service.c             |   10 +-
 4 files changed, 339 insertions(+), 4 deletions(-)
---
diff --git a/lib/history/ephy-history-service-hosts-table.c b/lib/history/ephy-history-service-hosts-table.c
new file mode 100644
index 0000000..e790796
--- /dev/null
+++ b/lib/history/ephy-history-service-hosts-table.c
@@ -0,0 +1,318 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
+/* vim: set sw=2 ts=2 sts=2 et: */
+/*
+ *  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.
+ */
+
+#include "config.h"
+
+#include "ephy-history-service.h"
+#include "ephy-history-service-private.h"
+#include "ephy-string.h"
+#include <glib/gi18n.h>
+
+gboolean
+ephy_history_service_initialize_hosts_table (EphyHistoryService *self)
+{
+  EphyHistoryServicePrivate *priv = EPHY_HISTORY_SERVICE (self)->priv;
+  GError *error = NULL;
+
+  if (ephy_sqlite_connection_table_exists (priv->history_database, "hosts")) {
+    return TRUE;
+  }
+  ephy_sqlite_connection_execute (priv->history_database,
+    "CREATE TABLE hosts ("
+    "id INTEGER PRIMARY KEY,"
+    "url LONGVARCAR,"
+    "title LONGVARCAR,"
+    "visit_count INTEGER DEFAULT 0 NOT NULL,"
+    "favicon_id INTEGER DEFAULT 0 NOT NULL)", &error);
+
+  if (error) {
+    g_error("Could not create hosts table: %s", error->message);
+    g_error_free (error);
+    return FALSE;
+  }
+  ephy_history_service_schedule_commit (self);
+  return TRUE;
+}
+
+void
+ephy_history_service_add_host_row (EphyHistoryService *self, EphyHistoryHost *host)
+{
+  EphyHistoryServicePrivate *priv = EPHY_HISTORY_SERVICE (self)->priv;
+  EphySQLiteStatement *statement = NULL;
+  GError *error = NULL;
+
+  g_assert (priv->history_thread == g_thread_self ());
+  g_assert (priv->history_database != NULL);
+
+  statement = ephy_sqlite_connection_create_statement (priv->history_database,
+    "INSERT INTO hosts (url, title, visit_count) "
+    "VALUES (?, ?, ?)", &error);
+
+  if (error) {
+    g_error ("Could not build hosts table addition statement: %s", error->message);
+    g_error_free (error);
+    return;
+  }
+
+  if (ephy_sqlite_statement_bind_string (statement, 0, host->url, &error) == FALSE ||
+      ephy_sqlite_statement_bind_string (statement, 1, host->title, &error) == FALSE ||
+      ephy_sqlite_statement_bind_int (statement, 2, host->visit_count, &error) == FALSE) {
+    g_error ("Could not insert host into hosts table: %s", error->message);
+    g_error_free (error);
+    return;
+  }
+
+  ephy_sqlite_statement_step (statement, &error);
+  if (error) {
+    g_error ("Could not insert host into hosts table: %s", error->message);
+    g_error_free (error);
+    return;
+  } else {
+    host->id = ephy_sqlite_connection_get_last_insert_id (priv->history_database);
+  }
+
+  g_object_unref (statement);
+}
+
+void
+ephy_history_service_update_host_row (EphyHistoryService *self, EphyHistoryHost *host)
+{
+  EphyHistoryServicePrivate *priv = EPHY_HISTORY_SERVICE (self)->priv;
+  EphySQLiteStatement *statement;
+  GError *error = NULL;
+
+  g_assert (priv->history_thread == g_thread_self ());
+  g_assert (priv->history_database != NULL);
+
+  statement = ephy_sqlite_connection_create_statement (priv->history_database,
+    "UPDATE hosts SET url=?, title=?, visit_count=?"
+    "WHERE id=?", &error);
+  if (error) {
+    g_error ("Could not build hosts table modification statement: %s", error->message);
+    g_error_free (error);
+    return;
+  }
+
+  if (ephy_sqlite_statement_bind_string (statement, 0, host->url, &error) == FALSE ||
+      ephy_sqlite_statement_bind_string (statement, 1, host->title, &error) == FALSE ||
+      ephy_sqlite_statement_bind_int (statement, 2, host->visit_count, &error) == FALSE ||
+      ephy_sqlite_statement_bind_int (statement, 3, host->id, &error) == FALSE) {
+    g_error ("Could not modify host in hosts table: %s", error->message);
+    g_error_free (error);
+    return;
+  }
+
+  ephy_sqlite_statement_step (statement, &error);
+  if (error) {
+    g_error ("Could not modify URL in urls table: %s", error->message);
+    g_error_free (error);
+  }
+  g_object_unref (statement);
+}
+
+EphyHistoryHost*
+ephy_history_service_get_host_row (EphyHistoryService *self, const gchar *host_string, EphyHistoryHost *host)
+{
+  EphyHistoryServicePrivate *priv = EPHY_HISTORY_SERVICE (self)->priv;
+  EphySQLiteStatement *statement = NULL;
+  GError *error = NULL;
+
+  g_assert (priv->history_thread == g_thread_self ());
+  g_assert (priv->history_database != NULL);
+
+  if (host_string == NULL && host != NULL) {
+    host_string = host->url;
+  }
+  g_assert (host_string || host->id !=-1);
+
+  if (host != NULL && host->id != -1) {
+    statement = ephy_sqlite_connection_create_statement (priv->history_database,
+        "SELECT id, url, title, visit_count FROM hosts "
+        "WHERE id=?", &error);
+  } else {
+    statement = ephy_sqlite_connection_create_statement (priv->history_database,
+        "SELECT id, url, title, visit_count FROM hosts "
+        "WHERE url=?", &error);
+  }
+
+  if (error) {
+    g_error ("Could not build hosts query statement: %s", error->message);
+    g_error_free (error);
+    return NULL;
+  }
+
+  if (host != NULL && host->id != -1) {
+    ephy_sqlite_statement_bind_int (statement, 0, host->id, &error);
+  } else {
+    ephy_sqlite_statement_bind_string (statement, 0, host_string, &error);
+  }
+  if (error) {
+    g_error ("Could not build hosts table query statement: %s", error->message);
+    g_error_free (error);
+    g_object_unref (statement);
+    return NULL;
+  }
+
+  if (ephy_sqlite_statement_step (statement, &error) == FALSE) {
+    g_object_unref (statement);
+    return NULL;
+  }
+
+  if (host == NULL) {
+    host = ephy_history_host_new (NULL, NULL, 0);
+  } else {
+    if (host->url)
+      g_free (host->url);
+    if (host->title)
+      g_free (host->title);
+  }
+
+  host->id = ephy_sqlite_statement_get_column_as_int (statement, 0);
+  host->url = g_strdup (ephy_sqlite_statement_get_column_as_string (statement, 1)),
+  host->title = g_strdup (ephy_sqlite_statement_get_column_as_string (statement, 2)),
+  host->visit_count = ephy_sqlite_statement_get_column_as_int (statement, 3),
+
+  g_object_unref (statement);
+  return host;
+}
+
+static EphyHistoryHost*
+create_host_from_statement (EphySQLiteStatement *statement)
+{
+  EphyHistoryHost *host =
+    ephy_history_host_new (ephy_sqlite_statement_get_column_as_string (statement, 1),
+                           ephy_sqlite_statement_get_column_as_string (statement, 2),
+                           ephy_sqlite_statement_get_column_as_int (statement, 3));
+  host->id = ephy_sqlite_statement_get_column_as_int (statement, 0);
+
+  return host;
+}
+
+GList*
+ephy_history_service_get_all_hosts (EphyHistoryService *self)
+{
+  EphyHistoryServicePrivate *priv = EPHY_HISTORY_SERVICE (self)->priv;
+  EphySQLiteStatement *statement = NULL;
+  GList *hosts = NULL;
+  GError *error = NULL;
+
+  g_assert (priv->history_thread == g_thread_self ());
+  g_assert (priv->history_database != NULL);
+
+  statement = ephy_sqlite_connection_create_statement (priv->history_database,
+      "SELECT id, url, title, visit_count FROM hosts", &error);
+
+  if (error) {
+    g_error ("Could not build hosts query statement: %s", error->message);
+    g_error_free (error);
+    return NULL;
+  }
+
+  while (ephy_sqlite_statement_step (statement, &error)) {
+    hosts = g_list_prepend (hosts, create_host_from_statement (statement));
+  }
+  hosts = g_list_reverse (hosts);
+
+  if (error) {
+    g_error ("Could not execute hosts table query statement: %s", error->message);
+    g_error_free (error);
+  }
+  g_object_unref (statement);
+
+  return hosts;
+}
+
+/* Inspired from ephy-history.c */
+static GList *
+get_hostname_and_locations (const gchar *url, gchar **hostname)
+{
+	GList *host_locations = NULL;
+	char *scheme = NULL;
+
+  if (url)
+	{
+		scheme = g_uri_parse_scheme (url);
+		*hostname = ephy_string_get_host_name (url);
+	}
+  /* Build an host name */
+  if (scheme == NULL || *hostname == NULL) {
+    *hostname = g_strdup (_("Others"));
+    host_locations = g_list_append (host_locations,
+                                    g_strdup ("about:blank"));
+  }  else if (strcmp (scheme, "file") == 0) {
+    *hostname = g_strdup (_("Local files"));
+    host_locations = g_list_append (host_locations,
+                                    g_strdup ("file:///"));
+  } else {
+    char *location;
+    char *tmp;
+
+    if (g_str_equal (scheme, "https")) {
+      /* If scheme is https, we still fake http. */
+      location = g_strconcat ("http://";, *hostname, "/", NULL);
+      host_locations = g_list_append (host_locations, location);
+    }
+
+    /* We append the real address */
+    location = g_strconcat (scheme,
+                            "://", *hostname, "/", NULL);
+    host_locations = g_list_append (host_locations, location);
+
+    /* and also a fake www-modified address if it's http or https. */
+    if (g_str_has_prefix (scheme, "http")) {
+      if (g_str_has_prefix (*hostname, "www.")) {
+        tmp = g_strdup (*hostname + 4);
+      } else {
+        tmp = g_strconcat ("www.", *hostname, NULL);
+      }
+      location = g_strconcat ("http://";, tmp, "/", NULL);
+      g_free (tmp);
+      host_locations = g_list_append (host_locations, location);
+    }
+  }
+  return host_locations;
+}
+
+EphyHistoryHost*
+ephy_history_service_get_host_row_from_url (EphyHistoryService *self,
+                                            const gchar *url)
+{
+  GList *host_locations, *l;
+  char *hostname;
+  EphyHistoryHost *host;
+
+  host_locations = get_hostname_and_locations (url, &hostname);
+
+  for (l = host_locations; l != NULL; l = l->next) {
+    host = ephy_history_service_get_host_row (self, l->data, NULL);
+    if (host != NULL)
+      break;
+  }
+
+  if (host == NULL) {
+    host = ephy_history_host_new (host_locations->data, hostname, 0);
+    ephy_history_service_add_host_row (self, host);
+  }
+
+  g_free (hostname);
+  g_list_free_full (host_locations, (GDestroyNotify) g_free);
+
+  return host;
+}
diff --git a/lib/history/ephy-history-service-private.h b/lib/history/ephy-history-service-private.h
index 94e8d8e..560e7b6 100644
--- a/lib/history/ephy-history-service-private.h
+++ b/lib/history/ephy-history-service-private.h
@@ -43,4 +43,11 @@ gboolean                 ephy_history_service_initialize_visits_table (EphyHisto
 void                     ephy_history_service_add_visit_row           (EphyHistoryService *self, EphyHistoryPageVisit *visit);
 GList *                  ephy_history_service_find_visit_rows         (EphyHistoryService *self, EphyHistoryQuery *query);
 
+gboolean                 ephy_history_service_initialize_hosts_table  (EphyHistoryService *self);
+void                     ephy_history_service_add_host_row            (EphyHistoryService *self, EphyHistoryHost *host);
+void                     ephy_history_service_update_host_row         (EphyHistoryService *self, EphyHistoryHost *host);
+EphyHistoryHost *        ephy_history_service_get_host_row            (EphyHistoryService *self, const gchar *url_string, EphyHistoryHost *host);
+GList *                  ephy_history_service_get_all_hosts           (EphyHistoryService *self);
+EphyHistoryHost *        ephy_history_service_get_host_row_from_url   (EphyHistoryService *self, const gchar *url);
+
 #endif /* EPHY_HISTORY_SERVICE_PRIVATE_H */
diff --git a/lib/history/ephy-history-service-urls-table.c b/lib/history/ephy-history-service-urls-table.c
index 56eb58c..61e8eb9 100644
--- a/lib/history/ephy-history-service-urls-table.c
+++ b/lib/history/ephy-history-service-urls-table.c
@@ -35,6 +35,7 @@ ephy_history_service_initialize_urls_table (EphyHistoryService *self)
   ephy_sqlite_connection_execute (priv->history_database,
     "CREATE TABLE urls ("
     "id INTEGER PRIMARY KEY,"
+    "host INTEGER NOT NULL REFERENCES hosts(id) ON DELETE CASCADE,"
     "url LONGVARCAR,"
     "title LONGVARCAR,"
     "visit_count INTEGER DEFAULT 0 NOT NULL,"
@@ -131,8 +132,8 @@ ephy_history_service_add_url_row (EphyHistoryService *self, EphyHistoryURL *url)
   g_assert (priv->history_database != NULL);
 
   statement = ephy_sqlite_connection_create_statement (priv->history_database,
-    "INSERT INTO urls (url, title, visit_count, typed_count, last_visit_time, zoom_level) "
-    " VALUES (?, ?, ?, ?, ?, ?)", &error);
+    "INSERT INTO urls (url, title, visit_count, typed_count, last_visit_time, zoom_level, host) "
+    " VALUES (?, ?, ?, ?, ?, ?, ?)", &error);
   if (error) {
     g_error ("Could not build urls table addition statement: %s", error->message);
     g_error_free (error);
@@ -144,7 +145,8 @@ ephy_history_service_add_url_row (EphyHistoryService *self, EphyHistoryURL *url)
       ephy_sqlite_statement_bind_int (statement, 2, url->visit_count, &error) == FALSE ||
       ephy_sqlite_statement_bind_int (statement, 3, url->typed_count, &error) == FALSE ||
       ephy_sqlite_statement_bind_int (statement, 4, url->last_visit_time, &error) == FALSE ||
-      ephy_sqlite_statement_bind_double (statement, 5, url->zoom_level, &error) == FALSE) {
+      ephy_sqlite_statement_bind_double (statement, 5, url->zoom_level, &error) == FALSE ||
+      ephy_sqlite_statement_bind_int (statement, 6, url->host->id, &error) == FALSE) {
     g_error ("Could not insert URL into urls table: %s", error->message);
     g_error_free (error);
     return;
diff --git a/lib/history/ephy-history-service.c b/lib/history/ephy-history-service.c
index aa12fa7..9fc9d63 100644
--- a/lib/history/ephy-history-service.c
+++ b/lib/history/ephy-history-service.c
@@ -267,7 +267,8 @@ ephy_history_service_open_database_connections (EphyHistoryService *self)
     return FALSE;
   }
 
-  if ((ephy_history_service_initialize_urls_table (self) == FALSE) || 
+  if ((ephy_history_service_initialize_hosts_table (self) == FALSE) ||
+      (ephy_history_service_initialize_urls_table (self) == FALSE) ||
       (ephy_history_service_initialize_visits_table (self) == FALSE)) {
     return FALSE;
   }
@@ -413,6 +414,13 @@ ephy_history_service_execute_job_on_history_thread (gpointer data)
 static gboolean
 ephy_history_service_execute_add_visit_helper (EphyHistoryService *self, EphyHistoryPageVisit *visit)
 {
+  if (visit->url->host == NULL) {
+    visit->url->host = ephy_history_service_get_host_row_from_url (self, visit->url->url);
+  }
+
+  visit->url->host->visit_count++;
+  ephy_history_service_update_host_row (self, visit->url->host);
+
   /* A NULL return here means that the URL does not yet exist in the database */
   if (NULL == ephy_history_service_get_url_row (self, visit->url->url, visit->url)) {
     visit->url->last_visit_time = visit->visit_time;



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