GnuCash  4.8a-132-gcdaeb421d+
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 = NULL;
94 static GHashTable *cmpTable = NULL;
95 static GHashTable *copyTable = NULL;
96 static GHashTable *freeTable = NULL;
97 static GHashTable *toStringTable = NULL;
98 static GHashTable *predEqualTable = NULL;
99 
100 #define COMPARE_ERROR -3
101 #define PREDICATE_ERROR -2
102 
103 #define VERIFY_PDATA(str) { \
104  g_return_if_fail (pd != NULL); \
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 != NULL, NULL); \
110  g_return_val_if_fail (pd->type_name == str || \
111  !g_strcmp0 (str, pd->type_name), \
112  NULL); \
113 }
114 #define VERIFY_PREDICATE(str) { \
115  g_return_val_if_fail (getter != NULL, PREDICATE_ERROR); \
116  g_return_val_if_fail (getter->param_getfcn != NULL, PREDICATE_ERROR); \
117  g_return_val_if_fail (pd != NULL, 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 NULL 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, NULL);
286 // g_return_val_if_fail (*str != '\0', NULL);
287  g_return_val_if_fail (how == QOF_COMPARE_CONTAINS || how == QOF_COMPARE_NCONTAINS ||
288  how == QOF_COMPARE_EQUAL || how == QOF_COMPARE_NEQ, NULL);
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 NULL;
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 NULL;
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 NULL;
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 = NULL;
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 NULL, we've walked the whole list without finding
624  * a match. Therefore break out now, the match has failed.
625  */
626  if (o_list == NULL)
627  break;
628  }
629 
630  /*
631  * The match is complete. If node == NULL 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 != NULL)
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-NULL
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 != NULL);
691  break;
692  case QOF_GUID_MATCH_NONE:
693  case QOF_GUID_MATCH_ALL:
694  return (node == NULL);
695  break;
696  case QOF_GUID_MATCH_NULL:
697  return ((guid == NULL) || 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, NULL);
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, NULL);
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, NULL);
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 static char *
1209 char_to_string (gpointer object, QofParam *getter)
1210 {
1211  char num = ((query_char_getter)getter->param_getfcn)(object, getter);
1212 
1213  return g_strdup_printf ("%c", num);
1214 }
1215 
1216 /* QOF_TYPE_COLLECT =============================================== */
1217 
1218 static int
1219 collect_match_predicate (gpointer object, QofParam *getter,
1220  QofQueryPredData *pd)
1221 {
1222  query_coll_t pdata;
1223  GList *node, *node2, *o_list;
1224  const GncGUID *guid;
1225 
1226  pdata = (query_coll_t)pd;
1227  VERIFY_PREDICATE (query_collect_type);
1228  guid = NULL;
1229  switch (pdata->options)
1230  {
1231  case QOF_GUID_MATCH_ALL :
1232  {
1233  for (node = pdata->guids; node; node = node->next)
1234  {
1235  for (o_list = static_cast<GList*>(object); o_list;
1236  o_list = static_cast<GList*>(o_list->next))
1237  {
1238  guid = ((query_guid_getter)getter->param_getfcn)
1239  (o_list->data, getter);
1240  if (guid_equal (static_cast<GncGUID*>(node->data), guid))
1241  {
1242  break;
1243  }
1244  }
1245  if (o_list == NULL)
1246  {
1247  break;
1248  }
1249  }
1250  break;
1251  }
1253  {
1254  o_list = ((query_glist_getter)getter->param_getfcn) (object, getter);
1255  for (node = o_list; node; node = node->next)
1256  {
1257  for (node2 = pdata->guids; node2; node2 = node2->next)
1258  {
1259  if (guid_equal (static_cast<GncGUID*>(node->data),
1260  static_cast<GncGUID*>(node2->data)))
1261  {
1262  break;
1263  }
1264  }
1265  if (node2 != NULL)
1266  {
1267  break;
1268  }
1269  }
1270  g_list_free(o_list);
1271  break;
1272  }
1273  default :
1274  {
1275  guid = ((query_guid_getter)getter->param_getfcn) (object, getter);
1276  for (node = pdata->guids; node; node = node->next)
1277  {
1278  if (guid_equal (static_cast<GncGUID*>(node->data), guid))
1279  {
1280  break;
1281  }
1282  }
1283  }
1284  switch (pdata->options)
1285  {
1286  case QOF_GUID_MATCH_ANY :
1288  {
1289  return (node != NULL);
1290  break;
1291  }
1292  case QOF_GUID_MATCH_NONE :
1293  case QOF_GUID_MATCH_ALL :
1294  {
1295  return (node == NULL);
1296  break;
1297  }
1298  case QOF_GUID_MATCH_NULL :
1299  {
1300  return ((guid == NULL) || guid_equal(guid, guid_null()));
1301  break;
1302  }
1303  default :
1304  {
1305  PWARN ("bad match type");
1306  return 0;
1307  }
1308  }
1309  }
1310  return 0;
1311 }
1312 
1313 static int
1314 collect_compare_func (gpointer a, gpointer b, gint options, QofParam *getter)
1315 {
1316  gint result;
1317  QofCollection *c1, *c2;
1318 
1319  c1 = ((query_collect_getter)getter->param_getfcn) (a, getter);
1320  c2 = ((query_collect_getter)getter->param_getfcn) (b, getter);
1321  result = qof_collection_compare(c1, c2);
1322  return result;
1323 }
1324 
1325 static void
1326 collect_free_pdata (QofQueryPredData *pd)
1327 {
1328  query_coll_t pdata;
1329  GList *node;
1330 
1331  node = NULL;
1332  pdata = (query_coll_t) pd;
1333  VERIFY_PDATA (query_collect_type);
1334  for (node = pdata->guids; node; node = node->next)
1335  {
1336  guid_free (static_cast<GncGUID*>(node->data));
1337  }
1338  qof_collection_destroy(pdata->coll);
1339  g_list_free (pdata->guids);
1340  g_free (pdata);
1341 }
1342 
1343 static QofQueryPredData *
1344 collect_copy_predicate (const QofQueryPredData *pd)
1345 {
1346  const query_coll_t pdata = (const query_coll_t) pd;
1347 
1348  VERIFY_PDATA_R (query_collect_type);
1349  return qof_query_collect_predicate (pdata->options, pdata->coll);
1350 }
1351 
1352 static gboolean
1353 collect_predicate_equal (const QofQueryPredData *p1, const QofQueryPredData *p2)
1354 {
1355  const query_coll_t pd1 = (const query_coll_t) p1;
1356  const query_coll_t pd2 = (const query_coll_t) p2;
1357  gint result;
1358 
1359  result = qof_collection_compare(pd1->coll, pd2->coll);
1360  if (result == 0)
1361  {
1362  return TRUE;
1363  }
1364  return FALSE;
1365 }
1366 
1367 static void
1368 query_collect_cb(QofInstance* ent, gpointer user_data)
1369 {
1370  query_coll_t pdata;
1371  GncGUID *guid;
1372 
1373  guid = (GncGUID*)qof_entity_get_guid(ent);
1374  pdata = (query_coll_t)user_data;
1375  pdata->guids = g_list_append(pdata->guids, guid);
1376 }
1377 
1378 QofQueryPredData *
1379 qof_query_collect_predicate (QofGuidMatch options, QofCollection *coll)
1380 {
1381  query_coll_t pdata;
1382 
1383  g_return_val_if_fail (coll, NULL);
1384  pdata = g_new0 (query_coll_def, 1);
1385  pdata->pd.type_name = query_collect_type;
1386  pdata->options = options;
1387  qof_collection_foreach(coll, query_collect_cb, pdata);
1388  if (NULL == pdata->guids)
1389  {
1390  return NULL;
1391  }
1392  return ((QofQueryPredData*)pdata);
1393 }
1394 
1395 /* QOF_TYPE_CHOICE */
1396 
1397 static int
1398 choice_match_predicate (gpointer object, QofParam *getter,
1399  QofQueryPredData *pd)
1400 {
1401  query_choice_t pdata = (query_choice_t)pd;
1402  GList *node, *o_list;
1403  const GncGUID *guid = NULL;
1404 
1405  VERIFY_PREDICATE (query_choice_type);
1406 
1407  switch (pdata->options)
1408  {
1409 
1410  case QOF_GUID_MATCH_ALL:
1411  /* object is a GList of objects; param_getfcn must be called on each one.
1412  * See if every guid in the predicate is accounted-for in the
1413  * object list
1414  */
1415 
1416  for (node = pdata->guids; node; node = node->next)
1417  {
1418  /* See if this GncGUID matches the object's guid */
1419  for (o_list = static_cast<GList*>(object); o_list;
1420  o_list = static_cast<GList*>(o_list->next))
1421  {
1422  guid = ((query_choice_getter)getter->param_getfcn) (o_list->data, getter);
1423  if (guid_equal (static_cast<GncGUID*>(node->data), guid))
1424  break;
1425  }
1426 
1427  /*
1428  * If o_list is NULL, we've walked the whole list without finding
1429  * a match. Therefore break out now, the match has failed.
1430  */
1431  if (o_list == NULL)
1432  break;
1433  }
1434 
1435  /*
1436  * The match is complete. If node == NULL then we've successfully
1437  * found a match for all the guids in the predicate. Return
1438  * appropriately below.
1439  */
1440 
1441  break;
1442 
1444 
1445  o_list = ((query_glist_getter)getter->param_getfcn) (object, getter);
1446 
1447  for (node = o_list; node; node = node->next)
1448  {
1449  GList *node2;
1450 
1451  for (node2 = pdata->guids; node2; node2 = node2->next)
1452  {
1453  if (guid_equal (static_cast<GncGUID*>(node->data),
1454  static_cast<GncGUID*>(node2->data)))
1455  break;
1456  }
1457 
1458  if (node2 != NULL)
1459  break;
1460  }
1461 
1462  g_list_free(o_list);
1463 
1464  break;
1465 
1466  default:
1467  /* object is a single object, getter returns a GncGUID*
1468  *
1469  * See if the guid is in the list
1470  */
1471 
1472  guid = ((query_choice_getter)getter->param_getfcn) (object, getter);
1473  for (node = pdata->guids; node; node = node->next)
1474  {
1475  if (guid_equal (static_cast<GncGUID*>(node->data), guid))
1476  break;
1477  }
1478  }
1479 
1480  switch (pdata->options)
1481  {
1482  case QOF_GUID_MATCH_ANY:
1484  return (node != NULL);
1485  break;
1486  case QOF_GUID_MATCH_NONE:
1487  case QOF_GUID_MATCH_ALL:
1488  return (node == NULL);
1489  break;
1490  case QOF_GUID_MATCH_NULL:
1491  return ((guid == NULL) || guid_equal(guid, guid_null()));
1492  break;
1493  default:
1494  PWARN ("bad match type");
1495  return 0;
1496  }
1497 }
1498 
1499 static void
1500 choice_free_pdata (QofQueryPredData *pd)
1501 {
1502  query_choice_t pdata = (query_choice_t)pd;
1503  GList *node;
1504  VERIFY_PDATA (query_choice_type);
1505  for (node = pdata->guids; node; node = node->next)
1506  {
1507  guid_free (static_cast<GncGUID*>(node->data));
1508  }
1509  g_list_free (pdata->guids);
1510  g_free (pdata);
1511 }
1512 
1513 static QofQueryPredData *
1514 choice_copy_predicate (const QofQueryPredData *pd)
1515 {
1516  const query_choice_t pdata = (const query_choice_t)pd;
1517  VERIFY_PDATA_R (query_choice_type);
1518  return qof_query_choice_predicate (pdata->options, pdata->guids);
1519 }
1520 
1521 static gboolean
1522 choice_predicate_equal (const QofQueryPredData *p1, const QofQueryPredData *p2)
1523 {
1524  const query_choice_t pd1 = (const query_choice_t) p1;
1525  const query_choice_t pd2 = (const query_choice_t) p2;
1526  GList *l1 = pd1->guids, *l2 = pd2->guids;
1527 
1528  if (pd1->options != pd2->options) return FALSE;
1529  for (; l1 || l2; l1 = l1->next, l2 = l2->next)
1530  {
1531  if (!l1 || !l2)
1532  return FALSE;
1533  if (!guid_equal (static_cast<GncGUID*>(l1->data),
1534  static_cast<GncGUID*>(l2->data)))
1535  return FALSE;
1536  }
1537  return TRUE;
1538 }
1539 
1540 QofQueryPredData *
1541 qof_query_choice_predicate (QofGuidMatch options, GList *guid_list)
1542 {
1543  query_choice_t pdata;
1544  GList *node;
1545 
1546  if (NULL == guid_list) return NULL;
1547 
1548  pdata = g_new0 (query_choice_def, 1);
1549  pdata->pd.how = QOF_COMPARE_EQUAL;
1550  pdata->pd.type_name = query_choice_type;
1551  pdata->options = options;
1552 
1553  pdata->guids = g_list_copy (guid_list);
1554  for (node = pdata->guids; node; node = node->next)
1555  {
1556  GncGUID *guid = guid_malloc ();
1557  *guid = *((GncGUID *)node->data);
1558  node->data = guid;
1559  }
1560  return ((QofQueryPredData*)pdata);
1561 }
1562 
1563 
1564 /* initialization ================================================== */
1576 static void
1577 qof_query_register_core_object (QofType core_name,
1578  QofQueryPredicateFunc pred,
1579  QofCompareFunc comp,
1580  QueryPredicateCopyFunc copy,
1581  QueryPredDataFree pd_free,
1582  QueryToString toString,
1583  QueryPredicateEqual pred_equal)
1584 {
1585  g_return_if_fail (core_name);
1586  g_return_if_fail (*core_name != '\0');
1587 
1588  if (pred)
1589  g_hash_table_insert (predTable, (char *)core_name,
1590  reinterpret_cast<void*>(pred));
1591 
1592  if (comp)
1593  g_hash_table_insert (cmpTable, (char *)core_name,
1594  reinterpret_cast<void*>(comp));
1595 
1596  if (copy)
1597  g_hash_table_insert (copyTable, (char *)core_name,
1598  reinterpret_cast<void*>(copy));
1599 
1600  if (pd_free)
1601  g_hash_table_insert (freeTable, (char *)core_name,
1602  reinterpret_cast<void*>(pd_free));
1603 
1604  if (toString)
1605  g_hash_table_insert (toStringTable, (char *)core_name,
1606  reinterpret_cast<void*>(toString));
1607 
1608  if (pred_equal)
1609  g_hash_table_insert (predEqualTable, (char *)core_name,
1610  reinterpret_cast<void*>(pred_equal));
1611 }
1612 
1613 static void init_tables (void)
1614 {
1615  unsigned int i;
1616  struct
1617  {
1618  QofType name;
1619  QofQueryPredicateFunc pred;
1620  QofCompareFunc comp;
1621  QueryPredicateCopyFunc copy;
1622  QueryPredDataFree pd_free;
1623  QueryToString toString;
1624  QueryPredicateEqual pred_equal;
1625  } knownTypes[] =
1626  {
1627  {
1628  QOF_TYPE_STRING, string_match_predicate, string_compare_func,
1629  string_copy_predicate, string_free_pdata, string_to_string,
1630  string_predicate_equal
1631  },
1632  {
1633  QOF_TYPE_DATE, date_match_predicate, date_compare_func,
1634  date_copy_predicate, date_free_pdata, date_to_string,
1635  date_predicate_equal
1636  },
1637  {
1638  QOF_TYPE_DEBCRED, numeric_match_predicate, numeric_compare_func,
1639  numeric_copy_predicate, numeric_free_pdata, debcred_to_string,
1640  numeric_predicate_equal
1641  },
1642  {
1643  QOF_TYPE_NUMERIC, numeric_match_predicate, numeric_compare_func,
1644  numeric_copy_predicate, numeric_free_pdata, numeric_to_string,
1645  numeric_predicate_equal
1646  },
1647  {
1648  QOF_TYPE_GUID, guid_match_predicate, NULL,
1649  guid_copy_predicate, guid_free_pdata, NULL,
1650  guid_predicate_equal
1651  },
1652  {
1653  QOF_TYPE_INT32, int32_match_predicate, int32_compare_func,
1654  int32_copy_predicate, int32_free_pdata, int32_to_string,
1655  int32_predicate_equal
1656  },
1657  {
1658  QOF_TYPE_INT64, int64_match_predicate, int64_compare_func,
1659  int64_copy_predicate, int64_free_pdata, int64_to_string,
1660  int64_predicate_equal
1661  },
1662  {
1663  QOF_TYPE_DOUBLE, double_match_predicate, double_compare_func,
1664  double_copy_predicate, double_free_pdata, double_to_string,
1665  double_predicate_equal
1666  },
1667  {
1668  QOF_TYPE_BOOLEAN, boolean_match_predicate, boolean_compare_func,
1669  boolean_copy_predicate, boolean_free_pdata, boolean_to_string,
1670  boolean_predicate_equal
1671  },
1672  {
1673  QOF_TYPE_CHAR, char_match_predicate, char_compare_func,
1674  char_copy_predicate, char_free_pdata, char_to_string,
1675  char_predicate_equal
1676  },
1677  {
1678  QOF_TYPE_COLLECT, collect_match_predicate, collect_compare_func,
1679  collect_copy_predicate, collect_free_pdata, NULL,
1680  collect_predicate_equal
1681  },
1682  {
1683  QOF_TYPE_CHOICE, choice_match_predicate, NULL,
1684  choice_copy_predicate, choice_free_pdata, NULL, choice_predicate_equal
1685  },
1686  };
1687 
1688  /* Register the known data types */
1689  for (i = 0; i < (sizeof(knownTypes) / sizeof(*knownTypes)); i++)
1690  {
1691  qof_query_register_core_object (knownTypes[i].name,
1692  knownTypes[i].pred,
1693  knownTypes[i].comp,
1694  knownTypes[i].copy,
1695  knownTypes[i].pd_free,
1696  knownTypes[i].toString,
1697  knownTypes[i].pred_equal);
1698  }
1699 }
1700 
1701 static QueryPredicateCopyFunc
1702 qof_query_copy_predicate (QofType type)
1703 {
1704  QueryPredicateCopyFunc rc;
1705  g_return_val_if_fail (type, NULL);
1706  rc = reinterpret_cast<QueryPredicateCopyFunc>(g_hash_table_lookup (copyTable, type));
1707  return rc;
1708 }
1709 
1710 static QueryPredDataFree
1711 qof_query_predicate_free (QofType type)
1712 {
1713  g_return_val_if_fail (type, NULL);
1714  return reinterpret_cast<QueryPredDataFree>(g_hash_table_lookup (freeTable, type));
1715 }
1716 
1717 /********************************************************************/
1718 /* PUBLISHED API FUNCTIONS */
1719 
1720 void qof_query_core_init (void)
1721 {
1722  /* Only let us initialize once */
1723  if (initialized) return;
1724  initialized = TRUE;
1725 
1726  /* Create the tables */
1727  predTable = g_hash_table_new (g_str_hash, g_str_equal);
1728  cmpTable = g_hash_table_new (g_str_hash, g_str_equal);
1729  copyTable = g_hash_table_new (g_str_hash, g_str_equal);
1730  freeTable = g_hash_table_new (g_str_hash, g_str_equal);
1731  toStringTable = g_hash_table_new (g_str_hash, g_str_equal);
1732  predEqualTable = g_hash_table_new (g_str_hash, g_str_equal);
1733 
1734  init_tables ();
1735 }
1736 
1737 void qof_query_core_shutdown (void)
1738 {
1739  if (!initialized) return;
1740  initialized = FALSE;
1741 
1742  g_hash_table_destroy (predTable);
1743  g_hash_table_destroy (cmpTable);
1744  g_hash_table_destroy (copyTable);
1745  g_hash_table_destroy (freeTable);
1746  g_hash_table_destroy (toStringTable);
1747  g_hash_table_destroy (predEqualTable);
1748 }
1749 
1750 QofQueryPredicateFunc
1751 qof_query_core_get_predicate (QofType type)
1752 {
1753  g_return_val_if_fail (type, NULL);
1754  return reinterpret_cast<QofQueryPredicateFunc>(g_hash_table_lookup (predTable, type));
1755 }
1756 
1757 QofCompareFunc
1758 qof_query_core_get_compare (QofType type)
1759 {
1760  g_return_val_if_fail (type, NULL);
1761  return reinterpret_cast<QofCompareFunc>(g_hash_table_lookup (cmpTable, type));
1762 }
1763 
1764 void
1765 qof_query_core_predicate_free (QofQueryPredData *pdata)
1766 {
1767  QueryPredDataFree free_fcn;
1768 
1769  g_return_if_fail (pdata);
1770  g_return_if_fail (pdata->type_name);
1771 
1772  free_fcn = qof_query_predicate_free (pdata->type_name);
1773  free_fcn (pdata);
1774 }
1775 
1776 QofQueryPredData *
1777 qof_query_core_predicate_copy (const QofQueryPredData *pdata)
1778 {
1779  QueryPredicateCopyFunc copy;
1780 
1781  g_return_val_if_fail (pdata, NULL);
1782  g_return_val_if_fail (pdata->type_name, NULL);
1783 
1784  copy = qof_query_copy_predicate (pdata->type_name);
1785  return (copy (pdata));
1786 }
1787 
1788 char *
1789 qof_query_core_to_string (QofType type, gpointer object,
1790  QofParam *getter)
1791 {
1792  QueryToString toString;
1793 
1794  g_return_val_if_fail (type, NULL);
1795  g_return_val_if_fail (object, NULL);
1796  g_return_val_if_fail (getter, NULL);
1797 
1798  toString = reinterpret_cast<QueryToString>(g_hash_table_lookup (toStringTable, type));
1799  g_return_val_if_fail (toString, NULL);
1800 
1801  return toString (object, getter);
1802 }
1803 
1804 gboolean
1805 qof_query_core_predicate_equal (const QofQueryPredData *p1, const QofQueryPredData *p2)
1806 {
1807  QueryPredicateEqual pred_equal;
1808 
1809  if (p1 == p2) return TRUE;
1810  if (!p1 || !p2) return FALSE;
1811 
1812  if (p1->how != p2->how) return FALSE;
1813  if (g_strcmp0 (p1->type_name, p2->type_name)) return FALSE;
1814 
1815  pred_equal = reinterpret_cast<QueryPredicateEqual>(g_hash_table_lookup (predEqualTable, p1->type_name));
1816  g_return_val_if_fail (pred_equal, FALSE);
1817 
1818  return pred_equal (p1, p2);
1819 }
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:101
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:158
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
Round to the nearest integer, rounding away from zero when there are two equidistant nearest integers...
Definition: gnc-numeric.h:166
void qof_collection_foreach(const QofCollection *col, QofInstanceForeachCB cb_func, gpointer user_data)
Call the callback for each entity in the collection.
Definition: qofid.cpp:323
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:177
#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:617
QofGuidMatch
Definition: qofquerycore.h:109
GncGUID * guid_malloc(void)
Allocate memory for a GUID.
Definition: guid.cpp:105
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:62
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:131
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
gint64 time64
Many systems, including Microsoft Windows and BSD-derived Unixes like Darwin, are retaining the int-3...
Definition: gnc-date.h:93
time64 time64CanonicalDayTime(time64 t)
convert a time64 on a certain day (localtime) to the time64 representing midday on that day...
Definition: gnc-date.cpp:413
QofQueryPredData * qof_query_core_predicate_copy(const QofQueryPredData *pdata)
Copy a predicate.
#define QOF_TYPE_CHOICE
Identify an object as containing a choice.
Definition: qofchoice.h:108
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