LCOV - code coverage report
Current view: top level - libgnucash/engine - qofquerycore.cpp (source / functions) Coverage Total Hit
Test: gnucash.info Lines: 53.2 % 698 371
Test Date: 2026-11-02 18:19:43 Functions: 61.9 % 84 52
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /********************************************************************\
       2              :  * QueryCore.c -- API for providing core Query data types           *
       3              :  * Copyright (C) 2002 Derek Atkins <warlord@MIT.EDU>                *
       4              :  *                                                                  *
       5              :  * This program is free software; you can redistribute it and/or    *
       6              :  * modify it under the terms of the GNU General Public License as   *
       7              :  * published by the Free Software Foundation; either version 2 of   *
       8              :  * the License, or (at your option) any later version.              *
       9              :  *                                                                  *
      10              :  * This program is distributed in the hope that it will be useful,  *
      11              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
      12              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
      13              :  * GNU General Public License for more details.                     *
      14              :  *                                                                  *
      15              :  * You should have received a copy of the GNU General Public License*
      16              :  * along with this program; if not, contact:                        *
      17              :  *                                                                  *
      18              :  * Free Software Foundation           Voice:  +1-617-542-5942       *
      19              :  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
      20              :  * Boston, MA  02110-1301,  USA       gnu@gnu.org                   *
      21              :  *                                                                  *
      22              : \********************************************************************/
      23              : 
      24              : #include "guid.hpp"
      25              : #include <config.h>
      26              : 
      27              : #include <glib.h>
      28              : #include <stdlib.h>
      29              : 
      30              : #include "gnc-glib-utils.h"
      31              : #include "qof.h"
      32              : #include "qofquerycore-p.h"
      33              : 
      34              : static QofLogModule log_module = QOF_MOD_QUERY;
      35              : 
      36              : /* A function to destroy a query predicate's pdata */
      37              : typedef void (*QueryPredDataFree) (QofQueryPredData *pdata);
      38              : 
      39              : /* A function to copy a query's predicate data */
      40              : typedef QofQueryPredData *(*QueryPredicateCopyFunc) (const QofQueryPredData *pdata);
      41              : 
      42              : /* A function to take the object, apply the getter->param_getfcn,
      43              :  * and return a printable string.  Note that this QofParam->getfnc
      44              :  * function should be returning a type equal to this core object type.
      45              :  *
      46              :  * Note that this string MUST be freed by the caller.
      47              :  */
      48              : typedef char * (*QueryToString) (gpointer object, QofParam *getter);
      49              : 
      50              : /* A function to test for equality of predicate data */
      51              : typedef gboolean (*QueryPredicateEqual) (const QofQueryPredData *p1,
      52              :         const QofQueryPredData *p2);
      53              : 
      54              : static QueryPredicateCopyFunc qof_query_copy_predicate (QofType type);
      55              : static QueryPredDataFree qof_query_predicate_free (QofType type);
      56              : 
      57              : /* Core Type Predicate helpers */
      58              : typedef const char * (*query_string_getter) (gpointer, QofParam *);
      59              : static const char * query_string_type = QOF_TYPE_STRING;
      60              : 
      61              : typedef time64 (*query_date_getter) (gpointer, QofParam *);
      62              : static const char * query_date_type = QOF_TYPE_DATE;
      63              : 
      64              : typedef gnc_numeric (*query_numeric_getter) (gpointer, QofParam *);
      65              : static const char * query_numeric_type = QOF_TYPE_NUMERIC;
      66              : 
      67              : typedef GList * (*query_glist_getter) (gpointer, QofParam *);
      68              : typedef const GncGUID * (*query_guid_getter) (gpointer, QofParam *);
      69              : static const char * query_guid_type = QOF_TYPE_GUID;
      70              : 
      71              : typedef gint32 (*query_int32_getter) (gpointer, QofParam *);
      72              : static const char * query_int32_type = QOF_TYPE_INT32;
      73              : 
      74              : typedef gint64 (*query_int64_getter) (gpointer, QofParam *);
      75              : static const char * query_int64_type = QOF_TYPE_INT64;
      76              : 
      77              : typedef double (*query_double_getter) (gpointer, QofParam *);
      78              : static const char * query_double_type = QOF_TYPE_DOUBLE;
      79              : 
      80              : typedef gboolean (*query_boolean_getter) (gpointer, QofParam *);
      81              : static const char * query_boolean_type = QOF_TYPE_BOOLEAN;
      82              : 
      83              : typedef char (*query_char_getter) (gpointer, QofParam *);
      84              : static const char * query_char_type = QOF_TYPE_CHAR;
      85              : 
      86              : typedef const GncGUID * (*query_choice_getter) (gpointer, QofParam *);
      87              : static const char * query_choice_type = QOF_TYPE_CHOICE;
      88              : 
      89              : /* Tables for predicate storage and lookup */
      90              : static gboolean initialized = FALSE;
      91              : static GHashTable *predTable = nullptr;
      92              : static GHashTable *cmpTable = nullptr;
      93              : static GHashTable *copyTable = nullptr;
      94              : static GHashTable *freeTable = nullptr;
      95              : static GHashTable *toStringTable = nullptr;
      96              : static GHashTable *predEqualTable = nullptr;
      97              : 
      98              : #define COMPARE_ERROR -3
      99              : #define PREDICATE_ERROR -2
     100              : 
     101              : #define VERIFY_PDATA(str) { \
     102              :         g_return_if_fail (pd != nullptr); \
     103              :         g_return_if_fail (pd->type_name == str || \
     104              :                         !g_strcmp0 (str, pd->type_name)); \
     105              : }
     106              : #define VERIFY_PDATA_R(str) { \
     107              :         g_return_val_if_fail (pd != nullptr, nullptr); \
     108              :         g_return_val_if_fail (pd->type_name == str || \
     109              :                                 !g_strcmp0 (str, pd->type_name), \
     110              :                                 nullptr); \
     111              : }
     112              : #define VERIFY_PREDICATE(str) { \
     113              :         g_return_val_if_fail (getter != nullptr, PREDICATE_ERROR); \
     114              :         g_return_val_if_fail (getter->param_getfcn != nullptr, PREDICATE_ERROR); \
     115              :         g_return_val_if_fail (pd != nullptr, PREDICATE_ERROR); \
     116              :         g_return_val_if_fail (pd->type_name == str || \
     117              :                                 !g_strcmp0 (str, pd->type_name), \
     118              :                                 PREDICATE_ERROR); \
     119              : }
     120              : 
     121              : /* *******************************************************************/
     122              : /* TYPE-HANDLING FUNCTIONS */
     123              : 
     124              : /* QOF_TYPE_STRING */
     125              : 
     126              : static int
     127         3297 : string_match_predicate (gpointer object,
     128              :                         QofParam *getter,
     129              :                         QofQueryPredData *pd)
     130              : {
     131         3297 :     query_string_t pdata = (query_string_t) pd;
     132              :     const char *s;
     133         3297 :     int ret = 0;
     134              : 
     135         3297 :     VERIFY_PREDICATE (query_string_type);
     136              : 
     137         3297 :     s = ((query_string_getter)getter->param_getfcn) (object, getter);
     138              : 
     139         3297 :     if (!s) s = "";
     140              : 
     141         3297 :     if (pdata->is_regex)
     142              :     {
     143              :         regmatch_t match;
     144            0 :         if (!regexec (&pdata->compiled, s, 1, &match, 0))
     145            0 :             ret = 1;
     146              :     }
     147              :     else
     148              :     {
     149         3297 :         if (pdata->options == QOF_STRING_MATCH_CASEINSENSITIVE)
     150              :         {
     151          297 :             if (pd->how == QOF_COMPARE_CONTAINS || pd->how == QOF_COMPARE_NCONTAINS)
     152              :             {
     153          317 :                 if (qof_utf8_substr_nocase (s, pdata->matchstring)) //uses strstr
     154           20 :                     ret = 1;
     155              :             }
     156              :             else
     157              :             {
     158            0 :                  if (safe_strcasecmp (s, pdata->matchstring) == 0) //uses collate
     159            0 :                     ret = 1;
     160              :             }
     161              :         }
     162              :         else
     163              :         {
     164         3000 :             if (pd->how == QOF_COMPARE_CONTAINS || pd->how == QOF_COMPARE_NCONTAINS)
     165              :             {
     166         3880 :                 if (strstr (s, pdata->matchstring))
     167          880 :                     ret = 1;
     168              :             }
     169              :             else
     170              :             {
     171            0 :                 if (g_strcmp0 (s, pdata->matchstring) == 0)
     172            0 :                     ret = 1;
     173              :             }
     174              :         }
     175              :     }
     176              : 
     177         3297 :     switch (pd->how)
     178              :     {
     179         3297 :     case QOF_COMPARE_CONTAINS:
     180         3297 :         return ret;
     181            0 :     case QOF_COMPARE_NCONTAINS:
     182            0 :         return !ret;
     183            0 :     case QOF_COMPARE_EQUAL:
     184            0 :         return ret;
     185            0 :     case QOF_COMPARE_NEQ:
     186            0 :         return !ret;
     187            0 :     default:
     188            0 :         PWARN ("bad match type: %d", pd->how);
     189            0 :         return 0;
     190              :     }
     191              : }
     192              : 
     193              : static int
     194           47 : string_compare_func (gpointer a, gpointer b, gint options,
     195              :                      QofParam *getter)
     196              : {
     197              :     const char *s1, *s2;
     198           47 :     g_return_val_if_fail (a && b && getter && getter->param_getfcn, COMPARE_ERROR);
     199              : 
     200           47 :     s1 = ((query_string_getter)getter->param_getfcn) (a, getter);
     201           47 :     s2 = ((query_string_getter)getter->param_getfcn) (b, getter);
     202              : 
     203           47 :     if (options == QOF_STRING_MATCH_CASEINSENSITIVE)
     204            0 :         return safe_strcasecmp (s1, s2);
     205              : 
     206           47 :     return g_strcmp0 (s1, s2);
     207              : }
     208              : 
     209              : static int
     210            0 : natural_compare_func (gpointer a, gpointer b, gint options,
     211              :                       QofParam *getter)
     212              : {
     213              :     const char *s1, *s2;
     214            0 :     g_return_val_if_fail (a && b && getter && getter->param_getfcn, COMPARE_ERROR);
     215              : 
     216            0 :     s1 = ((query_string_getter)getter->param_getfcn) (a, getter);
     217            0 :     s2 = ((query_string_getter)getter->param_getfcn) (b, getter);
     218              : 
     219              :     if (options == QOF_STRING_MATCH_CASEINSENSITIVE) {
     220              :       // There is no case-insensitive natural sort.
     221              :       // Downcasing/folding a/b for every compare
     222              :       // operation is too wasteful. 
     223              :       //
     224              :       // The best option is to downcase/fold only once
     225              :       // for each item and then store that as a property
     226              :       // that we use in natural_compare_func, but that
     227              :       // will require some work outside natural_compare_func,
     228              :       // and I dont think it is worth the extra code. 
     229              :     }
     230              : 
     231            0 :     return safe_utf8_collate_natural(s1, s2);
     232              : }
     233              : 
     234              : int
     235            7 : qof_string_number_compare_func (gpointer a, gpointer b, gint options,
     236              :                                 QofParam *getter)
     237              : {
     238              :     const char *s1, *s2;
     239              :     char *sr1, *sr2;
     240              :     long i1, i2;
     241            7 :     g_return_val_if_fail (a && b && getter && getter->param_getfcn, COMPARE_ERROR);
     242              : 
     243            7 :     s1 = ((query_string_getter)getter->param_getfcn) (a, getter);
     244            7 :     s2 = ((query_string_getter)getter->param_getfcn) (b, getter);
     245              : 
     246              :     // Deal with nullptr strings
     247            7 :     if (s1 == s2)  return 0;
     248            7 :     if (!s1 && s2) return -1;
     249            7 :     if (s1 && !s2) return 1;
     250              : 
     251              :     // Convert to integers and test
     252            7 :     i1 = strtol(s1, &sr1, 10);
     253            7 :     i2 = strtol(s2, &sr2, 10);
     254            7 :     if (i1 < i2)  return -1;
     255            7 :     if (i1 > i2)  return 1;
     256              : 
     257              :     // If the integers match, then test the REST of the string as text.
     258            7 :     if (options == QOF_STRING_MATCH_CASEINSENSITIVE)
     259            0 :         return safe_strcasecmp (sr1, sr2);
     260              : 
     261            7 :     return g_strcmp0 (sr1, sr2);
     262              : }
     263              : 
     264              : static void
     265        13315 : string_free_pdata (QofQueryPredData *pd)
     266              : {
     267        13315 :     query_string_t pdata = (query_string_t) pd;
     268              : 
     269        13315 :     VERIFY_PDATA (query_string_type);
     270              : 
     271        13315 :     if (pdata->is_regex)
     272          620 :         regfree (&pdata->compiled);
     273              : 
     274        13315 :     g_free (pdata->matchstring);
     275        13315 :     g_free (pdata);
     276              : }
     277              : 
     278              : static QofQueryPredData *
     279        12029 : string_copy_predicate (const QofQueryPredData *pd)
     280              : {
     281        12029 :     const query_string_t pdata = (const query_string_t) pd;
     282              : 
     283        12029 :     VERIFY_PDATA_R (query_string_type);
     284              : 
     285        12029 :     return qof_query_string_predicate (pd->how, pdata->matchstring,
     286              :                                        pdata->options,
     287        12029 :                                        pdata->is_regex);
     288              : }
     289              : 
     290              : static gboolean
     291          233 : string_predicate_equal (const QofQueryPredData *p1, const QofQueryPredData *p2)
     292              : {
     293          233 :     const query_string_t pd1 = (const query_string_t) p1;
     294          233 :     const query_string_t pd2 = (const query_string_t) p2;
     295              : 
     296          233 :     if (pd1->options != pd2->options) return FALSE;
     297          233 :     if (pd1->is_regex != pd2->is_regex) return FALSE;
     298          233 :     return (g_strcmp0 (pd1->matchstring, pd2->matchstring) == 0);
     299              : }
     300              : 
     301              : QofQueryPredData *
     302        13734 : qof_query_string_predicate (QofQueryCompare how,
     303              :                             const char *str, QofStringMatch options,
     304              :                             gboolean is_regex)
     305              : {
     306              :     query_string_t pdata;
     307              : 
     308        13734 :     g_return_val_if_fail (str, nullptr);
     309              : //    g_return_val_if_fail (*str != '\0', nullptr);
     310        13734 :     g_return_val_if_fail (how == QOF_COMPARE_CONTAINS || how == QOF_COMPARE_NCONTAINS ||
     311              :                           how == QOF_COMPARE_EQUAL || how == QOF_COMPARE_NEQ, nullptr);
     312              : 
     313        13374 :     pdata = g_new0 (query_string_def, 1);
     314        13374 :     pdata->pd.type_name = query_string_type;
     315        13374 :     pdata->pd.how = how;
     316        13374 :     pdata->options = options;
     317        13374 :     pdata->matchstring = g_strdup (str);
     318              : 
     319        13374 :     if (is_regex)
     320              :     {
     321              :         int rc;
     322          679 :         int flags = REG_EXTENDED;
     323          679 :         if (options == QOF_STRING_MATCH_CASEINSENSITIVE)
     324          345 :             flags |= REG_ICASE;
     325              : 
     326          679 :         rc = regcomp(&pdata->compiled, str, flags);
     327          679 :         if (rc)
     328              :         {
     329           59 :             g_free(pdata->matchstring);
     330           59 :             g_free(pdata);
     331           59 :             return nullptr;
     332              :         }
     333          620 :         pdata->is_regex = TRUE;
     334              :     }
     335              : 
     336        13315 :     return ((QofQueryPredData*)pdata);
     337              : }
     338              : 
     339              : static char *
     340            0 : string_to_string (gpointer object, QofParam *getter)
     341              : {
     342              :     const char *res;
     343            0 :     res = ((query_string_getter)getter->param_getfcn)(object, getter);
     344            0 :     if (res)
     345            0 :         return g_strdup (res);
     346            0 :     return nullptr;
     347              : }
     348              : 
     349              : /* QOF_TYPE_DATE =================================================== */
     350              : 
     351              : static int
     352        10764 : date_compare (time64 ta, time64 tb, QofDateMatch options)
     353              : {
     354              : 
     355        10764 :     if (options == QOF_DATE_MATCH_DAY)
     356              :     {
     357            0 :         ta = time64CanonicalDayTime (ta);
     358            0 :         tb = time64CanonicalDayTime (tb);
     359              :     }
     360              : 
     361        10764 :     if (ta < tb)
     362         4105 :         return -1;
     363         6659 :     if (ta > tb)
     364         6246 :         return 1;
     365              : 
     366          413 :     return 0;
     367              : }
     368              : 
     369              : static int
     370        10361 : date_match_predicate (gpointer object, QofParam *getter,
     371              :                       QofQueryPredData *pd)
     372              : {
     373        10361 :     query_date_t pdata = (query_date_t)pd;
     374              :     time64 objtime;
     375              :     int compare;
     376              : 
     377        10361 :     VERIFY_PREDICATE (query_date_type);
     378              : 
     379        10361 :     objtime = ((query_date_getter)getter->param_getfcn) (object, getter);
     380        10361 :     compare = date_compare (objtime, pdata->date, pdata->options);
     381              : 
     382        10361 :     switch (pd->how)
     383              :     {
     384            0 :     case QOF_COMPARE_LT:
     385            0 :         return (compare < 0);
     386         4589 :     case QOF_COMPARE_LTE:
     387         4589 :         return (compare <= 0);
     388            0 :     case QOF_COMPARE_EQUAL:
     389            0 :         return (compare == 0);
     390            0 :     case QOF_COMPARE_GT:
     391            0 :         return (compare > 0);
     392         5772 :     case QOF_COMPARE_GTE:
     393         5772 :         return (compare >= 0);
     394            0 :     case QOF_COMPARE_NEQ:
     395            0 :         return (compare != 0);
     396            0 :     default:
     397            0 :         PWARN ("bad match type: %d", pd->how);
     398            0 :         return 0;
     399              :     }
     400              : }
     401              : 
     402              : static int
     403          403 : date_compare_func (gpointer a, gpointer b, gint options, QofParam *getter)
     404              : {
     405              :     time64 ta, tb;
     406              : 
     407          403 :     g_return_val_if_fail (a && b && getter && getter->param_getfcn, COMPARE_ERROR);
     408              : 
     409          403 :     ta = ((query_date_getter)getter->param_getfcn) (a, getter);
     410          403 :     tb = ((query_date_getter)getter->param_getfcn) (b, getter);
     411              : 
     412          403 :     return date_compare (ta, tb, static_cast<QofDateMatch>(options));
     413              : }
     414              : 
     415              : static void
     416         8590 : date_free_pdata (QofQueryPredData *pd)
     417              : {
     418         8590 :     query_date_t pdata = (query_date_t)pd;
     419              : 
     420         8590 :     VERIFY_PDATA (query_date_type);
     421              : 
     422         8590 :     g_free (pdata);
     423              : }
     424              : 
     425              : static QofQueryPredData *
     426         7443 : date_copy_predicate (const QofQueryPredData *pd)
     427              : {
     428         7443 :     const query_date_t pdata = (const query_date_t)pd;
     429              : 
     430         7443 :     VERIFY_PDATA_R (query_date_type);
     431              : 
     432         7443 :     return qof_query_date_predicate (pd->how, pdata->options, pdata->date);
     433              : }
     434              : 
     435              : static gboolean
     436          241 : date_predicate_equal (const QofQueryPredData *p1, const QofQueryPredData *p2)
     437              : {
     438          241 :     const query_date_t pd1 = (const query_date_t) p1;
     439          241 :     const query_date_t pd2 = (const query_date_t) p2;
     440              : 
     441          241 :     if (pd1->options != pd2->options) return FALSE;
     442          241 :     return (pd1->date == pd2->date);
     443              : }
     444              : 
     445              : QofQueryPredData *
     446         8590 : qof_query_date_predicate (QofQueryCompare how,
     447              :                           QofDateMatch options, time64 date)
     448              : {
     449              :     query_date_t pdata;
     450              : 
     451         8590 :     pdata = g_new0 (query_date_def, 1);
     452         8590 :     pdata->pd.type_name = query_date_type;
     453         8590 :     pdata->pd.how = how;
     454         8590 :     pdata->options = options;
     455         8590 :     pdata->date = date;
     456         8590 :     return ((QofQueryPredData*)pdata);
     457              : }
     458              : 
     459              : gboolean
     460            2 : qof_query_date_predicate_get_date (const QofQueryPredData *pd, time64 *date)
     461              : {
     462            2 :     const query_date_t pdata = (const query_date_t)pd;
     463              : 
     464            2 :     if (pdata->pd.type_name != query_date_type)
     465            1 :         return FALSE;
     466            1 :     *date = pdata->date;
     467            1 :     return TRUE;
     468              : }
     469              : 
     470              : static char *
     471            0 : date_to_string (gpointer object, QofParam *getter)
     472              : {
     473            0 :     time64 tt = ((query_date_getter)getter->param_getfcn)(object, getter);
     474              : 
     475            0 :     if (tt != INT64_MAX)
     476            0 :         return qof_print_date (tt);
     477              : 
     478            0 :     return nullptr;
     479              : }
     480              : 
     481              : /* QOF_TYPE_NUMERIC ================================================= */
     482              : 
     483              : static int
     484          601 : numeric_match_predicate (gpointer object, QofParam *getter,
     485              :                          QofQueryPredData* pd)
     486              : {
     487          601 :     query_numeric_t pdata = (query_numeric_t)pd;
     488              :     gnc_numeric obj_val;
     489              :     int compare;
     490              : 
     491          601 :     VERIFY_PREDICATE (query_numeric_type);
     492              : 
     493          601 :     obj_val = ((query_numeric_getter)getter->param_getfcn) (object, getter);
     494              : 
     495          601 :     switch (pdata->options)
     496              :     {
     497            0 :     case QOF_NUMERIC_MATCH_CREDIT:
     498            0 :         if (gnc_numeric_positive_p (obj_val)) return 0;
     499            0 :         break;
     500            0 :     case QOF_NUMERIC_MATCH_DEBIT:
     501            0 :         if (gnc_numeric_negative_p (obj_val)) return 0;
     502            0 :         break;
     503          601 :     default:
     504          601 :         break;
     505              :     }
     506              : 
     507              :     /* Amounts are considered to be 'equal' if they match to
     508              :      * four decimal places. (epsilon=1/10000) */
     509          601 :     if (pd->how == QOF_COMPARE_EQUAL || pd->how == QOF_COMPARE_NEQ)
     510              :     {
     511          601 :         gnc_numeric cmp_val = gnc_numeric_create (1, 10000);
     512          601 :         compare =
     513          601 :             (gnc_numeric_compare (gnc_numeric_abs
     514              :                                   (gnc_numeric_sub (gnc_numeric_abs (obj_val),
     515              :                                           gnc_numeric_abs (pdata->amount),
     516              :                                           100000, GNC_HOW_RND_ROUND_HALF_UP)),
     517          601 :                                   cmp_val) < 0);
     518          601 :     }
     519              :     else
     520            0 :         compare = gnc_numeric_compare (gnc_numeric_abs (obj_val), pdata->amount);
     521              : 
     522          601 :     switch (pd->how)
     523              :     {
     524            0 :     case QOF_COMPARE_LT:
     525            0 :         return (compare < 0);
     526            0 :     case QOF_COMPARE_LTE:
     527            0 :         return (compare <= 0);
     528          601 :     case QOF_COMPARE_EQUAL:
     529          601 :         return compare;
     530            0 :     case QOF_COMPARE_GT:
     531            0 :         return (compare > 0);
     532            0 :     case QOF_COMPARE_GTE:
     533            0 :         return (compare >= 0);
     534            0 :     case QOF_COMPARE_NEQ:
     535            0 :         return !compare;
     536            0 :     default:
     537            0 :         PWARN ("bad match type: %d", pd->how);
     538            0 :         return 0;
     539              :     }
     540              : }
     541              : 
     542              : static int
     543            6 : numeric_compare_func (gpointer a, gpointer b, gint options, QofParam *getter)
     544              : {
     545              :     gnc_numeric va, vb;
     546              : 
     547            6 :     g_return_val_if_fail (a && b && getter && getter->param_getfcn, COMPARE_ERROR);
     548              : 
     549            6 :     va = ((query_numeric_getter)getter->param_getfcn) (a, getter);
     550            6 :     vb = ((query_numeric_getter)getter->param_getfcn) (b, getter);
     551              : 
     552            6 :     return gnc_numeric_compare (va, vb);
     553              : }
     554              : 
     555              : static void
     556        12985 : numeric_free_pdata (QofQueryPredData* pd)
     557              : {
     558        12985 :     query_numeric_t pdata = (query_numeric_t)pd;
     559        12985 :     VERIFY_PDATA (query_numeric_type);
     560        12985 :     g_free (pdata);
     561              : }
     562              : 
     563              : static QofQueryPredData *
     564        10985 : numeric_copy_predicate (const QofQueryPredData *pd)
     565              : {
     566        10985 :     const query_numeric_t pdata = (const query_numeric_t)pd;
     567        10985 :     VERIFY_PDATA_R (query_numeric_type);
     568        10985 :     return qof_query_numeric_predicate (pd->how, pdata->options, pdata->amount);
     569              : }
     570              : 
     571              : static gboolean
     572          729 : numeric_predicate_equal (const QofQueryPredData *p1, const QofQueryPredData *p2)
     573              : {
     574          729 :     const query_numeric_t pd1 = (const query_numeric_t) p1;
     575          729 :     const query_numeric_t pd2 = (const query_numeric_t) p2;
     576              : 
     577          729 :     if (pd1->options != pd2->options) return FALSE;
     578          729 :     return gnc_numeric_equal (pd1->amount, pd2->amount);
     579              : }
     580              : 
     581              : QofQueryPredData *
     582        12985 : qof_query_numeric_predicate (QofQueryCompare how,
     583              :                              QofNumericMatch options,
     584              :                              gnc_numeric value)
     585              : {
     586              :     query_numeric_t pdata;
     587        12985 :     pdata = g_new0 (query_numeric_def, 1);
     588        12985 :     pdata->pd.type_name = query_numeric_type;
     589        12985 :     pdata->pd.how = how;
     590        12985 :     pdata->options = options;
     591        12985 :     pdata->amount = value;
     592        12985 :     return ((QofQueryPredData*)pdata);
     593              : }
     594              : 
     595              : static char *
     596            0 : numeric_to_string (gpointer object, QofParam *getter)
     597              : {
     598              :     gnc_numeric num;
     599            0 :     num = ((query_numeric_getter)getter->param_getfcn)(object, getter);
     600              : 
     601            0 :     return gnc_numeric_to_string (num);
     602              : }
     603              : 
     604              : static char *
     605            0 : debcred_to_string (gpointer object, QofParam *getter)
     606              : {
     607              :     gnc_numeric num;
     608            0 :     num = ((query_numeric_getter)getter->param_getfcn)(object, getter);
     609              : 
     610            0 :     return gnc_numeric_to_string (num);
     611              : }
     612              : 
     613              : /* QOF_TYPE_GUID =================================================== */
     614              : 
     615              : static int
     616        43909 : guid_match_predicate (gpointer object, QofParam *getter,
     617              :                       QofQueryPredData *pd)
     618              : {
     619        43909 :     query_guid_t pdata = (query_guid_t)pd;
     620              :     GList *node, *o_list;
     621        43909 :     const GncGUID *guid = nullptr;
     622              : 
     623        43909 :     VERIFY_PREDICATE (query_guid_type);
     624              : 
     625        43909 :     switch (pdata->options)
     626              :     {
     627              : 
     628          200 :     case QOF_GUID_MATCH_ALL:
     629              :         /* object is a GList of objects; param_getfcn must be called on each one.
     630              :          * See if every guid in the predicate is accounted-for in the
     631              :          * object list
     632              :          */
     633              : 
     634          605 :         for (node = pdata->guids; node; node = node->next)
     635              :         {
     636              :             /* See if this GncGUID matches the object's guid */
     637          613 :             for (o_list = static_cast<GList*>(object); o_list;
     638          208 :                  o_list = static_cast<GList*>(o_list->next))
     639              :             {
     640          613 :                 guid = ((query_guid_getter)getter->param_getfcn) (o_list->data, getter);
     641          613 :                 if (guid_equal (static_cast<GncGUID*>(node->data), guid))
     642          405 :                     break;
     643              :             }
     644              : 
     645              :             /*
     646              :              * If o_list is nullptr, we've walked the whole list without finding
     647              :              * a match.  Therefore break out now, the match has failed.
     648              :              */
     649          405 :             if (o_list == nullptr)
     650            0 :                 break;
     651              :         }
     652              : 
     653              :         /*
     654              :          * The match is complete.  If node == nullptr then we've successfully
     655              :          * found a match for all the guids in the predicate.  Return
     656              :          * appropriately below.
     657              :          */
     658              : 
     659          200 :         break;
     660              : 
     661            0 :     case QOF_GUID_MATCH_LIST_ANY:
     662              :         /* object is a single object, getter returns a GList* of GncGUID*
     663              :          *
     664              :          * See if any GncGUID* in the returned list matches any guid in the
     665              :          * predicate match list.
     666              :          */
     667              : 
     668            0 :         o_list = ((query_glist_getter)getter->param_getfcn) (object, getter);
     669              : 
     670            0 :         for (node = o_list; node; node = node->next)
     671              :         {
     672              :             GList *node2;
     673              : 
     674              :             /* Search the predicate data for a match */
     675            0 :             for (node2 = pdata->guids; node2; node2 = node2->next)
     676              :             {
     677            0 :                 if (guid_equal (static_cast<GncGUID*>(node->data),
     678            0 :                                 static_cast<GncGUID*>(node2->data)))
     679            0 :                     break;
     680              :             }
     681              : 
     682              :             /* Check to see if we found a match.  If so, break now */
     683            0 :             if (node2 != nullptr)
     684            0 :                 break;
     685              :         }
     686              : 
     687            0 :         g_list_free(o_list);
     688              : 
     689              :         /* yea, node may point to an invalid location, but that's ok.
     690              :          * we're not _USING_ the value, just checking that it's non-nullptr
     691              :          */
     692              : 
     693            0 :         break;
     694              : 
     695        43709 :     default:
     696              :         /* object is a single object, getter returns a GncGUID*
     697              :          *
     698              :          * See if the guid is in the list
     699              :          */
     700              : 
     701        43709 :         guid = ((query_guid_getter)getter->param_getfcn) (object, getter);
     702        81237 :         for (node = pdata->guids; node; node = node->next)
     703              :         {
     704        64768 :             if (guid_equal (static_cast<GncGUID*>(node->data), guid))
     705        27240 :                 break;
     706              :         }
     707              :     }
     708              : 
     709        43909 :     switch (pdata->options)
     710              :     {
     711        43509 :     case QOF_GUID_MATCH_ANY:
     712              :     case QOF_GUID_MATCH_LIST_ANY:
     713        43509 :         return (node != nullptr);
     714              :         break;
     715          400 :     case QOF_GUID_MATCH_NONE:
     716              :     case QOF_GUID_MATCH_ALL:
     717          400 :         return (node == nullptr);
     718              :         break;
     719            0 :     case QOF_GUID_MATCH_NULL:
     720            0 :         return ((guid == nullptr) || guid_equal(guid, guid_null()));
     721              :         break;
     722            0 :     default:
     723            0 :         PWARN ("bad match type");
     724            0 :         return 0;
     725              :     }
     726              : }
     727              : 
     728              : static void
     729        15323 : guid_free_pdata (QofQueryPredData *pd)
     730              : {
     731        15323 :     query_guid_t pdata = (query_guid_t)pd;
     732              :     GList *node;
     733        15323 :     VERIFY_PDATA (query_guid_type);
     734        46474 :     for (node = pdata->guids; node; node = node->next)
     735              :     {
     736        31151 :         guid_free (static_cast<GncGUID*>(node->data));
     737              :     }
     738        15323 :     g_list_free (pdata->guids);
     739        15323 :     g_free (pdata);
     740              : }
     741              : 
     742              : static QofQueryPredData *
     743        12589 : guid_copy_predicate (const QofQueryPredData *pd)
     744              : {
     745        12589 :     const query_guid_t pdata = (const query_guid_t)pd;
     746        12589 :     VERIFY_PDATA_R (query_guid_type);
     747        12589 :     return qof_query_guid_predicate (pdata->options, pdata->guids);
     748              : }
     749              : 
     750              : static gboolean
     751          414 : guid_predicate_equal (const QofQueryPredData *p1, const QofQueryPredData *p2)
     752              : {
     753          414 :     const query_guid_t pd1 = (const query_guid_t) p1;
     754          414 :     const query_guid_t pd2 = (const query_guid_t) p2;
     755          414 :     GList *l1 = pd1->guids, *l2 = pd2->guids;
     756              : 
     757          414 :     if (pd1->options != pd2->options) return FALSE;
     758         1780 :     for (; l1 || l2; l1 = l1->next, l2 = l2->next)
     759              :     {
     760         1366 :         if (!l1 || !l2)
     761            0 :             return FALSE;
     762         1366 :         if (!guid_equal (static_cast<GncGUID*>(l1->data),
     763         1366 :                          static_cast<GncGUID*>(l2->data)))
     764            0 :             return FALSE;
     765              :     }
     766          414 :     return TRUE;
     767              : }
     768              : 
     769              : QofQueryPredData *
     770        15327 : qof_query_guid_predicate (QofGuidMatch options, GList *guid_list)
     771              : {
     772              :     query_guid_t pdata;
     773              :     GList *node;
     774              : 
     775              :     /* An empty list of guids is only valid when testing for a null GUID value */
     776        15327 :     if (!guid_list)
     777            0 :         g_return_val_if_fail (options == QOF_GUID_MATCH_NULL, nullptr);
     778              : 
     779        15327 :     pdata = g_new0 (query_guid_def, 1);
     780        15327 :     pdata->pd.how = QOF_COMPARE_EQUAL;
     781        15327 :     pdata->pd.type_name = query_guid_type;
     782        15327 :     pdata->options = options;
     783              : 
     784        15327 :     pdata->guids = g_list_copy (guid_list);
     785        46482 :     for (node = pdata->guids; node; node = node->next)
     786              :     {
     787        31155 :         GncGUID *guid = guid_malloc ();
     788        31155 :         *guid = *((GncGUID *)node->data);
     789        31155 :         node->data = guid;
     790              :     }
     791        15327 :     return ((QofQueryPredData*)pdata);
     792              : }
     793              : 
     794              : /* ================================================================ */
     795              : /* QOF_TYPE_INT32 */
     796              : 
     797              : static int
     798            0 : int32_match_predicate (gpointer object, QofParam *getter,
     799              :                        QofQueryPredData *pd)
     800              : {
     801              :     gint32 val;
     802            0 :     query_int32_t pdata = (query_int32_t)pd;
     803              : 
     804            0 :     VERIFY_PREDICATE (query_int32_type);
     805              : 
     806            0 :     val = ((query_int32_getter)getter->param_getfcn) (object, getter);
     807              : 
     808            0 :     switch (pd->how)
     809              :     {
     810            0 :     case QOF_COMPARE_LT:
     811            0 :         return (val < pdata->val);
     812            0 :     case QOF_COMPARE_LTE:
     813            0 :         return (val <= pdata->val);
     814            0 :     case QOF_COMPARE_EQUAL:
     815            0 :         return (val == pdata->val);
     816            0 :     case QOF_COMPARE_GT:
     817            0 :         return (val > pdata->val);
     818            0 :     case QOF_COMPARE_GTE:
     819            0 :         return (val >= pdata->val);
     820            0 :     case QOF_COMPARE_NEQ:
     821            0 :         return (val != pdata->val);
     822            0 :     default:
     823            0 :         PWARN ("bad match type: %d", pd->how);
     824            0 :         return 0;
     825              :     }
     826              : }
     827              : 
     828              : static int
     829            0 : int32_compare_func (gpointer a, gpointer b, gint options,
     830              :                     QofParam *getter)
     831              : {
     832              :     gint32 v1, v2;
     833            0 :     g_return_val_if_fail (a && b && getter && getter->param_getfcn, COMPARE_ERROR);
     834              : 
     835            0 :     v1 = ((query_int32_getter)getter->param_getfcn)(a, getter);
     836            0 :     v2 = ((query_int32_getter)getter->param_getfcn)(b, getter);
     837              : 
     838            0 :     if (v1 < v2) return -1;
     839            0 :     if (v1 > v2) return 1;
     840            0 :     return 0;
     841              : }
     842              : 
     843              : static void
     844            1 : int32_free_pdata (QofQueryPredData *pd)
     845              : {
     846            1 :     query_int32_t pdata = (query_int32_t)pd;
     847            1 :     VERIFY_PDATA (query_int32_type);
     848            1 :     g_free (pdata);
     849              : }
     850              : 
     851              : static QofQueryPredData *
     852            0 : int32_copy_predicate (const QofQueryPredData *pd)
     853              : {
     854            0 :     const query_int32_t pdata = (const query_int32_t)pd;
     855            0 :     VERIFY_PDATA_R (query_int32_type);
     856            0 :     return qof_query_int32_predicate (pd->how, pdata->val);
     857              : }
     858              : 
     859              : static gboolean
     860            0 : int32_predicate_equal (const QofQueryPredData *p1, const QofQueryPredData *p2)
     861              : {
     862            0 :     const query_int32_t pd1 = (const query_int32_t) p1;
     863            0 :     const query_int32_t pd2 = (const query_int32_t) p2;
     864              : 
     865            0 :     return (pd1->val == pd2->val);
     866              : }
     867              : 
     868              : QofQueryPredData *
     869            1 : qof_query_int32_predicate (QofQueryCompare how, gint32 val)
     870              : {
     871            1 :     query_int32_t pdata = g_new0 (query_int32_def, 1);
     872            1 :     pdata->pd.type_name = query_int32_type;
     873            1 :     pdata->pd.how = how;
     874            1 :     pdata->val = val;
     875            1 :     return ((QofQueryPredData*)pdata);
     876              : }
     877              : 
     878              : static char *
     879            0 : int32_to_string (gpointer object, QofParam *getter)
     880              : {
     881            0 :     gint32 num = ((query_int32_getter)getter->param_getfcn)(object, getter);
     882              : 
     883            0 :     return g_strdup_printf ("%d", num);
     884              : }
     885              : 
     886              : /* ================================================================ */
     887              : /* QOF_TYPE_INT64 */
     888              : 
     889              : static int
     890            0 : int64_match_predicate (gpointer object, QofParam *getter,
     891              :                        QofQueryPredData *pd)
     892              : {
     893              :     gint64 val;
     894            0 :     query_int64_t pdata = (query_int64_t)pd;
     895              : 
     896            0 :     VERIFY_PREDICATE (query_int64_type);
     897              : 
     898            0 :     val = ((query_int64_getter)getter->param_getfcn) (object, getter);
     899              : 
     900            0 :     switch (pd->how)
     901              :     {
     902            0 :     case QOF_COMPARE_LT:
     903            0 :         return (val < pdata->val);
     904            0 :     case QOF_COMPARE_LTE:
     905            0 :         return (val <= pdata->val);
     906            0 :     case QOF_COMPARE_EQUAL:
     907            0 :         return (val == pdata->val);
     908            0 :     case QOF_COMPARE_GT:
     909            0 :         return (val > pdata->val);
     910            0 :     case QOF_COMPARE_GTE:
     911            0 :         return (val >= pdata->val);
     912            0 :     case QOF_COMPARE_NEQ:
     913            0 :         return (val != pdata->val);
     914            0 :     default:
     915            0 :         PWARN ("bad match type: %d", pd->how);
     916            0 :         return 0;
     917              :     }
     918              : }
     919              : 
     920              : static int
     921            0 : int64_compare_func (gpointer a, gpointer b, gint options,
     922              :                     QofParam *getter)
     923              : {
     924              :     gint64 v1, v2;
     925            0 :     g_return_val_if_fail (a && b && getter && getter->param_getfcn, COMPARE_ERROR);
     926              : 
     927            0 :     v1 = ((query_int64_getter)getter->param_getfcn)(a, getter);
     928            0 :     v2 = ((query_int64_getter)getter->param_getfcn)(b, getter);
     929              : 
     930            0 :     if (v1 < v2) return -1;
     931            0 :     if (v1 > v2) return 1;
     932            0 :     return 0;
     933              : }
     934              : 
     935              : static void
     936            1 : int64_free_pdata (QofQueryPredData *pd)
     937              : {
     938            1 :     query_int64_t pdata = (query_int64_t)pd;
     939            1 :     VERIFY_PDATA (query_int64_type);
     940            1 :     g_free (pdata);
     941              : }
     942              : 
     943              : static QofQueryPredData *
     944            0 : int64_copy_predicate (const QofQueryPredData *pd)
     945              : {
     946            0 :     const query_int64_t pdata = (const query_int64_t)pd;
     947            0 :     VERIFY_PDATA_R (query_int64_type);
     948            0 :     return qof_query_int64_predicate (pd->how, pdata->val);
     949              : }
     950              : 
     951              : static gboolean
     952            0 : int64_predicate_equal (const QofQueryPredData *p1, const QofQueryPredData *p2)
     953              : {
     954            0 :     const query_int64_t pd1 = (const query_int64_t) p1;
     955            0 :     const query_int64_t pd2 = (const query_int64_t) p2;
     956              : 
     957            0 :     return (pd1->val == pd2->val);
     958              : }
     959              : 
     960              : QofQueryPredData *
     961            1 : qof_query_int64_predicate (QofQueryCompare how, gint64 val)
     962              : {
     963            1 :     query_int64_t pdata = g_new0 (query_int64_def, 1);
     964            1 :     pdata->pd.type_name = query_int64_type;
     965            1 :     pdata->pd.how = how;
     966            1 :     pdata->val = val;
     967            1 :     return ((QofQueryPredData*)pdata);
     968              : }
     969              : 
     970              : static char *
     971            0 : int64_to_string (gpointer object, QofParam *getter)
     972              : {
     973            0 :     gint64 num = ((query_int64_getter)getter->param_getfcn)(object, getter);
     974              : 
     975            0 :     return g_strdup_printf ("%" G_GINT64_FORMAT, num);
     976              : }
     977              : 
     978              : /* ================================================================ */
     979              : /* QOF_TYPE_DOUBLE */
     980              : 
     981              : static int
     982            0 : double_match_predicate (gpointer object, QofParam *getter,
     983              :                         QofQueryPredData *pd)
     984              : {
     985              :     double val;
     986            0 :     query_double_t pdata = (query_double_t)pd;
     987              : 
     988            0 :     VERIFY_PREDICATE (query_double_type);
     989              : 
     990            0 :     val = ((query_double_getter)getter->param_getfcn) (object, getter);
     991              : 
     992            0 :     switch (pd->how)
     993              :     {
     994            0 :     case QOF_COMPARE_LT:
     995            0 :         return (val < pdata->val);
     996            0 :     case QOF_COMPARE_LTE:
     997            0 :         return (val <= pdata->val);
     998            0 :     case QOF_COMPARE_EQUAL:
     999            0 :         return (val == pdata->val);
    1000            0 :     case QOF_COMPARE_GT:
    1001            0 :         return (val > pdata->val);
    1002            0 :     case QOF_COMPARE_GTE:
    1003            0 :         return (val >= pdata->val);
    1004            0 :     case QOF_COMPARE_NEQ:
    1005            0 :         return (val != pdata->val);
    1006            0 :     default:
    1007            0 :         PWARN ("bad match type: %d", pd->how);
    1008            0 :         return 0;
    1009              :     }
    1010              : }
    1011              : 
    1012              : static int
    1013            0 : double_compare_func (gpointer a, gpointer b, gint options,
    1014              :                      QofParam *getter)
    1015              : {
    1016              :     double v1, v2;
    1017            0 :     g_return_val_if_fail (a && b && getter && getter->param_getfcn, COMPARE_ERROR);
    1018              : 
    1019            0 :     v1 = ((query_double_getter)getter->param_getfcn) (a, getter);
    1020            0 :     v2 = ((query_double_getter)getter->param_getfcn) (b, getter);
    1021              : 
    1022            0 :     if (v1 < v2) return -1;
    1023            0 :     if (v1 > v2) return 1;
    1024            0 :     return 0;
    1025              : }
    1026              : 
    1027              : static void
    1028            1 : double_free_pdata (QofQueryPredData *pd)
    1029              : {
    1030            1 :     query_double_t pdata = (query_double_t)pd;
    1031            1 :     VERIFY_PDATA (query_double_type);
    1032            1 :     g_free (pdata);
    1033              : }
    1034              : 
    1035              : static QofQueryPredData *
    1036            0 : double_copy_predicate (const QofQueryPredData *pd)
    1037              : {
    1038            0 :     const query_double_t pdata = (const query_double_t)pd;
    1039            0 :     VERIFY_PDATA_R (query_double_type);
    1040            0 :     return qof_query_double_predicate (pd->how, pdata->val);
    1041              : }
    1042              : 
    1043              : static gboolean
    1044            0 : double_predicate_equal (const QofQueryPredData *p1, const QofQueryPredData *p2)
    1045              : {
    1046            0 :     const query_double_t pd1 = (const query_double_t) p1;
    1047            0 :     const query_double_t pd2 = (const query_double_t) p2;
    1048              : 
    1049            0 :     return (pd1->val == pd2->val);
    1050              : }
    1051              : 
    1052              : QofQueryPredData *
    1053            1 : qof_query_double_predicate (QofQueryCompare how, double val)
    1054              : {
    1055            1 :     query_double_t pdata = g_new0 (query_double_def, 1);
    1056            1 :     pdata->pd.type_name = query_double_type;
    1057            1 :     pdata->pd.how = how;
    1058            1 :     pdata->val = val;
    1059            1 :     return ((QofQueryPredData*)pdata);
    1060              : }
    1061              : 
    1062              : static char *
    1063            0 : double_to_string (gpointer object, QofParam *getter)
    1064              : {
    1065            0 :     double num = ((query_double_getter)getter->param_getfcn)(object, getter);
    1066              : 
    1067            0 :     return g_strdup_printf ("%f", num);
    1068              : }
    1069              : 
    1070              : /* QOF_TYPE_BOOLEAN =================================================== */
    1071              : 
    1072              : static int
    1073         1616 : boolean_match_predicate (gpointer object, QofParam *getter,
    1074              :                          QofQueryPredData *pd)
    1075              : {
    1076              :     gboolean val;
    1077         1616 :     query_boolean_t pdata = (query_boolean_t)pd;
    1078              : 
    1079         1616 :     VERIFY_PREDICATE (query_boolean_type);
    1080              : 
    1081         1616 :     val = ((query_boolean_getter)getter->param_getfcn) (object, getter);
    1082              : 
    1083         1616 :     switch (pd->how)
    1084              :     {
    1085         1616 :     case QOF_COMPARE_EQUAL:
    1086         1616 :         return (val == pdata->val);
    1087            0 :     case  QOF_COMPARE_NEQ:
    1088            0 :         return (val != pdata->val);
    1089            0 :     default:
    1090            0 :         PWARN ("bad match type: %d", pd->how);
    1091            0 :         return 0;
    1092              :     }
    1093              : }
    1094              : 
    1095              : static int
    1096            0 : boolean_compare_func (gpointer a, gpointer b, gint options,
    1097              :                       QofParam *getter)
    1098              : {
    1099              :     gboolean va, vb;
    1100            0 :     g_return_val_if_fail (a && b && getter && getter->param_getfcn, COMPARE_ERROR);
    1101            0 :     va = ((query_boolean_getter)getter->param_getfcn) (a, getter);
    1102            0 :     vb = ((query_boolean_getter)getter->param_getfcn) (b, getter);
    1103            0 :     if (!va && vb) return -1;
    1104            0 :     if (va && !vb) return 1;
    1105            0 :     return 0;
    1106              : }
    1107              : 
    1108              : static void
    1109          220 : boolean_free_pdata (QofQueryPredData *pd)
    1110              : {
    1111          220 :     query_boolean_t pdata = (query_boolean_t)pd;
    1112          220 :     VERIFY_PDATA (query_boolean_type);
    1113          220 :     g_free (pdata);
    1114              : }
    1115              : 
    1116              : static QofQueryPredData *
    1117          122 : boolean_copy_predicate (const QofQueryPredData *pd)
    1118              : {
    1119          122 :     const query_boolean_t pdata = (const query_boolean_t)pd;
    1120          122 :     VERIFY_PDATA_R (query_boolean_type);
    1121          122 :     return qof_query_boolean_predicate (pd->how, pdata->val);
    1122              : }
    1123              : 
    1124              : static gboolean
    1125            0 : boolean_predicate_equal (const QofQueryPredData *p1, const QofQueryPredData *p2)
    1126              : {
    1127            0 :     const query_boolean_t pd1 = (const query_boolean_t) p1;
    1128            0 :     const query_boolean_t pd2 = (const query_boolean_t) p2;
    1129              : 
    1130            0 :     return (pd1->val == pd2->val);
    1131              : }
    1132              : 
    1133              : QofQueryPredData *
    1134          220 : qof_query_boolean_predicate (QofQueryCompare how, gboolean val)
    1135              : {
    1136              :     query_boolean_t pdata;
    1137          220 :     g_return_val_if_fail (how == QOF_COMPARE_EQUAL || how == QOF_COMPARE_NEQ, nullptr);
    1138              : 
    1139          220 :     pdata = g_new0 (query_boolean_def, 1);
    1140          220 :     pdata->pd.type_name = query_boolean_type;
    1141          220 :     pdata->pd.how = how;
    1142          220 :     pdata->val = val;
    1143          220 :     return ((QofQueryPredData*)pdata);
    1144              : }
    1145              : 
    1146              : static char *
    1147            0 : boolean_to_string (gpointer object, QofParam *getter)
    1148              : {
    1149            0 :     gboolean num = ((query_boolean_getter)getter->param_getfcn)(object, getter);
    1150              : 
    1151            0 :     return g_strdup_printf ("%s", (num ? "X" : ""));
    1152              : }
    1153              : 
    1154              : /* QOF_TYPE_CHAR =================================================== */
    1155              : 
    1156              : static int
    1157        11345 : char_match_predicate (gpointer object, QofParam *getter,
    1158              :                       QofQueryPredData *pd)
    1159              : {
    1160              :     char c;
    1161        11345 :     query_char_t pdata = (query_char_t)pd;
    1162              : 
    1163        11345 :     VERIFY_PREDICATE (query_char_type);
    1164              : 
    1165        11345 :     c = ((query_char_getter)getter->param_getfcn) (object, getter);
    1166              : 
    1167        11345 :     switch (pdata->options)
    1168              :     {
    1169        11345 :     case QOF_CHAR_MATCH_ANY:
    1170        11345 :         if (strchr (pdata->char_list, c)) return 1;
    1171          401 :         return 0;
    1172            0 :     case QOF_CHAR_MATCH_NONE:
    1173            0 :         if (!strchr (pdata->char_list, c)) return 1;
    1174            0 :         return 0;
    1175            0 :     default:
    1176            0 :         PWARN ("bad match type");
    1177            0 :         return 0;
    1178              :     }
    1179              : }
    1180              : 
    1181              : static int
    1182            0 : char_compare_func (gpointer a, gpointer b, gint options, QofParam *getter)
    1183              : {
    1184              :     char va, vb;
    1185            0 :     g_return_val_if_fail (a && b && getter && getter->param_getfcn, COMPARE_ERROR);
    1186            0 :     va = ((query_char_getter)getter->param_getfcn)(a, getter);
    1187            0 :     vb = ((query_char_getter)getter->param_getfcn)(b, getter);
    1188            0 :     return (va - vb);
    1189              : }
    1190              : 
    1191              : static void
    1192         3791 : char_free_pdata (QofQueryPredData *pd)
    1193              : {
    1194         3791 :     query_char_t pdata = (query_char_t)pd;
    1195         3791 :     VERIFY_PDATA (query_char_type);
    1196         3791 :     g_free (pdata->char_list);
    1197         3791 :     g_free (pdata);
    1198              : }
    1199              : 
    1200              : static QofQueryPredData *
    1201         3068 : char_copy_predicate (const QofQueryPredData *pd)
    1202              : {
    1203         3068 :     const query_char_t pdata = (const query_char_t)pd;
    1204         3068 :     VERIFY_PDATA_R (query_char_type);
    1205         3068 :     return qof_query_char_predicate (pdata->options, pdata->char_list);
    1206              : }
    1207              : 
    1208              : static gboolean
    1209          192 : char_predicate_equal (const QofQueryPredData *p1, const QofQueryPredData *p2)
    1210              : {
    1211          192 :     const query_char_t pd1 = (const query_char_t) p1;
    1212          192 :     const query_char_t pd2 = (const query_char_t) p2;
    1213              : 
    1214          192 :     if (pd1->options != pd2->options) return FALSE;
    1215          192 :     return (g_strcmp0 (pd1->char_list, pd2->char_list) == 0);
    1216              : }
    1217              : 
    1218              : QofQueryPredData *
    1219         3791 : qof_query_char_predicate (QofCharMatch options, const char *chars)
    1220              : {
    1221              :     query_char_t pdata;
    1222         3791 :     g_return_val_if_fail (chars, nullptr);
    1223         3791 :     pdata = g_new0 (query_char_def, 1);
    1224         3791 :     pdata->pd.type_name = query_char_type;
    1225         3791 :     pdata->pd.how = QOF_COMPARE_EQUAL;
    1226         3791 :     pdata->options = options;
    1227         3791 :     pdata->char_list = g_strdup (chars);
    1228         3791 :     return ((QofQueryPredData*)pdata);
    1229              : }
    1230              : 
    1231              : gboolean
    1232            0 : qof_query_char_predicate_get_char (const QofQueryPredData *pd, char **chars)
    1233              : {
    1234            0 :     const query_char_t pdata = (const query_char_t)pd;
    1235              : 
    1236            0 :     if (pdata->pd.type_name != query_char_type)
    1237            0 :         return FALSE;
    1238              : 
    1239            0 :     *chars = g_strdup (pdata->char_list);
    1240            0 :     return TRUE;
    1241              : }
    1242              : 
    1243              : static char *
    1244            0 : char_to_string (gpointer object, QofParam *getter)
    1245              : {
    1246            0 :     char num = ((query_char_getter)getter->param_getfcn)(object, getter);
    1247              : 
    1248            0 :     return g_strdup_printf ("%c", num);
    1249              : }
    1250              : 
    1251              : 
    1252              : /* QOF_TYPE_CHOICE */
    1253              : 
    1254              : static int
    1255            0 : choice_match_predicate (gpointer object, QofParam *getter,
    1256              :                         QofQueryPredData *pd)
    1257              : {
    1258            0 :     query_choice_t pdata = (query_choice_t)pd;
    1259              :     GList *node, *o_list;
    1260            0 :     const GncGUID *guid = nullptr;
    1261              : 
    1262            0 :     VERIFY_PREDICATE (query_choice_type);
    1263              : 
    1264            0 :     switch (pdata->options)
    1265              :     {
    1266              : 
    1267            0 :     case QOF_GUID_MATCH_ALL:
    1268              :         /* object is a GList of objects; param_getfcn must be called on each one.
    1269              :          * See if every guid in the predicate is accounted-for in the
    1270              :          * object list
    1271              :          */
    1272              : 
    1273            0 :         for (node = pdata->guids; node; node = node->next)
    1274              :         {
    1275              :             /* See if this GncGUID matches the object's guid */
    1276            0 :             for (o_list = static_cast<GList*>(object); o_list;
    1277            0 :                  o_list = static_cast<GList*>(o_list->next))
    1278              :             {
    1279            0 :                 guid = ((query_choice_getter)getter->param_getfcn) (o_list->data, getter);
    1280            0 :                 if (guid_equal (static_cast<GncGUID*>(node->data), guid))
    1281            0 :                     break;
    1282              :             }
    1283              : 
    1284              :             /*
    1285              :              * If o_list is nullptr, we've walked the whole list without finding
    1286              :              * a match.  Therefore break out now, the match has failed.
    1287              :              */
    1288            0 :             if (o_list == nullptr)
    1289            0 :                 break;
    1290              :         }
    1291              : 
    1292              :         /*
    1293              :          * The match is complete.  If node == nullptr then we've successfully
    1294              :          * found a match for all the guids in the predicate.  Return
    1295              :          * appropriately below.
    1296              :          */
    1297              : 
    1298            0 :         break;
    1299              : 
    1300            0 :     case QOF_GUID_MATCH_LIST_ANY:
    1301              : 
    1302            0 :         o_list = ((query_glist_getter)getter->param_getfcn) (object, getter);
    1303              : 
    1304            0 :         for (node = o_list; node; node = node->next)
    1305              :         {
    1306              :             GList *node2;
    1307              : 
    1308            0 :             for (node2 = pdata->guids; node2; node2 = node2->next)
    1309              :             {
    1310            0 :                 if (guid_equal (static_cast<GncGUID*>(node->data),
    1311            0 :                                 static_cast<GncGUID*>(node2->data)))
    1312            0 :                     break;
    1313              :             }
    1314              : 
    1315            0 :             if (node2 != nullptr)
    1316            0 :                 break;
    1317              :         }
    1318              : 
    1319            0 :         g_list_free(o_list);
    1320              : 
    1321            0 :         break;
    1322              : 
    1323            0 :     default:
    1324              :         /* object is a single object, getter returns a GncGUID*
    1325              :          *
    1326              :          * See if the guid is in the list
    1327              :          */
    1328              : 
    1329            0 :         guid = ((query_choice_getter)getter->param_getfcn) (object, getter);
    1330            0 :         for (node = pdata->guids; node; node = node->next)
    1331              :         {
    1332            0 :             if (guid_equal (static_cast<GncGUID*>(node->data), guid))
    1333            0 :                 break;
    1334              :         }
    1335              :     }
    1336              : 
    1337            0 :     switch (pdata->options)
    1338              :     {
    1339            0 :     case QOF_GUID_MATCH_ANY:
    1340              :     case QOF_GUID_MATCH_LIST_ANY:
    1341            0 :         return (node != nullptr);
    1342              :         break;
    1343            0 :     case QOF_GUID_MATCH_NONE:
    1344              :     case QOF_GUID_MATCH_ALL:
    1345            0 :         return (node == nullptr);
    1346              :         break;
    1347            0 :     case QOF_GUID_MATCH_NULL:
    1348            0 :         return ((guid == nullptr) || guid_equal(guid, guid_null()));
    1349              :         break;
    1350            0 :     default:
    1351            0 :         PWARN ("bad match type");
    1352            0 :         return 0;
    1353              :     }
    1354              : }
    1355              : 
    1356              : static void
    1357            0 : choice_free_pdata (QofQueryPredData *pd)
    1358              : {
    1359            0 :     query_choice_t pdata = (query_choice_t)pd;
    1360              :     GList *node;
    1361            0 :     VERIFY_PDATA (query_choice_type);
    1362            0 :     for (node = pdata->guids; node; node = node->next)
    1363              :     {
    1364            0 :         guid_free (static_cast<GncGUID*>(node->data));
    1365              :     }
    1366            0 :     g_list_free (pdata->guids);
    1367            0 :     g_free (pdata);
    1368              : }
    1369              : 
    1370              : static QofQueryPredData *
    1371            0 : choice_copy_predicate (const QofQueryPredData *pd)
    1372              : {
    1373            0 :     const query_choice_t pdata = (const query_choice_t)pd;
    1374            0 :     VERIFY_PDATA_R (query_choice_type);
    1375            0 :     return qof_query_choice_predicate (pdata->options, pdata->guids);
    1376              : }
    1377              : 
    1378              : static gboolean
    1379            0 : choice_predicate_equal (const QofQueryPredData *p1, const QofQueryPredData *p2)
    1380              : {
    1381            0 :     const query_choice_t pd1 = (const query_choice_t) p1;
    1382            0 :     const query_choice_t pd2 = (const query_choice_t) p2;
    1383            0 :     GList *l1 = pd1->guids, *l2 = pd2->guids;
    1384              : 
    1385            0 :     if (pd1->options != pd2->options) return FALSE;
    1386            0 :     for (; l1 || l2; l1 = l1->next, l2 = l2->next)
    1387              :     {
    1388            0 :         if (!l1 || !l2)
    1389            0 :             return FALSE;
    1390            0 :         if (!guid_equal (static_cast<GncGUID*>(l1->data),
    1391            0 :                          static_cast<GncGUID*>(l2->data)))
    1392            0 :             return FALSE;
    1393              :     }
    1394            0 :     return TRUE;
    1395              : }
    1396              : 
    1397              : QofQueryPredData *
    1398            0 : qof_query_choice_predicate (QofGuidMatch options, GList *guid_list)
    1399              : {
    1400              :     query_choice_t pdata;
    1401              :     GList *node;
    1402              : 
    1403            0 :     if (nullptr == guid_list) return nullptr;
    1404              : 
    1405            0 :     pdata = g_new0 (query_choice_def, 1);
    1406            0 :     pdata->pd.how = QOF_COMPARE_EQUAL;
    1407            0 :     pdata->pd.type_name = query_choice_type;
    1408            0 :     pdata->options = options;
    1409              : 
    1410            0 :     pdata->guids = g_list_copy (guid_list);
    1411            0 :     for (node = pdata->guids; node; node = node->next)
    1412              :     {
    1413            0 :         GncGUID *guid = guid_malloc ();
    1414            0 :         *guid = *((GncGUID *)node->data);
    1415            0 :         node->data = guid;
    1416              :     }
    1417            0 :     return ((QofQueryPredData*)pdata);
    1418              : }
    1419              : 
    1420              : 
    1421              : /* initialization ================================================== */
    1422              : /** This function registers a new Core Object with the QofQuery
    1423              :  * subsystem.  It maps the "core_name" object to the given
    1424              :  * query_predicate, predicate_copy, and predicate_data_free functions.
    1425              :  *
    1426              :  * An example:
    1427              :  * qof_query_register_core_object (QOF_TYPE_STRING, string_match_predicate,
    1428              :  *                               string_compare_fcn, string_free_pdata,
    1429              :  *                               string_print_fcn, pred_equal_fcn);
    1430              :  */
    1431              : 
    1432              : 
    1433              : static void
    1434         1464 : qof_query_register_core_object (QofType core_name,
    1435              :                                 QofQueryPredicateFunc pred,
    1436              :                                 QofCompareFunc comp,
    1437              :                                 QueryPredicateCopyFunc copy,
    1438              :                                 QueryPredDataFree pd_free,
    1439              :                                 QueryToString toString,
    1440              :                                 QueryPredicateEqual pred_equal)
    1441              : {
    1442         1464 :     g_return_if_fail (core_name);
    1443         1464 :     g_return_if_fail (*core_name != '\0');
    1444              : 
    1445         1464 :     if (pred)
    1446         1464 :         g_hash_table_insert (predTable, (char *)core_name,
    1447              :                              reinterpret_cast<void*>(pred));
    1448              : 
    1449         1464 :     if (comp)
    1450         1220 :         g_hash_table_insert (cmpTable, (char *)core_name,
    1451              :                              reinterpret_cast<void*>(comp));
    1452              : 
    1453         1464 :     if (copy)
    1454         1464 :         g_hash_table_insert (copyTable, (char *)core_name,
    1455              :                              reinterpret_cast<void*>(copy));
    1456              : 
    1457         1464 :     if (pd_free)
    1458         1464 :         g_hash_table_insert (freeTable, (char *)core_name,
    1459              :                              reinterpret_cast<void*>(pd_free));
    1460              : 
    1461         1464 :     if (toString)
    1462         1220 :         g_hash_table_insert (toStringTable, (char *)core_name,
    1463              :                              reinterpret_cast<void*>(toString));
    1464              : 
    1465         1464 :     if (pred_equal)
    1466         1464 :         g_hash_table_insert (predEqualTable, (char *)core_name,
    1467              :                              reinterpret_cast<void*>(pred_equal));
    1468              : }
    1469              : 
    1470          122 : static void init_tables (void)
    1471              : {
    1472              :     unsigned int i;
    1473              :     struct
    1474              :     {
    1475              :         QofType                name;
    1476              :         QofQueryPredicateFunc  pred;
    1477              :         QofCompareFunc         comp;
    1478              :         QueryPredicateCopyFunc copy;
    1479              :         QueryPredDataFree      pd_free;
    1480              :         QueryToString          toString;
    1481              :         QueryPredicateEqual    pred_equal;
    1482          122 :     } knownTypes[] =
    1483              :     {
    1484              :         {
    1485              :             QOF_TYPE_STRING, string_match_predicate, string_compare_func,
    1486              :             string_copy_predicate, string_free_pdata, string_to_string,
    1487              :             string_predicate_equal
    1488              :         },
    1489              :         {
    1490              :             QOF_TYPE_NATURAL, string_match_predicate, natural_compare_func,
    1491              :             string_copy_predicate, string_free_pdata, string_to_string,
    1492              :             string_predicate_equal
    1493              :         },
    1494              :         {
    1495              :             QOF_TYPE_DATE, date_match_predicate, date_compare_func,
    1496              :             date_copy_predicate, date_free_pdata, date_to_string,
    1497              :             date_predicate_equal
    1498              :         },
    1499              :         {
    1500              :             QOF_TYPE_DEBCRED, numeric_match_predicate, numeric_compare_func,
    1501              :             numeric_copy_predicate, numeric_free_pdata, debcred_to_string,
    1502              :             numeric_predicate_equal
    1503              :         },
    1504              :         {
    1505              :             QOF_TYPE_NUMERIC, numeric_match_predicate, numeric_compare_func,
    1506              :             numeric_copy_predicate, numeric_free_pdata, numeric_to_string,
    1507              :             numeric_predicate_equal
    1508              :         },
    1509              :         {
    1510              :             QOF_TYPE_GUID, guid_match_predicate, nullptr,
    1511              :             guid_copy_predicate, guid_free_pdata, nullptr,
    1512              :             guid_predicate_equal
    1513              :         },
    1514              :         {
    1515              :             QOF_TYPE_INT32, int32_match_predicate, int32_compare_func,
    1516              :             int32_copy_predicate, int32_free_pdata, int32_to_string,
    1517              :             int32_predicate_equal
    1518              :         },
    1519              :         {
    1520              :             QOF_TYPE_INT64, int64_match_predicate, int64_compare_func,
    1521              :             int64_copy_predicate, int64_free_pdata, int64_to_string,
    1522              :             int64_predicate_equal
    1523              :         },
    1524              :         {
    1525              :             QOF_TYPE_DOUBLE, double_match_predicate, double_compare_func,
    1526              :             double_copy_predicate, double_free_pdata, double_to_string,
    1527              :             double_predicate_equal
    1528              :         },
    1529              :         {
    1530              :             QOF_TYPE_BOOLEAN, boolean_match_predicate, boolean_compare_func,
    1531              :             boolean_copy_predicate, boolean_free_pdata, boolean_to_string,
    1532              :             boolean_predicate_equal
    1533              :         },
    1534              :         {
    1535              :             QOF_TYPE_CHAR, char_match_predicate, char_compare_func,
    1536              :             char_copy_predicate, char_free_pdata, char_to_string,
    1537              :             char_predicate_equal
    1538              :         },
    1539              :         {
    1540              :             QOF_TYPE_CHOICE, choice_match_predicate, nullptr,
    1541              :             choice_copy_predicate, choice_free_pdata, nullptr, choice_predicate_equal
    1542              :         },
    1543              :     };
    1544              : 
    1545              :     /* Register the known data types */
    1546         1586 :     for (i = 0; i < (sizeof(knownTypes) / sizeof(*knownTypes)); i++)
    1547              :     {
    1548         1464 :         qof_query_register_core_object (knownTypes[i].name,
    1549              :                                         knownTypes[i].pred,
    1550              :                                         knownTypes[i].comp,
    1551              :                                         knownTypes[i].copy,
    1552              :                                         knownTypes[i].pd_free,
    1553              :                                         knownTypes[i].toString,
    1554              :                                         knownTypes[i].pred_equal);
    1555              :     }
    1556          122 : }
    1557              : 
    1558              : static QueryPredicateCopyFunc
    1559        46236 : qof_query_copy_predicate (QofType type)
    1560              : {
    1561              :     QueryPredicateCopyFunc rc;
    1562        46236 :     g_return_val_if_fail (type, nullptr);
    1563        46236 :     rc = reinterpret_cast<QueryPredicateCopyFunc>(g_hash_table_lookup (copyTable, type));
    1564        46236 :     return rc;
    1565              : }
    1566              : 
    1567              : static QueryPredDataFree
    1568        54227 : qof_query_predicate_free (QofType type)
    1569              : {
    1570        54227 :     g_return_val_if_fail (type, nullptr);
    1571        54227 :     return reinterpret_cast<QueryPredDataFree>(g_hash_table_lookup (freeTable, type));
    1572              : }
    1573              : 
    1574              : /********************************************************************/
    1575              : /* PUBLISHED API FUNCTIONS */
    1576              : 
    1577          130 : void qof_query_core_init (void)
    1578              : {
    1579              :     /* Only let us initialize once */
    1580          130 :     if (initialized) return;
    1581          122 :     initialized = TRUE;
    1582              : 
    1583              :     /* Create the tables */
    1584          122 :     predTable = g_hash_table_new (g_str_hash, g_str_equal);
    1585          122 :     cmpTable = g_hash_table_new (g_str_hash, g_str_equal);
    1586          122 :     copyTable = g_hash_table_new (g_str_hash, g_str_equal);
    1587          122 :     freeTable = g_hash_table_new (g_str_hash, g_str_equal);
    1588          122 :     toStringTable = g_hash_table_new (g_str_hash, g_str_equal);
    1589          122 :     predEqualTable = g_hash_table_new (g_str_hash, g_str_equal);
    1590              : 
    1591          122 :     init_tables ();
    1592              : }
    1593              : 
    1594           55 : void qof_query_core_shutdown (void)
    1595              : {
    1596           55 :     if (!initialized) return;
    1597           55 :     initialized = FALSE;
    1598              : 
    1599           55 :     g_hash_table_destroy (predTable);
    1600           55 :     g_hash_table_destroy (cmpTable);
    1601           55 :     g_hash_table_destroy (copyTable);
    1602           55 :     g_hash_table_destroy (freeTable);
    1603           55 :     g_hash_table_destroy (toStringTable);
    1604           55 :     g_hash_table_destroy (predEqualTable);
    1605              : }
    1606              : 
    1607              : QofQueryPredicateFunc
    1608         4685 : qof_query_core_get_predicate (QofType type)
    1609              : {
    1610         4685 :     g_return_val_if_fail (type, nullptr);
    1611         4685 :     return reinterpret_cast<QofQueryPredicateFunc>(g_hash_table_lookup (predTable, type));
    1612              : }
    1613              : 
    1614              : QofCompareFunc
    1615           66 : qof_query_core_get_compare (QofType type)
    1616              : {
    1617           66 :     g_return_val_if_fail (type, nullptr);
    1618           66 :     return reinterpret_cast<QofCompareFunc>(g_hash_table_lookup (cmpTable, type));
    1619              : }
    1620              : 
    1621              : void
    1622        54227 : qof_query_core_predicate_free (QofQueryPredData *pdata)
    1623              : {
    1624              :     QueryPredDataFree free_fcn;
    1625              : 
    1626        54227 :     g_return_if_fail (pdata);
    1627        54227 :     g_return_if_fail (pdata->type_name);
    1628              : 
    1629        54227 :     free_fcn = qof_query_predicate_free (pdata->type_name);
    1630        54227 :     free_fcn (pdata);
    1631              : }
    1632              : 
    1633              : QofQueryPredData *
    1634        46236 : qof_query_core_predicate_copy (const QofQueryPredData *pdata)
    1635              : {
    1636              :     QueryPredicateCopyFunc copy;
    1637              : 
    1638        46236 :     g_return_val_if_fail (pdata, nullptr);
    1639        46236 :     g_return_val_if_fail (pdata->type_name, nullptr);
    1640              : 
    1641        46236 :     copy = qof_query_copy_predicate (pdata->type_name);
    1642        46236 :     return (copy (pdata));
    1643              : }
    1644              : 
    1645              : char *
    1646            0 : qof_query_core_to_string (QofType type, gpointer object,
    1647              :                           QofParam *getter)
    1648              : {
    1649              :     QueryToString toString;
    1650              : 
    1651            0 :     g_return_val_if_fail (type, nullptr);
    1652            0 :     g_return_val_if_fail (object, nullptr);
    1653            0 :     g_return_val_if_fail (getter, nullptr);
    1654              : 
    1655            0 :     toString = reinterpret_cast<QueryToString>(g_hash_table_lookup (toStringTable, type));
    1656            0 :     g_return_val_if_fail (toString, nullptr);
    1657              : 
    1658            0 :     return toString (object, getter);
    1659              : }
    1660              : 
    1661              : gboolean
    1662         1809 : qof_query_core_predicate_equal (const QofQueryPredData *p1, const QofQueryPredData *p2)
    1663              : {
    1664              :     QueryPredicateEqual pred_equal;
    1665              : 
    1666         1809 :     if (p1 == p2) return TRUE;
    1667         1809 :     if (!p1 || !p2) return FALSE;
    1668              : 
    1669         1809 :     if (p1->how != p2->how) return FALSE;
    1670         1809 :     if (g_strcmp0 (p1->type_name, p2->type_name)) return FALSE;
    1671              : 
    1672         1809 :     pred_equal = reinterpret_cast<QueryPredicateEqual>(g_hash_table_lookup (predEqualTable, p1->type_name));
    1673         1809 :     g_return_val_if_fail (pred_equal, FALSE);
    1674              : 
    1675         1809 :     return pred_equal (p1, p2);
    1676              : }
        

Generated by: LCOV version 2.0-1