From 522298cf50e67d92b0aa85a85177ed7c16b00e08 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Sun, 29 Sep 2019 15:45:14 +0200
Subject: Provided a generic way to update DB values.

---
 src/analysis/db/collection.c | 142 ++++++-------------------------------------
 src/common/sqlite.c          | 131 +++++++++++++++++++++++++++++++++++----
 src/common/sqlite.h          |   3 +
 3 files changed, 142 insertions(+), 134 deletions(-)

diff --git a/src/analysis/db/collection.c b/src/analysis/db/collection.c
index 9ae7b9c..7b2082a 100644
--- a/src/analysis/db/collection.c
+++ b/src/analysis/db/collection.c
@@ -1219,147 +1219,43 @@ static bool g_db_collection_store_updated_item(const GDbCollection *collec, cons
     bool result;                            /* Conclusion à faire remonter */
     bound_value *values;                    /* Champs de table à inclure   */
     size_t count;                           /* Nombre de ces champs        */
-    char *sql;                              /* Requête SQL à construire    */
-    bool first;                             /* Première valeur ?           */
+    bound_value *updates;                   /* Champs à mettre à jour      */
+    size_t ucount;                          /* Nombre de ces champs        */
+    bound_value *conds;                     /* Champs de condition         */
+    size_t ccount;                          /* Nombre de ces champs        */
+    const bound_value *flags_ptr;           /* Emplacement des fanions     */
     size_t i;                               /* Boucle de parcours          */
-    sqlite3_stmt *stmt;                     /* Déclaration mise en place   */
-    int ret;                                /* Bilan d'un appel à SQLite   */
-    int index;                              /* Indice de valeur attachée   */
-    const bound_value *timestamp;           /* Valeur de l'horodatage      */
 
     result = false;
 
     if (!g_db_item_store(item, &values, &count))
-        goto gdcsui_building_values;
+        goto building_values;
 
-    /* Préparation de la requête */
+    updates = malloc(1 * sizeof(bound_value));
+    ucount = 0;
 
-    sql = strdup("UPDATE ");
-    sql = stradd(sql, collec->name);
+    conds = malloc((count - 1) * sizeof(bound_value));
+    ccount = 0;
 
-    sql = stradd(sql, " SET timestamp = ? ");
-
-    sql = stradd(sql, "WHERE ");
-
-    first = true;
+    flags_ptr = find_bound_value(values, count, "flags");
 
     for (i = 0; i < count; i++)
     {
-        if (strcmp(values[i].name, "timestamp") == 0)
-            continue;
-
-        if (first)
-            first = false;
-        else
-            sql = stradd(sql, " AND ");
-
-        sql = stradd(sql, values[i].name);
-
-        if (values[i].type == SQLITE_NULL)
-            sql = stradd(sql, " IS ");
-        else
-            sql = stradd(sql, " = ");
-
-        if (values[i].type == SQLITE_RAW)
-            sql = stradd(sql, values[i].cstring);
-        else
-            sql = stradd(sql, "?");
-
-    }
-
-    sql = stradd(sql, ";");
-
-	ret = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
-	if (ret != SQLITE_OK)
-    {
-		fprintf(stderr, "Can't prepare UPDATE statment '%s' (ret=%d): %s\n", sql, ret, sqlite3_errmsg(db));
-        goto gdcsui_exit;
-	}
-
-    /* Attribution des valeurs */
-
-    index = 1;
-
-    timestamp = find_bound_value(values, count, "timestamp");
-    assert(timestamp->type == SQLITE_INT64);
-
-    ret = sqlite3_bind_int64(stmt, index, timestamp->integer64);
-    index++;
-
-    if (ret != SQLITE_OK)
-    {
-        fprintf(stderr, "Can't bind value for parameter nb %d in '%s' (ret=%d): %s\n",
-                index - 1, sql, ret, sqlite3_errmsg(db));
-        goto gdcsui_exit;
-    }
-
-    for (i = 0; i < count; i++)
-    {
-        if (strcmp(values[i].name, "timestamp") == 0)
-            continue;
-
-        switch (values[i].type)
+        if (&values[i] == flags_ptr)
         {
-            case SQLITE_BOOLEAN:
-                ret = sqlite3_bind_int(stmt, index, values[i].boolean);
-                index++;
-                break;
-
-            case SQLITE_INTEGER:
-                ret = sqlite3_bind_int(stmt, index, values[i].integer);
-                index++;
-                break;
-
-            case SQLITE_INT64:
-                ret = sqlite3_bind_int64(stmt, index, values[i].integer64);
-                index++;
-                break;
-
-            case SQLITE_TEXT:
-                ret = sqlite3_bind_text(stmt, index, values[i].string, -1, values[i].delete);
-                index++;
-                break;
-
-            case SQLITE_NULL:
-                ret = sqlite3_bind_null(stmt, index);
-                index++;
-                break;
-
-            default:
-                assert(false);
-                ret = SQLITE_ERROR;
-                break;
-
+            assert(ucount < 1);
+            memcpy(&updates[ucount++], &values[i], sizeof(bound_value));
         }
-
-        if (ret != SQLITE_OK)
+        else
         {
-            fprintf(stderr, "Can't bind value for parameter nb %d in '%s' (ret=%d): %s\n",
-                    index - 1, sql, ret, sqlite3_errmsg(db));
-            goto gdcsui_exit;
+            assert(ccount < (count - 1));
+            memcpy(&conds[ccount++], &values[i], sizeof(bound_value));
         }
-
-    }
-
-    /* Exécution finale */
-
-	ret = sqlite3_step(stmt);
-
-    if (ret != SQLITE_DONE)
-    {
-		fprintf(stderr, "UPDATE statement '%s' didn't return DONE (ret=%d): %s\n", sql, ret, sqlite3_errmsg(db));
-        goto gdcsui_exit;
     }
 
-    sqlite3_finalize(stmt);
-
-    result = true;
-
- gdcsui_exit:
-
-    free(sql);
+    result = update_db_values(db, collec->name, updates, ucount, conds, ccount);
 
- gdcsui_building_values:
+ building_values:
 
     free_all_bound_values(values, count);
 
diff --git a/src/common/sqlite.c b/src/common/sqlite.c
index d497c81..3a94623 100644
--- a/src/common/sqlite.c
+++ b/src/common/sqlite.c
@@ -34,7 +34,7 @@
 
 
 /* Attribue une définition aux valeurs paramétrées. */
-static bool bind_bound_values(sqlite3 *, sqlite3_stmt *, const char *, const bound_value *, size_t, bool, int *);
+static bool bind_bound_values(sqlite3 *, sqlite3_stmt *, const char *, const bound_value *, size_t, int *);
 
 
 
@@ -106,12 +106,11 @@ const bound_value *find_bound_value(const bound_value *values, size_t count, con
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : db     = base de données à consulter.                        *
-*                stmt      = requête SQL en préparation à faire évoluer.      *
-*                sql       = définition brute de cette requête SQL.           *
-*                values    = tableau d'éléments à consulter.                  *
-*                count     = nombre de descriptions renseignées.              *
-*                has_value = fitre sur la définition des valeurs.             *
-*                index     = indice évolutif des valeurs paramétrées. [OUT]   *
+*                stmt   = requête SQL en préparation à faire évoluer.         *
+*                sql    = définition brute de cette requête SQL.              *
+*                values = tableau d'éléments à consulter.                     *
+*                count  = nombre de descriptions renseignées.                 *
+*                index  = indice évolutif des valeurs paramétrées. [OUT]      *
 *                                                                             *
 *  Description : Attribue une définition aux valeurs paramétrées.             *
 *                                                                             *
@@ -121,7 +120,7 @@ const bound_value *find_bound_value(const bound_value *values, size_t count, con
 *                                                                             *
 ******************************************************************************/
 
-static bool bind_bound_values(sqlite3 *db, sqlite3_stmt *stmt, const char *sql, const bound_value *values, size_t count, bool has_value, int *index)
+static bool bind_bound_values(sqlite3 *db, sqlite3_stmt *stmt, const char *sql, const bound_value *values, size_t count, int *index)
 {
     bool result;                            /* Bilan à retourner           */
     size_t i;                               /* Boucle de parcours          */
@@ -131,7 +130,7 @@ static bool bind_bound_values(sqlite3 *db, sqlite3_stmt *stmt, const char *sql,
 
     for (i = 0; i < count && result; i++)
     {
-        if (values[i].has_value != has_value)
+        if (!values[i].has_value)
             continue;
 
         switch (values[i].type)
@@ -269,7 +268,7 @@ bool load_db_values(sqlite3 *db, const char *table, bound_value *values, size_t
 
     index = 1;
 
-    if (!bind_bound_values(db, stmt, sql, values, count, true, &index))
+    if (!bind_bound_values(db, stmt, sql, values, count, &index))
         goto bind_error;
 
     /* Chargement des valeurs existantes */
@@ -446,7 +445,7 @@ bool store_db_values(sqlite3 *db, const char *table, const bound_value *values,
 
     index = 1;
 
-    if (!bind_bound_values(db, stmt, sql, values, count, true, &index))
+    if (!bind_bound_values(db, stmt, sql, values, count, &index))
         goto bind_error;
 
     /* Exécution finale */
@@ -474,3 +473,113 @@ bool store_db_values(sqlite3 *db, const char *table, const bound_value *values,
     return result;
 
 }
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : db     = base de données à mettre à jour.                    *
+*                table  = nom de la table concernée.                          *
+*                values = champs avec leur valeur nouvelle.                   *
+*                vcount = quantité de ces champs.                             *
+*                values = champs avec leur valeur de condition.               *
+*                ccount = quantité de ces champs.                             *
+*                                                                             *
+*  Description : Met à jour une série de valeurs dans une base de données.    *
+*                                                                             *
+*  Retour      : Bilan de l'exécution de l'opération.                         *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool update_db_values(sqlite3 *db, const char *table, const bound_value *values, size_t vcount, const bound_value *conds, size_t ccount)
+{
+    bool result;                            /* Conclusion à faire remonter */
+    char *sql;                              /* Requête SQL à construire    */
+    size_t i;                               /* Boucle de parcours          */
+    sqlite3_stmt *stmt;                     /* Déclaration mise en place   */
+    int ret;                                /* Bilan d'un appel à SQLite   */
+    int index;                              /* Indice de valeur attachée   */
+
+    result = false;
+
+    /* Préparation de la requête */
+
+    sql = strdup("UPDATE ");
+    sql = stradd(sql, table);
+    sql = stradd(sql, " SET");
+
+    for (i = 0; i < vcount; i++)
+    {
+        assert(values[i].has_value);
+
+        if (i > 0) sql = stradd(sql, " ,");
+
+        sql = stradd(sql, " ");
+        sql = stradd(sql, values[i].name);
+
+        sql = stradd(sql, " = ?");
+
+    }
+
+    if (ccount > 0)
+    {
+        sql = stradd(sql, " WHERE");
+
+        for (i = 0; i < ccount; i++)
+        {
+            if (i > 0) sql = stradd(sql, " AND");
+
+            sql = stradd(sql, " ");
+            sql = stradd(sql, conds[i].name);
+
+            sql = stradd(sql, " = ?");
+
+        }
+
+    }
+
+    sql = stradd(sql, ";");
+
+	ret = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
+	if (ret != SQLITE_OK)
+    {
+		fprintf(stderr, "Can't prepare UPDATE statment '%s' (ret=%d): %s\n", sql, ret, sqlite3_errmsg(db));
+        goto prepare_error;
+	}
+
+    /* Attribution des valeurs */
+
+    index = 1;
+
+    if (!bind_bound_values(db, stmt, sql, values, vcount, &index))
+        goto bind_error;
+
+    if (!bind_bound_values(db, stmt, sql, conds, ccount, &index))
+        goto bind_error;
+
+    /* Exécution finale */
+
+	ret = sqlite3_step(stmt);
+
+    if (ret != SQLITE_DONE)
+    {
+		fprintf(stderr, "UPDATE statement '%s' didn't return DONE (ret=%d): %s\n", sql, ret, sqlite3_errmsg(db));
+        goto update_error;
+    }
+
+    result = true;
+
+ update_error:
+
+ bind_error:
+
+    sqlite3_finalize(stmt);
+
+ prepare_error:
+
+    free(sql);
+
+    return result;
+
+}
diff --git a/src/common/sqlite.h b/src/common/sqlite.h
index 291eec8..99de12d 100644
--- a/src/common/sqlite.h
+++ b/src/common/sqlite.h
@@ -84,6 +84,9 @@ bool load_db_values(sqlite3 *, const char *, bound_value *, size_t, db_load_cb,
 /* Enregistre une série de valeurs dans une base de données. */
 bool store_db_values(sqlite3 *, const char *, const bound_value *, size_t);
 
+/* Met à jour une série de valeurs dans une base de données. */
+bool update_db_values(sqlite3 *, const char *, const bound_value *, size_t, const bound_value *, size_t);
+
 
 
 #endif  /* _COMMON_SQLITE_H */
-- 
cgit v0.11.2-87-g4458