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