diff options
Diffstat (limited to 'telepathy-logger/log-store-sqlite.c')
-rw-r--r-- | telepathy-logger/log-store-sqlite.c | 992 |
1 files changed, 0 insertions, 992 deletions
diff --git a/telepathy-logger/log-store-sqlite.c b/telepathy-logger/log-store-sqlite.c deleted file mode 100644 index bd86340..0000000 --- a/telepathy-logger/log-store-sqlite.c +++ /dev/null @@ -1,992 +0,0 @@ -/* - * Copyright (C) 2010-2011 Collabora Ltd. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - * Authors: Danielle Madeley <danielle.madeley@collabora.co.uk> - * Cosimo Alfarano <cosimo.alfarano@collabora.co.uk> - * Nicolas Dufresne <nicolas.dufresne@collabora.co.uk> - */ - -#include <config.h> -#include "log-store-sqlite-internal.h" - -#include <string.h> - -#include <telepathy-glib/telepathy-glib.h> -#include <telepathy-glib/telepathy-glib-dbus.h> -#include <sqlite3.h> - -#include "event-internal.h" -#include "text-event.h" -#include "text-event-internal.h" -#include "entity-internal.h" -#include "log-manager-internal.h" - -#define DEBUG_FLAG TPL_DEBUG_LOG_STORE -#include "debug-internal.h" -#include "util-internal.h" - -#define TPL_LOG_STORE_SQLITE_NAME "Sqlite" - -static void log_store_iface_init (TplLogStoreInterface *iface); - -G_DEFINE_TYPE_WITH_CODE (TplLogStoreSqlite, _tpl_log_store_sqlite, - G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (TPL_TYPE_LOG_STORE, log_store_iface_init)); - -enum /* properties */ -{ - PROP_0, - PROP_READABLE, -}; - -struct _TplLogStoreSqlitePrivate -{ - sqlite3 *db; -}; - -static GObject *singleton = NULL; - - -static GObject * -tpl_log_store_sqlite_constructor (GType type, - guint n_props, - GObjectConstructParam *props) -{ - if (singleton != NULL) - g_object_ref (singleton); - else - { - singleton = - G_OBJECT_CLASS (_tpl_log_store_sqlite_parent_class)->constructor ( - type, n_props, props); - - if (singleton == NULL) - return NULL; - - g_object_add_weak_pointer (singleton, (gpointer *) &singleton); - } - - return singleton; -} - - -static char * -get_db_filename (void) -{ - return g_build_filename (g_get_user_cache_dir (), - "telepathy", - "logger", - "sqlite-data", - NULL); -} - - -static void -tpl_log_store_sqlite_get_property (GObject *self, - guint id, - GValue *value, - GParamSpec *pspec) -{ - switch (id) - { - case PROP_READABLE: - /* this store should never be queried by the LogManager */ - g_value_set_boolean (value, FALSE); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (self, id, pspec); - break; - } -} - - -static void -purge_pending_messages (TplLogStoreSqlitePrivate *priv, - GTimeSpan delta, - GError **error) -{ - sqlite3_stmt *sql = NULL; - GDateTime *now; - GDateTime *timestamp; - gchar *date; - int e; - - g_return_if_fail (error == NULL || *error == NULL); - - now = g_date_time_new_now_utc (); - timestamp = g_date_time_add (now, -(delta * G_TIME_SPAN_SECOND)); - - date = g_date_time_format (timestamp, - TPL_LOG_STORE_SQLITE_TIMESTAMP_FORMAT); - - g_date_time_unref (now); - - DEBUG ("Purging entries older than %s (%u seconds ago)", date, (guint) delta); - - e = sqlite3_prepare_v2 (priv->db, - "DELETE FROM pending_messages WHERE timestamp<?", - -1, &sql, NULL); - - if (e != SQLITE_OK) - { - g_set_error (error, TPL_LOG_STORE_ERROR, - TPL_LOG_STORE_ERROR_ADD_EVENT, - "SQL Error preparing statement in %s: %s", G_STRFUNC, - sqlite3_errmsg (priv->db)); - - goto out; - } - - sqlite3_bind_int64 (sql, 1, g_date_time_to_unix (timestamp)); - - e = sqlite3_step (sql); - if (e != SQLITE_DONE) - { - g_set_error (error, TPL_LOG_STORE_ERROR, - TPL_LOG_STORE_ERROR_ADD_EVENT, - "SQL Error in %s: %s", G_STRFUNC, sqlite3_errmsg (priv->db)); - } - -out: - g_date_time_unref (timestamp); - - if (sql != NULL) - sqlite3_finalize (sql); - - g_free (date); -} - - -static void -_tpl_log_store_sqlite_init (TplLogStoreSqlite *self) -{ - TplLogStoreSqlitePrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (self, - TPL_TYPE_LOG_STORE_SQLITE, TplLogStoreSqlitePrivate); - char *filename = get_db_filename (); - int e; - char *errmsg = NULL; - GError *error = NULL; - - self->priv = priv; - - DEBUG ("cache file is '%s'", filename); - - /* counter & cache tables - common part */ - /* check to see if the sqlite db exists */ - if (!g_file_test (filename, G_FILE_TEST_EXISTS)) - { - char *dirname = g_path_get_dirname (filename); - - DEBUG ("Creating cache"); - - g_mkdir_with_parents (dirname, 0700); - g_free (dirname); - } - - e = sqlite3_open_v2 (filename, &priv->db, - SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, - NULL); - if (e != SQLITE_OK) - { - CRITICAL ("Failed to open Sqlite3 DB: %s\n", - sqlite3_errmsg (priv->db)); - goto out; - } - /* end of common part */ - - /* start of cache table init */ - - /* drop deprecated table (since 0.2.6) */ - sqlite3_exec (priv->db, "DROP TABLE IF EXISTS message_cache", - NULL, NULL, &errmsg); - if (errmsg != NULL) - { - CRITICAL ("Failed to drop deprecated message_cache table: %s\n", errmsg); - sqlite3_free (errmsg); - goto out; - } - - sqlite3_exec (priv->db, "CREATE TABLE IF NOT EXISTS pending_messages ( " - "channel TEXT NOT NULL, " - "id INTEGER, " - "timestamp INTEGER)", - NULL, NULL, &errmsg); - if (errmsg != NULL) - { - CRITICAL ("Failed to create table pending_messages: %s\n", errmsg); - sqlite3_free (errmsg); - goto out; - } - - /* purge old entries */ - purge_pending_messages (priv, - TPL_LOG_STORE_SQLITE_CLEANUP_DELTA_LIMIT, &error); - if (error != NULL) - { - CRITICAL ("Failed to purge pending messages: %s", error->message); - g_error_free (error); - goto out; - } - - /* end of cache table init */ - - /* start of counter table init */ - sqlite3_exec (priv->db, - "CREATE TABLE IF NOT EXISTS messagecounts (" - "account TEXT, " - "identifier TEXT, " - "chatroom BOOLEAN, " - "date DATE, " - "messages INTEGER)", - NULL, - NULL, - &errmsg); - if (errmsg != NULL) - { - CRITICAL ("Failed to create table messagecounts: %s\n", errmsg); - sqlite3_free (errmsg); - goto out; - } - /* end of counter table init */ - -out: - g_free (filename); -} - - -static void -tpl_log_store_sqlite_dispose (GObject *self) -{ - TplLogStoreSqlitePrivate *priv = TPL_LOG_STORE_SQLITE (self)->priv; - - if (priv->db != NULL) - { - sqlite3_close (priv->db); - priv->db = NULL; - } - - G_OBJECT_CLASS (_tpl_log_store_sqlite_parent_class)->dispose (self); -} - - -static void -_tpl_log_store_sqlite_class_init (TplLogStoreSqliteClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - - gobject_class->constructor = tpl_log_store_sqlite_constructor; - gobject_class->get_property = tpl_log_store_sqlite_get_property; - gobject_class->dispose = tpl_log_store_sqlite_dispose; - - g_object_class_override_property (gobject_class, PROP_READABLE, "readable"); - - g_type_class_add_private (gobject_class, sizeof (TplLogStoreSqlitePrivate)); -} - - -static const char * -get_account_name (TpAccount *account) -{ - return tp_proxy_get_object_path (account) + - strlen (TP_ACCOUNT_OBJECT_PATH_BASE); -} - - -static const char * -get_account_name_from_event (TplEvent *event) -{ - return tpl_event_get_account_path (event) + - strlen (TP_ACCOUNT_OBJECT_PATH_BASE); -} - - -static const char * -get_channel_name (TpChannel *chan) -{ - return tp_proxy_get_object_path (chan) + - strlen (TP_CONN_OBJECT_PATH_BASE); -} - - -static char * -get_date (TplEvent *event) -{ - GDateTime *ts; - gchar *date; - - ts = g_date_time_new_from_unix_utc (tpl_event_get_timestamp (event)); - g_return_val_if_fail (ts != NULL, NULL); - date = g_date_time_format (ts, "%Y-%m-%d"); - - g_date_time_unref (ts); - - return date; -} - - -static char * -get_datetime (gint64 timestamp) -{ - GDateTime *ts; - gchar *date; - - ts = g_date_time_new_from_unix_utc (timestamp); - date = g_date_time_format (ts, TPL_LOG_STORE_SQLITE_TIMESTAMP_FORMAT); - - g_date_time_unref (ts); - - return date; -} - - -static const char * -tpl_log_store_sqlite_get_name (TplLogStore *self) -{ - return TPL_LOG_STORE_SQLITE_NAME; -} - - -static gboolean -tpl_log_store_sqlite_add_message_counter (TplLogStore *self, - TplEvent *message, - GError **error) -{ - TplLogStoreSqlitePrivate *priv = TPL_LOG_STORE_SQLITE (self)->priv; - const char *account, *identifier; - gboolean chatroom; - char *date = NULL; - int count = 0; - sqlite3_stmt *sql = NULL; - gboolean retval = FALSE; - gboolean insert = FALSE; - int e; - - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - if (TPL_IS_TEXT_EVENT (message) == FALSE) - { - DEBUG ("ignoring non-text event not intersting for message-counter"); - retval = TRUE; - goto out; - } - - DEBUG ("message received"); - - account = get_account_name_from_event (message); - identifier = _tpl_event_get_target_id (message); - chatroom = _tpl_event_target_is_room (message); - date = get_date (message); - - DEBUG ("account = %s", account); - DEBUG ("identifier = %s", identifier); - DEBUG ("chatroom = %i", chatroom); - DEBUG ("date = %s", date); - - /* get the existing row */ - e = sqlite3_prepare_v2 (priv->db, - "SELECT messages FROM messagecounts WHERE " - "account=? AND " - "identifier=? AND " - "chatroom=? AND " - "date=date(?)", - -1, &sql, NULL); - if (e != SQLITE_OK) - { - g_set_error (error, TPL_LOG_STORE_ERROR, - TPL_LOG_STORE_ERROR_ADD_EVENT, - "SQL Error checking current counter in %s: %s", G_STRFUNC, - sqlite3_errmsg (priv->db)); - - goto out; - } - - sqlite3_bind_text (sql, 1, account, -1, SQLITE_TRANSIENT); - sqlite3_bind_text (sql, 2, identifier, -1, SQLITE_TRANSIENT); - sqlite3_bind_int (sql, 3, chatroom); - sqlite3_bind_text (sql, 4, date, -1, SQLITE_TRANSIENT); - - e = sqlite3_step (sql); - if (e == SQLITE_DONE) - { - DEBUG ("no rows, insert"); - insert = TRUE; - } - else if (e == SQLITE_ROW) - { - count = sqlite3_column_int (sql, 0); - DEBUG ("got row, count = %i", count); - } - else - { - g_set_error (error, TPL_LOG_STORE_ERROR, - TPL_LOG_STORE_ERROR_ADD_EVENT, - "SQL Error binding counter checking query in %s: %s", G_STRFUNC, - sqlite3_errmsg (priv->db)); - - goto out; - } - - sqlite3_finalize (sql); - sql = NULL; - - /* increment the message count */ - count++; - - DEBUG ("new count = %i, insert = %i", count, insert); - - /* update table with new message count */ - if (insert) - e = sqlite3_prepare_v2 (priv->db, - "INSERT INTO messagecounts " - "(messages, account, identifier, chatroom, date) " - "VALUES (?, ?, ?, ?, date(?))", - -1, &sql, NULL); - else - e = sqlite3_prepare_v2 (priv->db, - "UPDATE messagecounts SET messages=? WHERE " - "account=? AND " - "identifier=? AND " - "chatroom=? AND " - "date=date(?)", - -1, &sql, NULL); - - if (e != SQLITE_OK) - { - g_set_error (error, TPL_LOG_STORE_ERROR, - TPL_LOG_STORE_ERROR_ADD_EVENT, - "SQL Error preparing query in %s: %s", G_STRFUNC, - sqlite3_errmsg (priv->db)); - - goto out; - } - - sqlite3_bind_int (sql, 1, count); - sqlite3_bind_text (sql, 2, account, -1, SQLITE_TRANSIENT); - sqlite3_bind_text (sql, 3, identifier, -1, SQLITE_TRANSIENT); - sqlite3_bind_int (sql, 4, chatroom); - sqlite3_bind_text (sql, 5, date, -1, SQLITE_TRANSIENT); - - e = sqlite3_step (sql); - if (e != SQLITE_DONE) - { - g_set_error (error, TPL_LOG_STORE_ERROR, - TPL_LOG_STORE_ERROR_ADD_EVENT, - "SQL Error %s counter in %s: %s", - (insert ? "inserting new" : "updating"), - G_STRFUNC, sqlite3_errmsg (priv->db)); - - goto out; - } - - retval = TRUE; - -out: - g_free (date); - - if (sql != NULL) - sqlite3_finalize (sql); - - /* check that we set an error if appropriate */ - g_assert ((retval == TRUE && *error == NULL) || - (retval == FALSE && *error != NULL)); - - return retval; -} - - -/** - * tpl_log_store_sqlite_add_event: - * @self: TplLogstoreSqlite instance - * @message: a TplEvent instance - * @error: memory pointer use in case of error - * - * Text messages will be accounted for statistics purpose. - * - * Returns: %TRUE if @self was able to store, %FALSE with @error set if an error occurred. - */ -static gboolean -tpl_log_store_sqlite_add_event (TplLogStore *self, - TplEvent *message, - GError **error) -{ - gboolean retval = FALSE; - - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - if (!TPL_IS_LOG_STORE_SQLITE (self)) - { - g_set_error (error, TPL_LOG_STORE_ERROR, - TPL_LOG_STORE_ERROR_ADD_EVENT, - "TplLogStoreSqlite intance needed"); - goto out; - } - - if (!TPL_IS_EVENT (message)) - { - g_set_error (error, TPL_LOG_STORE_ERROR, - TPL_LOG_STORE_ERROR_ADD_EVENT, "TplEvent instance needed"); - goto out; - } - - retval = tpl_log_store_sqlite_add_message_counter (self, message, error); - -out: - /* check that we set an error if appropriate */ - g_assert ((retval == TRUE && *error == NULL) || - (retval == FALSE && *error != NULL)); - - DEBUG ("returning with %d", retval); - return retval; -} - - -static GList * -tpl_log_store_sqlite_get_entities (TplLogStore *self, - TpAccount *account) -{ - TplLogStoreSqlitePrivate *priv = TPL_LOG_STORE_SQLITE (self)->priv; - sqlite3_stmt *sql = NULL; - int e; - GList *list = NULL; - const char *account_name = get_account_name (account); - - DEBUG ("account = %s", account_name); - - /* list all the identifiers known to the database */ - e = sqlite3_prepare_v2 (priv->db, - "SELECT DISTINCT identifier, chatroom FROM messagecounts WHERE " - "account=?", - -1, &sql, NULL); - if (e != SQLITE_OK) - { - DEBUG ("Failed to prepare SQL: %s", - sqlite3_errmsg (priv->db)); - - goto out; - } - - sqlite3_bind_text (sql, 1, account_name, -1, SQLITE_TRANSIENT); - - while ((e = sqlite3_step (sql)) == SQLITE_ROW) - { - TplEntity *entity; - const char *identifier; - gboolean chatroom; - TplEntityType type; - - /* for some reason this returns unsigned char */ - identifier = (const char *) sqlite3_column_text (sql, 0); - chatroom = sqlite3_column_int (sql, 1); - type = chatroom ? TPL_ENTITY_ROOM : TPL_ENTITY_CONTACT; - - DEBUG ("identifier = %s, chatroom = %i", identifier, chatroom); - - entity = tpl_entity_new (identifier, type, NULL, NULL); - - list = g_list_prepend (list, entity); - } - if (e != SQLITE_DONE) - { - DEBUG ("Failed to execute SQL: %s", - sqlite3_errmsg (priv->db)); - goto out; - } - -out: - if (sql != NULL) - sqlite3_finalize (sql); - - return list; -} - -static void -log_store_iface_init (TplLogStoreInterface *iface) -{ - iface->get_name = tpl_log_store_sqlite_get_name; - iface->add_event = tpl_log_store_sqlite_add_event; - iface->get_entities = tpl_log_store_sqlite_get_entities; -} - -TplLogStore * -_tpl_log_store_sqlite_dup (void) -{ - return g_object_new (TPL_TYPE_LOG_STORE_SQLITE, NULL); -} - - -/** - * _tpl_log_store_sqlite_get_pending_messages: - * @self: a TplLogStoreSqlite instance - * @channel: a pointer to a TpChannel - * @error: set if an error occurs - * - * Returns the list of pending message IDs and timestamp for this @channel. - * Note that those message might not be valid anymore, check timestamp match - * before assuming a message is not new. - * - * Returns: (transfer full): a #GList of #TplLogStoreSqlitePendingMessage - */ -GList * -_tpl_log_store_sqlite_get_pending_messages (TplLogStore *self, - TpChannel *channel, - GError **error) -{ - TplLogStoreSqlitePrivate *priv = TPL_LOG_STORE_SQLITE (self)->priv; - sqlite3_stmt *sql = NULL; - GList *retval = NULL; - int e; - - g_return_val_if_fail (TPL_IS_LOG_STORE_SQLITE (self), NULL); - g_return_val_if_fail (TP_IS_CHANNEL (channel), NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); - - DEBUG ("Listing pending messages for channel %s", - get_channel_name (channel)); - - e = sqlite3_prepare_v2 (priv->db, "SELECT id,timestamp " - "FROM pending_messages " - "WHERE channel=? " - "ORDER BY id ASC", - -1, &sql, NULL); - - if (e != SQLITE_OK) - { - CRITICAL ("Error preparing SQL for pending messages list: %s", - sqlite3_errmsg (priv->db)); - g_set_error (error, TPL_LOG_STORE_SQLITE_ERROR, - TPL_LOG_STORE_SQLITE_ERROR_GET_PENDING_MESSAGES, - "SQL Error in %s: %s", G_STRFUNC, sqlite3_errmsg (priv->db)); - goto out; - } - - sqlite3_bind_text (sql, 1, get_channel_name (channel), -1, - SQLITE_TRANSIENT); - - while (SQLITE_ROW == (e = sqlite3_step (sql))) - { - /* create the pending messages list */ - TplPendingMessage *pending; - - pending = g_new (TplPendingMessage, 1); - - pending->id = (guint) sqlite3_column_int64 (sql, 0); - pending->timestamp = sqlite3_column_int64 (sql, 1); - - DEBUG (" - pending id=%u timestamp=%"G_GINT64_FORMAT, - pending->id, pending->timestamp); - - retval = g_list_prepend (retval, pending); - } - - if (e != SQLITE_DONE) - { - g_set_error (error, TPL_LOG_STORE_SQLITE_ERROR, - TPL_LOG_STORE_SQLITE_ERROR_GET_PENDING_MESSAGES, - "SQL Error in %s: %s", G_STRFUNC, sqlite3_errmsg (priv->db)); - - /* free partial result, which might be misleading */ - g_list_foreach (retval, (GFunc) g_free, NULL); - g_list_free (retval); - retval = NULL; - } - -out: - if (sql != NULL) - sqlite3_finalize (sql); - - /* check that we set an error if appropriate - * NOTE: retval == NULL && *error != - * NULL doesn't apply to this method, since NULL is also for an empty list */ - g_assert ((retval != NULL && *error == NULL) || retval == NULL); - - return retval; -} - - -/** - *_tpl_log_store_sqlite_remove_pending_messages: - * @self: a #TplLogStore - * @channel: a #TpAccount - * @pending_ids: a #GList of pending message IDs (guint) - * @error: a #GError to be set on error, or NULL - * - * Removes listed pending IDs for @channel. - * - * Returns: #TRUE on success, #FALSE on error with @error set - */ -gboolean -_tpl_log_store_sqlite_remove_pending_messages (TplLogStore *self, - TpChannel *channel, - GList *pending_ids, - GError **error) -{ - TplLogStoreSqlitePrivate *priv = TPL_LOG_STORE_SQLITE (self)->priv; - gboolean retval = TRUE; - GString *query = NULL; - GList *it; - sqlite3_stmt *sql = NULL; - - g_return_val_if_fail (TPL_IS_LOG_STORE_SQLITE (self), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - g_return_val_if_fail (pending_ids != NULL, FALSE); - - DEBUG ("Removing pending messages for channel %s", - get_channel_name (channel)); - - query = g_string_new ("DELETE FROM pending_messages WHERE "); - - g_string_append_printf (query, "channel='%s' AND id IN (%u", - get_channel_name (channel), GPOINTER_TO_UINT (pending_ids->data)); - - DEBUG (" - pending_id: %u", GPOINTER_TO_UINT (pending_ids->data)); - - for (it = g_list_next (pending_ids); it != NULL; it = g_list_next (it)) - { - DEBUG (" - pending_id: %u", GPOINTER_TO_UINT (it->data)); - g_string_append_printf (query, ",%u", GPOINTER_TO_UINT (it->data)); - } - - g_string_append (query, ")"); - - if (sqlite3_prepare_v2 (priv->db, query->str, -1, &sql, NULL) != SQLITE_OK) - { - g_set_error (error, TPL_LOG_STORE_SQLITE_ERROR, - TPL_LOG_STORE_SQLITE_ERROR_REMOVE_PENDING_MESSAGES, - "SQL Error in %s: %s", G_STRFUNC, sqlite3_errmsg (priv->db)); - retval = FALSE; - goto out; - } - - if (sqlite3_step (sql) != SQLITE_DONE) - { - g_set_error (error, TPL_LOG_STORE_SQLITE_ERROR, - TPL_LOG_STORE_SQLITE_ERROR_REMOVE_PENDING_MESSAGES, - "SQL Error in %s: %s", G_STRFUNC, sqlite3_errmsg (priv->db)); - retval = FALSE; - goto out; - } - -out: - if (query != NULL) - g_string_free (query, TRUE); - - if (sql != NULL) - sqlite3_finalize (sql); - - return retval; -} - -/** - *_tpl_log_store_sqlite_add_pending_message: - * @self: a #TplLogStore - * @channel: a #TpChannel - * @pending_msg_id: the pending message ID - * @timestamp: a unix utc timestamp - * @error: a #GError to be set on error, or NULL - * - * Add an entry to the list of pending message. - * - * Returns: #TRUE on success, #FALSE on error with @error set - */ -gboolean -_tpl_log_store_sqlite_add_pending_message (TplLogStore *self, - TpChannel *channel, - guint id, - gint64 timestamp, - GError **error) -{ - TplLogStoreSqlitePrivate *priv = TPL_LOG_STORE_SQLITE (self)->priv; - gboolean retval = FALSE; - const gchar *channel_path; - gchar *date = NULL; - sqlite3_stmt *sql = NULL; - int e; - - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - channel_path = get_channel_name (channel); - date = get_datetime (timestamp); - - DEBUG ("Caching pending message %u", id); - DEBUG (" - channel = %s", channel_path); - DEBUG (" - date = %s", date); - - if (TPL_STR_EMPTY (channel_path) - || timestamp <= 0) - { - g_set_error_literal (error, TPL_LOG_STORE_ERROR, - TPL_LOG_STORE_SQLITE_ERROR_ADD_PENDING_MESSAGE, - "passed LogStore has at least one of the needed properties unset: " - "channel-path, timestamp"); - goto out; - } - - e = sqlite3_prepare_v2 (priv->db, - "INSERT INTO pending_messages (channel, id, timestamp) VALUES (?, ?, ?)", - -1, &sql, NULL); - if (e != SQLITE_OK) - { - g_set_error (error, TPL_LOG_STORE_ERROR, - TPL_LOG_STORE_SQLITE_ERROR_ADD_PENDING_MESSAGE, - "SQL Error in %s: %s", G_STRFUNC, sqlite3_errmsg (priv->db)); - goto out; - } - - sqlite3_bind_text (sql, 1, channel_path, -1, SQLITE_TRANSIENT); - sqlite3_bind_int (sql, 2, (gint) id); - sqlite3_bind_int64 (sql, 3, timestamp); - - e = sqlite3_step (sql); - if (e != SQLITE_DONE) - { - g_set_error (error, TPL_LOG_STORE_ERROR, - TPL_LOG_STORE_SQLITE_ERROR_ADD_PENDING_MESSAGE, - "SQL Error bind in %s: %s", G_STRFUNC, sqlite3_errmsg (priv->db)); - goto out; - } - - retval = TRUE; - -out: - g_free (date); - - if (sql != NULL) - sqlite3_finalize (sql); - - /* check that we set an error if appropriate */ - g_assert ((retval == TRUE && *error == NULL) || - (retval == FALSE && *error != NULL)); - - return retval; -} - - -gint64 -_tpl_log_store_sqlite_get_most_recent (TplLogStoreSqlite *self, - TpAccount *account, - const char *identifier) -{ - TplLogStoreSqlitePrivate *priv = TPL_LOG_STORE_SQLITE (self)->priv; - sqlite3_stmt *sql = NULL; - int e; - gint64 date = -1;; - const char *account_name; - - account_name = get_account_name (account); - - /* this SQL gets this most recent date for a single identifier */ - e = sqlite3_prepare_v2 (priv->db, - "SELECT STRFTIME('%s', date) FROM messagecounts WHERE " - "account=? AND " - "identifier=? " - "ORDER BY date DESC LIMIT 1", - -1, &sql, NULL); - if (e != SQLITE_OK) - { - DEBUG ("Failed to prepare SQL: %s", - sqlite3_errmsg (priv->db)); - - goto out; - } - - sqlite3_bind_text (sql, 1, account_name, -1, SQLITE_TRANSIENT); - sqlite3_bind_text (sql, 2, identifier, -1, SQLITE_TRANSIENT); - - e = sqlite3_step (sql); - if (e == SQLITE_DONE) - { - DEBUG ("no rows (account identifer doesn't exist?)"); - } - else if (e == SQLITE_ROW) - { - date = sqlite3_column_int64 (sql, 0); - DEBUG ("got row, date = %" G_GINT64_FORMAT, date); - } - else - { - DEBUG ("Failed to execute SQL: %s", - sqlite3_errmsg (priv->db)); - - goto out; - } - -out: - - if (sql != NULL) - sqlite3_finalize (sql); - - return date; -} - - -double -_tpl_log_store_sqlite_get_frequency (TplLogStoreSqlite *self, - TpAccount *account, - const char *identifier) -{ - TplLogStoreSqlitePrivate *priv = TPL_LOG_STORE_SQLITE (self)->priv; - sqlite3_stmt *sql = NULL; - int e; - double freq = -1.; - const char *account_name; - - account_name = get_account_name (account); - - /* this SQL query builds the frequency for a single identifier */ - e = sqlite3_prepare_v2 (priv->db, - "SELECT SUM(messages / ROUND(JULIANDAY('now') - JULIANDAY(date) + 1)) " - "FROM messagecounts WHERE " - "account=? AND " - "identifier=?", - -1, &sql, NULL); - if (e != SQLITE_OK) - { - DEBUG ("Failed to prepare SQL: %s", - sqlite3_errmsg (priv->db)); - - goto out; - } - - sqlite3_bind_text (sql, 1, account_name, -1, SQLITE_TRANSIENT); - sqlite3_bind_text (sql, 2, identifier, -1, SQLITE_TRANSIENT); - - e = sqlite3_step (sql); - if (e == SQLITE_DONE) - { - DEBUG ("no rows (account identifer doesn't exist?)"); - } - else if (e == SQLITE_ROW) - { - freq = sqlite3_column_double (sql, 0); - DEBUG ("got row, freq = %g", freq); - } - else - { - DEBUG ("Failed to execute SQL: %s", - sqlite3_errmsg (priv->db)); - - goto out; - } - -out: - - if (sql != NULL) - sqlite3_finalize (sql); - - return freq; -} |