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.6 % 366 295
Test Date: 2025-02-07 16:25:45 Functions: 97.1 % 35 34
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: - 0 0

             Branch data     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                 :          36 : _retrieve_guid_ (gpointer pObject,  gpointer pValue)
     157                 :             : {
     158                 :          36 :     GncGUID* pGuid = (GncGUID*)pObject;
     159                 :          36 :     GncGUID* guid = (GncGUID*)pValue;
     160                 :             : 
     161                 :          36 :     g_return_if_fail (pObject != NULL);
     162                 :          36 :     g_return_if_fail (pValue != NULL);
     163                 :             : 
     164                 :          36 :     *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                 :          10 : GncSqlSlotsBackend::GncSqlSlotsBackend() :
     182                 :             :     GncSqlObjectBackend(TABLE_VERSION, GNC_ID_ACCOUNT,
     183                 :          50 :                         TABLE_NAME, col_table) {}
     184                 :             : 
     185                 :             : /* ================================================================= */
     186                 :             : 
     187                 :             : static std::string
     188                 :          58 : get_key (slot_info_t* pInfo)
     189                 :             : {
     190                 :          58 :     if (!pInfo) return "";
     191                 :             : 
     192                 :          58 :     auto path = pInfo->path;
     193                 :          58 :     path.erase (0, pInfo->parent_path.size());
     194                 :          58 :     return path;
     195                 :          58 : }
     196                 :             : 
     197                 :             : static void
     198                 :          49 : set_slot_from_value (slot_info_t* pInfo, KvpValue* pValue)
     199                 :             : {
     200                 :          49 :     g_return_if_fail (pInfo != NULL);
     201                 :          49 :     g_return_if_fail (pValue != NULL);
     202                 :             : 
     203                 :          49 :     switch (pInfo->context)
     204                 :             :     {
     205                 :          49 :     case FRAME:
     206                 :             :     {
     207                 :          49 :         auto key = get_key (pInfo);
     208                 :         147 :         pInfo->pKvpFrame->set ({key}, pValue);
     209                 :          49 :         break;
     210                 :          49 :     }
     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                 :          49 : }
     232                 :             : 
     233                 :             : static  gpointer
     234                 :          72 : get_obj_guid (gpointer pObject)
     235                 :             : {
     236                 :          72 :     slot_info_t* pInfo = (slot_info_t*)pObject;
     237                 :             : 
     238                 :          72 :     g_return_val_if_fail (pObject != NULL, NULL);
     239                 :             : 
     240                 :          72 :     return (gpointer)pInfo->guid;
     241                 :             : }
     242                 :             : 
     243                 :             : static void
     244                 :          58 : set_obj_guid (void)
     245                 :             : {
     246                 :             :     // Nowhere to put the GncGUID
     247                 :          58 : }
     248                 :             : 
     249                 :             : static  gpointer
     250                 :          65 : get_path (gpointer pObject)
     251                 :             : {
     252                 :          65 :     slot_info_t* pInfo = (slot_info_t*)pObject;
     253                 :             : 
     254                 :          65 :     g_return_val_if_fail (pObject != NULL, NULL);
     255                 :             : 
     256                 :          65 :     return (gpointer)pInfo->path.c_str();
     257                 :             : }
     258                 :             : 
     259                 :             : static void
     260                 :          58 : set_path (gpointer pObject,  gpointer pValue)
     261                 :             : {
     262                 :          58 :     slot_info_t* pInfo = (slot_info_t*)pObject;
     263                 :          58 :     pInfo->path = static_cast<char*>(pValue);
     264                 :          58 :     if (pInfo->path.find (pInfo->parent_path) != 0)
     265                 :           0 :         pInfo->parent_path.clear();
     266                 :          58 : }
     267                 :             : 
     268                 :             : static KvpValue::Type
     269                 :          65 : get_slot_type (gpointer pObject)
     270                 :             : {
     271                 :          65 :     slot_info_t* pInfo = (slot_info_t*)pObject;
     272                 :             : 
     273                 :          65 :     g_return_val_if_fail (pObject != NULL, KvpValue::Type::INVALID);
     274                 :             : 
     275                 :             : //    return (gpointer)kvp_value_get_type( pInfo->pKvpValue );
     276                 :          65 :     return pInfo->value_type;
     277                 :             : }
     278                 :             : 
     279                 :             : static void
     280                 :          58 : set_slot_type (gpointer pObject,  gpointer pValue)
     281                 :             : {
     282                 :          58 :     slot_info_t* pInfo = (slot_info_t*)pObject;
     283                 :             : 
     284                 :          58 :     g_return_if_fail (pObject != NULL);
     285                 :          58 :     g_return_if_fail (pValue != NULL);
     286                 :             : 
     287                 :          58 :     pInfo->value_type = static_cast<KvpValue::Type> (GPOINTER_TO_INT (pValue));
     288                 :             : }
     289                 :             : 
     290                 :             : static gint64
     291                 :          65 : get_int64_val (gpointer pObject)
     292                 :             : {
     293                 :          65 :     slot_info_t* pInfo = (slot_info_t*)pObject;
     294                 :             : 
     295                 :          65 :     g_return_val_if_fail (pObject != NULL, 0);
     296                 :             : 
     297                 :          65 :     if (pInfo->pKvpValue->get_type () == KvpValue::Type::INT64)
     298                 :             :     {
     299                 :          14 :         return pInfo->pKvpValue->get<int64_t> ();
     300                 :             :     }
     301                 :             :     else
     302                 :             :     {
     303                 :          51 :         return 0;
     304                 :             :     }
     305                 :             : }
     306                 :             : 
     307                 :             : static void
     308                 :          58 : set_int64_val (gpointer pObject, gint64 value)
     309                 :             : {
     310                 :          58 :     slot_info_t* pInfo = (slot_info_t*)pObject;
     311                 :          58 :     KvpValue* pValue = NULL;
     312                 :             : 
     313                 :          58 :     g_return_if_fail (pObject != NULL);
     314                 :             : 
     315                 :          58 :     if (pInfo->value_type != KvpValue::Type::INT64) return;
     316                 :          14 :     pValue = new KvpValue {value};
     317                 :          14 :     set_slot_from_value (pInfo, pValue);
     318                 :             : }
     319                 :             : 
     320                 :             : static  gpointer
     321                 :          65 : get_string_val (gpointer pObject)
     322                 :             : {
     323                 :          65 :     slot_info_t* pInfo = (slot_info_t*)pObject;
     324                 :             : 
     325                 :          65 :     g_return_val_if_fail (pObject != NULL, NULL);
     326                 :             : 
     327                 :          65 :     if (pInfo->pKvpValue->get_type () == KvpValue::Type::STRING)
     328                 :             :     {
     329                 :          24 :         return (gpointer)pInfo->pKvpValue->get<const char*> ();
     330                 :             :     }
     331                 :             :     else
     332                 :             :     {
     333                 :          41 :         return NULL;
     334                 :             :     }
     335                 :             : }
     336                 :             : 
     337                 :             : static void
     338                 :          58 : set_string_val (gpointer pObject,  gpointer pValue)
     339                 :             : {
     340                 :          58 :     slot_info_t* pInfo = (slot_info_t*)pObject;
     341                 :          58 :     g_return_if_fail (pObject != NULL);
     342                 :             : 
     343                 :          58 :     if (pInfo->value_type != KvpValue::Type::STRING || pValue == NULL)
     344                 :          38 :         return;
     345                 :          40 :     auto value = new KvpValue {g_strdup(static_cast<const char*> (pValue))};
     346                 :          20 :     set_slot_from_value (pInfo, value);
     347                 :             : }
     348                 :             : 
     349                 :             : static  gpointer
     350                 :          65 : get_double_val (gpointer pObject)
     351                 :             : {
     352                 :             :     static double d_val; /* static so that we can return it. */
     353                 :          65 :     g_return_val_if_fail (pObject != NULL, NULL);
     354                 :          65 :     auto pInfo = static_cast<slot_info_t*>(pObject);
     355                 :          65 :     if (pInfo->pKvpValue->get_type () == KvpValue::Type::DOUBLE)
     356                 :             :     {
     357                 :           3 :         d_val = pInfo->pKvpValue->get<double> ();
     358                 :           3 :         return (gpointer)&d_val;
     359                 :             :     }
     360                 :             :     else
     361                 :             :     {
     362                 :          62 :         return NULL;
     363                 :             :     }
     364                 :             : }
     365                 :             : 
     366                 :             : static void
     367                 :          58 : set_double_val (gpointer pObject,  gpointer pValue)
     368                 :             : {
     369                 :          58 :     slot_info_t* pInfo = (slot_info_t*)pObject;
     370                 :          58 :     KvpValue* value = NULL;
     371                 :             : 
     372                 :          58 :     g_return_if_fail (pObject != NULL);
     373                 :             : 
     374                 :          58 :     if (pInfo->value_type != KvpValue::Type::DOUBLE || pValue == NULL) return;
     375                 :           3 :     value = new KvpValue {* (static_cast<double*> (pValue))};
     376                 :           3 :     set_slot_from_value (pInfo, value);
     377                 :             : }
     378                 :             : 
     379                 :             : static time64
     380                 :          65 : get_time_val (gpointer pObject)
     381                 :             : {
     382                 :          65 :     slot_info_t* pInfo = (slot_info_t*)pObject;
     383                 :             : 
     384                 :          65 :     g_return_val_if_fail (pObject != NULL, 0);
     385                 :             : 
     386                 :             : //if( kvp_value_get_type( pInfo->pKvpValue ) == KvpValue::Type::TIME64 ) {
     387                 :          65 :     auto t = pInfo->pKvpValue->get<Time64> ();
     388                 :          65 :     return t.t;
     389                 :             : }
     390                 :             : 
     391                 :             : static void
     392                 :          58 : set_time_val (gpointer pObject, time64 time)
     393                 :             : {
     394                 :          58 :     slot_info_t* pInfo = (slot_info_t*)pObject;
     395                 :          58 :     KvpValue* value = NULL;
     396                 :          58 :     Time64 t{time};
     397                 :         115 :     g_return_if_fail (pObject != NULL);
     398                 :             : 
     399                 :          58 :     if (pInfo->value_type != KvpValue::Type::TIME64) return;
     400                 :           1 :     value = new KvpValue {t};
     401                 :           1 :     set_slot_from_value (pInfo, value);
     402                 :             : }
     403                 :             : 
     404                 :             : static  gpointer
     405                 :          65 : get_guid_val (gpointer pObject)
     406                 :             : {
     407                 :          65 :     slot_info_t* pInfo = (slot_info_t*)pObject;
     408                 :             : 
     409                 :          65 :     g_return_val_if_fail (pObject != NULL, NULL);
     410                 :             : 
     411                 :          65 :     if (pInfo->pKvpValue->get_type () == KvpValue::Type::GUID)
     412                 :             :     {
     413                 :          20 :         return (gpointer)pInfo->pKvpValue->get<GncGUID*> ();
     414                 :             :     }
     415                 :             :     else
     416                 :             :     {
     417                 :          45 :         return NULL;
     418                 :             :     }
     419                 :             : }
     420                 :             : 
     421                 :             : static void
     422                 :          17 : set_guid_val (gpointer pObject,  gpointer pValue)
     423                 :             : {
     424                 :          17 :     slot_info_t* pInfo = (slot_info_t*)pObject;
     425                 :             : 
     426                 :          17 :     g_return_if_fail (pObject != NULL);
     427                 :          17 :     if (pValue == NULL) return;
     428                 :             : 
     429                 :          17 :     switch (pInfo->value_type)
     430                 :             :     {
     431                 :           8 :     case KvpValue::Type::GUID:
     432                 :             :     {
     433                 :           8 :         auto new_guid = guid_copy (static_cast<GncGUID*> (pValue));
     434                 :           8 :         set_slot_from_value (pInfo, new KvpValue {new_guid});
     435                 :           8 :         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                 :           9 :     case KvpValue::Type::FRAME:
     452                 :             :     {
     453                 :           9 :         slot_info_t* newInfo = slot_info_copy (pInfo, (GncGUID*)pValue) ;
     454                 :           9 :         auto newFrame = new KvpFrame;
     455                 :           9 :         newInfo->pKvpFrame = newFrame;
     456                 :             : 
     457                 :           9 :         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                 :           9 :         case FRAME:
     467                 :             :         default:
     468                 :             :         {
     469                 :           9 :             auto key = get_key (pInfo);
     470                 :          36 :             pInfo->pKvpFrame->set ({key.c_str()}, new KvpValue {newFrame});
     471                 :           9 :             break;
     472                 :           9 :         }
     473                 :             :         }
     474                 :             : 
     475                 :           9 :         newInfo->context = FRAME;
     476                 :           9 :         slots_load_info (newInfo);
     477                 :           9 :         delete newInfo;
     478                 :           9 :         break;
     479                 :             :     }
     480                 :           0 :     default:
     481                 :           0 :         break;
     482                 :             :     }
     483                 :          27 : }
     484                 :             : 
     485                 :             : static gnc_numeric
     486                 :          65 : get_numeric_val (gpointer pObject)
     487                 :             : {
     488                 :          65 :     slot_info_t* pInfo = (slot_info_t*)pObject;
     489                 :             : 
     490                 :          65 :     g_return_val_if_fail (pObject != NULL, gnc_numeric_zero ());
     491                 :             : 
     492                 :          65 :     if (pInfo->pKvpValue->get_type () == KvpValue::Type::NUMERIC)
     493                 :             :     {
     494                 :           3 :         return pInfo->pKvpValue->get<gnc_numeric> ();
     495                 :             :     }
     496                 :             :     else
     497                 :             :     {
     498                 :          62 :         return gnc_numeric_zero ();
     499                 :             :     }
     500                 :             : }
     501                 :             : 
     502                 :             : static void
     503                 :          58 : set_numeric_val (gpointer pObject, gnc_numeric value)
     504                 :             : {
     505                 :          58 :     slot_info_t* pInfo = (slot_info_t*)pObject;
     506                 :             : 
     507                 :          58 :     g_return_if_fail (pObject != NULL);
     508                 :             : 
     509                 :          58 :     if (pInfo->value_type != KvpValue::Type::NUMERIC) return;
     510                 :           3 :     set_slot_from_value (pInfo, new KvpValue {value});
     511                 :             : }
     512                 :             : 
     513                 :             : static GDate*
     514                 :          65 : get_gdate_val (gpointer pObject)
     515                 :             : {
     516                 :          65 :     slot_info_t* pInfo = (slot_info_t*)pObject;
     517                 :             :     static GDate date;
     518                 :             : 
     519                 :          65 :     g_return_val_if_fail (pObject != NULL, NULL);
     520                 :             : 
     521                 :          65 :     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                 :          65 :         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                 :          43 : slot_info_copy (slot_info_t* pInfo, GncGUID* guid)
     545                 :             : {
     546                 :          43 :     g_return_val_if_fail (pInfo != NULL, NULL);
     547                 :          43 :     auto newSlot = new slot_info_t;
     548                 :             : 
     549                 :          43 :     newSlot->be = pInfo->be;
     550                 :          43 :     newSlot->guid = guid == NULL ? pInfo->guid : guid;
     551                 :          43 :     newSlot->is_ok = pInfo->is_ok;
     552                 :          43 :     newSlot->pKvpFrame = pInfo->pKvpFrame;
     553                 :          43 :     newSlot->value_type = pInfo->value_type;
     554                 :          43 :     newSlot->pList = pInfo->pList;
     555                 :          43 :     newSlot->context = pInfo->context;
     556                 :          43 :     newSlot->pKvpValue = pInfo->pKvpValue;
     557                 :          43 :     if (!pInfo->path.empty())
     558                 :          21 :         newSlot->parent_path = pInfo->path + "/";
     559                 :             :     else
     560                 :          22 :         newSlot->parent_path = pInfo->parent_path;
     561                 :          43 :     return newSlot;
     562                 :             : }
     563                 :             : 
     564                 :             : static void
     565                 :          65 : save_slot (const char* key, KvpValue* value, slot_info_t & slot_info)
     566                 :             : {
     567                 :          65 :     g_return_if_fail (value != NULL);
     568                 :             : 
     569                 :             :     // Ignore if we've already run into a failure
     570                 :          65 :     if (!slot_info.is_ok)
     571                 :             :     {
     572                 :           0 :         return;
     573                 :             :     }
     574                 :          65 :     slot_info.pKvpValue = value;
     575                 :          65 :     slot_info.path = slot_info.parent_path + key;
     576                 :          65 :     slot_info.value_type = value->get_type ();
     577                 :             : 
     578                 :          65 :     switch (slot_info.value_type)
     579                 :             :     {
     580                 :          12 :     case KvpValue::Type::FRAME:
     581                 :             :     {
     582                 :          12 :         auto pKvpFrame = value->get<KvpFrame*> ();
     583                 :          12 :         auto guid = guid_new ();
     584                 :          12 :         slot_info_t* pNewInfo = slot_info_copy (&slot_info, guid);
     585                 :          12 :         KvpValue* oldValue = slot_info.pKvpValue;
     586                 :          12 :         slot_info.pKvpValue = new KvpValue {guid};
     587                 :          12 :         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                 :          12 :         g_return_if_fail (slot_info.is_ok);
     593                 :          12 :         pKvpFrame->for_each_slot_temp (save_slot, *pNewInfo);
     594                 :          12 :         delete slot_info.pKvpValue;
     595                 :          12 :         slot_info.pKvpValue = oldValue;
     596                 :          12 :         delete pNewInfo;
     597                 :             :     }
     598                 :          12 :     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                 :          53 :     default:
     622                 :             :     {
     623                 :          53 :         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                 :          53 :     break;
     630                 :             :     }
     631                 :             : }
     632                 :             : 
     633                 :             : gboolean
     634                 :          94 : gnc_sql_slots_save (GncSqlBackend* sql_be, const GncGUID* guid, gboolean is_infant,
     635                 :             :                     QofInstance* inst)
     636                 :             : {
     637                 :          94 :     slot_info_t slot_info = { NULL, NULL, TRUE, NULL, KvpValue::Type::INVALID,
     638                 :          94 :                               NULL, FRAME, NULL, "" };
     639                 :          94 :     KvpFrame* pFrame = qof_instance_get_slots (inst);
     640                 :             : 
     641                 :          94 :     g_return_val_if_fail (sql_be != NULL, FALSE);
     642                 :          94 :     g_return_val_if_fail (guid != NULL, FALSE);
     643                 :          94 :     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                 :          94 :     if (!sql_be->pristine() && !is_infant)
     647                 :             :     {
     648                 :           6 :         (void)gnc_sql_slots_delete (sql_be, guid);
     649                 :             :     }
     650                 :             : 
     651                 :          94 :     slot_info.be = sql_be;
     652                 :          94 :     slot_info.guid = guid;
     653                 :          94 :     pFrame->for_each_slot_temp (save_slot, slot_info);
     654                 :             : 
     655                 :          94 :     return slot_info.is_ok;
     656                 :          94 : }
     657                 :             : 
     658                 :             : gboolean
     659                 :           7 : gnc_sql_slots_delete (GncSqlBackend* sql_be, const GncGUID* guid)
     660                 :             : {
     661                 :             :     gchar* buf;
     662                 :             :     gchar guid_buf[GUID_ENCODING_LENGTH + 1];
     663                 :           7 :     slot_info_t slot_info = { NULL, NULL, TRUE, NULL, KvpValue::Type::INVALID,
     664                 :           7 :                               NULL, FRAME, NULL, "" };
     665                 :             : 
     666                 :           7 :     g_return_val_if_fail (sql_be != NULL, FALSE);
     667                 :           7 :     g_return_val_if_fail (guid != NULL, FALSE);
     668                 :             : 
     669                 :           7 :     (void)guid_to_string_buff (guid, guid_buf);
     670                 :             : 
     671                 :           7 :     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                 :          14 :     auto stmt = sql_be->create_statement_from_sql(buf);
     674                 :           7 :     g_free (buf);
     675                 :           7 :     if (stmt != nullptr)
     676                 :             :     {
     677                 :           7 :         auto result = sql_be->execute_select_statement(stmt);
     678                 :           8 :         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                 :           8 :         }
     687                 :             :     }
     688                 :             : 
     689                 :           7 :     slot_info.be = sql_be;
     690                 :           7 :     slot_info.guid = guid;
     691                 :           7 :     slot_info.is_ok = TRUE;
     692                 :           7 :     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                 :           7 :     return slot_info.is_ok;
     697                 :           7 : }
     698                 :             : 
     699                 :             : static void
     700                 :          22 : load_slot (slot_info_t* pInfo, GncSqlRow& row)
     701                 :             : {
     702                 :             :     slot_info_t* slot_info;
     703                 :             : 
     704                 :          22 :     g_return_if_fail (pInfo != NULL);
     705                 :          22 :     g_return_if_fail (pInfo->be != NULL);
     706                 :          22 :     g_return_if_fail (pInfo->pKvpFrame != NULL);
     707                 :             : 
     708                 :          22 :     slot_info = slot_info_copy (pInfo, NULL);
     709                 :             : 
     710                 :          22 :     gnc_sql_load_object (pInfo->be, row, TABLE_NAME, slot_info, col_table);
     711                 :             : 
     712                 :          22 :     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                 :          22 :     delete slot_info;
     724                 :             : }
     725                 :             : 
     726                 :             : void
     727                 :           7 : gnc_sql_slots_load (GncSqlBackend* sql_be, QofInstance* inst)
     728                 :             : {
     729                 :           7 :     slot_info_t info = { NULL, NULL, TRUE, NULL, KvpValue::Type::INVALID,
     730                 :           7 :                          NULL, FRAME, NULL, "" };
     731                 :           7 :     g_return_if_fail (sql_be != NULL);
     732                 :           7 :     g_return_if_fail (inst != NULL);
     733                 :             : 
     734                 :           7 :     info.be = sql_be;
     735                 :           7 :     info.guid = qof_instance_get_guid (inst);
     736                 :           7 :     info.pKvpFrame = qof_instance_get_slots (inst);
     737                 :           7 :     info.context = NONE;
     738                 :             : 
     739                 :           7 :     slots_load_info (&info);
     740                 :           7 : }
     741                 :             : 
     742                 :             : static void
     743                 :          16 : slots_load_info (slot_info_t* pInfo)
     744                 :             : {
     745                 :          16 :     g_return_if_fail (pInfo != NULL);
     746                 :          16 :     g_return_if_fail (pInfo->be != NULL);
     747                 :          16 :     g_return_if_fail (pInfo->guid != NULL);
     748                 :          16 :     g_return_if_fail (pInfo->pKvpFrame != NULL);
     749                 :             : 
     750                 :          16 :     gnc::GUID guid(*pInfo->guid);
     751                 :          16 :     std::string sql("SELECT * FROM " TABLE_NAME " WHERE obj_guid='");
     752                 :          16 :     sql += guid.to_string() + "'";
     753                 :          16 :     auto stmt = pInfo->be->create_statement_from_sql(sql);
     754                 :          16 :     if (stmt != nullptr)
     755                 :             :     {
     756                 :          16 :         auto result = pInfo->be->execute_select_statement (stmt);
     757                 :          38 :         for (auto row : *result)
     758                 :          38 :             load_slot (pInfo, row);
     759                 :          16 :         delete result;
     760                 :             :     }
     761                 :          16 : }
     762                 :             : 
     763                 :             : static  const GncGUID*
     764                 :          36 : load_obj_guid (const GncSqlBackend* sql_be, GncSqlRow& row)
     765                 :             : {
     766                 :             :     static GncGUID guid;
     767                 :             : 
     768                 :          36 :     g_return_val_if_fail (sql_be != NULL, NULL);
     769                 :             : 
     770                 :          36 :     gnc_sql_load_object (sql_be, row, NULL, &guid, obj_guid_col_table);
     771                 :             : 
     772                 :          36 :     return &guid;
     773                 :             : }
     774                 :             : 
     775                 :             : static void
     776                 :          36 : load_slot_for_book_object (GncSqlBackend* sql_be, GncSqlRow& row,
     777                 :             :                            BookLookupFn lookup_fn)
     778                 :             : {
     779                 :          36 :     slot_info_t slot_info = { NULL, NULL, TRUE, NULL, KvpValue::Type::INVALID,
     780                 :          36 :                               NULL, FRAME, NULL, "" };
     781                 :             :     const GncGUID* guid;
     782                 :             :     QofInstance* inst;
     783                 :             : 
     784                 :          36 :     g_return_if_fail (sql_be != NULL);
     785                 :          36 :     g_return_if_fail (lookup_fn != NULL);
     786                 :             : 
     787                 :          36 :     guid = load_obj_guid (sql_be, row);
     788                 :          36 :     g_return_if_fail (guid != NULL);
     789                 :          36 :     inst = lookup_fn (guid, sql_be->book());
     790                 :          36 :     if (inst == NULL) return; /* Silently bail if the guid isn't loaded yet. */
     791                 :             : 
     792                 :          36 :     slot_info.be = sql_be;
     793                 :          36 :     slot_info.pKvpFrame = qof_instance_get_slots (inst);
     794                 :          36 :     slot_info.path.clear();
     795                 :             : 
     796                 :          36 :     gnc_sql_load_object (sql_be, row, TABLE_NAME, &slot_info, col_table);
     797                 :          36 : }
     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                 :          69 : void gnc_sql_slots_load_for_sql_subquery (GncSqlBackend* sql_be,
     809                 :             :                                           const std::string subquery,
     810                 :             :                                           BookLookupFn lookup_fn)
     811                 :             : {
     812                 :          69 :     g_return_if_fail (sql_be != NULL);
     813                 :             : 
     814                 :             :     // Ignore empty subquery
     815                 :          69 :     if (subquery.empty()) return;
     816                 :             : 
     817                 :         138 :     std::string pkey(obj_guid_col_table[0]->name());
     818                 :          69 :     std::string sql("SELECT * FROM " TABLE_NAME " WHERE ");
     819                 :          69 :     sql += pkey + " IN (" + subquery + ")";
     820                 :             : 
     821                 :             :     // Execute the query and load the slots
     822                 :          69 :     auto stmt = sql_be->create_statement_from_sql(sql);
     823                 :          69 :     if (stmt == nullptr)
     824                 :             :     {
     825                 :           0 :         PERR ("stmt == NULL, SQL = '%s'\n", sql.c_str());
     826                 :           0 :         return;
     827                 :             :     }
     828                 :          69 :     auto result = sql_be->execute_select_statement(stmt);
     829                 :         105 :     for (auto row : *result)
     830                 :         105 :         load_slot_for_book_object (sql_be, row, lookup_fn);
     831                 :          69 :     delete result;
     832                 :          69 : }
     833                 :             : 
     834                 :             : /* ================================================================= */
     835                 :             : void
     836                 :          10 : GncSqlSlotsBackend::create_tables (GncSqlBackend* sql_be)
     837                 :             : {
     838                 :             :     gint version;
     839                 :             :     gboolean ok;
     840                 :             : 
     841                 :          10 :     g_return_if_fail (sql_be != NULL);
     842                 :             : 
     843                 :          20 :     version = sql_be->get_table_version( TABLE_NAME);
     844                 :          10 :     if (version == 0)
     845                 :             :     {
     846                 :          10 :         (void)sql_be->create_table(TABLE_NAME, TABLE_VERSION, col_table);
     847                 :             : 
     848                 :          20 :         ok = sql_be->create_index ("slots_guid_index", TABLE_NAME,
     849                 :             :                                obj_guid_col_table);
     850                 :           5 :         if (!ok)
     851                 :             :         {
     852                 :           0 :             PERR ("Unable to create index\n");
     853                 :             :         }
     854                 :             :     }
     855                 :           5 :     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