[evolution-data-server] Provide database file name in SQLITE_CORRUPT error message



commit 2e18d2f2b64b1c98beeef8ec39d04aab328ebc97
Author: Milan Crha <mcrha redhat com>
Date:   Mon Jan 24 14:31:36 2022 +0100

    Provide database file name in SQLITE_CORRUPT error message
    
    This will help to locate the affected file.
    
    Related to https://gitlab.gnome.org/GNOME/evolution/-/issues/1780

 src/camel/camel-db.c      | 53 +++++++++++++++++++++++++++++------------------
 src/camel/camel-db.h      | 19 +++++++++++++++++
 src/libebackend/e-cache.c | 29 +++++++++++++-------------
 src/libebackend/e-cache.h |  4 +++-
 4 files changed, 69 insertions(+), 36 deletions(-)
---
diff --git a/src/camel/camel-db.c b/src/camel/camel-db.c
index 8656359c7..c1ded8c2b 100644
--- a/src/camel/camel-db.c
+++ b/src/camel/camel-db.c
@@ -43,6 +43,8 @@
 /* how long to wait before invoking sync on the file */
 #define SYNC_TIMEOUT_SECONDS 5
 
+G_DEFINE_QUARK (camel-db-error-quark, camel_db_error)
+
 static sqlite3_vfs *old_vfs = NULL;
 static GThreadPool *sync_pool = NULL;
 
@@ -540,20 +542,21 @@ camel_db_init (CamelDB *cdb)
 
 /*
  * cdb_sql_exec 
- * @db: 
- * @stmt: 
- * @error: 
- * 
+ * @cdb:
+ * @stmt:
+ * @error:
+ *
  * Callers should hold the lock
  */
 static gint
-cdb_sql_exec (sqlite3 *db,
+cdb_sql_exec (CamelDB *cdb,
               const gchar *stmt,
               gint (*callback)(gpointer ,gint,gchar **,gchar **),
               gpointer data,
              gint *out_sqlite_error_code,
               GError **error)
 {
+       sqlite3 *db = cdb->priv->db;
        gchar *errmsg = NULL;
        gint   ret = -1, retries = 0;
 
@@ -580,9 +583,19 @@ cdb_sql_exec (sqlite3 *db,
 
        if (ret != SQLITE_OK) {
                d (g_print ("Error in SQL EXEC statement: %s [%s].\n", stmt, errmsg));
-               g_set_error (
-                       error, CAMEL_ERROR,
-                       CAMEL_ERROR_GENERIC, "%s", errmsg);
+               if (ret == SQLITE_CORRUPT) {
+                       if (cdb->priv->filename && *cdb->priv->filename) {
+                               g_set_error (error, CAMEL_DB_ERROR,
+                                       CAMEL_DB_ERROR_CORRUPT, "%s (%s)", errmsg, cdb->priv->filename);
+                       } else {
+                               g_set_error (error, CAMEL_DB_ERROR,
+                                       CAMEL_DB_ERROR_CORRUPT, "%s", errmsg);
+                       }
+               } else {
+                       g_set_error (
+                               error, CAMEL_ERROR,
+                               CAMEL_ERROR_GENERIC, "%s", errmsg);
+               }
                sqlite3_free (errmsg);
                errmsg = NULL;
                return -1;
@@ -775,7 +788,7 @@ camel_db_command_internal (CamelDB *cdb,
        cdb_writer_lock (cdb);
 
        START (stmt);
-       ret = cdb_sql_exec (cdb->priv->db, stmt, NULL, NULL, out_sqlite_error_code, error);
+       ret = cdb_sql_exec (cdb, stmt, NULL, NULL, out_sqlite_error_code, error);
        END;
 
        cdb_writer_unlock (cdb);
@@ -997,7 +1010,7 @@ camel_db_begin_transaction (CamelDB *cdb,
        stmt = cdb_construct_transaction_stmt (cdb, "SAVEPOINT ");
 
        STARTTS (stmt);
-       res = cdb_sql_exec (cdb->priv->db, stmt, NULL, NULL, NULL, error);
+       res = cdb_sql_exec (cdb, stmt, NULL, NULL, NULL, error);
        g_free (stmt);
 
        return res;
@@ -1025,7 +1038,7 @@ camel_db_end_transaction (CamelDB *cdb,
                return -1;
 
        stmt = cdb_construct_transaction_stmt (cdb, "RELEASE SAVEPOINT ");
-       ret = cdb_sql_exec (cdb->priv->db, stmt, NULL, NULL, NULL, error);
+       ret = cdb_sql_exec (cdb, stmt, NULL, NULL, NULL, error);
        g_free (stmt);
 
        ENDTS;
@@ -1054,7 +1067,7 @@ camel_db_abort_transaction (CamelDB *cdb,
        gint ret;
 
        stmt = cdb_construct_transaction_stmt (cdb, "ROLLBACK TO SAVEPOINT ");
-       ret = cdb_sql_exec (cdb->priv->db, stmt, NULL, NULL, NULL, error);
+       ret = cdb_sql_exec (cdb, stmt, NULL, NULL, NULL, error);
        g_free (stmt);
 
        cdb_writer_unlock (cdb);
@@ -1086,7 +1099,7 @@ camel_db_add_to_transaction (CamelDB *cdb,
        g_return_val_if_fail (cdb_is_in_transaction (cdb), -1);
        g_return_val_if_fail (query != NULL, -1);
 
-       return (cdb_sql_exec (cdb->priv->db, query, NULL, NULL, NULL, error));
+       return (cdb_sql_exec (cdb, query, NULL, NULL, NULL, error));
 }
 
 /**
@@ -1121,7 +1134,7 @@ camel_db_transaction_command (CamelDB *cdb,
 
        while (qry_list) {
                query = qry_list->data;
-               ret = cdb_sql_exec (cdb->priv->db, query, NULL, NULL, NULL, error);
+               ret = cdb_sql_exec (cdb, query, NULL, NULL, NULL, error);
                if (ret)
                        goto end;
                qry_list = g_list_next (qry_list);
@@ -1180,7 +1193,7 @@ camel_db_count_message_info (CamelDB *cdb,
        cdb_reader_lock (cdb);
 
        START (query);
-       ret = cdb_sql_exec (cdb->priv->db, query, count_cb, count, NULL, error);
+       ret = cdb_sql_exec (cdb, query, count_cb, count, NULL, error);
        END;
 
        cdb_reader_unlock (cdb);
@@ -1454,7 +1467,7 @@ camel_db_select (CamelDB *cdb,
        cdb_reader_lock (cdb);
 
        START (stmt);
-       ret = cdb_sql_exec (cdb->priv->db, stmt, callback, user_data, NULL, error);
+       ret = cdb_sql_exec (cdb, stmt, callback, user_data, NULL, error);
        END;
 
        cdb_reader_unlock (cdb);
@@ -2945,12 +2958,12 @@ camel_db_maybe_run_maintenance (CamelDB *cdb,
 
        cdb_writer_lock (cdb);
 
-       if (cdb_sql_exec (cdb->priv->db, "PRAGMA page_count;", get_number_cb, &page_count, NULL, 
&local_error) == SQLITE_OK &&
-           cdb_sql_exec (cdb->priv->db, "PRAGMA page_size;", get_number_cb, &page_size, NULL, &local_error) 
== SQLITE_OK &&
-           cdb_sql_exec (cdb->priv->db, "PRAGMA freelist_count;", get_number_cb, &freelist_count, NULL, 
&local_error) == SQLITE_OK) {
+       if (cdb_sql_exec (cdb, "PRAGMA page_count;", get_number_cb, &page_count, NULL, &local_error) == 
SQLITE_OK &&
+           cdb_sql_exec (cdb, "PRAGMA page_size;", get_number_cb, &page_size, NULL, &local_error) == 
SQLITE_OK &&
+           cdb_sql_exec (cdb, "PRAGMA freelist_count;", get_number_cb, &freelist_count, NULL, &local_error) 
== SQLITE_OK) {
                /* Vacuum, if there's more than 5% of the free pages, or when free pages use more than 10MB */
                success = !page_count || !freelist_count || (freelist_count * page_size < 1024 * 1024 * 10 && 
freelist_count * 1000 / page_count <= 50) ||
-                   cdb_sql_exec (cdb->priv->db, "vacuum;", NULL, NULL, NULL, &local_error) == SQLITE_OK;
+                   cdb_sql_exec (cdb, "vacuum;", NULL, NULL, NULL, &local_error) == SQLITE_OK;
        }
 
        cdb_writer_unlock (cdb);
diff --git a/src/camel/camel-db.h b/src/camel/camel-db.h
index ec42bf516..72f0bb356 100644
--- a/src/camel/camel-db.h
+++ b/src/camel/camel-db.h
@@ -46,8 +46,26 @@
        (G_TYPE_INSTANCE_GET_CLASS \
        ((obj), CAMEL_TYPE_DB, CamelDBClass))
 
+/**
+ * CAMEL_DB_ERROR:
+ *
+ * Since: 3.44
+ **/
+#define CAMEL_DB_ERROR \
+       (camel_db_error_quark ())
+
 G_BEGIN_DECLS
 
+/**
+ * CamelDBError:
+ * @CAMEL_DB_ERROR_CORRUPT: database is corrupt
+ *
+ * Since: 3.44
+ **/
+typedef enum {
+       CAMEL_DB_ERROR_CORRUPT
+} CamelDBError;
+
 typedef struct _CamelDB CamelDB;
 typedef struct _CamelDBClass CamelDBClass;
 typedef struct _CamelDBPrivate CamelDBPrivate;
@@ -336,6 +354,7 @@ CamelDBKnownColumnNames camel_db_get_column_ident (GHashTable **hash, gint index
  **/
 typedef gint (* CamelDBSelectCB) (gpointer user_data, gint ncol, gchar **colvalues, gchar **colnames);
 
+GQuark         camel_db_error_quark            (void) G_GNUC_CONST;
 GType          camel_db_get_type               (void) G_GNUC_CONST;
 
 CamelDB *      camel_db_new                    (const gchar *filename,
diff --git a/src/libebackend/e-cache.c b/src/libebackend/e-cache.c
index 240040cf5..7710e9ad0 100644
--- a/src/libebackend/e-cache.c
+++ b/src/libebackend/e-cache.c
@@ -504,20 +504,6 @@ e_cache_column_info_free (gpointer info)
        }
 }
 
-#define E_CACHE_SET_ERROR_FROM_SQLITE(error, code, message, stmt) \
-       G_STMT_START { \
-               if (code == SQLITE_CONSTRAINT) { \
-                       g_set_error_literal (error, E_CACHE_ERROR, E_CACHE_ERROR_CONSTRAINT, message); \
-               } else if (code == SQLITE_ABORT || code == SQLITE_INTERRUPT) { \
-                       g_set_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED, "Operation cancelled: %s", 
message); \
-               } else { \
-                       gchar *valid_utf8 = e_util_utf8_make_valid (stmt); \
-                       g_set_error (error, E_CACHE_ERROR, E_CACHE_ERROR_ENGINE, \
-                               "SQLite error code '%d': %s (statement:%s)", code, message, valid_utf8 ? 
valid_utf8 : stmt); \
-                       g_free (valid_utf8); \
-               } \
-       } G_STMT_END
-
 struct CacheSQLiteExecData {
        ECache *cache;
        ECacheSelectFunc callback;
@@ -587,8 +573,21 @@ e_cache_sqlite_exec_internal (ECache *cache,
        g_rec_mutex_unlock (&cache->priv->lock);
 
        if (ret != SQLITE_OK) {
-               E_CACHE_SET_ERROR_FROM_SQLITE (error, ret, errmsg, stmt);
+               if (ret == SQLITE_CONSTRAINT) {
+                       g_set_error_literal (error, E_CACHE_ERROR, E_CACHE_ERROR_CONSTRAINT, errmsg);
+               } else if (ret == SQLITE_ABORT || ret == SQLITE_INTERRUPT) {
+                       g_set_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED, "Operation cancelled: %s", 
errmsg);
+               } else if (ret == SQLITE_CORRUPT && cache->priv->filename && *cache->priv->filename) {
+                       g_set_error (error, E_CACHE_ERROR, E_CACHE_ERROR_CORRUPT,
+                               "%s (%s)", errmsg, cache->priv->filename);
+               } else {
+                       gchar *valid_utf8 = e_util_utf8_make_valid (stmt);
+                       g_set_error (error, E_CACHE_ERROR, E_CACHE_ERROR_ENGINE,
+                               "SQLite error code '%d': %s (statement:%s)", ret, errmsg, valid_utf8 ? 
valid_utf8 : stmt);
+                       g_free (valid_utf8);
+               }
                sqlite3_free (errmsg);
+
                return FALSE;
        }
 
diff --git a/src/libebackend/e-cache.h b/src/libebackend/e-cache.h
index 3fe2e9c9d..b8645f734 100644
--- a/src/libebackend/e-cache.h
+++ b/src/libebackend/e-cache.h
@@ -78,6 +78,7 @@ GQuark                e_cache_error_quark     (void);
  * @E_CACHE_ERROR_UNSUPPORTED_QUERY: A query was not supported.
  * @E_CACHE_ERROR_END_OF_LIST: An attempt was made to fetch results past the end of a the list.
  * @E_CACHE_ERROR_LOAD: An error occured while loading or creating the database.
+ * @E_CACHE_ERROR_CORRUPT: The database file is corrupt. (Since: 3.44)
  *
  * Defines the types of possible errors reported by the #ECache
  *
@@ -91,7 +92,8 @@ typedef enum {
        E_CACHE_ERROR_UNSUPPORTED_FIELD,
        E_CACHE_ERROR_UNSUPPORTED_QUERY,
        E_CACHE_ERROR_END_OF_LIST,
-       E_CACHE_ERROR_LOAD
+       E_CACHE_ERROR_LOAD,
+       E_CACHE_ERROR_CORRUPT
 } ECacheError;
 
 typedef struct _ECacheColumnValues ECacheColumnValues;


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