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