LCOV - code coverage report
Current view: top level - libgnucash/backend/sql - gnc-slots-sql.cpp (source / functions) Coverage Total Hit
Test: gnucash.info Lines: 80.7 % 367 296
Test Date: 2026-11-02 18:19:43 Functions: 97.1 % 35 34
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /********************************************************************
       2              :  * gnc-slots-sql.c: load and save data to SQL                       *
       3              :  *                                                                  *
       4              :  * This program is free software; you can redistribute it and/or    *
       5              :  * modify it under the terms of the GNU General Public License as   *
       6              :  * published by the Free Software Foundation; either version 2 of   *
       7              :  * the License, or (at your option) any later version.              *
       8              :  *                                                                  *
       9              :  * This program is distributed in the hope that it will be useful,  *
      10              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
      11              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
      12              :  * GNU General Public License for more details.                     *
      13              :  *                                                                  *
      14              :  * You should have received a copy of the GNU General Public License*
      15              :  * along with this program; if not, contact:                        *
      16              :  *                                                                  *
      17              :  * Free Software Foundation           Voice:  +1-617-542-5942       *
      18              :  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
      19              :  * Boston, MA  02110-1301,  USA       gnu@gnu.org                   *
      20              : \********************************************************************/
      21              : /** @file gnc-slots-sql.c
      22              :  *  @brief load and save data to SQL
      23              :  *  @author Copyright (c) 2006-2008 Phil Longstaff <plongstaff@rogers.com>
      24              :  *
      25              :  * This file implements the top-level QofBackend API for saving/
      26              :  * restoring data to/from an SQL db
      27              :  */
      28              : #include <guid.hpp>
      29              : #include <config.h>
      30              : 
      31              : #include <glib.h>
      32              : 
      33              : #include <qof.h>
      34              : #include <gnc-engine.h>
      35              : 
      36              : #ifdef S_SPLINT_S
      37              : #include "splint-defs.h"
      38              : #endif
      39              : 
      40              : #include <string>
      41              : #include <sstream>
      42              : #include <cstdint>
      43              : 
      44              : #include "gnc-sql-connection.hpp"
      45              : #include "gnc-sql-backend.hpp"
      46              : #include "gnc-sql-object-backend.hpp"
      47              : #include "gnc-sql-column-table-entry.hpp"
      48              : #include "gnc-slots-sql.h"
      49              : 
      50              : #include <kvp-frame.hpp>
      51              : 
      52              : static QofLogModule log_module = G_LOG_DOMAIN;
      53              : 
      54              : #define TABLE_NAME "slots"
      55              : #define TABLE_VERSION 4
      56              : 
      57              : typedef enum
      58              : {
      59              :     NONE,
      60              :     FRAME,
      61              :     LIST
      62              : } context_t;
      63              : 
      64              : struct slot_info_t
      65              : {
      66              :     GncSqlBackend* be;
      67              :     const GncGUID* guid;
      68              :     gboolean is_ok;
      69              :     KvpFrame* pKvpFrame;
      70              :     KvpValue::Type value_type;
      71              :     GList* pList;
      72              :     context_t context;
      73              :     KvpValue* pKvpValue;
      74              :     std::string path;
      75              :     std::string parent_path;
      76              : };
      77              : 
      78              : 
      79              : static  gpointer get_obj_guid (gpointer pObject);
      80              : static void set_obj_guid (void);
      81              : static  gpointer get_path (gpointer pObject);
      82              : static void set_path (gpointer pObject,  gpointer pValue);
      83              : static KvpValue::Type get_slot_type (gpointer pObject);
      84              : static void set_slot_type (gpointer pObject,  gpointer pValue);
      85              : static gint64 get_int64_val (gpointer pObject);
      86              : static void set_int64_val (gpointer pObject, gint64 pValue);
      87              : static  gpointer get_string_val (gpointer pObject);
      88              : static void set_string_val (gpointer pObject,  gpointer pValue);
      89              : static  gpointer get_double_val (gpointer pObject);
      90              : static void set_double_val (gpointer pObject,  gpointer pValue);
      91              : static time64 get_time_val (gpointer pObject);
      92              : static void set_time_val (gpointer pObject, time64 t);
      93              : static  gpointer get_guid_val (gpointer pObject);
      94              : static void set_guid_val (gpointer pObject,  gpointer pValue);
      95              : static gnc_numeric get_numeric_val (gpointer pObject);
      96              : static void set_numeric_val (gpointer pObject, gnc_numeric value);
      97              : static GDate* get_gdate_val (gpointer pObject);
      98              : static void set_gdate_val (gpointer pObject, GDate* value);
      99              : static slot_info_t* slot_info_copy (slot_info_t* pInfo, GncGUID* guid);
     100              : static void slots_load_info (slot_info_t* pInfo);
     101              : 
     102              : #define SLOT_MAX_PATHNAME_LEN 4096
     103              : #define SLOT_MAX_STRINGVAL_LEN 4096
     104              : enum
     105              : {
     106              :     id_col = 0,
     107              :     obj_guid_col,
     108              :     name_col,
     109              :     slot_type_col,
     110              :     int64_val_col,
     111              :     string_val_col,
     112              :     double_val_col,
     113              :     time_val_col,
     114              :     guid_val_col,
     115              :     numeric_val_col,
     116              :     gdate_val_col
     117              : };
     118              : 
     119              : static const EntryVec col_table
     120              : {
     121              :     /* col_name, col_type, size, flags, g0bj_param_name, qof_param_name, getter, setter */
     122              :     gnc_sql_make_table_entry<CT_INT>(
     123              :         "id", 0, COL_PKEY | COL_NNUL | COL_AUTOINC),
     124              :     gnc_sql_make_table_entry<CT_GUID>("obj_guid", 0, COL_NNUL,
     125              :                                       (QofAccessFunc)get_obj_guid,
     126              :                                       (QofSetterFunc)set_obj_guid),
     127              :     gnc_sql_make_table_entry<CT_STRING>("name", SLOT_MAX_PATHNAME_LEN, COL_NNUL,
     128              :                                         (QofAccessFunc)get_path, set_path),
     129              :     gnc_sql_make_table_entry<CT_INT>("slot_type", 0, COL_NNUL,
     130              :                                      (QofAccessFunc)get_slot_type,
     131              :                                      set_slot_type),
     132              :     gnc_sql_make_table_entry<CT_INT64>("int64_val", 0, 0,
     133              :                                        (QofAccessFunc)get_int64_val,
     134              :                                        (QofSetterFunc)set_int64_val),
     135              :     gnc_sql_make_table_entry<CT_STRING>("string_val", SLOT_MAX_PATHNAME_LEN, 0,
     136              :                                         (QofAccessFunc)get_string_val,
     137              :                                         set_string_val),
     138              :     gnc_sql_make_table_entry<CT_DOUBLE>("double_val", 0, 0,
     139              :                                         (QofAccessFunc)get_double_val,
     140              :                                         set_double_val),
     141              :     gnc_sql_make_table_entry<CT_TIME>("timespec_val", 0, 0,
     142              :                                           (QofAccessFunc)get_time_val,
     143              :                                           (QofSetterFunc)set_time_val),
     144              :     gnc_sql_make_table_entry<CT_GUID>("guid_val", 0, 0,
     145              :                                       (QofAccessFunc)get_guid_val,
     146              :                                       set_guid_val),
     147              :     gnc_sql_make_table_entry<CT_NUMERIC>("numeric_val", 0, 0,
     148              :                                          (QofAccessFunc)get_numeric_val,
     149              :                                          (QofSetterFunc)set_numeric_val),
     150              :     gnc_sql_make_table_entry<CT_GDATE>("gdate_val", 0, 0,
     151              :                                        (QofAccessFunc)get_gdate_val,
     152              :                                        (QofSetterFunc)set_gdate_val),
     153              : };
     154              : 
     155              : static void
     156           50 : _retrieve_guid_ (gpointer pObject,  gpointer pValue)
     157              : {
     158           50 :     GncGUID* pGuid = (GncGUID*)pObject;
     159           50 :     GncGUID* guid = (GncGUID*)pValue;
     160              : 
     161           50 :     g_return_if_fail (pObject != NULL);
     162           50 :     g_return_if_fail (pValue != NULL);
     163              : 
     164           50 :     *pGuid = *guid;
     165              : }
     166              : 
     167              : /* Special column table because we need to be able to access the table by
     168              : a column other than the primary key */
     169              : static const EntryVec obj_guid_col_table
     170              : {
     171              :     gnc_sql_make_table_entry<CT_GUID>("obj_guid", 0, 0,
     172              :                                       (QofAccessFunc)get_obj_guid,
     173              :                                       _retrieve_guid_),
     174              : };
     175              : 
     176              : static const EntryVec gdate_col_table
     177              : {
     178              :     gnc_sql_make_table_entry<CT_GDATE>("gdate_val", 0, 0),
     179              : };
     180              : 
     181           15 : GncSqlSlotsBackend::GncSqlSlotsBackend() :
     182           30 :     GncSqlObjectBackend(TABLE_VERSION, GNC_ID_ACCOUNT,
     183           75 :                         TABLE_NAME, col_table) {}
     184              : 
     185              : /* ================================================================= */
     186              : 
     187              : static std::string
     188           74 : get_key (slot_info_t* pInfo)
     189              : {
     190           74 :     if (!pInfo) return "";
     191              : 
     192           74 :     auto path = pInfo->path;
     193           74 :     path.erase (0, pInfo->parent_path.size());
     194           74 :     return path;
     195           74 : }
     196              : 
     197              : static void
     198           64 : set_slot_from_value (slot_info_t* pInfo, KvpValue* pValue)
     199              : {
     200           64 :     g_return_if_fail (pInfo != NULL);
     201           64 :     g_return_if_fail (pValue != NULL);
     202              : 
     203           64 :     switch (pInfo->context)
     204              :     {
     205           64 :     case FRAME:
     206              :     {
     207           64 :         auto key = get_key (pInfo);
     208          192 :         pInfo->pKvpFrame->set ({key}, pValue);
     209           64 :         break;
     210           64 :     }
     211            0 :     case LIST:
     212              :     {
     213            0 :         pInfo->pList = g_list_append (pInfo->pList, pValue);
     214            0 :         break;
     215              :     }
     216            0 :     case NONE:
     217              :     default:
     218              :     {
     219            0 :         auto key = get_key (pInfo);
     220            0 :         auto path = pInfo->parent_path;
     221            0 :         auto frame = pInfo->pKvpFrame;
     222            0 :         if (!path.empty())
     223              :         {
     224            0 :             frame->set_path ({path, key}, pValue);
     225              :         }
     226              :         else
     227            0 :             frame->set ({key}, pValue);
     228            0 :         break;
     229            0 :     }
     230              :     }
     231           64 : }
     232              : 
     233              : static  gpointer
     234           86 : get_obj_guid (gpointer pObject)
     235              : {
     236           86 :     slot_info_t* pInfo = (slot_info_t*)pObject;
     237              : 
     238           86 :     g_return_val_if_fail (pObject != NULL, NULL);
     239              : 
     240           86 :     return (gpointer)pInfo->guid;
     241              : }
     242              : 
     243              : static void
     244           74 : set_obj_guid (void)
     245              : {
     246              :     // Nowhere to put the GncGUID
     247           74 : }
     248              : 
     249              : static  gpointer
     250           75 : get_path (gpointer pObject)
     251              : {
     252           75 :     slot_info_t* pInfo = (slot_info_t*)pObject;
     253              : 
     254           75 :     g_return_val_if_fail (pObject != NULL, NULL);
     255              : 
     256           75 :     return (gpointer)pInfo->path.c_str();
     257              : }
     258              : 
     259              : static void
     260           74 : set_path (gpointer pObject,  gpointer pValue)
     261              : {
     262           74 :     slot_info_t* pInfo = (slot_info_t*)pObject;
     263           74 :     pInfo->path = static_cast<char*>(pValue);
     264           74 :     if (pInfo->path.find (pInfo->parent_path) != 0)
     265            0 :         pInfo->parent_path.clear();
     266           74 : }
     267              : 
     268              : static KvpValue::Type
     269           75 : get_slot_type (gpointer pObject)
     270              : {
     271           75 :     slot_info_t* pInfo = (slot_info_t*)pObject;
     272              : 
     273           75 :     g_return_val_if_fail (pObject != NULL, KvpValue::Type::INVALID);
     274              : 
     275              : //    return (gpointer)kvp_value_get_type( pInfo->pKvpValue );
     276           75 :     return pInfo->value_type;
     277              : }
     278              : 
     279              : static void
     280           74 : set_slot_type (gpointer pObject,  gpointer pValue)
     281              : {
     282           74 :     slot_info_t* pInfo = (slot_info_t*)pObject;
     283              : 
     284           74 :     g_return_if_fail (pObject != NULL);
     285           74 :     g_return_if_fail (pValue != NULL);
     286              : 
     287           74 :     pInfo->value_type = static_cast<KvpValue::Type> (GPOINTER_TO_INT (pValue));
     288              : }
     289              : 
     290              : static gint64
     291           75 : get_int64_val (gpointer pObject)
     292              : {
     293           75 :     slot_info_t* pInfo = (slot_info_t*)pObject;
     294              : 
     295           75 :     g_return_val_if_fail (pObject != NULL, 0);
     296              : 
     297           75 :     if (pInfo->pKvpValue->get_type () == KvpValue::Type::INT64)
     298              :     {
     299           12 :         return pInfo->pKvpValue->get<int64_t> ();
     300              :     }
     301              :     else
     302              :     {
     303           63 :         return 0;
     304              :     }
     305              : }
     306              : 
     307              : static void
     308           74 : set_int64_val (gpointer pObject, gint64 value)
     309              : {
     310           74 :     slot_info_t* pInfo = (slot_info_t*)pObject;
     311           74 :     KvpValue* pValue = NULL;
     312              : 
     313           74 :     g_return_if_fail (pObject != NULL);
     314              : 
     315           74 :     if (pInfo->value_type != KvpValue::Type::INT64) return;
     316           13 :     pValue = new KvpValue {value};
     317           13 :     set_slot_from_value (pInfo, pValue);
     318              : }
     319              : 
     320              : static  gpointer
     321           75 : get_string_val (gpointer pObject)
     322              : {
     323           75 :     slot_info_t* pInfo = (slot_info_t*)pObject;
     324              : 
     325           75 :     g_return_val_if_fail (pObject != NULL, NULL);
     326              : 
     327           75 :     if (pInfo->pKvpValue->get_type () == KvpValue::Type::STRING)
     328              :     {
     329           28 :         return (gpointer)pInfo->pKvpValue->get<const char*> ();
     330              :     }
     331              :     else
     332              :     {
     333           47 :         return NULL;
     334              :     }
     335              : }
     336              : 
     337              : static void
     338           74 : set_string_val (gpointer pObject,  gpointer pValue)
     339              : {
     340           74 :     slot_info_t* pInfo = (slot_info_t*)pObject;
     341           74 :     g_return_if_fail (pObject != NULL);
     342              : 
     343           74 :     if (pInfo->value_type != KvpValue::Type::STRING || pValue == NULL)
     344           49 :         return;
     345           50 :     auto value = new KvpValue {g_strdup(static_cast<const char*> (pValue))};
     346           25 :     set_slot_from_value (pInfo, value);
     347              : }
     348              : 
     349              : static  gpointer
     350           75 : get_double_val (gpointer pObject)
     351              : {
     352              :     static double d_val; /* static so that we can return it. */
     353           75 :     g_return_val_if_fail (pObject != NULL, NULL);
     354           75 :     auto pInfo = static_cast<slot_info_t*>(pObject);
     355           75 :     if (pInfo->pKvpValue->get_type () == KvpValue::Type::DOUBLE)
     356              :     {
     357            4 :         d_val = pInfo->pKvpValue->get<double> ();
     358            4 :         return (gpointer)&d_val;
     359              :     }
     360              :     else
     361              :     {
     362           71 :         return NULL;
     363              :     }
     364              : }
     365              : 
     366              : static void
     367           74 : set_double_val (gpointer pObject,  gpointer pValue)
     368              : {
     369           74 :     slot_info_t* pInfo = (slot_info_t*)pObject;
     370           74 :     KvpValue* value = NULL;
     371              : 
     372           74 :     g_return_if_fail (pObject != NULL);
     373              : 
     374           74 :     if (pInfo->value_type != KvpValue::Type::DOUBLE || pValue == NULL) return;
     375            5 :     value = new KvpValue {* (static_cast<double*> (pValue))};
     376            5 :     set_slot_from_value (pInfo, value);
     377              : }
     378              : 
     379              : static time64
     380           75 : get_time_val (gpointer pObject)
     381              : {
     382           75 :     slot_info_t* pInfo = (slot_info_t*)pObject;
     383              : 
     384           75 :     g_return_val_if_fail (pObject != NULL, 0);
     385              : 
     386              : //if( kvp_value_get_type( pInfo->pKvpValue ) == KvpValue::Type::TIME64 ) {
     387           75 :     auto t = pInfo->pKvpValue->get<Time64> ();
     388           75 :     return t.t;
     389              : }
     390              : 
     391              : static void
     392           74 : set_time_val (gpointer pObject, time64 time)
     393              : {
     394           74 :     slot_info_t* pInfo = (slot_info_t*)pObject;
     395           74 :     KvpValue* value = NULL;
     396           74 :     Time64 t{time};
     397          142 :     g_return_if_fail (pObject != NULL);
     398              : 
     399           74 :     if (pInfo->value_type != KvpValue::Type::TIME64) return;
     400            6 :     value = new KvpValue {t};
     401            6 :     set_slot_from_value (pInfo, value);
     402              : }
     403              : 
     404              : static  gpointer
     405           75 : get_guid_val (gpointer pObject)
     406              : {
     407           75 :     slot_info_t* pInfo = (slot_info_t*)pObject;
     408              : 
     409           75 :     g_return_val_if_fail (pObject != NULL, NULL);
     410              : 
     411           75 :     if (pInfo->pKvpValue->get_type () == KvpValue::Type::GUID)
     412              :     {
     413           22 :         return (gpointer)pInfo->pKvpValue->get<GncGUID*> ();
     414              :     }
     415              :     else
     416              :     {
     417           53 :         return NULL;
     418              :     }
     419              : }
     420              : 
     421              : static void
     422           20 : set_guid_val (gpointer pObject,  gpointer pValue)
     423              : {
     424           20 :     slot_info_t* pInfo = (slot_info_t*)pObject;
     425              : 
     426           20 :     g_return_if_fail (pObject != NULL);
     427           20 :     if (pValue == NULL) return;
     428              : 
     429           20 :     switch (pInfo->value_type)
     430              :     {
     431           10 :     case KvpValue::Type::GUID:
     432              :     {
     433           10 :         auto new_guid = guid_copy (static_cast<GncGUID*> (pValue));
     434           10 :         set_slot_from_value (pInfo, new KvpValue {new_guid});
     435           10 :         break;
     436              :     }
     437            0 :     case KvpValue::Type::GLIST:
     438              :     {
     439            0 :         slot_info_t* newInfo = slot_info_copy (pInfo, (GncGUID*)pValue);
     440            0 :         KvpValue* pValue = NULL;
     441            0 :         auto key = get_key (pInfo);
     442              : 
     443            0 :         newInfo->context = LIST;
     444              : 
     445            0 :         slots_load_info (newInfo);
     446            0 :         pValue = new KvpValue {newInfo->pList};
     447            0 :         pInfo->pKvpFrame->set ({key.c_str()}, pValue);
     448            0 :         delete newInfo;
     449            0 :         break;
     450            0 :     }
     451           10 :     case KvpValue::Type::FRAME:
     452              :     {
     453           10 :         slot_info_t* newInfo = slot_info_copy (pInfo, (GncGUID*)pValue) ;
     454           10 :         auto newFrame = new KvpFrame;
     455           10 :         newInfo->pKvpFrame = newFrame;
     456              : 
     457           10 :         switch (pInfo->context)
     458              :         {
     459            0 :         case LIST:
     460              :         {
     461            0 :             auto value = new KvpValue {newFrame};
     462            0 :             newInfo->path = get_key (pInfo);
     463            0 :             pInfo->pList = g_list_append (pInfo->pList, value);
     464            0 :             break;
     465              :         }
     466           10 :         case FRAME:
     467              :         default:
     468              :         {
     469           10 :             auto key = get_key (pInfo);
     470           50 :             pInfo->pKvpFrame->set ({key.c_str()}, new KvpValue {newFrame});
     471           10 :             break;
     472           10 :         }
     473              :         }
     474              : 
     475           10 :         newInfo->context = FRAME;
     476           10 :         slots_load_info (newInfo);
     477           10 :         delete newInfo;
     478           10 :         break;
     479              :     }
     480            0 :     default:
     481            0 :         break;
     482              :     }
     483           20 : }
     484              : 
     485              : static gnc_numeric
     486           75 : get_numeric_val (gpointer pObject)
     487              : {
     488           75 :     slot_info_t* pInfo = (slot_info_t*)pObject;
     489              : 
     490           75 :     g_return_val_if_fail (pObject != NULL, gnc_numeric_zero ());
     491              : 
     492           75 :     if (pInfo->pKvpValue->get_type () == KvpValue::Type::NUMERIC)
     493              :     {
     494            4 :         return pInfo->pKvpValue->get<gnc_numeric> ();
     495              :     }
     496              :     else
     497              :     {
     498           71 :         return gnc_numeric_zero ();
     499              :     }
     500              : }
     501              : 
     502              : static void
     503           74 : set_numeric_val (gpointer pObject, gnc_numeric value)
     504              : {
     505           74 :     slot_info_t* pInfo = (slot_info_t*)pObject;
     506              : 
     507           74 :     g_return_if_fail (pObject != NULL);
     508              : 
     509           74 :     if (pInfo->value_type != KvpValue::Type::NUMERIC) return;
     510            5 :     set_slot_from_value (pInfo, new KvpValue {value});
     511              : }
     512              : 
     513              : static GDate*
     514           75 : get_gdate_val (gpointer pObject)
     515              : {
     516           75 :     slot_info_t* pInfo = (slot_info_t*)pObject;
     517              :     static GDate date;
     518              : 
     519           75 :     g_return_val_if_fail (pObject != NULL, NULL);
     520              : 
     521           75 :     if (pInfo->pKvpValue->get_type () == KvpValue::Type::GDATE)
     522              :     {
     523            0 :         date = pInfo->pKvpValue->get<GDate> ();
     524            0 :         return &date;
     525              :     }
     526              :     else
     527              :     {
     528           75 :         return NULL;
     529              :     }
     530              : }
     531              : 
     532              : static void
     533            0 : set_gdate_val (gpointer pObject, GDate* value)
     534              : {
     535            0 :     slot_info_t* pInfo = (slot_info_t*)pObject;
     536              : 
     537            0 :     g_return_if_fail (pObject != NULL);
     538              : 
     539            0 :     if (pInfo->value_type != KvpValue::Type::GDATE) return;
     540            0 :     set_slot_from_value (pInfo, new KvpValue {*value});
     541              : }
     542              : 
     543              : static slot_info_t*
     544           47 : slot_info_copy (slot_info_t* pInfo, GncGUID* guid)
     545              : {
     546           47 :     g_return_val_if_fail (pInfo != NULL, NULL);
     547           47 :     auto newSlot = new slot_info_t;
     548              : 
     549           47 :     newSlot->be = pInfo->be;
     550           47 :     newSlot->guid = guid == NULL ? pInfo->guid : guid;
     551           47 :     newSlot->is_ok = pInfo->is_ok;
     552           47 :     newSlot->pKvpFrame = pInfo->pKvpFrame;
     553           47 :     newSlot->value_type = pInfo->value_type;
     554           47 :     newSlot->pList = pInfo->pList;
     555           47 :     newSlot->context = pInfo->context;
     556           47 :     newSlot->pKvpValue = pInfo->pKvpValue;
     557           47 :     if (!pInfo->path.empty())
     558           23 :         newSlot->parent_path = pInfo->path + "/";
     559              :     else
     560           24 :         newSlot->parent_path = pInfo->parent_path;
     561           47 :     return newSlot;
     562              : }
     563              : 
     564              : static void
     565           75 : save_slot (const char* key, KvpValue* value, slot_info_t & slot_info)
     566              : {
     567           75 :     g_return_if_fail (value != NULL);
     568              : 
     569              :     // Ignore if we've already run into a failure
     570           75 :     if (!slot_info.is_ok)
     571              :     {
     572            0 :         return;
     573              :     }
     574           75 :     slot_info.pKvpValue = value;
     575           75 :     slot_info.path = slot_info.parent_path + key;
     576           75 :     slot_info.value_type = value->get_type ();
     577              : 
     578           75 :     switch (slot_info.value_type)
     579              :     {
     580           13 :     case KvpValue::Type::FRAME:
     581              :     {
     582           13 :         auto pKvpFrame = value->get<KvpFrame*> ();
     583           13 :         auto guid = guid_new ();
     584           13 :         slot_info_t* pNewInfo = slot_info_copy (&slot_info, guid);
     585           13 :         KvpValue* oldValue = slot_info.pKvpValue;
     586           13 :         slot_info.pKvpValue = new KvpValue {guid};
     587           13 :         slot_info.is_ok = slot_info.be->do_db_operation(OP_DB_INSERT,
     588              :                                                             TABLE_NAME,
     589              :                                                             TABLE_NAME,
     590              :                                                             &slot_info,
     591              :                                                             col_table);
     592           13 :         g_return_if_fail (slot_info.is_ok);
     593           13 :         pKvpFrame->for_each_slot_temp (save_slot, *pNewInfo);
     594           13 :         delete slot_info.pKvpValue;
     595           13 :         slot_info.pKvpValue = oldValue;
     596           13 :         delete pNewInfo;
     597              :     }
     598           13 :     break;
     599            0 :     case KvpValue::Type::GLIST:
     600              :     {
     601            0 :         GncGUID* guid = guid_new ();
     602            0 :         slot_info_t* pNewInfo = slot_info_copy (&slot_info, guid);
     603            0 :         KvpValue* oldValue = slot_info.pKvpValue;
     604            0 :         slot_info.pKvpValue = new KvpValue {guid};  // Transfer ownership!
     605            0 :         slot_info.is_ok = slot_info.be->do_db_operation(OP_DB_INSERT,
     606              :                                                             TABLE_NAME,
     607              :                                                             TABLE_NAME,
     608              :                                                             &slot_info,
     609              :                                                             col_table);
     610            0 :         g_return_if_fail (slot_info.is_ok);
     611            0 :         for (auto cursor = value->get<GList*> (); cursor; cursor = cursor->next)
     612              :         {
     613            0 :             auto val = static_cast<KvpValue*> (cursor->data);
     614            0 :             save_slot ("", val, *pNewInfo);
     615              :         }
     616            0 :         delete slot_info.pKvpValue;
     617            0 :         slot_info.pKvpValue = oldValue;
     618            0 :         delete pNewInfo;
     619              :     }
     620            0 :     break;
     621           62 :     default:
     622              :     {
     623           62 :         slot_info.is_ok = slot_info.be->do_db_operation (OP_DB_INSERT,
     624              :                                                              TABLE_NAME,
     625              :                                                              TABLE_NAME,
     626              :                                                              &slot_info,
     627              :                                                              col_table);
     628              :     }
     629           62 :     break;
     630              :     }
     631              : }
     632              : 
     633              : gboolean
     634          107 : gnc_sql_slots_save (GncSqlBackend* sql_be, const GncGUID* guid, gboolean is_infant,
     635              :                     QofInstance* inst)
     636              : {
     637          107 :     slot_info_t slot_info = { NULL, NULL, TRUE, NULL, KvpValue::Type::INVALID,
     638          107 :                               NULL, FRAME, NULL, "" };
     639          107 :     KvpFrame* pFrame = qof_instance_get_slots (inst);
     640              : 
     641          107 :     g_return_val_if_fail (sql_be != NULL, FALSE);
     642          107 :     g_return_val_if_fail (guid != NULL, FALSE);
     643          107 :     g_return_val_if_fail (pFrame != NULL, FALSE);
     644              : 
     645              :     // If this is not saving into a new db, clear out the old saved slots first
     646          107 :     if (!sql_be->pristine() && !is_infant)
     647              :     {
     648            8 :         (void)gnc_sql_slots_delete (sql_be, guid);
     649              :     }
     650              : 
     651          107 :     slot_info.be = sql_be;
     652          107 :     slot_info.guid = guid;
     653          107 :     pFrame->for_each_slot_temp (save_slot, slot_info);
     654              : 
     655          107 :     return slot_info.is_ok;
     656          107 : }
     657              : 
     658              : gboolean
     659           11 : gnc_sql_slots_delete (GncSqlBackend* sql_be, const GncGUID* guid)
     660              : {
     661              :     gchar* buf;
     662              :     gchar guid_buf[GUID_ENCODING_LENGTH + 1];
     663           11 :     slot_info_t slot_info = { NULL, NULL, TRUE, NULL, KvpValue::Type::INVALID,
     664           11 :                               NULL, FRAME, NULL, "" };
     665              : 
     666           11 :     g_return_val_if_fail (sql_be != NULL, FALSE);
     667           11 :     g_return_val_if_fail (guid != NULL, FALSE);
     668              : 
     669           11 :     (void)guid_to_string_buff (guid, guid_buf);
     670              : 
     671           11 :     buf = g_strdup_printf ("SELECT * FROM %s WHERE obj_guid='%s' and slot_type in ('%d', '%d') and not guid_val is null",
     672              :                            TABLE_NAME, guid_buf, KvpValue::Type::FRAME, KvpValue::Type::GLIST);
     673           22 :     auto stmt = sql_be->create_statement_from_sql(buf);
     674           11 :     g_free (buf);
     675           11 :     if (stmt != nullptr)
     676              :     {
     677           11 :         auto result = sql_be->execute_select_statement(stmt);
     678           12 :         for (auto row : *result)
     679              :         {
     680              :             const GncSqlColumnTableEntryPtr table_row =
     681            1 :                     col_table[guid_val_col];
     682              :             GncGUID child_guid;
     683            1 :             auto val = row.get_string_at_col (table_row->name());
     684            1 :             if (val && string_to_guid (val->c_str(), &child_guid))
     685            1 :                 gnc_sql_slots_delete (sql_be, &child_guid);
     686           12 :         }
     687              :     }
     688              : 
     689           11 :     slot_info.be = sql_be;
     690           11 :     slot_info.guid = guid;
     691           11 :     slot_info.is_ok = TRUE;
     692           11 :     slot_info.is_ok = sql_be->do_db_operation(OP_DB_DELETE, TABLE_NAME,
     693              :                                               TABLE_NAME, &slot_info,
     694              :                                               obj_guid_col_table);
     695              : 
     696           11 :     return slot_info.is_ok;
     697           11 : }
     698              : 
     699              : static void
     700           24 : load_slot (slot_info_t* pInfo, GncSqlRow& row)
     701              : {
     702              :     slot_info_t* slot_info;
     703              : 
     704           24 :     g_return_if_fail (pInfo != NULL);
     705           24 :     g_return_if_fail (pInfo->be != NULL);
     706           24 :     g_return_if_fail (pInfo->pKvpFrame != NULL);
     707              : 
     708           24 :     slot_info = slot_info_copy (pInfo, NULL);
     709              : 
     710           24 :     gnc_sql_load_object (pInfo->be, row, TABLE_NAME, slot_info, col_table);
     711              : 
     712           24 :     if (slot_info->pList != pInfo->pList)
     713              :     {
     714            0 :         if (pInfo->pList != NULL)
     715              :         {
     716            0 :             PWARN ("Load slot returned a different list than the original");
     717              :         }
     718              :         else
     719              :         {
     720            0 :             pInfo->pList = slot_info->pList;
     721              :         }
     722              :     }
     723           24 :     delete slot_info;
     724              : }
     725              : 
     726              : void
     727            9 : gnc_sql_slots_load (GncSqlBackend* sql_be, QofInstance* inst)
     728              : {
     729            9 :     slot_info_t info = { NULL, NULL, TRUE, NULL, KvpValue::Type::INVALID,
     730            9 :                          NULL, FRAME, NULL, "" };
     731            9 :     g_return_if_fail (sql_be != NULL);
     732            9 :     g_return_if_fail (inst != NULL);
     733              : 
     734            9 :     info.be = sql_be;
     735            9 :     info.guid = qof_instance_get_guid (inst);
     736            9 :     info.pKvpFrame = qof_instance_get_slots (inst);
     737            9 :     info.context = NONE;
     738              : 
     739            9 :     slots_load_info (&info);
     740            9 : }
     741              : 
     742              : static void
     743           19 : slots_load_info (slot_info_t* pInfo)
     744              : {
     745           19 :     g_return_if_fail (pInfo != NULL);
     746           19 :     g_return_if_fail (pInfo->be != NULL);
     747           19 :     g_return_if_fail (pInfo->guid != NULL);
     748           19 :     g_return_if_fail (pInfo->pKvpFrame != NULL);
     749              : 
     750           19 :     gnc::GUID guid(*pInfo->guid);
     751           19 :     std::string sql("SELECT * FROM " TABLE_NAME " WHERE obj_guid='");
     752           19 :     sql += guid.to_string() + "'";
     753           19 :     auto stmt = pInfo->be->create_statement_from_sql(sql);
     754           19 :     if (stmt != nullptr)
     755              :     {
     756           19 :         auto result = pInfo->be->execute_select_statement (stmt);
     757           43 :         for (auto row : *result)
     758           43 :             load_slot (pInfo, row);
     759           19 :         delete result;
     760              :     }
     761           19 : }
     762              : 
     763              : static  const GncGUID*
     764           50 : load_obj_guid (const GncSqlBackend* sql_be, GncSqlRow& row)
     765              : {
     766              :     static GncGUID guid;
     767              : 
     768           50 :     g_return_val_if_fail (sql_be != NULL, NULL);
     769              : 
     770           50 :     gnc_sql_load_object (sql_be, row, NULL, &guid, obj_guid_col_table);
     771              : 
     772           50 :     return &guid;
     773              : }
     774              : 
     775              : static void
     776           50 : load_slot_for_book_object (GncSqlBackend* sql_be, GncSqlRow& row,
     777              :                            BookLookupFn lookup_fn)
     778              : {
     779           50 :     slot_info_t slot_info = { NULL, NULL, TRUE, NULL, KvpValue::Type::INVALID,
     780           50 :                               NULL, FRAME, NULL, "" };
     781              :     const GncGUID* guid;
     782              :     QofInstance* inst;
     783              : 
     784           50 :     g_return_if_fail (sql_be != NULL);
     785           50 :     g_return_if_fail (lookup_fn != NULL);
     786              : 
     787           50 :     guid = load_obj_guid (sql_be, row);
     788           50 :     g_return_if_fail (guid != NULL);
     789           50 :     inst = lookup_fn (guid, sql_be->book());
     790           50 :     if (inst == NULL) return; /* Silently bail if the guid isn't loaded yet. */
     791              : 
     792           50 :     slot_info.be = sql_be;
     793           50 :     slot_info.pKvpFrame = qof_instance_get_slots (inst);
     794           50 :     slot_info.path.clear();
     795              : 
     796           50 :     gnc_sql_load_object (sql_be, row, TABLE_NAME, &slot_info, col_table);
     797           50 : }
     798              : 
     799              : /**
     800              :  * gnc_sql_slots_load_for_sql_subquery - Loads slots for all objects whose guid is
     801              :  * supplied by a subquery.  The subquery should be of the form "SELECT DISTINCT guid FROM ...".
     802              :  * This is faster than loading for one object at a time because fewer SQL queries * are used.
     803              :  *
     804              :  * @param sql_be SQL backend
     805              :  * @param subquery Subquery SQL string
     806              :  * @param lookup_fn Lookup function
     807              :  */
     808           97 : void gnc_sql_slots_load_for_sql_subquery (GncSqlBackend* sql_be,
     809              :                                           const std::string subquery,
     810              :                                           BookLookupFn lookup_fn)
     811              : {
     812           97 :     g_return_if_fail (sql_be != NULL);
     813              : 
     814              :     // Ignore empty subquery
     815           97 :     if (subquery.empty()) return;
     816              : 
     817          194 :     std::string pkey(obj_guid_col_table[0]->name());
     818           97 :     std::string sql("SELECT * FROM " TABLE_NAME " WHERE ");
     819           97 :     sql += pkey + " IN (" + subquery + ")";
     820              : 
     821              :     // Execute the query and load the slots
     822           97 :     auto stmt = sql_be->create_statement_from_sql(sql);
     823           97 :     if (stmt == nullptr)
     824              :     {
     825            0 :         PERR ("stmt == NULL, SQL = '%s'\n", sql.c_str());
     826            0 :         return;
     827              :     }
     828           97 :     auto result = sql_be->execute_select_statement(stmt);
     829          147 :     for (auto row : *result)
     830          147 :         load_slot_for_book_object (sql_be, row, lookup_fn);
     831           97 :     delete result;
     832           97 : }
     833              : 
     834              : /* ================================================================= */
     835              : void
     836           13 : GncSqlSlotsBackend::create_tables (GncSqlBackend* sql_be)
     837              : {
     838              :     gint version;
     839              :     gboolean ok;
     840              : 
     841           13 :     g_return_if_fail (sql_be != NULL);
     842              : 
     843           26 :     version = sql_be->get_table_version( TABLE_NAME);
     844           13 :     if (version == 0)
     845              :     {
     846           12 :         (void)sql_be->create_table(TABLE_NAME, TABLE_VERSION, col_table);
     847              : 
     848           24 :         ok = sql_be->create_index ("slots_guid_index", TABLE_NAME,
     849              :                                obj_guid_col_table);
     850            6 :         if (!ok)
     851              :         {
     852            0 :             PERR ("Unable to create index\n");
     853              :         }
     854              :     }
     855            7 :     else if (version < m_version)
     856              :     {
     857              :         /* Upgrade:
     858              :             1->2: 64-bit int values to proper definition, add index
     859              :             2->3: Add gdate field
     860              :             3->4: Use DATETIME instead of TIMESTAMP in MySQL
     861              :         */
     862            0 :         if (version == 1)
     863              :         {
     864            0 :             sql_be->upgrade_table(TABLE_NAME, col_table);
     865            0 :             ok = sql_be->create_index ("slots_guid_index", TABLE_NAME,
     866              :                                    obj_guid_col_table);
     867            0 :             if (!ok)
     868              :             {
     869            0 :                 PERR ("Unable to create index\n");
     870              :             }
     871              :         }
     872            0 :         else if (version == 2)
     873              :         {
     874            0 :             ok = sql_be->add_columns_to_table(TABLE_NAME, gdate_col_table);
     875            0 :             if (!ok)
     876              :             {
     877            0 :                 PERR ("Unable to add gdate column\n");
     878              :             }
     879              :         }
     880              :         else
     881              :         {
     882            0 :             sql_be->upgrade_table(TABLE_NAME, col_table);
     883              :         }
     884            0 :         sql_be->set_table_version (TABLE_NAME, TABLE_VERSION);
     885            0 :         PINFO ("Slots table upgraded from version %d to version %d\n", version,
     886              :                TABLE_VERSION);
     887              :     }
     888              : }
     889              : 
     890              : /* ========================== END OF FILE ===================== */
        

Generated by: LCOV version 2.0-1