diff options
Add EphyHistoryService and helper classes
EphyHistoryService provides a high-level API to store history
information. It will processed by a worker thread using SQLite to
provide a fast, responsive service to the main UI.
Based on the code by Martin Robinson (mrobinson@igalia.com) and
Claudio Saavedra (csaavedra@igalia.com).
Diffstat (limited to 'lib/history/ephy-history-service-urls-table.c')
-rw-r--r-- | lib/history/ephy-history-service-urls-table.c | 371 |
1 files changed, 371 insertions, 0 deletions
diff --git a/lib/history/ephy-history-service-urls-table.c b/lib/history/ephy-history-service-urls-table.c new file mode 100644 index 000000000..3c7834bb8 --- /dev/null +++ b/lib/history/ephy-history-service-urls-table.c @@ -0,0 +1,371 @@ +/* -*- 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" + +gboolean +ephy_history_service_initialize_urls_table (EphyHistoryService *self) +{ + EphyHistoryServicePrivate *priv = EPHY_HISTORY_SERVICE (self)->priv; + GError *error = NULL; + + if (ephy_sqlite_connection_table_exists (priv->history_database, "visits")) { + return TRUE; + } + 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," + "typed_count INTEGER DEFAULT 0 NOT NULL," + "last_visit_time INTEGER," + "zoom_level REAL DEFAULT 1.0)", &error); + + if (error) { + g_error("Could not create urls table: %s", error->message); + g_error_free (error); + return FALSE; + } + ephy_history_service_schedule_commit (self); + return TRUE; +} + +EphyHistoryURL * +ephy_history_service_get_url_row (EphyHistoryService *self, const char *url_string, EphyHistoryURL *url) +{ + 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 (url_string == NULL && url != NULL) { + url_string = url->url; + } + g_assert (url_string || url->id != -1); + + if (url != NULL && url->id != -1) { + statement = ephy_sqlite_connection_create_statement (priv->history_database, + "SELECT id, url, title, visit_count, typed_count, last_visit_time, zoom_level FROM urls " + "WHERE id=?", &error); + } else { + statement = ephy_sqlite_connection_create_statement (priv->history_database, + "SELECT id, url, title, visit_count, typed_count, last_visit_time, zoom_level FROM urls " + "WHERE url=?", &error); + } + + if (error) { + g_error ("Could not build urls table query statement: %s", error->message); + g_error_free (error); + return NULL; + } + + if (url != NULL && url->id != -1) { + ephy_sqlite_statement_bind_int (statement, 0, url->id, &error); + } else { + ephy_sqlite_statement_bind_string (statement, 0, url_string, &error); + } + if (error) { + g_error ("Could not build urls 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 (url == NULL) { + url = ephy_history_url_new (NULL, NULL, 0, 0, 0, 1.0); + } else { + if (url->url) + g_free (url->url); + if (url->title) + g_free (url->title); + } + + url->id = ephy_sqlite_statement_get_column_as_int (statement, 0); + url->url = g_strdup (ephy_sqlite_statement_get_column_as_string (statement, 1)), + url->title = g_strdup (ephy_sqlite_statement_get_column_as_string (statement, 2)), + url->visit_count = ephy_sqlite_statement_get_column_as_int (statement, 3), + url->typed_count = ephy_sqlite_statement_get_column_as_int (statement, 4), + url->last_visit_time = ephy_sqlite_statement_get_column_as_int (statement, 5); + url->zoom_level = ephy_sqlite_statement_get_column_as_double (statement, 6); + + g_object_unref (statement); + return url; +} + +void +ephy_history_service_add_url_row (EphyHistoryService *self, EphyHistoryURL *url) +{ + 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 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); + return; + } + + if (ephy_sqlite_statement_bind_string (statement, 0, url->url, &error) == FALSE || + ephy_sqlite_statement_bind_string (statement, 1, url->title, &error) == FALSE || + 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_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; + } + + ephy_sqlite_statement_step (statement, &error); + if (error) { + g_error ("Could not insert URL into urls table: %s", error->message); + g_error_free (error); + } else { + url->id = ephy_sqlite_connection_get_last_insert_id (priv->history_database); + } + + g_object_unref (statement); +} + +void +ephy_history_service_update_url_row (EphyHistoryService *self, EphyHistoryURL *url) +{ + 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 urls SET title=?, visit_count=?, typed_count=?, last_visit_time=?, zoom_level=? " + "WHERE id=?", &error); + if (error) { + g_error ("Could not build urls table modification statement: %s", error->message); + g_error_free (error); + return; + } + + if (ephy_sqlite_statement_bind_string (statement, 0, url->title, &error) == FALSE || + ephy_sqlite_statement_bind_int (statement, 1, url->visit_count, &error) == FALSE || + ephy_sqlite_statement_bind_int (statement, 2, url->typed_count, &error) == FALSE || + ephy_sqlite_statement_bind_int (statement, 3, url->last_visit_time, &error) == FALSE || + ephy_sqlite_statement_bind_double (statement, 4, url->zoom_level, &error) == FALSE || + ephy_sqlite_statement_bind_int (statement, 5, url->id, &error) == FALSE) { + g_error ("Could not modify URL in urls 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); +} + +static EphyHistoryURL * +create_url_from_statement (EphySQLiteStatement *statement) +{ + EphyHistoryURL *url = ephy_history_url_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), + ephy_sqlite_statement_get_column_as_int (statement, 4), + ephy_sqlite_statement_get_column_as_int (statement, 5), + ephy_sqlite_statement_get_column_as_int (statement, 6)); + + url->id = ephy_sqlite_statement_get_column_as_int (statement, 0); + url->host = ephy_history_host_new (NULL, NULL, 0); + url->host->id = ephy_sqlite_statement_get_column_as_int (statement, 7); + + return url; +} + +GList * +ephy_history_service_find_url_rows (EphyHistoryService *self, EphyHistoryQuery *query) +{ + EphyHistoryServicePrivate *priv = EPHY_HISTORY_SERVICE (self)->priv; + EphySQLiteStatement *statement = NULL; + GList *substring; + GString *statement_str; + GList *urls = NULL; + GError *error = NULL; + const char *base_statement = "" + "SELECT " + "DISTINCT urls.id, " + "urls.url, " + "urls.title, " + "urls.visit_count, " + "urls.typed_count, " + "urls.last_visit_time, " + "urls.zoom_level, " + "urls.host " + "FROM " + "urls JOIN visits ON visits.url = urls.id " + "WHERE "; + + int i = 0; + + g_assert (priv->history_thread == g_thread_self ()); + g_assert (priv->history_database != NULL); + + statement_str = g_string_new (base_statement); + + if (query->from >= 0) + statement_str = g_string_append (statement_str, "visits.visit_time >= ? AND "); + if (query->to >= 0) + statement_str = g_string_append (statement_str, "visits.visit_time <= ? AND "); + + for (substring = query->substring_list; substring != NULL; substring = substring->next) + statement_str = g_string_append (statement_str, "(urls.url LIKE ? OR urls.title LIKE ?) AND "); + + statement_str = g_string_append (statement_str, "1"); + + statement = ephy_sqlite_connection_create_statement (priv->history_database, + statement_str->str, &error); + g_string_free (statement_str, TRUE); + + if (error) { + g_error ("Could not build urls table query statement: %s", error->message); + g_error_free (error); + g_object_unref (statement); + return NULL; + } + + if (query->from >= 0) { + if (ephy_sqlite_statement_bind_int (statement, i++, (int)query->from, &error) == FALSE) { + g_error ("Could not build urls table query statement: %s", error->message); + g_error_free (error); + g_object_unref (statement); + return NULL; + } + } + if (query->to >= 0) { + if (ephy_sqlite_statement_bind_int (statement, i++, (int)query->to, &error) == FALSE) { + g_error ("Could not build urls table query statement: %s", error->message); + g_error_free (error); + g_object_unref (statement); + return NULL; + } + } + for (substring = query->substring_list; substring != NULL; substring = substring->next) { + char *string = g_strdup_printf ("%%%s%%", (char*)substring->data); + if (ephy_sqlite_statement_bind_string (statement, i++, string, &error) == FALSE) { + g_error ("Could not build urls table query statement: %s", error->message); + g_error_free (error); + g_object_unref (statement); + g_free (string); + return NULL; + } + if (ephy_sqlite_statement_bind_string (statement, i++, string, &error) == FALSE) { + g_error ("Could not build urls table query statement: %s", error->message); + g_error_free (error); + g_object_unref (statement); + g_free (string); + return NULL; + } + g_free (string); + } + + while (ephy_sqlite_statement_step (statement, &error)) + urls = g_list_prepend (urls, create_url_from_statement (statement)); + + urls = g_list_reverse (urls); + + if (error) { + g_error ("Could not execute urls table query statement: %s", error->message); + g_error_free (error); + g_object_unref (statement); + g_list_free_full (urls, (GDestroyNotify)ephy_history_url_free); + return NULL; + } + + g_object_unref (statement); + return urls; +} + +void +ephy_history_service_delete_url (EphyHistoryService *self, EphyHistoryURL *url) +{ + EphyHistoryServicePrivate *priv = EPHY_HISTORY_SERVICE (self)->priv; + EphySQLiteStatement *statement = NULL; + gchar *sql_statement; + GError *error = NULL; + + g_assert (priv->history_thread == g_thread_self ()); + g_assert (priv->history_database != NULL); + + g_assert (url->id != -1 || url->url); + + if (url->id != -1) + sql_statement = g_strdup ("DELETE FROM urls WHERE id=?"); + else + sql_statement = g_strdup ("DELETE FROM urls WHERE url=?"); + + statement = ephy_sqlite_connection_create_statement (priv->history_database, + sql_statement, &error); + g_free (sql_statement); + + if (error) { + g_error ("Could not build urls table query statement: %s", error->message); + g_error_free (error); + g_object_unref (statement); + return; + } + + if (url->id != -1) + ephy_sqlite_statement_bind_int (statement, 0, url->id, &error); + else + ephy_sqlite_statement_bind_string (statement, 0, url->url, &error); + + if (error) { + g_error ("Could not build urls table query statement: %s", error->message); + g_error_free (error); + g_object_unref (statement); + 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); +} |