LCOV - code coverage report
Current view: top level - libgnucash/backend/sql - gnc-sql-column-table-entry.cpp (source / functions) Coverage Total Hit
Test: gnucash.info Lines: 90.8 % 303 275
Test Date: 2026-11-02 18:19:43 Functions: 95.0 % 40 38
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /********************************************************************
       2              :  * gnc-sql-column-table-entry.cpp: Implement GncSqlColumnTableEntry *
       3              :  *                                                                  *
       4              :  * Copyright 2016 John Ralls <jralls@ceridwen.us>                   *
       5              :  *                                                                  *
       6              :  * This program is free software; you can redistribute it and/or    *
       7              :  * modify it under the terms of the GNU General Public License as   *
       8              :  * published by the Free Software Foundation; either version 2 of   *
       9              :  * the License, or (at your option) any later version.              *
      10              :  *                                                                  *
      11              :  * This program is distributed in the hope that it will be useful,  *
      12              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
      13              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
      14              :  * GNU General Public License for more details.                     *
      15              :  *                                                                  *
      16              :  * You should have received a copy of the GNU General Public License*
      17              :  * along with this program; if not, contact:                        *
      18              :  *                                                                  *
      19              :  * Free Software Foundation           Voice:  +1-617-542-5942       *
      20              :  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
      21              :  * Boston, MA  02110-1301,  USA       gnu@gnu.org                   *
      22              : \********************************************************************/
      23              : 
      24              : #include <config.h>
      25              : #include <qof.h>
      26              : #include <sstream>
      27              : #include <iomanip>
      28              : #include <cstdint>
      29              : #include <gnc-datetime.hpp>
      30              : #include "gnc-sql-backend.hpp"
      31              : #include "gnc-sql-object-backend.hpp"
      32              : #include "gnc-sql-column-table-entry.hpp"
      33              : #include "gnc-sql-result.hpp"
      34              : 
      35              : static QofLogModule log_module = G_LOG_DOMAIN;
      36              : 
      37              : /* ================================================================= */
      38              : static gpointer
      39            0 : get_autoinc_id (void* object, const QofParam* param)
      40              : {
      41              :     // Just need a 0 to force a new autoinc value
      42            0 :     return (gpointer)0;
      43              : }
      44              : 
      45              : static void
      46           81 : set_autoinc_id (void* object, void* item)
      47              : {
      48              :     // Nowhere to put the ID
      49           81 : }
      50              : 
      51              : QofAccessFunc
      52         1121 : GncSqlColumnTableEntry::get_getter (QofIdTypeConst obj_name) const noexcept
      53              : {
      54              :     QofAccessFunc getter;
      55              : 
      56         1121 :     g_return_val_if_fail (obj_name != NULL, NULL);
      57              : 
      58         1121 :     if (m_flags & COL_AUTOINC)
      59              :     {
      60            0 :         getter = get_autoinc_id;
      61              :     }
      62         1121 :     else if (m_qof_param_name != NULL)
      63              :     {
      64           76 :         getter = qof_class_get_parameter_getter (obj_name, m_qof_param_name);
      65              :     }
      66              :     else
      67              :     {
      68         1045 :         getter = m_getter;
      69              :     }
      70              : 
      71         1121 :     return getter;
      72              : }
      73              : 
      74              : QofSetterFunc
      75         2983 : GncSqlColumnTableEntry::get_setter(QofIdTypeConst obj_name) const noexcept
      76              : {
      77         2983 :     QofSetterFunc setter = nullptr;
      78         2983 :     if (m_flags & COL_AUTOINC)
      79              :     {
      80          162 :         setter = set_autoinc_id;
      81              :     }
      82         2821 :     else if (m_qof_param_name != nullptr)
      83              :     {
      84          140 :         g_assert (obj_name != NULL);
      85          140 :         setter = qof_class_get_parameter_setter (obj_name, m_qof_param_name);
      86              :     }
      87              :     else
      88              :     {
      89         2681 :         setter = m_setter;
      90              :     }
      91         2983 :     return setter;
      92              : }
      93              : 
      94              : void
      95          147 : GncSqlColumnTableEntry::add_objectref_guid_to_query (QofIdTypeConst obj_name,
      96              :                                                      const void* pObject,
      97              :                                                      PairVec& vec) const noexcept
      98              : {
      99          147 :     auto inst = get_row_value_from_object<QofInstance*>(obj_name, pObject);
     100          147 :     if (inst == nullptr) return;
     101          100 :     auto guid = qof_instance_get_guid (inst);
     102          100 :     if (guid != nullptr) {
     103          100 :         gchar *guid_s = guid_to_string(guid);
     104          300 :         vec.emplace_back (std::make_pair (std::string{m_col_name}, quote_string(guid_s)));
     105          100 :         g_free(guid_s);
     106              :     }
     107              : }
     108              : 
     109              : void
     110          198 : GncSqlColumnTableEntry::add_objectref_guid_to_table (ColVec& vec) const noexcept
     111              : {
     112          198 :     GncSqlColumnInfo info{*this, BCT_STRING, GUID_ENCODING_LENGTH, FALSE};
     113          198 :     vec.emplace_back(std::move(info));
     114          198 : }
     115              : 
     116              : 
     117              : /* ----------------------------------------------------------------- */
     118              : template<> void
     119          506 : GncSqlColumnTableEntryImpl<CT_STRING>::load (const GncSqlBackend* sql_be,
     120              :                                              GncSqlRow& row,
     121              :                                              QofIdTypeConst obj_name,
     122              :                                              gpointer pObject) const noexcept
     123              : {
     124          506 :     g_return_if_fail (pObject != NULL);
     125          506 :     g_return_if_fail (m_gobj_param_name != NULL || get_setter(obj_name) != NULL);
     126              : 
     127          506 :     auto s = row.get_string_at_col (m_col_name);
     128          506 :     if (s)
     129          506 :         set_parameter(pObject, s->c_str(), get_setter(obj_name), m_gobj_param_name);
     130          506 : }
     131              : 
     132              : template<> void
     133          324 : GncSqlColumnTableEntryImpl<CT_STRING>::add_to_table(ColVec& vec) const noexcept
     134              : {
     135          324 :     GncSqlColumnInfo info{*this, BCT_STRING, m_size, TRUE};
     136          324 :     vec.emplace_back(std::move(info));
     137          324 : }
     138              : 
     139              : /* char is unusual in that we get a pointer but don't deref it to pass
     140              :  * it to operator<<().
     141              :  */
     142              : template<> void
     143          789 : GncSqlColumnTableEntryImpl<CT_STRING>::add_to_query(QofIdTypeConst obj_name,
     144              :                                                     const gpointer pObject,
     145              :                                                     PairVec& vec) const noexcept
     146              : {
     147          789 :     auto s = get_row_value_from_object<char*>(obj_name, pObject);
     148              : 
     149          789 :     if (s != nullptr)
     150              :     {
     151          736 :         std::ostringstream stream;
     152          736 :         stream << s;
     153         1472 :         vec.emplace_back (std::make_pair (std::string{m_col_name},
     154         1472 :                                           quote_string(stream.str())));
     155          736 :         return;
     156          736 :     }
     157              : }
     158              : 
     159              : /* ----------------------------------------------------------------- */
     160              : typedef gint (*IntAccessFunc) (const gpointer);
     161              : typedef void (*IntSetterFunc) (const gpointer, gint);
     162              : 
     163              : template<> void
     164          232 : GncSqlColumnTableEntryImpl<CT_INT>::load (const GncSqlBackend* sql_be,
     165              :                                           GncSqlRow& row,
     166              :                                           QofIdTypeConst obj_name,
     167              :                                           gpointer pObject) const noexcept
     168              : {
     169              : 
     170          232 :     g_return_if_fail (pObject != NULL);
     171          232 :     g_return_if_fail (m_gobj_param_name != NULL || get_setter(obj_name) != NULL);
     172              : 
     173          232 :     auto val = row.get_int_at_col(m_col_name);
     174          232 :     if (val)
     175          232 :         set_parameter(pObject, *val,
     176          232 :                       reinterpret_cast<IntSetterFunc>(get_setter(obj_name)),
     177          232 :                       m_gobj_param_name);
     178              : }
     179              : 
     180              : template<> void
     181          138 : GncSqlColumnTableEntryImpl<CT_INT>::add_to_table(ColVec& vec) const noexcept
     182              : {
     183          138 :     GncSqlColumnInfo info{*this, BCT_INT, 0, FALSE};
     184          138 :     vec.emplace_back(std::move(info));
     185          138 : }
     186              : 
     187              : template<> void
     188          199 : GncSqlColumnTableEntryImpl<CT_INT>::add_to_query(QofIdTypeConst obj_name,
     189              :                                                  const gpointer pObject,
     190              :                                                  PairVec& vec) const noexcept
     191              : {
     192          199 :     add_value_to_vec<int>(obj_name, pObject, vec);
     193          199 : }
     194              : 
     195              : /* ----------------------------------------------------------------- */
     196              : typedef gboolean (*BooleanAccessFunc) (const gpointer);
     197              : typedef void (*BooleanSetterFunc) (const gpointer, gboolean);
     198              : 
     199              : template<> void
     200          160 : GncSqlColumnTableEntryImpl<CT_BOOLEAN>::load (const GncSqlBackend* sql_be,
     201              :                                               GncSqlRow& row,
     202              :                                               QofIdTypeConst obj_name,
     203              :                                               gpointer pObject)
     204              :     const noexcept
     205              : {
     206          160 :     g_return_if_fail (pObject != NULL);
     207          160 :     g_return_if_fail (m_gobj_param_name != NULL || get_setter(obj_name) != NULL);
     208              : 
     209          160 :     auto val = row.get_int_at_col (m_col_name);
     210          160 :     if (val)
     211          160 :         set_parameter(pObject, static_cast<int>(*val),
     212          160 :                       reinterpret_cast<BooleanSetterFunc>(get_setter(obj_name)),
     213          160 :                       m_gobj_param_name);
     214              : }
     215              : 
     216              : template<> void
     217          138 : GncSqlColumnTableEntryImpl<CT_BOOLEAN>::add_to_table(ColVec& vec) const noexcept
     218              : {
     219          138 :     GncSqlColumnInfo info{*this, BCT_INT, 0, FALSE};
     220          138 :     vec.emplace_back(std::move(info));
     221          138 : }
     222              : 
     223              : template<> void
     224          203 : GncSqlColumnTableEntryImpl<CT_BOOLEAN>::add_to_query(QofIdTypeConst obj_name,
     225              :                                                     const gpointer pObject,
     226              :                                                     PairVec& vec) const noexcept
     227              : {
     228          203 :     add_value_to_vec<int>(obj_name, pObject, vec);
     229          203 : }
     230              : 
     231              : /* ----------------------------------------------------------------- */
     232              : typedef gint64 (*Int64AccessFunc) (const gpointer);
     233              : typedef void (*Int64SetterFunc) (const gpointer, gint64);
     234              : 
     235              : template<> void
     236           76 : GncSqlColumnTableEntryImpl<CT_INT64>::load (const GncSqlBackend* sql_be,
     237              :                                             GncSqlRow& row,
     238              :                                             QofIdTypeConst obj_name,
     239              :                                             gpointer pObject)
     240              :     const noexcept
     241              : {
     242           76 :     g_return_if_fail (m_gobj_param_name != nullptr || get_setter(obj_name) != nullptr);
     243              : 
     244           76 :     auto val = row.get_int_at_col (m_col_name);
     245           76 :     if (val)
     246           76 :         set_parameter(pObject, *val,
     247           76 :                       reinterpret_cast<Int64SetterFunc>(get_setter(obj_name)),
     248           76 :                       m_gobj_param_name);
     249              : }
     250              : 
     251              : template<> void
     252           12 : GncSqlColumnTableEntryImpl<CT_INT64>::add_to_table(ColVec& vec) const noexcept
     253              : {
     254              : 
     255           12 :     GncSqlColumnInfo info{*this, BCT_INT64, 0, FALSE};
     256           12 :     vec.emplace_back(std::move(info));
     257           12 : }
     258              : 
     259              : template<> gint64
     260           77 : GncSqlColumnTableEntry::get_row_value_from_object<int64_t>(QofIdTypeConst obj_name,
     261              :                                                                const void* pObject) const
     262              : {
     263           77 :     g_return_val_if_fail(obj_name != nullptr && pObject != nullptr,
     264              :                          INT64_C(0));
     265           77 :     int64_t result = INT64_C(0);
     266           77 :     if (m_gobj_param_name != nullptr)
     267            2 :         g_object_get(const_cast<void*>(pObject), m_gobj_param_name,
     268              :                      &result, nullptr);
     269              :     else
     270              :     {
     271           75 :         auto getter = (Int64AccessFunc)get_getter(obj_name);
     272           75 :         if (getter != nullptr)
     273           75 :             result = (getter)(const_cast<void*>(pObject));
     274              :     }
     275           77 :     return result;
     276              : }
     277              : 
     278              : template<> void
     279           77 : GncSqlColumnTableEntryImpl<CT_INT64>::add_to_query(QofIdTypeConst obj_name,
     280              :                                                    const gpointer pObject,
     281              :                                                    PairVec& vec) const noexcept
     282              : {
     283           77 :     add_value_to_vec<int64_t>(obj_name, pObject, vec);
     284           77 : }
     285              : /* ----------------------------------------------------------------- */
     286              : 
     287              : template<> void
     288           74 : GncSqlColumnTableEntryImpl<CT_DOUBLE>::load (const GncSqlBackend* sql_be,
     289              :                                              GncSqlRow& row,
     290              :                                              QofIdTypeConst obj_name,
     291              :                                              gpointer pObject)
     292              :     const noexcept
     293              : {
     294           74 :     g_return_if_fail (pObject != NULL);
     295           74 :     g_return_if_fail (m_gobj_param_name != nullptr || get_setter(obj_name) != nullptr);
     296           74 :     double val{0.0};
     297              : 
     298           74 :     if (auto int_val{row.get_int_at_col(m_col_name)})
     299            0 :         val = static_cast<decltype(val)>(*int_val);
     300           74 :     else if (auto float_val{row.get_float_at_col(m_col_name)})
     301            0 :         val = static_cast<decltype(val)>(*float_val);
     302           74 :     else if (auto double_val{row.get_double_at_col(m_col_name)})
     303           74 :         val = *double_val;
     304              : 
     305           74 :     set_parameter(pObject, val, get_setter(obj_name), m_gobj_param_name);
     306              : }
     307              : 
     308              : template<> void
     309            6 : GncSqlColumnTableEntryImpl<CT_DOUBLE>::add_to_table(ColVec& vec) const noexcept
     310              : {
     311            6 :     GncSqlColumnInfo info{*this, BCT_DOUBLE, 0, FALSE};
     312            6 :     vec.emplace_back(std::move(info));
     313            6 : }
     314              : 
     315              : template<> void
     316           75 : GncSqlColumnTableEntryImpl<CT_DOUBLE>::add_to_query(QofIdTypeConst obj_name,
     317              :                                                     const gpointer pObject,
     318              :                                                     PairVec& vec) const noexcept
     319              : {
     320           75 :     add_value_to_vec<double*>(obj_name, pObject, vec);
     321           75 : }
     322              : 
     323              : /* ----------------------------------------------------------------- */
     324              : 
     325              : template<> void
     326          474 : GncSqlColumnTableEntryImpl<CT_GUID>::load (const GncSqlBackend* sql_be,
     327              :                                            GncSqlRow& row,
     328              :                                            QofIdTypeConst obj_name,
     329              :                                            gpointer pObject)
     330              :     const noexcept
     331              : {
     332              : 
     333              :     GncGUID guid;
     334              : 
     335          474 :     g_return_if_fail (pObject != NULL);
     336          474 :     g_return_if_fail (m_gobj_param_name != nullptr || get_setter(obj_name) != nullptr);
     337              : 
     338          474 :     auto strval{row.get_string_at_col(m_col_name)};
     339          474 :     if (strval && string_to_guid (strval->c_str(), &guid))
     340          395 :         set_parameter(pObject, &guid, get_setter(obj_name), m_gobj_param_name);
     341          474 : }
     342              : 
     343              : template<> void
     344          156 : GncSqlColumnTableEntryImpl<CT_GUID>::add_to_table(ColVec& vec) const noexcept
     345              : {
     346          156 :     GncSqlColumnInfo info{*this, BCT_STRING, GUID_ENCODING_LENGTH, FALSE};
     347          156 :     vec.emplace_back(std::move(info));
     348          156 : }
     349              : 
     350              : template<> void
     351          397 : GncSqlColumnTableEntryImpl<CT_GUID>::add_to_query(QofIdTypeConst obj_name,
     352              :                                                   const gpointer pObject,
     353              :                                                   PairVec& vec) const noexcept
     354              : {
     355          397 :     auto s = get_row_value_from_object<GncGUID*>(obj_name, pObject);
     356              : 
     357          397 :     if (s != nullptr)
     358              :     {
     359          327 :         gchar *guid_s = guid_to_string(s);
     360          981 :         vec.emplace_back (std::make_pair (std::string{m_col_name}, quote_string(guid_s)));
     361          327 :         g_free(guid_s);
     362          327 :         return;
     363              :     }
     364              : }
     365              : /* ----------------------------------------------------------------- */
     366              : typedef time64 (*Time64AccessFunc) (const gpointer);
     367              : typedef void (*Time64SetterFunc) (const gpointer, time64);
     368              : constexpr int TIME_COL_SIZE = 4 + 3 + 3 + 3 + 3 + 3;
     369              : 
     370              : template<> void
     371          125 : GncSqlColumnTableEntryImpl<CT_TIME>::load (const GncSqlBackend* sql_be,
     372              :                                             GncSqlRow& row,
     373              :                                             QofIdTypeConst obj_name,
     374              :                                             gpointer pObject)
     375              :     const noexcept
     376              : {
     377          125 :     time64 t{0};
     378          125 :     g_return_if_fail (m_gobj_param_name != nullptr || get_setter(obj_name) != nullptr);
     379          125 :     auto strval = row.get_string_at_col(m_col_name);
     380          125 :     if (strval)
     381              :     {
     382          125 :         if (!strval->empty())
     383              :             try
     384              :             {
     385          124 :                 GncDateTime time(*strval);
     386          124 :                 t = static_cast<time64>(time);
     387          124 :             }
     388            0 :             catch (const std::invalid_argument& err)
     389              :             {
     390            0 :                 PWARN("An invalid date %s was found in your database."
     391              :                       "It has been set to 1 January 1970.",
     392              :                       strval->c_str());
     393            0 :             }
     394              :     }
     395              :     else
     396              :     {
     397            0 :         if (auto time64val = row.get_time64_at_col (m_col_name))
     398            0 :             t = *time64val;
     399              :     }
     400              : 
     401          125 :     if (m_gobj_param_name != nullptr)
     402              :     {
     403           47 :         Time64 t64{t};
     404           47 :         set_parameter(pObject, &t64, m_gobj_param_name);
     405              :     }
     406              :     else
     407              :     {
     408           78 :         set_parameter(pObject, t,
     409           78 :                       reinterpret_cast<Time64SetterFunc>(get_setter(obj_name)),
     410              :                       nullptr);
     411              :     }
     412          125 : }
     413              : 
     414              : template<> void
     415           66 : GncSqlColumnTableEntryImpl<CT_TIME>::add_to_table(ColVec& vec) const noexcept
     416              : {
     417              : 
     418           66 :     GncSqlColumnInfo info{*this, BCT_DATETIME, TIME_COL_SIZE, FALSE};
     419           66 :     vec.emplace_back(std::move(info));
     420           66 : }
     421              : 
     422              : template<> void
     423          123 : GncSqlColumnTableEntryImpl<CT_TIME>::add_to_query(QofIdTypeConst obj_name,
     424              :                                                    const gpointer pObject,
     425              :                                                    PairVec& vec) const noexcept
     426              : {
     427              :     /* We still can't use get_row_value_from_object because while g_value could
     428              :      * contentedly store a time64 in an int64, KVP wouldn't be able to tell them
     429              :      * apart, so we have the struct Time64 hack, see engine/gnc-date.c.
     430              :      */
     431              :     time64 t64;
     432          123 :     if (m_gobj_param_name != nullptr)
     433              :     {
     434              :         Time64* t;
     435           44 :         g_object_get (pObject, m_gobj_param_name, &t, nullptr);
     436           44 :         t64 = t->t;
     437              :     }
     438              :     else
     439              :     {
     440           79 :         auto getter = (Time64AccessFunc)get_getter (obj_name);
     441           79 :         g_return_if_fail(getter != nullptr);
     442           79 :         t64 = (*getter)(pObject);
     443              :     }
     444          123 :     if (t64 > MINTIME && t64 < MAXTIME)
     445              :     {
     446          122 :         GncDateTime time(t64);
     447          122 :         std::string timestr("'");
     448          122 :         timestr += time.format_iso8601() + "'";
     449          244 :         vec.emplace_back (std::make_pair (std::string{m_col_name}, timestr));
     450          122 :     }
     451              :     else
     452              :     {
     453            3 :         vec.emplace_back (std::make_pair (std::string{m_col_name},
     454              :                                           "NULL"));
     455              :     }
     456              : }
     457              : 
     458              : /* ----------------------------------------------------------------- */
     459              : #define DATE_COL_SIZE 8
     460              : 
     461              : template<> void
     462           87 : GncSqlColumnTableEntryImpl<CT_GDATE>::load (const GncSqlBackend* sql_be,
     463              :                                             GncSqlRow& row,
     464              :                                             QofIdTypeConst obj_name,
     465              :                                             gpointer pObject) const noexcept
     466              : {
     467          166 :     g_return_if_fail (pObject != NULL);
     468           87 :     g_return_if_fail (m_gobj_param_name != nullptr || get_setter(obj_name) != nullptr);
     469           87 :     if (row.is_col_null(m_col_name))
     470           79 :         return;
     471              :     GDate date;
     472            8 :     g_date_clear (&date, 1);
     473              : 
     474            8 :     auto strval{row.get_string_at_col(m_col_name)};
     475            8 :     if (strval)
     476              :     {
     477            8 :         if (strval->empty())
     478            0 :             return;
     479            8 :         auto year = static_cast<GDateYear>(stoi (strval->substr (0,4)));
     480            8 :         auto month = static_cast<GDateMonth>(stoi (strval->substr (4,2)));
     481            8 :         auto day = static_cast<GDateDay>(stoi (strval->substr (6,2)));
     482              : 
     483            8 :         if (year != 0 || month != 0 || day != (GDateDay)0)
     484            8 :             g_date_set_dmy(&date, day, month, year);
     485              :     }
     486              :     else
     487              :     {
     488            0 :         auto timeval = row.get_time64_at_col(m_col_name);
     489            0 :         if (!timeval)
     490            0 :             return;
     491              :         /* time64_to_gdate applies the tz, and gdates are saved
     492              :          * as ymd, so we don't want that.
     493              :          */
     494            0 :         auto time = *timeval;
     495            0 :         auto tm = gnc_gmtime(&time);
     496            0 :         g_date_set_dmy(&date, tm->tm_mday,
     497            0 :                        static_cast<GDateMonth>(tm->tm_mon + 1),
     498            0 :                        tm->tm_year + 1900);
     499            0 :         free(tm);
     500              :     }
     501              : 
     502            8 :     set_parameter(pObject, &date, get_setter(obj_name), m_gobj_param_name);
     503            8 : }
     504              : 
     505              : template<> void
     506           30 : GncSqlColumnTableEntryImpl<CT_GDATE>::add_to_table(ColVec& vec) const noexcept
     507              : {
     508           30 :     GncSqlColumnInfo info{*this,  BCT_DATE, DATE_COL_SIZE, FALSE};
     509           30 :     vec.emplace_back(std::move(info));
     510           30 : }
     511              : 
     512              : template<> void
     513           88 : GncSqlColumnTableEntryImpl<CT_GDATE>::add_to_query(QofIdTypeConst obj_name,
     514              :                                                    const gpointer pObject,
     515              :                                                    PairVec& vec) const noexcept
     516              : {
     517           88 :     GDate *date = get_row_value_from_object<GDate*>(obj_name, pObject);
     518              : 
     519           88 :     if (date && g_date_valid (date))
     520              :     {
     521            8 :         std::ostringstream buf;
     522            8 :         buf << std::setfill ('0') << std::setw (4) << g_date_get_year (date) <<
     523            8 :             std::setw (2) << g_date_get_month (date) <<
     524            8 :             std::setw (2) << static_cast<int>(g_date_get_day (date));
     525           16 :         vec.emplace_back (std::make_pair (std::string{m_col_name},
     526           16 :                                           quote_string(buf.str())));
     527            8 :         return;
     528            8 :     }
     529              : }
     530              : 
     531              : /* ----------------------------------------------------------------- */
     532              : typedef gnc_numeric (*NumericGetterFunc) (const gpointer);
     533              : typedef void (*NumericSetterFunc) (gpointer, gnc_numeric);
     534              : 
     535              : static const EntryVec numeric_col_table =
     536              : {
     537              :     gnc_sql_make_table_entry<CT_INT64>("num", 0, COL_NNUL, "guid"),
     538              :     gnc_sql_make_table_entry<CT_INT64>("denom", 0, COL_NNUL, "guid")
     539              : };
     540              : 
     541              : template <>
     542           48 : void set_parameter<gpointer, gnc_numeric>(gpointer object,
     543              :                                           gnc_numeric item,
     544              :                                           const char* property)
     545              : {
     546           48 :     qof_instance_increase_editlevel(object);
     547           48 :     g_object_set(object, property, &item, nullptr);
     548           48 :     qof_instance_decrease_editlevel(object);
     549           48 : };
     550              : 
     551              : template<> void
     552          132 : GncSqlColumnTableEntryImpl<CT_NUMERIC>::load (const GncSqlBackend* sql_be,
     553              :                                               GncSqlRow& row,
     554              :                                               QofIdTypeConst obj_name,
     555              :                                               gpointer pObject) const noexcept
     556              : {
     557              : 
     558              : 
     559          132 :     g_return_if_fail (pObject != NULL);
     560          132 :     g_return_if_fail (m_gobj_param_name != nullptr || get_setter(obj_name) != nullptr);
     561              : 
     562          132 :     auto buf = g_strdup_printf ("%s_num", m_col_name);
     563          132 :     auto num = row.get_int_at_col (buf);
     564          132 :     g_free (buf);
     565          132 :     buf = g_strdup_printf ("%s_denom", m_col_name);
     566          132 :     auto denom = row.get_int_at_col (buf);
     567          132 :     g_free (buf);
     568              : 
     569          132 :     if (num && denom)
     570              :     {
     571          132 :         auto n = gnc_numeric_create (*num, *denom);
     572          132 :         set_parameter(pObject, n,
     573          132 :                       reinterpret_cast<NumericSetterFunc>(get_setter(obj_name)),
     574          132 :                       m_gobj_param_name);
     575              :     }
     576              : }
     577              : 
     578              : template<> void
     579           96 : GncSqlColumnTableEntryImpl<CT_NUMERIC>::add_to_table(ColVec& vec) const noexcept
     580              : {
     581              : 
     582          384 :     for (auto const& subtable_row : numeric_col_table)
     583              :     {
     584          192 :         gchar* buf = g_strdup_printf("%s_%s", m_col_name,
     585          192 :                                      subtable_row->m_col_name);
     586          384 :         GncSqlColumnInfo info(buf, BCT_INT64, 0, false, false,
     587          384 :                               m_flags & COL_PKEY, m_flags & COL_NNUL);
     588          192 :         g_free (buf);
     589          192 :         vec.emplace_back(std::move(info));
     590          192 :     }
     591           96 : }
     592              : 
     593              : template<> void
     594          131 : GncSqlColumnTableEntryImpl<CT_NUMERIC>::add_to_query(QofIdTypeConst obj_name,
     595              :                                                      const gpointer pObject,
     596              :                                                      PairVec& vec) const noexcept
     597              : {
     598              : /* We can't use get_row_value_from_object for the same reason as time64. */
     599              :     NumericGetterFunc getter;
     600              :     gnc_numeric n;
     601              : 
     602          131 :     g_return_if_fail (obj_name != NULL);
     603          131 :     g_return_if_fail (pObject != NULL);
     604              : 
     605          131 :     if (m_gobj_param_name != nullptr)
     606              :     {
     607              :         gnc_numeric* s;
     608           46 :         g_object_get (pObject, m_gobj_param_name, &s, NULL);
     609           46 :         n = *s;
     610              :     }
     611              :     else
     612              :     {
     613           85 :         getter = reinterpret_cast<NumericGetterFunc>(get_getter (obj_name));
     614           85 :         if (getter != NULL)
     615              :         {
     616           85 :             n = (*getter) (pObject);
     617              :         }
     618              :         else
     619              :         {
     620            0 :             n = gnc_numeric_zero ();
     621              :         }
     622              :     }
     623              : 
     624          131 :     std::ostringstream buf;
     625          262 :     std::string num_col{m_col_name};
     626          262 :     std::string denom_col{m_col_name};
     627          131 :     num_col += "_num";
     628          131 :     denom_col += "_denom";
     629          131 :     buf << gnc_numeric_num (n);
     630          131 :     vec.emplace_back (std::make_pair (num_col, buf.str ()));
     631          131 :     buf.str ("");
     632          131 :     buf << gnc_numeric_denom (n);
     633          131 :     vec.emplace_back (denom_col, buf.str ());
     634          131 : }
     635              : 
     636              : static void
     637           98 : _retrieve_guid_ (gpointer pObject,  gpointer pValue)
     638              : {
     639           98 :     GncGUID* pGuid = (GncGUID*)pObject;
     640           98 :     GncGUID* guid = (GncGUID*)pValue;
     641              : 
     642           98 :     g_return_if_fail (pObject != NULL);
     643           98 :     g_return_if_fail (pValue != NULL);
     644              : 
     645           98 :     *pGuid = *guid;
     646              : }
     647              : 
     648              : // Table to retrieve just the guid
     649              : static EntryVec guid_table
     650              : {
     651              :     gnc_sql_make_table_entry<CT_GUID>("guid", 0, 0, nullptr, _retrieve_guid_)
     652              : };
     653              : 
     654              : const GncGUID*
     655           98 : gnc_sql_load_guid (const GncSqlBackend* sql_be, GncSqlRow& row)
     656              : {
     657              :     static GncGUID guid;
     658              : 
     659           98 :     g_return_val_if_fail (sql_be != NULL, NULL);
     660              : 
     661           98 :     gnc_sql_load_object (sql_be, row, NULL, &guid, guid_table);
     662              : 
     663           98 :     return &guid;
     664              : }
     665              : 
     666              : void
     667          345 : gnc_sql_load_object (const GncSqlBackend* sql_be, GncSqlRow& row,
     668              :                      QofIdTypeConst obj_name, gpointer pObject,
     669              :                      const EntryVec& table)
     670              : {
     671          345 :     g_return_if_fail (sql_be != NULL);
     672          345 :     g_return_if_fail (pObject != NULL);
     673              : 
     674         2717 :     for (auto const& table_row : table)
     675              :     {
     676         2027 :         table_row->load (sql_be, row, obj_name, pObject);
     677              :     }
     678              : }
     679              : 
     680              : uint_t
     681            0 : gnc_sql_append_guids_to_sql (std::stringstream& sql,
     682              :                              const InstanceVec& instances)
     683              : {
     684              :     char guid_buf[GUID_ENCODING_LENGTH + 1];
     685              : 
     686            0 :     for (auto inst : instances)
     687              :     {
     688            0 :         (void)guid_to_string_buff (qof_instance_get_guid (inst), guid_buf);
     689              : 
     690            0 :         if (inst != *(instances.begin()))
     691              :         {
     692            0 :             sql << ",";
     693              :         }
     694            0 :         sql << "'" << guid_buf << "'";
     695              :     }
     696              : 
     697            0 :     return instances.size();
     698              : }
     699              : 
     700              : /* This is necessary for 64-bit builds because g++ complains
     701              :  * that reinterpret_casting a void* (64 bits) to an int (32 bits)
     702              :  * loses precision, so we have to explicitly dispose of the precision.
     703              :  * FIXME: We shouldn't be storing ints in ptrs in the first place.
     704              :  */
     705              : #ifdef __LP64__
     706              : template <> int
     707          402 : GncSqlColumnTableEntry::get_row_value_from_object<int>(QofIdTypeConst obj_name,
     708              :                                                        const void* pObject,
     709              :                                                        std::false_type) const
     710              : {
     711          402 :     g_return_val_if_fail(obj_name != nullptr && pObject != nullptr, 0);
     712          402 :     int result = 0;
     713          402 :     if (m_gobj_param_name != nullptr)
     714          309 :         g_object_get(const_cast<void*>(pObject), m_gobj_param_name, &result,
     715              :                      nullptr);
     716              :     else
     717              :     {
     718           93 :         QofAccessFunc getter = get_getter(obj_name);
     719           93 :         if (getter != nullptr)
     720              :         {
     721           93 :             auto value = ((getter)(const_cast<void*>(pObject), nullptr));
     722           93 :             result = reinterpret_cast<uint64_t>(value) &
     723              :                 UINT64_C(0x00000000FFFFFFFF);
     724              :         }
     725              :     }
     726          402 :     return result;
     727              : }
     728              : #endif
        

Generated by: LCOV version 2.0-1